1 package fr.ifremer.quadrige3.synchro.server.pages.admin;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import fr.ifremer.quadrige3.core.vo.administration.program.ProgramVO;
27 import fr.ifremer.quadrige3.synchro.server.application.WebSession;
28 import fr.ifremer.quadrige3.synchro.server.pages.BasePage;
29 import fr.ifremer.quadrige3.synchro.server.service.ServiceLocator;
30 import fr.ifremer.quadrige3.synchro.server.service.synchro.ReferentialSynchroService;
31 import org.apache.commons.collections4.SetUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.wicket.ajax.AjaxRequestTarget;
35 import org.apache.wicket.ajax.attributes.AjaxCallListener;
36 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
37 import org.apache.wicket.ajax.markup.html.form.AjaxButton;
38 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
39 import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
40 import org.apache.wicket.extensions.markup.html.form.palette.Palette;
41 import org.apache.wicket.extensions.markup.html.form.palette.theme.DefaultTheme;
42 import org.apache.wicket.markup.html.basic.Label;
43 import org.apache.wicket.markup.html.form.ChoiceRenderer;
44 import org.apache.wicket.markup.html.form.Form;
45 import org.apache.wicket.model.CompoundPropertyModel;
46 import org.apache.wicket.model.IModel;
47 import org.apache.wicket.model.LoadableDetachableModel;
48 import org.apache.wicket.model.StringResourceModel;
49 import org.apache.wicket.request.mapper.parameter.PageParameters;
50
51 import java.util.*;
52 import java.util.stream.Collectors;
53
54 @AuthorizeInstantiation("ROLE_ADMIN")
55 public class ConfigPage extends BasePage {
56 private static final long serialVersionUID = 1L;
57 private static final Log log = LogFactory.getLog(ConfigPage.class);
58
59 private boolean confirmPanelVisible = false;
60
61 private Set<String> synchroProgramCodeIncludes;
62
63 private List<ProgramVO> availablePrograms;
64 private List<ProgramVO> selectedPrograms;
65
66 public ConfigPage(final PageParameters parameters) {
67 super(parameters);
68
69
70 loadConfig();
71
72 IModel<ConfigPage> model = new CompoundPropertyModel<>(this);
73 Form<ConfigPage> form = new Form<>("form", model);
74 form.setOutputMarkupId(true);
75 add(form);
76
77 Palette<ProgramVO> programsPalette = new Palette<>("programsPalette",
78 new LoadableDetachableModel<List<ProgramVO>>() {
79 @Override
80 protected List<ProgramVO> load() {
81 return selectedPrograms;
82 }
83 },
84 new LoadableDetachableModel<List<ProgramVO>>() {
85 @Override
86 protected List<ProgramVO> load() {
87 return availablePrograms;
88 }
89 },
90 new ChoiceRenderer<>("progCd", "progCd"),
91 10,
92 false,
93 false
94 );
95 programsPalette.add(new DefaultTheme());
96 form.add(programsPalette);
97
98
99 Label confirmMessage = new Label("confirmMessage", new LoadableDetachableModel<String>() {
100 @Override
101 protected String load() {
102 return getConfirmationMessage();
103 }
104 }) {
105 @Override
106 public boolean isVisible() {
107 return confirmPanelVisible;
108 }
109 };
110 confirmMessage.setOutputMarkupPlaceholderTag(true);
111 confirmMessage.setEscapeModelStrings(false);
112 form.add(confirmMessage);
113
114 AjaxButton cancelButton = new AjaxButton("cancelButton", form) {
115 @Override
116 public boolean isVisible() {
117 return confirmPanelVisible;
118 }
119
120 @Override
121 protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
122 confirmPanelVisible = false;
123 loadConfig();
124 target.add(ConfigPage.this);
125 }
126 };
127 cancelButton.setOutputMarkupPlaceholderTag(true);
128 form.add(cancelButton);
129
130 AjaxButton confirmButton = new IndicatingAjaxButton("confirmButton", form) {
131 @Override
132 public boolean isVisible() {
133 return confirmPanelVisible;
134 }
135
136 @Override
137 protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
138 confirmPanelVisible = false;
139 saveConfig();
140 target.add(ConfigPage.this);
141 }
142
143 @Override
144 protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
145 super.updateAjaxAttributes(attributes);
146 attributes.getAjaxCallListeners().add(new AjaxCallListener()
147 .onBefore(String.format("$('#%s').hide();$('#%s').hide()", getMarkupId(), cancelButton.getMarkupId())));
148 }
149 };
150 confirmButton.setOutputMarkupPlaceholderTag(true);
151 form.add(confirmButton);
152
153
154 AjaxButton applyButton = new IndicatingAjaxButton("applyButton", form) {
155 private static final long serialVersionUID = 1L;
156
157 @Override
158 public boolean isVisible() {
159 return !confirmPanelVisible;
160 }
161
162 @Override
163 protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
164 ConfigPage.this.getWebSession().getFeedbackMessages().clear();
165 if (getConfirmationMessage().isEmpty()) {
166 saveConfig();
167 } else {
168 confirmPanelVisible = true;
169 }
170 target.add(ConfigPage.this);
171 }
172
173 @Override
174 protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
175 super.updateAjaxAttributes(attributes);
176 attributes.getAjaxCallListeners().add(new AjaxCallListener()
177 .onBefore(String.format("$('#%s').hide()", getMarkupId())));
178 }
179 };
180 applyButton.setOutputMarkupPlaceholderTag(true);
181 form.add(applyButton);
182 }
183
184 private String getConfirmationMessage() {
185
186 StringBuilder message = new StringBuilder();
187
188 Set<String> programCodesToRemove = getProgramCodesToRemove();
189 if (!programCodesToRemove.isEmpty()) {
190 String messageRemove = new StringResourceModel("config.confirmRemove").getString();
191 message.append(messageRemove).append(listify(programCodesToRemove));
192 }
193
194 return message.toString();
195 }
196
197 private Set<String> getProgramCodesToRemove() {
198
199 Set<String> programCodesToRemove = new HashSet<>(synchroProgramCodeIncludes);
200 programCodesToRemove.removeAll(selectedPrograms.stream().map(ProgramVO::getProgCd).collect(Collectors.toSet()));
201 return programCodesToRemove;
202 }
203
204 private String listify(Collection<String> strings) {
205 StringJoiner joiner = new StringJoiner("</li><li>", "<ul><li>", "</li></ul>");
206 strings.forEach(joiner::add);
207 return joiner.toString();
208 }
209
210 private void saveConfig() {
211
212
213 Set<String> selectedProgramCodes = selectedPrograms.stream()
214 .map(ProgramVO::getProgCd).sorted().collect(Collectors.toCollection(LinkedHashSet::new));
215
216
217 if (SetUtils.isEqualSet(synchroProgramCodeIncludes, selectedProgramCodes)) {
218 return;
219 }
220
221 try {
222
223 ServiceLocator.instance().getProgramService().saveUpdateDate(selectedProgramCodes);
224
225 ServiceLocator.instance().getCacheService().clearCache(ReferentialSynchroService.REFERENTIAL_UPDATE_DATE_CACHE);
226
227
228 getConfiguration().setSynchroProgramCodeIncludes(selectedProgramCodes);
229
230 getConfiguration().save();
231
232
233 ServiceLocator.instance().getReferentialSynchroService().updateMetadata();
234
235
236 String message = new StringResourceModel("config.saved", ConfigPage.this, null).getString();
237 info(message);
238 log.info(message);
239 log.info(String.format("%s : %s", new StringResourceModel("config.compatiblePrograms", ConfigPage.this, null).getString(), selectedProgramCodes));
240
241 } catch (Exception e) {
242 log.error(e.getLocalizedMessage(), e);
243 info(e.getLocalizedMessage());
244 }
245
246
247 loadConfig();
248
249 }
250
251 private void loadConfig() {
252 availablePrograms = ServiceLocator.instance().getProgramService().getAll();
253 availablePrograms.sort(Comparator.comparing(ProgramVO::getProgCd));
254 synchroProgramCodeIncludes = getConfiguration().getSynchroProgramCodeIncludes();
255 selectedPrograms = synchroProgramCodeIncludes.stream().sorted()
256 .map(s -> new ProgramVO(s, null, null))
257 .collect(Collectors.toList());
258 }
259
260
261
262 protected IModel<String> getTitleModel() {
263 return new StringResourceModel("config.title", this, null);
264 }
265
266 protected WebSession getWebSession() {
267 return (WebSession) getSession();
268 }
269
270 }