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.wizards.any;
20  
21  import java.io.Serializable;
22  import java.util.List;
23  import java.util.Optional;
24  import java.util.concurrent.Callable;
25  import java.util.concurrent.Future;
26  import org.apache.commons.lang3.tuple.Pair;
27  import org.apache.syncope.client.console.SyncopeConsoleSession;
28  import org.apache.syncope.client.console.SyncopeWebApplication;
29  import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
30  import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
31  import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
32  import org.apache.syncope.client.ui.commons.layout.AbstractAnyFormLayout;
33  import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
34  import org.apache.syncope.client.ui.commons.wizards.any.AbstractAnyWizardBuilder;
35  import org.apache.syncope.client.ui.commons.wizards.any.AnyForm;
36  import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
37  import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper;
38  import org.apache.syncope.common.lib.Attr;
39  import org.apache.syncope.common.lib.to.AnyObjectTO;
40  import org.apache.syncope.common.lib.to.AnyTO;
41  import org.apache.syncope.common.lib.to.GroupTO;
42  import org.apache.syncope.common.lib.to.GroupableRelatableTO;
43  import org.apache.syncope.common.lib.to.UserTO;
44  import org.apache.wicket.PageReference;
45  import org.apache.wicket.extensions.wizard.WizardModel;
46  
47  public abstract class AnyWizardBuilder<A extends AnyTO> extends AbstractAnyWizardBuilder<A> {
48  
49      private static final long serialVersionUID = -2480279868319546243L;
50  
51      @SuppressWarnings("unchecked")
52      protected static <T extends AnyTO> AnyWrapper<T> wrapper(final T anyTO) {
53          return (AnyWrapper<T>) (anyTO instanceof UserTO
54                  ? new UserWrapper((UserTO) anyTO)
55                  : anyTO instanceof GroupTO
56                          ? new GroupWrapper((GroupTO) anyTO)
57                          : new AnyObjectWrapper((AnyObjectTO) anyTO));
58      }
59  
60      protected final List<String> anyTypeClasses;
61  
62      protected AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo;
63  
64      /**
65       * Construct.
66       *
67       * @param anyTO any
68       * @param anyTypeClasses any type classes
69       * @param formLayoutInfo form layout info
70       * @param pageRef caller page reference.
71       */
72      public AnyWizardBuilder(
73              final A anyTO,
74              final List<String> anyTypeClasses,
75              final AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo,
76              final PageReference pageRef) {
77  
78          super(wrapper(anyTO), pageRef);
79          this.anyTypeClasses = anyTypeClasses;
80          this.formLayoutInfo = formLayoutInfo;
81      }
82  
83      /**
84       * Construct.
85       *
86       * @param wrapper any wrapper
87       * @param anyTypeClasses any type classes
88       * @param formLayoutInfo form layout info
89       * @param pageRef caller page reference.
90       */
91      public AnyWizardBuilder(
92              final AnyWrapper<A> wrapper,
93              final List<String> anyTypeClasses,
94              final AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo,
95              final PageReference pageRef) {
96  
97          super(wrapper, pageRef);
98          this.anyTypeClasses = anyTypeClasses;
99          this.formLayoutInfo = formLayoutInfo;
100     }
101 
102     @Override
103     protected WizardModel buildModelSteps(final AnyWrapper<A> modelObject, final WizardModel wizardModel) {
104         // optional details panel step
105         addOptionalDetailsPanel(modelObject).ifPresent(wizardModel::add);
106 
107         if ((this instanceof GroupWizardBuilder)
108                 && (modelObject.getInnerObject() instanceof GroupTO)
109                 && (formLayoutInfo instanceof GroupFormLayoutInfo)) {
110 
111             GroupFormLayoutInfo groupFormLayoutInfo = GroupFormLayoutInfo.class.cast(formLayoutInfo);
112             if (groupFormLayoutInfo.isOwnership()) {
113                 wizardModel.add(new Ownership(GroupWrapper.class.cast(modelObject), pageRef));
114             }
115             if (groupFormLayoutInfo.isDynamicMemberships()) {
116                 wizardModel.add(new DynamicMemberships(GroupWrapper.class.cast(modelObject), pageRef));
117             }
118         }
119 
120         if (formLayoutInfo.isAuxClasses()) {
121             wizardModel.add(new ConsoleAuxClasses(modelObject, anyTypeClasses));
122         }
123 
124         if (formLayoutInfo.isGroups()) {
125             wizardModel.add(new Groups(modelObject, mode == AjaxWizard.Mode.TEMPLATE));
126         }
127 
128         // attributes panel steps
129         if (formLayoutInfo.isPlainAttrs()) {
130             wizardModel.add(
131                     new PlainAttrs(modelObject, mode, anyTypeClasses, formLayoutInfo.getWhichPlainAttrs()) {
132 
133                 private static final long serialVersionUID = 8167894751609598306L;
134 
135                 @Override
136                 public PageReference getPageReference() {
137                     return pageRef;
138                 }
139             });
140         }
141         if (formLayoutInfo.isDerAttrs() && mode != AjaxWizard.Mode.TEMPLATE) {
142             wizardModel.add(new DerAttrs(modelObject, anyTypeClasses, formLayoutInfo.getWhichDerAttrs()));
143         }
144         if (formLayoutInfo.isVirAttrs()) {
145             wizardModel.add(new VirAttrs(modelObject, mode, anyTypeClasses, formLayoutInfo.getWhichVirAttrs()));
146         }
147 
148         // role panel step (just available for users)
149         if ((this instanceof UserWizardBuilder)
150                 && modelObject instanceof UserWrapper
151                 && formLayoutInfo instanceof UserFormLayoutInfo
152                 && UserFormLayoutInfo.class.cast(formLayoutInfo).isRoles()) {
153 
154             wizardModel.add(new Roles((UserWrapper) modelObject));
155         }
156 
157         // relationship panel step (available for users and any objects)
158         if ((formLayoutInfo instanceof UserFormLayoutInfo
159                 && UserFormLayoutInfo.class.cast(formLayoutInfo).isRelationships())
160                 || (formLayoutInfo instanceof AnyObjectFormLayoutInfo
161                 && AnyObjectFormLayoutInfo.class.cast(formLayoutInfo).isRelationships())) {
162 
163             wizardModel.add(new Relationships(modelObject, pageRef));
164         }
165 
166         SyncopeWebApplication.get().getAnyWizardBuilderAdditionalSteps().
167                 buildModelSteps(modelObject, wizardModel, formLayoutInfo);
168 
169         return wizardModel;
170     }
171 
172     protected Optional<Details<A>> addOptionalDetailsPanel(final AnyWrapper<A> modelObject) {
173         if (modelObject.getInnerObject().getKey() == null) {
174             return Optional.empty();
175         } else {
176             return Optional.of(new Details<>(modelObject, mode == AjaxWizard.Mode.TEMPLATE, true, pageRef));
177         }
178     }
179 
180     @Override
181     protected void fixPlainAndVirAttrs(final AnyTO updated, final AnyTO original) {
182         // re-add to the updated object any missing plain or virtual attribute (compared to original): this to cope with
183         // form layout, which might have not included some plain or virtual attributes
184         for (Attr plainAttr : original.getPlainAttrs()) {
185             if (updated.getPlainAttr(plainAttr.getSchema()).isEmpty()) {
186                 updated.getPlainAttrs().add(plainAttr);
187             }
188         }
189         for (Attr virAttr : original.getVirAttrs()) {
190             if (updated.getVirAttr(virAttr.getSchema()).isEmpty()) {
191                 updated.getVirAttrs().add(virAttr);
192             }
193         }
194 
195         if (updated instanceof GroupableRelatableTO && original instanceof GroupableRelatableTO) {
196             GroupableRelatableTO.class.cast(original).getMemberships().
197                     forEach(oMemb -> GroupableRelatableTO.class.cast(updated).getMembership(oMemb.getGroupKey()).
198                     ifPresent(uMemb -> {
199                         oMemb.getPlainAttrs().stream().
200                                 filter(attr -> uMemb.getPlainAttr(attr.getSchema()).isEmpty()).
201                                 forEach(attr -> uMemb.getPlainAttrs().add(attr));
202                         oMemb.getVirAttrs().stream().
203                                 filter(attr -> uMemb.getVirAttr(attr.getSchema()).isEmpty()).
204                                 forEach(attr -> uMemb.getVirAttrs().add(attr));
205                     }));
206         }
207 
208         // remove from the updated object any plain or virtual attribute without values, thus triggering for removal in
209         // the generated patch
210         updated.getPlainAttrs().removeIf(attr -> attr.getValues().isEmpty());
211         updated.getVirAttrs().removeIf(attr -> attr.getValues().isEmpty());
212         if (updated instanceof GroupableRelatableTO) {
213             GroupableRelatableTO.class.cast(updated).getMemberships().forEach(memb -> {
214                 memb.getPlainAttrs().removeIf(attr -> attr.getValues().isEmpty());
215                 memb.getVirAttrs().removeIf(attr -> attr.getValues().isEmpty());
216             });
217         }
218     }
219 
220     @Override
221     protected long getMaxWaitTimeInSeconds() {
222         return SyncopeWebApplication.get().getMaxWaitTimeInSeconds();
223     }
224 
225     @Override
226     protected void sendError(final Exception exception) {
227         SyncopeConsoleSession.get().onException(exception);
228     }
229 
230     @Override
231     protected void sendWarning(final String message) {
232         SyncopeConsoleSession.get().warn(message);
233     }
234 
235     @Override
236     protected Future<Pair<Serializable, Serializable>> execute(
237             final Callable<Pair<Serializable, Serializable>> future) {
238 
239         return SyncopeConsoleSession.get().execute(future);
240     }
241 }