1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.panels;
20
21 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
22 import java.io.IOException;
23 import java.io.Serializable;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.Future;
30 import javax.ws.rs.core.MediaType;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.commons.lang3.tuple.Pair;
33 import org.apache.syncope.client.console.SyncopeConsoleSession;
34 import org.apache.syncope.client.console.SyncopeWebApplication;
35 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
36 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
37 import org.apache.syncope.client.console.pages.BasePage;
38 import org.apache.syncope.client.console.pages.ModelerPopupPage;
39 import org.apache.syncope.client.console.panels.BpmnProcessDirectoryPanel.BpmProcessDataProvider;
40 import org.apache.syncope.client.console.rest.BpmnProcessRestClient;
41 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
42 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
43 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
44 import org.apache.syncope.client.console.wicket.markup.html.form.ImageModalPanel;
45 import org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
46 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
47 import org.apache.syncope.client.ui.commons.Constants;
48 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
49 import org.apache.syncope.client.ui.commons.wizards.AjaxWizardBuilder;
50 import org.apache.syncope.common.lib.SyncopeClientException;
51 import org.apache.syncope.common.lib.to.BpmnProcess;
52 import org.apache.syncope.common.lib.types.FlowableEntitlement;
53 import org.apache.wicket.Page;
54 import org.apache.wicket.PageReference;
55 import org.apache.wicket.ajax.AjaxRequestTarget;
56 import org.apache.wicket.ajax.markup.html.AjaxLink;
57 import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
58 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
59 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
60 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
61 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
62 import org.apache.wicket.extensions.wizard.WizardModel;
63 import org.apache.wicket.markup.html.WebMarkupContainer;
64 import org.apache.wicket.model.CompoundPropertyModel;
65 import org.apache.wicket.model.IModel;
66 import org.apache.wicket.model.Model;
67 import org.apache.wicket.model.ResourceModel;
68 import org.apache.wicket.request.mapper.parameter.PageParameters;
69 import org.apache.wicket.util.io.IOUtils;
70
71 public class BpmnProcessDirectoryPanel extends DirectoryPanel<
72 BpmnProcess, BpmnProcess, BpmProcessDataProvider, BpmnProcessRestClient> {
73
74 private static final long serialVersionUID = 2705668831139984998L;
75
76 private static final String PREF_WORKFLOW_PAGINATOR_ROWS = "workflow.paginator.rows";
77
78 private static final String FLOWABLE_MODELER_CTX = "flowable-modeler";
79
80 private final BaseModal<String> utility;
81
82 protected BpmnProcessDirectoryPanel(final String id, final Builder builder) {
83 super(id, builder);
84
85 this.addNewItemPanelBuilder(new AjaxWizardBuilder<BpmnProcess>(new BpmnProcess(), pageRef) {
86
87 private static final long serialVersionUID = 1633859795677053912L;
88
89 @Override
90 protected WizardModel buildModelSteps(final BpmnProcess modelObject, final WizardModel wizardModel) {
91 return wizardModel;
92 }
93
94 @Override
95 protected long getMaxWaitTimeInSeconds() {
96 return SyncopeWebApplication.get().getMaxWaitTimeInSeconds();
97 }
98
99 @Override
100 protected void sendError(final Exception exception) {
101 SyncopeConsoleSession.get().onException(exception);
102 }
103
104 @Override
105 protected void sendWarning(final String message) {
106 SyncopeConsoleSession.get().warn(message);
107 }
108
109 @Override
110 protected Future<Pair<Serializable, Serializable>> execute(
111 final Callable<Pair<Serializable, Serializable>> future) {
112 return SyncopeConsoleSession.get().execute(future);
113 }
114 }, false);
115 NewBpmnProcess newBpmnProcess = new NewBpmnProcess("newBpmnProcess", container, pageRef);
116 addInnerObject(newBpmnProcess);
117 AjaxLink<Void> newBpmnProcessLink = new AjaxLink<>("add") {
118
119 private static final long serialVersionUID = -7978723352517770644L;
120
121 @Override
122 public void onClick(final AjaxRequestTarget target) {
123 newBpmnProcess.toggle(target, true);
124 }
125 };
126 ((WebMarkupContainer) get("container:content")).addOrReplace(newBpmnProcessLink);
127
128 setShowResultPanel(true);
129
130 modal.size(Modal.Size.Large);
131
132 utility = new BaseModal<>("outer");
133 addOuterObject(utility);
134 utility.size(Modal.Size.Large);
135 AjaxSubmitLink xmlEditorSubmit = utility.addSubmitButton();
136 MetaDataRoleAuthorizationStrategy.authorize(xmlEditorSubmit, RENDER, FlowableEntitlement.BPMN_PROCESS_SET);
137 utility.setWindowClosedCallback(target -> {
138 utility.show(false);
139 utility.close(target);
140 });
141 initResultTable();
142 }
143
144 @Override
145 protected BpmProcessDataProvider dataProvider() {
146 return new BpmProcessDataProvider(rows);
147 }
148
149 @Override
150 protected String paginatorRowsKey() {
151 return PREF_WORKFLOW_PAGINATOR_ROWS;
152 }
153
154 @Override
155 protected List<IColumn<BpmnProcess, String>> getColumns() {
156 List<IColumn<BpmnProcess, String>> columns = new ArrayList<>();
157
158 columns.add(new PropertyColumn<>(new ResourceModel("key"), "key"));
159 columns.add(new PropertyColumn<>(new ResourceModel("name"), "name", "name"));
160
161 return columns;
162 }
163
164 @Override
165 public ActionsPanel<BpmnProcess> getActions(final IModel<BpmnProcess> model) {
166 final ActionsPanel<BpmnProcess> panel = super.getActions(model);
167
168 panel.add(new ActionLink<>() {
169
170 private static final long serialVersionUID = -184018732772021627L;
171
172 @Override
173 public void onClick(final AjaxRequestTarget target, final BpmnProcess ignore) {
174 final IModel<String> wfDefinition = new Model<>();
175 try {
176 wfDefinition.setObject(IOUtils.toString(restClient.getDefinition(
177 MediaType.APPLICATION_XML_TYPE, model.getObject().getKey())));
178 } catch (IOException e) {
179 LOG.error("Could not get workflow definition", e);
180 }
181
182 utility.header(Model.of(model.getObject().getKey()));
183 utility.setContent(new XMLEditorPanel(utility, wfDefinition, false, pageRef) {
184
185 private static final long serialVersionUID = -7688359318035249200L;
186
187 @Override
188 public void onSubmit(final AjaxRequestTarget target) {
189 if (StringUtils.isNotBlank(wfDefinition.getObject())) {
190 try {
191 restClient.setDefinition(MediaType.APPLICATION_XML_TYPE,
192 model.getObject().getKey(), wfDefinition.getObject());
193 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
194
195 target.add(container);
196 utility.show(false);
197 utility.close(target);
198 } catch (SyncopeClientException e) {
199 SyncopeConsoleSession.get().onException(e);
200 }
201 ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
202 }
203 }
204 });
205 utility.show(target);
206 target.add(utility);
207 }
208 }, ActionLink.ActionType.EDIT, FlowableEntitlement.BPMN_PROCESS_SET);
209
210 panel.add(new ActionLink<>() {
211
212 private static final long serialVersionUID = 3109256773218160485L;
213
214 @Override
215 public void onClick(final AjaxRequestTarget target, final BpmnProcess ignore) {
216 modal.header(Model.of(model.getObject().getKey()));
217 modal.setContent(new ImageModalPanel<>(
218 modal, restClient.getDiagram(model.getObject().getKey()), pageRef));
219 modal.show(target);
220 target.add(modal);
221 }
222 }, ActionLink.ActionType.VIEW, FlowableEntitlement.BPMN_PROCESS_GET);
223
224 panel.add(new ActionLink<>() {
225
226 private static final long serialVersionUID = -184018732772021627L;
227
228 @Override
229 public Class<? extends Page> getPageClass() {
230 return ModelerPopupPage.class;
231 }
232
233 @Override
234 public PageParameters getPageParameters() {
235 PageParameters parameters = new PageParameters();
236 parameters.add(Constants.MODELER_CONTEXT, FLOWABLE_MODELER_CTX);
237 parameters.add(Constants.MODEL_ID_PARAM, model.getObject().getModelId());
238
239 return parameters;
240 }
241
242 @Override
243 public void onClick(final AjaxRequestTarget target, final BpmnProcess ignore) {
244
245 }
246 }, ActionLink.ActionType.EXTERNAL_EDITOR, FlowableEntitlement.BPMN_PROCESS_SET);
247
248 panel.add(new ActionLink<>() {
249
250 private static final long serialVersionUID = -7978723352517770644L;
251
252 @Override
253 protected boolean statusCondition(final BpmnProcess modelObject) {
254 return !modelObject.isUserWorkflow();
255 }
256
257 @Override
258 public void onClick(final AjaxRequestTarget target, final BpmnProcess ignore) {
259 try {
260 restClient.deleteDefinition(model.getObject().getKey());
261 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
262 target.add(container);
263 } catch (SyncopeClientException e) {
264 LOG.error("While deleting BPMN definition {}", model.getObject().getName(), e);
265 SyncopeConsoleSession.get().onException(e);
266 }
267 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
268 }
269 }, ActionLink.ActionType.DELETE, FlowableEntitlement.BPMN_PROCESS_DELETE, true);
270
271 return panel;
272 }
273
274 @Override
275 protected Collection<ActionLink.ActionType> getBatches() {
276 return List.of();
277 }
278
279 protected class BpmProcessDataProvider extends DirectoryDataProvider<BpmnProcess> {
280
281 private static final long serialVersionUID = 1764153405387687592L;
282
283 private final SortableDataProviderComparator<BpmnProcess> comparator;
284
285 public BpmProcessDataProvider(final int paginatorRows) {
286 super(paginatorRows);
287 this.comparator = new SortableDataProviderComparator<>(this);
288 setSort("key", SortOrder.ASCENDING);
289 }
290
291 @Override
292 public Iterator<BpmnProcess> iterator(final long first, final long count) {
293 List<BpmnProcess> result = restClient.getDefinitions();
294 result.sort(comparator);
295 return result.subList((int) first, (int) first + (int) count).iterator();
296 }
297
298 @Override
299 public long size() {
300 return restClient.getDefinitions().size();
301 }
302
303 @Override
304 public IModel<BpmnProcess> model(final BpmnProcess object) {
305 return new CompoundPropertyModel<>(object);
306 }
307 }
308
309 public abstract static class Builder
310 extends DirectoryPanel.Builder<BpmnProcess, BpmnProcess, BpmnProcessRestClient> {
311
312 private static final long serialVersionUID = 5088962796986706805L;
313
314 public Builder(final BpmnProcessRestClient restClient, final PageReference pageRef) {
315 super(restClient, pageRef);
316 }
317
318 @Override
319 protected WizardMgtPanel<BpmnProcess> newInstance(final String id, final boolean wizardInModal) {
320 return new BpmnProcessDirectoryPanel(id, this);
321 }
322 }
323 }