View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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                 // do nothing
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 }