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 de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
23  import java.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Optional;
27  import java.util.stream.Collectors;
28  import org.apache.commons.lang3.StringUtils;
29  import org.apache.commons.lang3.tuple.Pair;
30  import org.apache.syncope.client.console.SyncopeWebApplication;
31  import org.apache.syncope.client.console.commons.ITabComponent;
32  import org.apache.syncope.client.console.layout.AnyLayout;
33  import org.apache.syncope.client.console.layout.AnyLayoutUtils;
34  import org.apache.syncope.client.console.rest.RealmRestClient;
35  import org.apache.syncope.client.console.rest.RoleRestClient;
36  import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
37  import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
38  import org.apache.syncope.client.console.wizards.WizardMgtPanel;
39  import org.apache.syncope.client.console.wizards.any.ConnObjectPanel;
40  import org.apache.syncope.client.ui.commons.ConnIdSpecialName;
41  import org.apache.syncope.client.ui.commons.Constants;
42  import org.apache.syncope.client.ui.commons.status.StatusUtils;
43  import org.apache.syncope.common.lib.SyncopeConstants;
44  import org.apache.syncope.common.lib.to.AnyTypeTO;
45  import org.apache.syncope.common.lib.to.ConnObject;
46  import org.apache.syncope.common.lib.to.PropagationStatus;
47  import org.apache.syncope.common.lib.to.ProvisioningResult;
48  import org.apache.syncope.common.lib.to.RealmTO;
49  import org.apache.syncope.common.lib.types.ExecStatus;
50  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
51  import org.apache.wicket.Component;
52  import org.apache.wicket.PageReference;
53  import org.apache.wicket.ajax.AjaxRequestTarget;
54  import org.apache.wicket.extensions.markup.html.tabs.ITab;
55  import org.apache.wicket.markup.html.WebMarkupContainer;
56  import org.apache.wicket.markup.html.basic.Label;
57  import org.apache.wicket.markup.html.panel.Panel;
58  import org.apache.wicket.model.IModel;
59  import org.apache.wicket.model.ResourceModel;
60  import org.apache.wicket.spring.injection.annot.SpringBean;
61  import org.slf4j.Logger;
62  import org.slf4j.LoggerFactory;
63  
64  public abstract class Realm extends WizardMgtPanel<RealmTO> {
65  
66      private static final long serialVersionUID = -1100228004207271270L;
67  
68      protected static final Logger LOG = LoggerFactory.getLogger(Realm.class);
69  
70      @SpringBean
71      protected RoleRestClient roleRestClient;
72  
73      @SpringBean
74      protected RealmRestClient realmRestClient;
75  
76      protected final RealmTO realmTO;
77  
78      protected final List<AnyTypeTO> anyTypes;
79  
80      protected final int selectedIndex;
81  
82      protected final RealmWizardBuilder wizardBuilder;
83  
84      public Realm(
85              final String id,
86              final RealmTO realmTO,
87              final List<AnyTypeTO> anyTypes,
88              final int selectedIndex,
89              final PageReference pageRef) {
90  
91          super(id, true);
92          this.realmTO = realmTO;
93          this.anyTypes = anyTypes;
94          this.selectedIndex = selectedIndex;
95  
96          setPageRef(pageRef);
97  
98          addInnerObject(new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList(pageRef)).
99                  setSelectedTab(selectedIndex));
100 
101         this.wizardBuilder = buildNewItemPanelBuilder(pageRef);
102         addNewItemPanelBuilder(this.wizardBuilder, false);
103 
104         setShowResultPanel(true);
105 
106         modal.size(Modal.Size.Large);
107         setWindowClosedReloadCallback(modal);
108     }
109 
110     protected RealmWizardBuilder buildNewItemPanelBuilder(final PageReference pageRef) {
111         return new RealmWizardBuilder(realmRestClient, pageRef);
112     }
113 
114     public RealmTO getRealmTO() {
115         return realmTO;
116     }
117 
118     protected List<ITab> buildTabList(final PageReference pageRef) {
119         List<ITab> tabs = new ArrayList<>();
120 
121         tabs.add(new RealmDetailsTabPanel());
122 
123         AnyLayout anyLayout = AnyLayoutUtils.fetch(
124                 roleRestClient,
125                 anyTypes.stream().map(AnyTypeTO::getKey).collect(Collectors.toList()));
126         for (AnyTypeTO anyType : anyTypes) {
127             tabs.add(new ITabComponent(
128                     new ResourceModel("anyType." + anyType.getKey(), anyType.getKey()),
129                     String.format("%s_SEARCH", anyType.getKey())) {
130 
131                 private static final long serialVersionUID = 1169585538404171118L;
132 
133                 @Override
134                 public WebMarkupContainer getPanel(final String panelId) {
135                     return new AnyPanel.Builder<>(
136                             anyLayout.getAnyPanelClass(), panelId, anyType, realmTO, anyLayout, true, pageRef).build();
137                 }
138 
139                 @Override
140                 public boolean isVisible() {
141                     return SyncopeWebApplication.get().getSecuritySettings().getAuthorizationStrategy().
142                             isActionAuthorized(this, RENDER);
143                 }
144             });
145         }
146 
147         return tabs;
148     }
149 
150     @Override
151     @SuppressWarnings("unchecked")
152     protected Panel customResultBody(final String panelId, final RealmTO item, final Serializable result) {
153         if (!(result instanceof ProvisioningResult)) {
154             throw new IllegalStateException("Unsupported result type");
155         }
156 
157         MultilevelPanel mlp = new MultilevelPanel(panelId);
158         add(mlp);
159 
160         PropagationStatus syncope = new PropagationStatus();
161         syncope.setStatus(ExecStatus.SUCCESS);
162         syncope.setResource(Constants.SYNCOPE);
163 
164         List<PropagationStatus> propagations = new ArrayList<>();
165         propagations.add(syncope);
166         propagations.addAll(((ProvisioningResult) result).getPropagationStatuses());
167 
168         ListViewPanel.Builder<PropagationStatus> builder =
169                 new ListViewPanel.Builder<>(PropagationStatus.class, pageRef) {
170 
171             private static final long serialVersionUID = -6809736686861678498L;
172 
173             @Override
174             protected Component getValueComponent(final String key, final PropagationStatus bean) {
175                 if ("afterObj".equalsIgnoreCase(key)) {
176                     String remoteId = Optional.ofNullable(bean.getAfterObj()).
177                             flatMap(afterObj -> afterObj.getAttr(ConnIdSpecialName.NAME).
178                             filter(s -> !s.getValues().isEmpty()).map(s -> s.getValues().get(0))).
179                             orElse(StringUtils.EMPTY);
180 
181                     return new Label("field", remoteId);
182                 }
183 
184                 if ("status".equalsIgnoreCase(key)) {
185                     return StatusUtils.getStatusImagePanel("field", bean.getStatus());
186                 }
187 
188                 return super.getValueComponent(key, bean);
189             }
190         };
191 
192         builder.setItems(propagations);
193 
194         builder.includes("resource", "afterObj", "status");
195         builder.withChecks(ListViewPanel.CheckAvailability.NONE);
196         builder.setReuseItem(false);
197 
198         ActionLink<PropagationStatus> connObjectLink = new ActionLink<>() {
199 
200             private static final long serialVersionUID = -3722207913631435501L;
201 
202             @Override
203             protected boolean statusCondition(final PropagationStatus bean) {
204                 return !Constants.SYNCOPE.equals(bean.getResource())
205                         && (ExecStatus.CREATED == bean.getStatus()
206                         || ExecStatus.SUCCESS == bean.getStatus());
207             }
208 
209             @Override
210             public void onClick(final AjaxRequestTarget target, final PropagationStatus status) {
211                 mlp.next(status.getResource(), new RemoteRealmPanel(status), target);
212             }
213         };
214         SyncopeWebApplication.get().getStatusProvider().addConnObjectLink(builder, connObjectLink);
215 
216         builder.addAction(new ActionLink<>() {
217 
218             private static final long serialVersionUID = -3722207913631435501L;
219 
220             @Override
221             protected boolean statusCondition(final PropagationStatus status) {
222                 return StringUtils.isNotBlank(status.getFailureReason());
223             }
224 
225             @Override
226             public void onClick(final AjaxRequestTarget target, final PropagationStatus status) {
227                 mlp.next(status.getResource(), new PropagationErrorPanel(status.getFailureReason()), target);
228             }
229         }, ActionLink.ActionType.PROPAGATION_TASKS, StringUtils.EMPTY);
230 
231         mlp.setFirstLevel(builder.build(MultilevelPanel.FIRST_LEVEL_ID));
232         return mlp;
233     }
234 
235     protected abstract void onClickTemplate(AjaxRequestTarget target);
236 
237     protected abstract void onClickCreate(AjaxRequestTarget target);
238 
239     protected abstract void onClickEdit(AjaxRequestTarget target, RealmTO realmTO);
240 
241     protected abstract void onClickDelete(AjaxRequestTarget target, RealmTO realmTO);
242 
243     protected static class RemoteRealmPanel extends RemoteObjectPanel {
244 
245         private static final long serialVersionUID = 4303365227411467563L;
246 
247         protected final PropagationStatus bean;
248 
249         protected RemoteRealmPanel(final PropagationStatus bean) {
250             this.bean = bean;
251             add(new ConnObjectPanel(
252                     REMOTE_OBJECT_PANEL_ID,
253                     Pair.<IModel<?>, IModel<?>>of(new ResourceModel("before"), new ResourceModel("after")),
254                     getConnObjectTOs(),
255                     false));
256         }
257 
258         @Override
259         protected final Pair<ConnObject, ConnObject> getConnObjectTOs() {
260             return Pair.of(bean.getBeforeObj(), bean.getAfterObj());
261         }
262     }
263 
264     protected class RealmDetailsTabPanel extends ITabComponent {
265 
266         private static final long serialVersionUID = -5861786415855103549L;
267 
268         protected RealmDetailsTabPanel() {
269             super(new ResourceModel("realm.details", "DETAILS"),
270                     IdRepoEntitlement.REALM_CREATE, IdRepoEntitlement.REALM_UPDATE, IdRepoEntitlement.REALM_DELETE);
271         }
272 
273         @Override
274         public Panel getPanel(final String panelId) {
275             ActionsPanel<RealmTO> actionPanel = new ActionsPanel<>("actions", null);
276 
277             if (StringUtils.startsWith(realmTO.getFullPath(), SyncopeConstants.ROOT_REALM)) {
278                 actionPanel.add(new ActionLink<>(realmTO) {
279 
280                     private static final long serialVersionUID = 2802988981431379827L;
281 
282                     @Override
283                     public void onClick(final AjaxRequestTarget target, final RealmTO ignore) {
284                         onClickCreate(target);
285                     }
286                 }, ActionLink.ActionType.CREATE, IdRepoEntitlement.REALM_CREATE).hideLabel();
287 
288                 actionPanel.add(new ActionLink<>(realmTO) {
289 
290                     private static final long serialVersionUID = 2802988981431379828L;
291 
292                     @Override
293                     public void onClick(final AjaxRequestTarget target, final RealmTO ignore) {
294                         onClickEdit(target, realmTO);
295                     }
296                 }, ActionLink.ActionType.EDIT, IdRepoEntitlement.REALM_UPDATE).hideLabel();
297 
298                 actionPanel.add(new ActionLink<>(realmTO) {
299 
300                     private static final long serialVersionUID = 2802988981431379827L;
301 
302                     @Override
303                     public void onClick(final AjaxRequestTarget target, final RealmTO ignore) {
304                         onClickTemplate(target);
305                     }
306                 }, ActionLink.ActionType.TEMPLATE, IdRepoEntitlement.REALM_UPDATE).hideLabel();
307 
308                 actionPanel.add(new ActionLink<>(realmTO) {
309 
310                     private static final long serialVersionUID = 2802988981431379829L;
311 
312                     @Override
313                     public void onClick(final AjaxRequestTarget target, final RealmTO ignore) {
314                         onClickDelete(target, realmTO);
315                     }
316                 }, ActionLink.ActionType.DELETE, IdRepoEntitlement.REALM_DELETE, true).hideLabel();
317             }
318 
319             RealmDetails panel = new RealmDetails(panelId, realmTO, actionPanel, false);
320             panel.setContentEnabled(false);
321             actionPanel.setEnabled(true);
322             return panel;
323         }
324 
325         @Override
326         public boolean isVisible() {
327             return SyncopeWebApplication.get().getSecuritySettings().getAuthorizationStrategy().
328                     isActionAuthorized(this, RENDER);
329         }
330     }
331 }