/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.syncope.client.console.wizards.any; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.Predicate; import org.apache.syncope.client.console.commons.Constants; import org.apache.syncope.client.console.commons.SerializableTransformer; import org.apache.syncope.client.console.panels.AnyDirectoryPanel; import org.apache.syncope.client.console.panels.ListViewPanel; import org.apache.syncope.client.console.panels.ListViewPanel.ListViewReload; import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel; import org.apache.syncope.client.console.panels.search.AnyObjectSelectionDirectoryPanel; import org.apache.syncope.client.console.panels.search.AnySelectionDirectoryPanel; import org.apache.syncope.client.console.panels.search.SearchClause; import org.apache.syncope.client.console.panels.search.SearchClausePanel; import org.apache.syncope.client.console.panels.search.SearchUtils; import org.apache.syncope.client.console.rest.AnyTypeClassRestClient; import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.console.rest.RelationshipTypeRestClient; import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel; import org.apache.syncope.client.console.wizards.WizardMgtPanel; import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.common.lib.EntityTOUtils; import org.apache.syncope.common.lib.to.AnyObjectTO; import org.apache.syncope.common.lib.to.AnyTO; import org.apache.syncope.common.lib.to.AnyTypeTO; import org.apache.syncope.common.lib.to.GroupableRelatableTO; import org.apache.syncope.common.lib.to.RelationshipTO; import org.apache.syncope.common.lib.to.RelationshipTypeTO; import org.apache.syncope.common.lib.types.AnyEntitlement; import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.event.Broadcast; import org.apache.wicket.event.IEvent; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.extensions.wizard.WizardStep; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnDomReadyHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.util.ListModel; public class Relationships extends WizardStep { private static final long serialVersionUID = 855618618337931784L; private final PageReference pageRef; private final AnyTypeRestClient anyTypeRestClient = new AnyTypeRestClient(); private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient(); private final AnyTO anyTO; public Relationships(final AnyTO anyTO, final PageReference pageRef) { super(); setTitleModel(new ResourceModel("any.relationships")); this.anyTO = anyTO; this.pageRef = pageRef; // ------------------------ // Existing relationships // ------------------------ add(getViewFragment().setRenderBodyOnly(true)); // ------------------------ } private Fragment getViewFragment() { final Map<String, List<RelationshipTO>> relationships = new HashMap<>(); addRelationship(relationships, getCurrentRelationships().toArray(new RelationshipTO[] {})); final Fragment viewFragment = new Fragment("relationships", "viewFragment", this); viewFragment.setOutputMarkupId(true); viewFragment.add(new Accordion("relationships", CollectionUtils.collect(relationships.keySet(), new SerializableTransformer<String, ITab>() { private static final long serialVersionUID = 3514912643300593122L; @Override public ITab transform(final String input) { return new AbstractTab(new ResourceModel("relationship", input)) { private static final long serialVersionUID = 1037272333056449378L; @Override public Panel getPanel(final String panelId) { return new ListViewPanel.Builder<>(RelationshipTO.class, pageRef). setItems(relationships.get(input)). includes("rightType", "rightKey"). addAction(new ActionLink<RelationshipTO>() { private static final long serialVersionUID = -6847033126124401556L; @Override public void onClick( final AjaxRequestTarget target, final RelationshipTO modelObject) { removeRelationships(relationships, modelObject); send(Relationships.this, Broadcast.DEPTH, new ListViewReload<>(target)); } }, ActionType.DELETE, AnyEntitlement.UPDATE.getFor(anyTO.getType())). build(panelId); } }; } }, new ArrayList<ITab>())) { private static final long serialVersionUID = 1037272333056449379L; @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); if (relationships.isEmpty()) { response.render(OnDomReadyHeaderItem.forScript(String.format( "$('#emptyPlaceholder').append(\"%s\")", getString("relationships.empty.list")))); } } }); final ActionsPanel<RelationshipTO> panel = new ActionsPanel<>("actions", null); viewFragment.add(panel); panel.add(new ActionLink<RelationshipTO>() { private static final long serialVersionUID = 3257738274365467945L; @Override public void onClick(final AjaxRequestTarget target, final RelationshipTO ignore) { Fragment addFragment = new Fragment("relationships", "addFragment", Relationships.this); addOrReplace(addFragment); addFragment.add(new Specification().setRenderBodyOnly(true)); target.add(Relationships.this); } }, ActionType.CREATE, AnyEntitlement.UPDATE.getFor(anyTO.getType())).hideLabel(); return viewFragment; } private List<RelationshipTO> getCurrentRelationships() { return anyTO instanceof GroupableRelatableTO ? GroupableRelatableTO.class.cast(anyTO).getRelationships() : Collections.<RelationshipTO>emptyList(); } private void addRelationship(final Map<String, List<RelationshipTO>> relationships, final RelationshipTO... rels) { for (RelationshipTO relationship : rels) { final List<RelationshipTO> listrels; if (relationships.containsKey(relationship.getType())) { listrels = relationships.get(relationship.getType()); } else { listrels = new ArrayList<>(); relationships.put(relationship.getType(), listrels); } listrels.add(relationship); } } private void addNewRelationships(final RelationshipTO... rels) { getCurrentRelationships().addAll(Arrays.asList(rels)); } private void removeRelationships( final Map<String, List<RelationshipTO>> relationships, final RelationshipTO... rels) { final List<RelationshipTO> currentRels = getCurrentRelationships(); for (RelationshipTO relationship : rels) { currentRels.remove(relationship); if (relationships.containsKey(relationship.getType())) { final List<RelationshipTO> rellist = relationships.get(relationship.getType()); rellist.remove(relationship); if (rellist.isEmpty()) { relationships.remove(relationship.getType()); } } } } public class Specification extends Panel { private static final long serialVersionUID = 6199050589175839467L; private final RelationshipTO rel; private AnyObjectSearchPanel anyObjectSearchPanel; private WizardMgtPanel<AnyWrapper<AnyObjectTO>> anyObjectDirectoryPanel; private final RelationshipTypeRestClient relationshipTypeRestClient = new RelationshipTypeRestClient(); public Specification() { super("specification"); rel = new RelationshipTO(); final ArrayList<String> availableRels = CollectionUtils.collect( relationshipTypeRestClient.list(), EntityTOUtils.<RelationshipTypeTO>keyTransformer(), new ArrayList<String>()); final AjaxDropDownChoicePanel<String> type = new AjaxDropDownChoicePanel<>( "type", "type", new PropertyModel<String>(rel, "type")); type.setChoices(availableRels); add(type.setRenderBodyOnly(true)); final List<AnyTypeTO> availableTypes = ListUtils.select(anyTypeRestClient.list(), new Predicate<AnyTypeTO>() { @Override public boolean evaluate(final AnyTypeTO object) { return object.getKind() != AnyTypeKind.GROUP && object.getKind() != AnyTypeKind.USER; } }); final AjaxDropDownChoicePanel<AnyTypeTO> rightType = new AjaxDropDownChoicePanel<>( "rightType", "rightType", new PropertyModel<AnyTypeTO>(rel, "rightType") { private static final long serialVersionUID = -5861057041758169508L; @Override public AnyTypeTO getObject() { for (AnyTypeTO obj : availableTypes) { if (obj.getKey().equals(rel.getRightType())) { return obj; } } return null; } @Override public void setObject(final AnyTypeTO object) { rel.setRightType(object == null ? null : object.getKey()); } }, false); rightType.setChoices(availableTypes); rightType.setChoiceRenderer(new IChoiceRenderer<AnyTypeTO>() { private static final long serialVersionUID = -734743540442190178L; @Override public Object getDisplayValue(final AnyTypeTO object) { return object.getKey(); } @Override public String getIdValue(final AnyTypeTO object, final int index) { return object.getKey(); } @Override public AnyTypeTO getObject(final String id, final IModel<? extends List<? extends AnyTypeTO>> choices) { return IterableUtils.find(choices.getObject(), new Predicate<AnyTypeTO>() { @Override public boolean evaluate(final AnyTypeTO object) { return id.equals(object.getKey()); } }); } }); add(rightType); final WebMarkupContainer container = new WebMarkupContainer("searchPanelContainer"); container.setOutputMarkupId(true); add(container); Fragment emptyFragment = new Fragment("searchPanel", "emptyFragment", this); container.add(emptyFragment.setRenderBodyOnly(true)); type.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { private static final long serialVersionUID = -1107858522700306810L; @Override protected void onUpdate(final AjaxRequestTarget target) { Fragment emptyFragment = new Fragment("searchPanel", "emptyFragment", Specification.this); container.addOrReplace(emptyFragment.setRenderBodyOnly(true)); rightType.setModelObject(null); target.add(rightType); target.add(container); } }); rightType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { private static final long serialVersionUID = -1107858522700306810L; @Override protected void onUpdate(final AjaxRequestTarget target) { final AnyTypeTO anyType = rightType.getModelObject(); if (anyType == null) { Fragment emptyFragment = new Fragment("searchPanel", "emptyFragment", Specification.this); container.addOrReplace(emptyFragment.setRenderBodyOnly(true)); } else { final Fragment fragment = new Fragment("searchPanel", "searchFragment", Specification.this); container.addOrReplace(fragment.setRenderBodyOnly(true)); anyObjectSearchPanel = new AnyObjectSearchPanel.Builder( anyType.getKey(), new ListModel<>(new ArrayList<SearchClause>())). enableSearch(Specification.this). build("searchPanel"); fragment.add(anyObjectSearchPanel.setRenderBodyOnly(true)); anyObjectDirectoryPanel = new AnyObjectSelectionDirectoryPanel.Builder( anyTypeClassRestClient.list(anyType.getClasses()), anyType.getKey(), pageRef).setFiltered(true). setFiql(SyncopeClient.getAnyObjectSearchConditionBuilder(anyType.getKey()). is("key").notNullValue().query()). setWizardInModal(true).build("searchResultPanel"); fragment.add(anyObjectDirectoryPanel.setRenderBodyOnly(true)); } target.add(container); } }); } @Override public void onEvent(final IEvent<?> event) { if (event.getPayload() instanceof SearchClausePanel.SearchEvent) { final AjaxRequestTarget target = SearchClausePanel.SearchEvent.class.cast(event.getPayload()). getTarget(); final String fiql = SearchUtils.buildFIQL(anyObjectSearchPanel.getModel().getObject(), SyncopeClient.getAnyObjectSearchConditionBuilder(anyObjectSearchPanel.getBackObjectType())); AnyDirectoryPanel.class.cast(anyObjectDirectoryPanel).search(fiql, target); } else if (event.getPayload() instanceof AnySelectionDirectoryPanel.ItemSelection) { final AjaxRequestTarget target = AnySelectionDirectoryPanel.ItemSelection.class.cast(event. getPayload()).getTarget(); AnyTO right = AnySelectionDirectoryPanel.ItemSelection.class.cast(event.getPayload()).getSelection(); rel.setRightKey(right.getKey()); Relationships.this.addNewRelationships(rel); Relationships.this.addOrReplace(getViewFragment().setRenderBodyOnly(true)); target.add(Relationships.this); } else { super.onEvent(event); } } } }