Return-Path: X-Original-To: apmail-syncope-commits-archive@www.apache.org Delivered-To: apmail-syncope-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BF3CB18780 for ; Mon, 19 Oct 2015 14:37:03 +0000 (UTC) Received: (qmail 86981 invoked by uid 500); 19 Oct 2015 14:37:03 -0000 Delivered-To: apmail-syncope-commits-archive@syncope.apache.org Received: (qmail 86911 invoked by uid 500); 19 Oct 2015 14:37:03 -0000 Mailing-List: contact commits-help@syncope.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@syncope.apache.org Delivered-To: mailing list commits@syncope.apache.org Received: (qmail 86731 invoked by uid 99); 19 Oct 2015 14:37:03 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 19 Oct 2015 14:37:02 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id C2AC5E048E; Mon, 19 Oct 2015 14:37:02 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ilgrosso@apache.org To: commits@syncope.apache.org Date: Mon, 19 Oct 2015 14:37:05 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [4/8] syncope git commit: Upgrading surefire, failsafe and checkstyle plugins http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java ---------------------------------------------------------------------- diff --cc client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java index 409a16b,0000000..24cd09d mode 100644,000000..100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java @@@ -1,570 -1,0 +1,570 @@@ +/* + * 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.topology; + +import java.io.Serializable; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.pages.BasePage; +import org.apache.syncope.client.console.panels.AbstractResourceModal.CreateEvent; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel; +import org.apache.syncope.common.lib.to.ConnInstanceTO; +import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.syncope.common.lib.types.Entitlement; +import org.apache.syncope.common.rest.api.service.SyncopeService; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AbstractAjaxTimerBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.IAjaxIndicatorAware; +import org.apache.wicket.behavior.Behavior; +import org.apache.wicket.event.IEvent; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +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.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.util.time.Duration; + +public class Topology extends BasePage { + + private static final long serialVersionUID = -1100228004207271272L; + + public static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://"; + + public static final String ROOT_NAME = "Syncope"; + + private final int origX = 3100; + + private final int origY = 2800; + + private static final int RESOURCE_MODAL_WIN_HEIGHT = 700; + + private static final int RESOURCE_MODAL_WIN_WIDTH = 1000; + + private final ModalWindow modal; + + private final WebMarkupContainer newlyCreatedContainer; + + private final ListView newlyCreated; + + private final LoadableDetachableModel> resModel = new LoadableDetachableModel>() { + + private static final long serialVersionUID = 5275935387613157431L; + + @Override + protected List load() { + final List result = resourceRestClient.getAll(); + return result; + } + }; + + private final LoadableDetachableModel>> connModel + = new LoadableDetachableModel>>() { + + private static final long serialVersionUID = 5275935387613157432L; + + @Override + protected Map> load() { + final Map> res = new HashMap<>(); + + for (ConnInstanceTO conn : connectorRestClient.getAllConnectors()) { + final List conns; + if (res.containsKey(conn.getLocation())) { + conns = res.get(conn.getLocation()); + } else { + conns = new ArrayList<>(); + res.put(conn.getLocation(), conns); + } + conns.add(conn); + } + + return res; + } + }; + + private final LoadableDetachableModel, List>> csModel + = new LoadableDetachableModel, List>>() { + + private static final long serialVersionUID = 5275935387613157433L; + + @Override + protected Pair, List> load() { + final List connectorServers = new ArrayList<>(); + final List filePaths = new ArrayList<>(); + + for (String location : SyncopeConsoleSession.get().getSyncopeTO().getConnIdLocations()) { + if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) { + connectorServers.add(URI.create(location)); + } else { + filePaths.add(URI.create(location)); + } + } + + return Pair.of(connectorServers, filePaths); + } + }; + + protected enum SupportedOperation { + + CHECK_RESOURCE, + CHECK_CONNECTOR, + ADD_ENDPOINT; + + } + + public Topology() { + modal = new ModalWindow("modal"); + add(modal); + + modal.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + modal.setInitialHeight(RESOURCE_MODAL_WIN_HEIGHT); + modal.setInitialWidth(RESOURCE_MODAL_WIN_WIDTH); + modal.setCookieName("resource-modal"); + + add(new WebSocketBehavior()); + + // ----------------------------------------- + // Add Zoom panel + // ----------------------------------------- + final ActionLinksPanel.Builder zoomActionPanel = ActionLinksPanel.builder(getPageReference()); + zoomActionPanel.setDisableIndicator(true); + + zoomActionPanel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final Serializable ignore) { + target.appendJavaScript("zoomIn($('#drawing')[0]);"); + } + }, ActionLink.ActionType.ZOOM_IN, Entitlement.RESOURCE_LIST).add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final Serializable ignore) { + target.appendJavaScript("zoomOut($('#drawing')[0]);"); + } + }, ActionLink.ActionType.ZOOM_OUT, Entitlement.RESOURCE_LIST); + + add(zoomActionPanel.build("zoom")); + // ----------------------------------------- + + // ----------------------------------------- + // Add Syncope (root topologynode) + // ----------------------------------------- + final TopologyNode syncopeTopologyNode = new TopologyNode(ROOT_NAME, ROOT_NAME, TopologyNode.Kind.SYNCOPE); + syncopeTopologyNode.setX(origX); + syncopeTopologyNode.setY(origY); + + final URI uri = WebClient.client(SyncopeConsoleSession.get().getService(SyncopeService.class)).getBaseURI(); + syncopeTopologyNode.setHost(uri.getHost()); + syncopeTopologyNode.setPort(uri.getPort()); + + add(topologyNodePanel("syncope", syncopeTopologyNode)); + + final Map> connections = new HashMap<>(); + final Map syncopeConnections = new HashMap<>(); + connections.put(syncopeTopologyNode.getKey(), syncopeConnections); + + // required to retrieve parent positions + final Map servers = new HashMap<>(); + final Map connectors = new HashMap<>(); + // ----------------------------------------- + + // ----------------------------------------- + // Add Connector Servers + // ----------------------------------------- + final ListView connectorServers = new ListView("connectorServers", csModel.getObject().getLeft()) { + + private static final long serialVersionUID = 6978621871488360380L; + + private final int size = csModel.getObject().getLeft().size() + 1; + + @Override + protected void populateItem(final ListItem item) { + int kx = size >= 4 ? 800 : (200 * size); + + int x = (int) Math.round(origX + kx * Math.cos(Math.PI + Math.PI * (item.getIndex() + 1) / size)); + int y = (int) Math.round(origY + 100 * Math.sin(Math.PI + Math.PI * (item.getIndex() + 1) / size)); + + final URI location = item.getModelObject(); + final String url = location.toASCIIString(); + + final TopologyNode topologynode = new TopologyNode(url, url, TopologyNode.Kind.CONNECTOR_SERVER); + + topologynode.setHost(location.getHost()); + topologynode.setPort(location.getPort()); + topologynode.setX(x); + topologynode.setY(y); + + servers.put(String.class.cast(topologynode.getKey()), topologynode); + + item.add(topologyNodePanel("cs", topologynode)); + + syncopeConnections.put(url, topologynode); + connections.put(url, new HashMap()); + } + }; + + connectorServers.setOutputMarkupId(true); + add(connectorServers); + // ----------------------------------------- + + // ----------------------------------------- + // Add File Paths + // ----------------------------------------- + final ListView filePaths = new ListView("filePaths", csModel.getObject().getRight()) { + + private static final long serialVersionUID = 6978621871488360380L; + + private final int size = csModel.getObject().getRight().size() + 1; + + @Override + protected void populateItem(final ListItem item) { + int kx = size >= 4 ? 800 : (200 * size); + + int x = (int) Math.round(origX + kx * Math.cos(Math.PI * (item.getIndex() + 1) / size)); + int y = (int) Math.round(origY + 100 * Math.sin(Math.PI * (item.getIndex() + 1) / size)); + + final URI location = item.getModelObject(); + final String url = location.toASCIIString(); + + final TopologyNode topologynode = new TopologyNode(url, url, TopologyNode.Kind.FS_PATH); + + topologynode.setHost(location.getHost()); + topologynode.setPort(location.getPort()); + topologynode.setX(x); + topologynode.setY(y); + + servers.put(String.class.cast(topologynode.getKey()), topologynode); + + item.add(topologyNodePanel("fp", topologynode)); + + syncopeConnections.put(url, topologynode); + connections.put(url, new HashMap()); + } + }; + + filePaths.setOutputMarkupId(true); + add(filePaths); + // ----------------------------------------- + + // ----------------------------------------- + // Add Connector Intances + // ----------------------------------------- + final List> allConns = new ArrayList<>(connModel.getObject().values()); + + final ListView> conns = new ListView>("conns", allConns) { + + private static final long serialVersionUID = 697862187148836036L; + + @Override + protected void populateItem(final ListItem> item) { + + final int size = item.getModelObject().size() + 1; + + final ListView conns = new ListView("conns", item.getModelObject()) { + + private static final long serialVersionUID = 6978621871488360381L; + + @Override + protected void populateItem(final ListItem item) { + final ConnInstanceTO conn = item.getModelObject(); + + final TopologyNode topologynode = new TopologyNode( + Long.valueOf(conn.getKey()), conn.getDisplayName(), TopologyNode.Kind.CONNECTOR); + + // Define the parent note + final TopologyNode parent = servers.get(conn.getLocation()); + + // Set the position + int kx = size >= 6 ? 800 : (130 * size); + + final double hpos; + if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) { + hpos = Math.PI; + } else { + hpos = 0.0; + } + + int x = (int) Math.round((parent == null ? origX : parent.getX()) + + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size)); + int y = (int) Math.round((parent == null ? origY : parent.getY()) + + 100 * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size)); + + topologynode.setConnectionDisplayName(conn.getBundleName()); + topologynode.setX(x); + topologynode.setY(y); + + connectors.put(Long.class.cast(topologynode.getKey()), topologynode); + item.add(topologyNodePanel("conn", topologynode)); + + // Update connections + final Map remoteConnections; + + if (connections.containsKey(conn.getLocation())) { + remoteConnections = connections.get(conn.getLocation()); + } else { + remoteConnections = new HashMap<>(); + connections.put(conn.getLocation(), remoteConnections); + } + remoteConnections.put(conn.getKey(), topologynode); + } + }; + + conns.setOutputMarkupId(true); + item.add(conns); + } + }; + + conns.setOutputMarkupId(true); + add(conns); + // ----------------------------------------- + + // ----------------------------------------- + // Add Resources + // ----------------------------------------- + final List connToBeProcessed = new ArrayList<>(); + for (ResourceTO resourceTO : resModel.getObject()) { + final TopologyNode topologynode = new TopologyNode( + resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE); + + final Map remoteConnections; + + if (connections.containsKey(resourceTO.getConnector())) { + remoteConnections = connections.get(resourceTO.getConnector()); + } else { + remoteConnections = new HashMap<>(); + connections.put(resourceTO.getConnector(), remoteConnections); + } + + remoteConnections.put(topologynode.getKey(), topologynode); + + if (!connToBeProcessed.contains(resourceTO.getConnector())) { + connToBeProcessed.add(resourceTO.getConnector()); + } + } + + final ListView resources = new ListView("resources", connToBeProcessed) { + + private static final long serialVersionUID = 697862187148836038L; + + @Override + protected void populateItem(final ListItem item) { + final Long connectorId = item.getModelObject(); + + final ListView innerListView = new ListView("resources", + new ArrayList<>(connections.get(connectorId).values())) { + + private static final long serialVersionUID = 1L; + + private final int size = getModelObject().size() + 1; + + @Override + protected void populateItem(final ListItem item) { + final TopologyNode topologynode = item.getModelObject(); + final TopologyNode parent = connectors.get(connectorId); + + // Set position + int kx = size >= 16 ? 800 : (48 * size); + int ky = size < 4 ? 100 : size < 6 ? 350 : 750; + + final double hpos; + if (parent == null || parent.getY() < syncopeTopologyNode.getY()) { + hpos = Math.PI; + } else { + hpos = 0.0; + } + + int x = (int) Math.round((parent == null ? origX : parent.getX()) + + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size)); + int y = (int) Math.round((parent == null ? origY : parent.getY()) + + ky * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size)); + + topologynode.setX(x); + topologynode.setY(y); + + item.add(topologyNodePanel("res", topologynode)); + } + }; + + innerListView.setOutputMarkupId(true); + item.add(innerListView); + } + }; + + resources.setOutputMarkupId(true); + add(resources); + // ----------------------------------------- + + // ----------------------------------------- + // Create connections + // ----------------------------------------- + final WebMarkupContainer jsPlace = new WebMarkupContainerNoVeil("jsPlace"); + jsPlace.setOutputMarkupId(true); + add(jsPlace); + + jsPlace.add(new Behavior() { + + private static final long serialVersionUID = 2661717818979056044L; + + @Override + public void renderHead(final Component component, final IHeaderResponse response) { + final StringBuilder jsPlumbConf = new StringBuilder(); + jsPlumbConf.append(String.format(Locale.US, "activate(%.2f);", 0.68f)); + + for (String str : createConnections(connections)) { + jsPlumbConf.append(str); + } + + response.render(OnDomReadyHeaderItem.forScript(jsPlumbConf.toString())); + } + }); + + jsPlace.add(new AbstractAjaxTimerBehavior(Duration.seconds(2)) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onTimer(final AjaxRequestTarget target) { + target.appendJavaScript("checkConnection()"); + + if (getUpdateInterval().seconds() < 5.0) { + setUpdateInterval(Duration.seconds(5)); + } else if (getUpdateInterval().seconds() < 10.0) { + setUpdateInterval(Duration.seconds(10)); + } else if (getUpdateInterval().seconds() < 15.0) { + setUpdateInterval(Duration.seconds(15)); + } else if (getUpdateInterval().seconds() < 20.0) { + setUpdateInterval(Duration.seconds(20)); + } else if (getUpdateInterval().seconds() < 30.0) { + setUpdateInterval(Duration.seconds(30)); + } else if (getUpdateInterval().seconds() < 60.0) { + setUpdateInterval(Duration.seconds(60)); + } + } + }); + // ----------------------------------------- + + newlyCreatedContainer = new WebMarkupContainer("newlyCreatedContainer"); + newlyCreatedContainer.setOutputMarkupId(true); + add(newlyCreatedContainer); + + newlyCreated = new ListView("newlyCreated", new ArrayList()) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(final ListItem item) { + item.add(topologyNodePanel("el", item.getModelObject())); + } + }; + newlyCreated.setOutputMarkupId(true); + newlyCreated.setReuseItems(true); + + newlyCreatedContainer.add(newlyCreated); + } + + private List createConnections(final Map> targets) { + List list = new ArrayList<>(); + + for (Map.Entry> source : targets.entrySet()) { + for (Map.Entry target : source.getValue().entrySet()) { + list.add(String.format("connect('%s','%s','%s');", + source.getKey(), + target.getKey(), + target.getValue().getKind())); + } + } + return list; + } + + private TopologyNodePanel topologyNodePanel(final String id, final TopologyNode node) { + + final TopologyNodePanel panel = new TopologyNodePanel(id, node, getPageReference(), modal); + panel.setMarkupId(String.valueOf(node.getKey())); + panel.setOutputMarkupId(true); + + panel.add(new Behavior() { + + private static final long serialVersionUID = 1L; + + @Override + public void renderHead(final Component component, final IHeaderResponse response) { + response.render(OnDomReadyHeaderItem.forScript(String.format("setPosition('%s', %d, %d)", + node.getKey(), node.getX(), node.getY()))); + } + }); + + return panel; + } + + @Override + @SuppressWarnings("unchecked") + public void onEvent(final IEvent event) { + super.onEvent(event); + + if (event.getPayload() instanceof CreateEvent) { + final CreateEvent resourceCreateEvent = CreateEvent.class.cast(event.getPayload()); + + final TopologyNode node = new TopologyNode( + resourceCreateEvent.getKey(), + resourceCreateEvent.getDisplayName(), + resourceCreateEvent.getKind()); + + newlyCreated.getModelObject().add(node); + resourceCreateEvent.getTarget().add(newlyCreatedContainer); + + resourceCreateEvent.getTarget().appendJavaScript(String.format( + "window.Wicket.WebSocket.send('" + + "{\"kind\":\"%s\",\"target\":\"%s\",\"source\":\"%s\",\"scope\":\"%s\"}" + + "');", + SupportedOperation.ADD_ENDPOINT, + resourceCreateEvent.getKey(), + resourceCreateEvent.getParent(), + resourceCreateEvent.getKind())); + } + } + + private static class WebMarkupContainerNoVeil extends WebMarkupContainer implements IAjaxIndicatorAware { + + private static final long serialVersionUID = 1L; + - public WebMarkupContainerNoVeil(final String id) { ++ WebMarkupContainerNoVeil(final String id) { + super(id); + } + + @Override + public String getAjaxIndicatorMarkupId() { + return StringUtils.EMPTY; + } + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java ---------------------------------------------------------------------- diff --cc client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java index 1b847f9,0000000..8e3267d mode 100644,000000..100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/WebSocketBehavior.java @@@ -1,208 -1,0 +1,208 @@@ +/* + * 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.topology; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.apache.syncope.client.console.rest.ConnectorRestClient; +import org.apache.syncope.client.console.rest.ResourceRestClient; +import org.apache.syncope.common.lib.to.ConnInstanceTO; +import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.wicket.Application; +import org.apache.wicket.Session; +import org.apache.wicket.ThreadContext; +import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; +import org.apache.wicket.protocol.ws.api.message.TextMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebSocketBehavior extends org.apache.wicket.protocol.ws.api.WebSocketBehavior { + + protected static final Logger LOG = LoggerFactory.getLogger(WebSocketBehavior.class); + + private static final long serialVersionUID = -1653665542635275551L; + + private final Map resources = new HashMap<>(); + + private final Set runningResCheck = new HashSet<>(); + + private final Map connectors = new HashMap<>(); + + private final Set runningConnCheck = new HashSet<>(); + + private final ConnectorRestClient connectorRestClient = new ConnectorRestClient(); + + private final ResourceRestClient resourceRestClient = new ResourceRestClient(); + + @Override + protected void onMessage(final WebSocketRequestHandler handler, final TextMessage message) { + try { + final ObjectMapper mapper = new ObjectMapper(); + final JsonNode obj = mapper.readTree(message.getText()); + + final ExecutorService executorService = Executors.newFixedThreadPool(1); + + switch (Topology.SupportedOperation.valueOf(obj.get("kind").asText())) { + case CHECK_CONNECTOR: + final Long ckey = obj.get("target").asLong(); + + if (connectors.containsKey(ckey)) { + handler.push(connectors.get(ckey)); + } else { + handler.push(String.format( + "{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.UNKNOWN, ckey)); + } + + synchronized (runningConnCheck) { + if (runningConnCheck.contains(ckey)) { + LOG.debug("Running connection check for connector {}", ckey); + } else { + runningConnCheck.add(ckey); + } + } + + executorService.execute(new ConnCheck(ckey)); + + break; + case CHECK_RESOURCE: + final String rkey = obj.get("target").asText(); + + if (resources.containsKey(rkey)) { + handler.push(resources.get(rkey)); + } else { + handler.push(String.format( + "{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.UNKNOWN, rkey)); + } + + synchronized (runningResCheck) { + if (runningResCheck.contains(rkey)) { + LOG.debug("Running connection check for resource {}", rkey); + } else { + runningResCheck.add(rkey); + } + } + + executorService.execute(new ResCheck(rkey)); + + break; + case ADD_ENDPOINT: + handler.appendJavaScript(String.format("addEndpoint('%s', '%s', '%s');", + obj.get("source").asText(), + obj.get("target").asText(), + obj.get("scope").asText())); + break; + default: + } + + executorService.shutdown(); + + } catch (IOException e) { + LOG.error("Eror managing websocket message", e); + } + } + + class ConnCheck implements Runnable { + + private final Long key; + + private final Application application; + + private final Session session; + - public ConnCheck(final Long key) { ++ ConnCheck(final Long key) { + this.key = key; + this.application = Application.get(); + this.session = Session.exists() ? Session.get() : null; + } + + @Override + public void run() { + try { + ThreadContext.setApplication(application); + ThreadContext.setSession(session); + + String res; + try { + final ConnInstanceTO connector = connectorRestClient.read(key); + res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", + connectorRestClient.check(connector) + ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key); + } catch (Exception e) { + LOG.warn("Error checking connection for {}", key, e); + res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key); + } + + synchronized (runningConnCheck) { + connectors.put(key, res); + runningConnCheck.remove(key); + } + } finally { + ThreadContext.detach(); + } + } + } + + class ResCheck implements Runnable { + + private final String key; + + private final Application application; + + private final Session session; + - public ResCheck(final String key) { ++ ResCheck(final String key) { + this.key = key; + this.application = Application.get(); + this.session = Session.exists() ? Session.get() : null; + } + + @Override + public void run() { + try { + ThreadContext.setApplication(application); + ThreadContext.setSession(session); + + String res; + try { + final ResourceTO resource = resourceRestClient.read(key); + res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", + connectorRestClient.check(resource) + ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key); + } catch (Exception e) { + LOG.warn("Error checking connection for {}", key, e); + res = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key); + } + + synchronized (runningResCheck) { + resources.put(key, res); + runningResCheck.remove(key); + } + } finally { + ThreadContext.detach(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java ---------------------------------------------------------------------- diff --cc client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java index ec405a2,0000000..1c6731f mode 100644,000000..100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java @@@ -1,102 -1,0 +1,102 @@@ +/* + * 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.wicket.markup.html.form; + +import java.io.Serializable; +import org.apache.wicket.ajax.AjaxRequestTarget; + +public abstract class ActionLink implements Serializable { + + private static final long serialVersionUID = 7031329706998320639L; + + private boolean reloadFeedbackPanel = true; + + private T modelObject; + + public ActionLink() { + } + + public ActionLink(final T modelObject) { + this.modelObject = modelObject; + } + + public enum ActionType { + + MAPPING("update"), + ACCOUNT_LINK("update"), + RESET_TIME("update"), + CLONE("create"), + CREATE("create"), + EDIT("read"), + USER_TEMPLATE("read"), + GROUP_TEMPLATE("read"), + RESET("update"), + ENABLE("update"), + SEARCH("read"), + DELETE("delete"), + EXECUTE("execute"), + DRYRUN("execute"), + CLAIM("claim"), + SELECT("read"), + EXPORT("read"), + SUSPEND("update"), + REACTIVATE("update"), + RELOAD("reload"), + CHANGE_VIEW("changeView"), + UNLINK("update"), + LINK("update"), + UNASSIGN("update"), + ASSIGN("update"), + DEPROVISION("update"), + PROVISION("update"), + MANAGE_RESOURCES("update"), + MANAGE_USERS("update"), + MANAGE_GROUPS("update"), + ZOOM_IN("zoomin"), + ZOOM_OUT("zoomout"); + + private final String actionId; + - private ActionType(final String actionId) { ++ ActionType(final String actionId) { + this.actionId = actionId; + } + + public String getActionId() { + return actionId; + } + } + + public T getModelObject() { + return modelObject; + } + + public abstract void onClick(final AjaxRequestTarget target, final T modelObject); + + public void postClick() { + } + + public boolean feedbackPanelAutomaticReload() { + return reloadFeedbackPanel; + } + + public ActionLink feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) { + this.reloadFeedbackPanel = reloadFeedbackPanel; + return this; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java ---------------------------------------------------------------------- diff --cc client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java index 30a7bbc,0000000..161df03 mode 100644,000000..100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/provision/ProvisionWizardBuilder.java @@@ -1,222 -1,0 +1,222 @@@ +/* + * Copyright 2015 The Apache Software Foundation. + * + * Licensed 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.provision; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.panels.ResourceMappingPanel; +import org.apache.syncope.client.console.rest.AnyTypeRestClient; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.client.console.wizards.AjaxWizardBuilder; +import org.apache.syncope.common.lib.to.AnyTypeTO; +import org.apache.syncope.common.lib.to.ProvisionTO; +import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.extensions.wizard.WizardModel; +import org.apache.wicket.extensions.wizard.WizardStep; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.model.StringResourceModel; + +public class ProvisionWizardBuilder extends AjaxWizardBuilder implements Serializable { + + private static final long serialVersionUID = 1L; + + private final ResourceTO resourceTO; + + private final LoadableDetachableModel> anyTypes = new LoadableDetachableModel>() { + + private static final long serialVersionUID = 1L; + + @Override + protected List load() { + final List currentlyAdded = new ArrayList<>(); + + CollectionUtils.collect(resourceTO.getProvisions(), new Transformer() { + + @Override + public String transform(final ProvisionTO provisionTO) { + return provisionTO.getAnyType(); + } + }, currentlyAdded); + + final List res = new ArrayList<>(); + + CollectionUtils.filter( + CollectionUtils.collect(new AnyTypeRestClient().getAll(), new Transformer() { + + @Override + public String transform(final AnyTypeTO anyTypeTO) { + return anyTypeTO.getKey(); + } + }, res), new Predicate() { + + @Override + public boolean evaluate(final String key) { + return !currentlyAdded.contains(key); + } + }); + + return res; + } + }; + + /** + * The object type specification step. + */ + private final class ObjectType extends WizardStep { + + private static final long serialVersionUID = 1L; + + /** + * Construct. + */ - public ObjectType(final ProvisionTO item) { ++ ObjectType(final ProvisionTO item) { + super(new ResourceModel("type.title", StringUtils.EMPTY), + new ResourceModel("type.summary", StringUtils.EMPTY), new Model(item)); + + add(new AjaxDropDownChoicePanel("type", "type", new PropertyModel(item, "anyType"), false). + setChoices(anyTypes). + setStyleSheet("form-control"). + setRequired(true)); + + add(new TextField( + "class", new PropertyModel(item, "objectClass")).setRequired(true)); + } + } + + /** + * Mapping definition step. + */ + private final class Mapping extends WizardStep { + + private static final long serialVersionUID = 1L; + + /** + * Construct. + */ - public Mapping(final ProvisionTO item) { ++ Mapping(final ProvisionTO item) { + setTitleModel(new ResourceModel("mapping.title", "Mapping")); + setSummaryModel(new StringResourceModel("mapping.summary", this, new Model(item))); + + add(new ResourceMappingPanel("mapping", resourceTO, item)); + } + } + + /** + * AccountLink specification step. + */ + private final class ConnObjectLink extends WizardStep { + + private static final long serialVersionUID = 1L; + + /** + * Construct. + */ - public ConnObjectLink(final ProvisionTO item) { ++ ConnObjectLink(final ProvisionTO item) { + super(new ResourceModel("link.title", StringUtils.EMPTY), + new ResourceModel("link.summary", StringUtils.EMPTY)); + + final WebMarkupContainer connObjectLinkContainer = new WebMarkupContainer("connObjectLinkContainer"); + connObjectLinkContainer.setOutputMarkupId(true); + add(connObjectLinkContainer); + + boolean connObjectLinkEnabled = false; + if (StringUtils.isNotBlank(item.getMapping().getConnObjectLink())) { + connObjectLinkEnabled = true; + } + + final AjaxCheckBoxPanel connObjectLinkCheckbox = new AjaxCheckBoxPanel( + "connObjectLinkCheckbox", + new ResourceModel("connObjectLinkCheckbox", "connObjectLinkCheckbox").getObject(), + new Model<>(connObjectLinkEnabled), + false); + connObjectLinkCheckbox.setEnabled(true); + + connObjectLinkContainer.add(connObjectLinkCheckbox); + + final AjaxTextFieldPanel connObjectLink = new AjaxTextFieldPanel( + "connObjectLink", + new ResourceModel("connObjectLink", "connObjectLink").getObject(), + new PropertyModel(item.getMapping(), "connObjectLink"), + false); + connObjectLink.setEnabled(connObjectLinkEnabled); + connObjectLinkContainer.add(connObjectLink); + + connObjectLinkCheckbox.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + if (connObjectLinkCheckbox.getModelObject()) { + connObjectLink.setEnabled(Boolean.TRUE); + connObjectLink.setModelObject(""); + } else { + connObjectLink.setEnabled(Boolean.FALSE); + connObjectLink.setModelObject(""); + } + + target.add(connObjectLink); + } + }); + } + } + + /** + * Construct. + * + * @param id The component id + * @param resourceTO external resource to be updated. + * @param pageRef Caller page reference. + */ + public ProvisionWizardBuilder(final String id, final ResourceTO resourceTO, final PageReference pageRef) { + super(id, new ProvisionTO(), pageRef); + this.resourceTO = resourceTO; + } + + @Override + protected WizardModel buildModelSteps(final ProvisionTO modelObject, final WizardModel wizardModel) { + wizardModel.add(new ObjectType(modelObject)); + wizardModel.add(new Mapping(modelObject)); + wizardModel.add(new ConnObjectLink(modelObject)); + return wizardModel; + } + + @Override + protected void onCancelInternal() { + // d nothing + } + + @Override + protected void onApplyInternal() { + // do nothing + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java ---------------------------------------------------------------------- diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java index 46dc302,0000000..724da5a mode 100644,000000..100644 --- a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java @@@ -1,254 -1,0 +1,254 @@@ +/* + * 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.lib; + +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.Marshaller; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.feature.Feature; +import org.apache.cxf.feature.LoggingFeature; +import org.apache.cxf.jaxrs.provider.JAXBElementProvider; +import org.apache.cxf.staxutils.DocumentDepthProperties; +import org.apache.syncope.common.lib.policy.AbstractPolicyTO; +import org.apache.syncope.common.rest.api.RESTHeaders; + +/** + * Factory bean for creating instances of {@link SyncopeClient}. + * Supports Spring-bean configuration and override via subclassing (see protected methods). + */ +public class SyncopeClientFactoryBean { + + public enum ContentType { + + JSON(MediaType.APPLICATION_JSON_TYPE), + XML(MediaType.APPLICATION_XML_TYPE); + + private final MediaType mediaType; + - private ContentType(final MediaType mediaType) { ++ ContentType(final MediaType mediaType) { + this.mediaType = mediaType; + } + + public MediaType getMediaType() { + return mediaType; + } + + public static ContentType fromString(final String value) { + return StringUtils.isNotBlank(value) && value.equalsIgnoreCase(XML.getMediaType().toString()) + ? XML + : JSON; + } + } + + private JacksonJaxbJsonProvider jsonProvider; + + private JAXBElementProvider jaxbProvider; + + private RestClientExceptionMapper exceptionMapper; + + private String address; + + private ContentType contentType; + + private String domain; + + private boolean useCompression; + + private RestClientFactoryBean restClientFactoryBean; + + protected JacksonJaxbJsonProvider defaultJsonProvider() { + return new JacksonJaxbJsonProvider(); + } + + @SuppressWarnings({ "rawtypes" }) + protected JAXBElementProvider defaultJAXBProvider() { + JAXBElementProvider defaultJAXBProvider = new JAXBElementProvider(); + + DocumentDepthProperties depthProperties = new DocumentDepthProperties(); + depthProperties.setInnerElementCountThreshold(500); + defaultJAXBProvider.setDepthProperties(depthProperties); + + Map marshallerProperties = new HashMap<>(); + marshallerProperties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + defaultJAXBProvider.setMarshallerProperties(marshallerProperties); + + Map collectionWrapperMap = new HashMap<>(); + collectionWrapperMap.put(AbstractPolicyTO.class.getName(), "policies"); + defaultJAXBProvider.setCollectionWrapperMap(collectionWrapperMap); + + return defaultJAXBProvider; + } + + protected RestClientExceptionMapper defaultExceptionMapper() { + return new RestClientExceptionMapper(); + } + + protected RestClientFactoryBean defaultRestClientFactoryBean() { + RestClientFactoryBean defaultRestClientFactoryBean = new RestClientFactoryBean(); + + if (StringUtils.isBlank(address)) { + throw new IllegalArgumentException("Property 'address' is missing"); + } + defaultRestClientFactoryBean.setAddress(address); + + if (StringUtils.isNotBlank(domain)) { + defaultRestClientFactoryBean.setHeaders(Collections.singletonMap(RESTHeaders.DOMAIN, domain)); + } + + defaultRestClientFactoryBean.setThreadSafe(true); + defaultRestClientFactoryBean.setInheritHeaders(true); + + List features = new ArrayList<>(); + features.add(new LoggingFeature()); + defaultRestClientFactoryBean.setFeatures(features); + + List providers = new ArrayList<>(3); + providers.add(getJaxbProvider()); + providers.add(getJsonProvider()); + providers.add(getExceptionMapper()); + defaultRestClientFactoryBean.setProviders(providers); + + return defaultRestClientFactoryBean; + } + + public JacksonJaxbJsonProvider getJsonProvider() { + return jsonProvider == null + ? defaultJsonProvider() + : jsonProvider; + } + + public void setJsonProvider(final JacksonJaxbJsonProvider jsonProvider) { + this.jsonProvider = jsonProvider; + } + + public JAXBElementProvider getJaxbProvider() { + return jaxbProvider == null + ? defaultJAXBProvider() + : jaxbProvider; + } + + public SyncopeClientFactoryBean setJaxbProvider(final JAXBElementProvider jaxbProvider) { + this.jaxbProvider = jaxbProvider; + return this; + } + + public RestClientExceptionMapper getExceptionMapper() { + return exceptionMapper == null + ? defaultExceptionMapper() + : exceptionMapper; + } + + public SyncopeClientFactoryBean setExceptionMapper(final RestClientExceptionMapper exceptionMapper) { + this.exceptionMapper = exceptionMapper; + return this; + } + + public String getAddress() { + return address; + } + + public SyncopeClientFactoryBean setAddress(final String address) { + this.address = address; + return this; + } + + public ContentType getContentType() { + return contentType == null + ? ContentType.JSON + : contentType; + } + + public SyncopeClientFactoryBean setContentType(final ContentType contentType) { + this.contentType = contentType; + return this; + } + + public SyncopeClientFactoryBean setContentType(final String contentType) { + this.contentType = ContentType.fromString(contentType); + return this; + } + + public String getDomain() { + return domain; + } + + public SyncopeClientFactoryBean setDomain(final String domain) { + this.domain = domain; + return this; + } + + /** + * Sets the given service instance for transparent gzip Content-Encoding handling. + * + * @param useCompression whether transparent gzip Content-Encoding handling is to be enabled + * @return the current instance + */ + public SyncopeClientFactoryBean setUseCompression(final boolean useCompression) { + this.useCompression = useCompression; + return this; + } + + public boolean isUseCompression() { + return useCompression; + } + + public RestClientFactoryBean getRestClientFactoryBean() { + return restClientFactoryBean == null + ? defaultRestClientFactoryBean() + : restClientFactoryBean; + } + + public SyncopeClientFactoryBean setRestClientFactoryBean(final RestClientFactoryBean restClientFactoryBean) { + this.restClientFactoryBean = restClientFactoryBean; + return this; + } + + /** + * Builds client instance with no authentication, for user self-registration and related queries (schema, + * resources, ...). + * + * @return client instance with no authentication + */ + public SyncopeClient create() { + return create(null, null); + } + + /** + * Builds client instance with the given credentials. + * + * @param username username + * @param password password + * @return client instance with the given credentials + */ + public SyncopeClient create(final String username, final String password) { + return new SyncopeClient( + getContentType().getMediaType(), + getRestClientFactoryBean(), + getExceptionMapper(), + username, + password, + useCompression); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java ---------------------------------------------------------------------- diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java index ee35e28,0000000..136d798 mode 100644,000000..100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AnyTypeKind.java @@@ -1,44 -1,0 +1,44 @@@ +/* + * 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.common.lib.types; + +import javax.xml.bind.annotation.XmlEnum; +import org.apache.syncope.common.lib.to.AnyObjectTO; +import org.apache.syncope.common.lib.to.AnyTO; +import org.apache.syncope.common.lib.to.GroupTO; +import org.apache.syncope.common.lib.to.UserTO; + +@XmlEnum +public enum AnyTypeKind { + + USER(UserTO.class), + GROUP(GroupTO.class), + ANY_OBJECT(AnyObjectTO.class); + + private final Class toClass; + - private AnyTypeKind(final Class toClass) { ++ AnyTypeKind(final Class toClass) { + this.toClass = toClass; + } + + public Class getToClass() { + return toClass; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java ---------------------------------------------------------------------- diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java index 0c19403,0000000..e4a0f10 mode 100644,000000..100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java @@@ -1,103 -1,0 +1,103 @@@ +/* + * 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.common.lib.types; + +import javax.ws.rs.core.Response; + +public enum ClientExceptionType { + + AssociatedResources(Response.Status.BAD_REQUEST), + Composite(Response.Status.BAD_REQUEST), + ConcurrentModification(Response.Status.PRECONDITION_FAILED), + ConnectorException(Response.Status.BAD_REQUEST), + DataIntegrityViolation(Response.Status.CONFLICT), + EntityExists(Response.Status.CONFLICT), + GenericPersistence(Response.Status.BAD_REQUEST), + InvalidSecurityAnswer(Response.Status.BAD_REQUEST), + InvalidEntity(Response.Status.BAD_REQUEST), + InvalidLogger(Response.Status.BAD_REQUEST), + InvalidConnInstance(Response.Status.BAD_REQUEST), + InvalidConnIdConf(Response.Status.BAD_REQUEST), + InvalidPolicy(Response.Status.BAD_REQUEST), + InvalidConf(Response.Status.BAD_REQUEST), + InvalidPath(Response.Status.BAD_REQUEST), + InvalidProvision(Response.Status.BAD_REQUEST), + InvalidReport(Response.Status.BAD_REQUEST), + InvalidReportExec(Response.Status.BAD_REQUEST), + InvalidRelationshipType(Response.Status.BAD_REQUEST), + InvalidAnyType(Response.Status.BAD_REQUEST), + InvalidAnyObject(Response.Status.BAD_REQUEST), + InvalidGroup(Response.Status.BAD_REQUEST), + InvalidSchemaDefinition(Response.Status.BAD_REQUEST), + InvalidSearchExpression(Response.Status.BAD_REQUEST), + InvalidPageOrSize(Response.Status.BAD_REQUEST), + InvalidPropagationTaskExecReport(Response.Status.BAD_REQUEST), + InvalidPlainSchema(Response.Status.BAD_REQUEST), + InvalidDerSchema(Response.Status.BAD_REQUEST), + InvalidVirSchema(Response.Status.BAD_REQUEST), + InvalidMapping(Response.Status.BAD_REQUEST), + InvalidRealm(Response.Status.BAD_REQUEST), + InvalidUser(Response.Status.BAD_REQUEST), + InvalidExternalResource(Response.Status.BAD_REQUEST), + InvalidNotification(Response.Status.BAD_REQUEST), + InvalidPropagationTask(Response.Status.BAD_REQUEST), + InvalidSchedTask(Response.Status.BAD_REQUEST), + InvalidSyncTask(Response.Status.BAD_REQUEST), + InvalidValues(Response.Status.BAD_REQUEST), + NotFound(Response.Status.NOT_FOUND), + RejectedUserCreate(Response.Status.BAD_REQUEST), + RequiredValuesMissing(Response.Status.BAD_REQUEST), + RESTValidation(Response.Status.BAD_REQUEST), + GroupOwnership(Response.Status.BAD_REQUEST), + Scheduling(Response.Status.BAD_REQUEST), + DelegatedAdministration(Response.Status.FORBIDDEN), + UnallowedSchemas(Response.Status.BAD_REQUEST), + Unknown(Response.Status.BAD_REQUEST), + Workflow(Response.Status.BAD_REQUEST); + + private final Response.Status responseStatus; + - private ClientExceptionType(final Response.Status responseStatus) { ++ ClientExceptionType(final Response.Status responseStatus) { + this.responseStatus = responseStatus; + } + + public static ClientExceptionType fromHeaderValue(final String exceptionTypeHeaderValue) { + ClientExceptionType result = null; + for (ClientExceptionType type : values()) { + if (exceptionTypeHeaderValue.equals(type.name())) { + result = type; + } + } + + if (result == null) { + throw new IllegalArgumentException("Unexpected header value: " + exceptionTypeHeaderValue); + } + + return result; + } + + public String getInfoHeaderValue(final String value) { + return name() + ":" + value; + } + + public Response.Status getResponseStatus() { + return responseStatus; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java ---------------------------------------------------------------------- diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java index 4588a36,0000000..eccb89d mode 100644,000000..100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java @@@ -1,201 -1,0 +1,201 @@@ +/* + * 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.common.lib.types; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +import javax.xml.bind.annotation.XmlEnum; + +/** + * Internal attribute mapping type. + */ +@XmlEnum +public enum IntMappingType { + + // Unfortunately enum type cannot be extended ... + // ------------------------- + // User attribute types (the same in UserMappingType) + // ------------------------- + UserPlainSchema(AnyTypeKind.USER), + UserDerivedSchema(AnyTypeKind.USER), + UserVirtualSchema(AnyTypeKind.USER), + UserKey(AnyTypeKind.USER), + Username(AnyTypeKind.USER), + Password(AnyTypeKind.USER), + // ------------------------- + // Group attribute types (the same in GroupMappingType) + // ------------------------- + GroupPlainSchema(AnyTypeKind.GROUP), + GroupDerivedSchema(AnyTypeKind.GROUP), + GroupVirtualSchema(AnyTypeKind.GROUP), + GroupKey(AnyTypeKind.GROUP), + GroupName(AnyTypeKind.GROUP), + GroupOwnerSchema(AnyTypeKind.GROUP), + // ------------------------- + // Any attribute types (the same in AnyMappingType) + // ------------------------- + AnyObjectPlainSchema(AnyTypeKind.ANY_OBJECT), + AnyObjectDerivedSchema(AnyTypeKind.ANY_OBJECT), + AnyObjectVirtualSchema(AnyTypeKind.ANY_OBJECT), + AnyObjectKey(AnyTypeKind.ANY_OBJECT); + + private final AnyTypeKind anyTypeKind; + - private IntMappingType(final AnyTypeKind anyTypeKind) { ++ IntMappingType(final AnyTypeKind anyTypeKind) { + this.anyTypeKind = anyTypeKind; + } + + public AnyTypeKind getAnyTypeKind() { + return anyTypeKind; + } + + /** + * Get attribute types for a certain any object type. + * + * @param anyTypeKind any object type + * @param toBeFiltered types to be filtered from the result. + * @return set of attribute types. + */ + public static Set getAttributeTypes( + final AnyTypeKind anyTypeKind, final Collection toBeFiltered) { + + final Set res = getAttributeTypes(anyTypeKind); + res.removeAll(toBeFiltered); + + return res; + } + + /** + * Get attribute types for a certain any object type. + * + * @param anyTypeKind any object type + * @return set of attribute types. + */ + public static Set getAttributeTypes(final AnyTypeKind anyTypeKind) { + EnumSet enumset; + + switch (anyTypeKind) { + case GROUP: + enumset = EnumSet.allOf(GroupMappingType.class); + break; + + case ANY_OBJECT: + enumset = EnumSet.allOf(AnyMappingType.class); + break; + + case USER: + default: + enumset = EnumSet.allOf(UserMappingType.class); + break; + } + + final Set result = new HashSet<>(enumset.size()); + for (Object obj : enumset) { + result.add(IntMappingType.valueOf(obj.toString())); + } + + return result; + } + + public static Set getEmbedded() { + return EnumSet.of(IntMappingType.UserKey, IntMappingType.Username, IntMappingType.Password, + IntMappingType.GroupKey, IntMappingType.GroupName, IntMappingType.GroupOwnerSchema, + IntMappingType.AnyObjectKey); + } + + /** + * Check if attribute type belongs to the specified any object type set. + * + * @param anyTypeKind any object type. + * @param type attribute type. + * @return true if attribute type belongs to the specified any object type set. + */ + public static boolean contains(final AnyTypeKind anyTypeKind, final String type) { + switch (anyTypeKind) { + case GROUP: + for (GroupMappingType c : GroupMappingType.values()) { + if (c.name().equals(type)) { + return true; + } + } + break; + + case ANY_OBJECT: + for (AnyMappingType c : AnyMappingType.values()) { + if (c.name().equals(type)) { + return true; + } + } + break; + + case USER: + default: + for (UserMappingType c : UserMappingType.values()) { + if (c.name().equals(type)) { + return true; + } + } + break; + } + return false; + } + + /** + * User attribute types. + */ + private enum UserMappingType { + + UserPlainSchema, + UserDerivedSchema, + UserVirtualSchema, + UserKey, + Username, + Password; + + } + + /** + * Group attribute types. + */ + private enum GroupMappingType { + + GroupPlainSchema, + GroupDerivedSchema, + GroupVirtualSchema, + GroupKey, + GroupName, + GroupOwnerSchema; + + } + + /** + * Any attribute types. + */ + private enum AnyMappingType { + + AnyObjectPlainSchema, + AnyObjectDerivedSchema, + AnyObjectVirtualSchema, + AnyObjectKey; + + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java ---------------------------------------------------------------------- diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java index a60a5af,0000000..ce1b5cd mode 100644,000000..100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/TaskType.java @@@ -1,54 -1,0 +1,54 @@@ +/* + * 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.common.lib.types; + +import javax.xml.bind.annotation.XmlEnum; + +@XmlEnum +public enum TaskType { + + PROPAGATION("propagation"), + NOTIFICATION("notification"), + SCHEDULED("sched"), + SYNCHRONIZATION("sync"), + PUSH("push"); + + private final String name; + - private TaskType(final String name) { ++ TaskType(final String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public static TaskType fromString(final String name) { + if (name != null) { + for (TaskType t : TaskType.values()) { + if (t.name.equalsIgnoreCase(name)) { + return t; + } + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java ---------------------------------------------------------------------- diff --cc common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java index a448c03,0000000..8d21e54 mode 100644,000000..100644 --- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java +++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/Preference.java @@@ -1,59 -1,0 +1,59 @@@ +/* + * 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.common.rest.api; + +/** + * Preferences available to be specified during requests. + * + * @see RESTHeaders#PREFER + * @see RESTHeaders#PREFERENCE_APPLIED + */ +public enum Preference { + + NONE(""), + RETURN_CONTENT("return-content"), + RETURN_NO_CONTENT("return-no-content"); + + private final String literal; + - private Preference(final String literal) { ++ Preference(final String literal) { + this.literal = literal; + } + + @Override + public String toString() { + return literal; + } + + public static Preference fromString(final String literal) { + Preference result = null; + + for (Preference preference : values()) { + if (preference.toString().equalsIgnoreCase(literal)) { + result = preference; + } + } + + if (result == null) { + result = NONE; + } + + return result; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/4e0783e1/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java ---------------------------------------------------------------------- diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java index e85058c,0000000..9a796ef mode 100644,000000..100644 --- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java +++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java @@@ -1,259 -1,0 +1,259 @@@ +/* + * 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.core.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.patch.AnyPatch; +import org.apache.syncope.common.lib.to.AnyTO; +import org.apache.syncope.common.lib.to.GroupTO; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.ClientExceptionType; +import org.apache.syncope.core.misc.RealmUtils; +import org.apache.syncope.core.misc.TemplateUtils; +import org.apache.syncope.core.misc.security.DelegatedAdministrationException; +import org.apache.syncope.core.misc.spring.ApplicationContextProvider; +import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; +import org.apache.syncope.core.persistence.api.dao.RealmDAO; +import org.apache.syncope.core.persistence.api.dao.search.OrderByClause; +import org.apache.syncope.core.persistence.api.dao.search.SearchCond; +import org.apache.syncope.core.persistence.api.entity.AnyType; +import org.apache.syncope.core.persistence.api.entity.Realm; +import org.apache.syncope.core.provisioning.api.LogicActions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.AbstractBeanDefinition; + +public abstract class AbstractAnyLogic + extends AbstractResourceAssociator { + + @Autowired + private RealmDAO realmDAO; + + @Autowired + private AnyTypeDAO anyTypeDAO; + + @Autowired + private TemplateUtils templateUtils; + + private List getActions(final Realm realm) { + List actions = new ArrayList<>(); + + for (String className : realm.getActionsClassNames()) { + try { + Class actionsClass = Class.forName(className); + LogicActions logicActions = (LogicActions) ApplicationContextProvider.getBeanFactory(). + createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true); + + actions.add(logicActions); + } catch (Exception e) { + LOG.warn("Class '{}' not found", className, e); + } + } + + return actions; + } + + protected Pair> beforeCreate(final TO input) { + Realm realm = realmDAO.find(input.getRealm()); + if (realm == null) { + SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm); + sce.getElements().add(input.getRealm()); + throw sce; + } + + AnyType anyType = input instanceof UserTO + ? anyTypeDAO.findUser() + : input instanceof GroupTO + ? anyTypeDAO.findGroup() + : anyTypeDAO.find(input.getType()); + if (anyType == null) { + SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidAnyType); + sce.getElements().add(input.getType()); + throw sce; + } + + TO any = input; + + templateUtils.apply(any, realm.getTemplate(anyType)); + + List actions = getActions(realm); + for (LogicActions action : actions) { + any = action.beforeCreate(any); + } + + LOG.debug("Input: {}\nOutput: {}\n", input, any); + + return ImmutablePair.of(any, actions); + } + + protected TO afterCreate(final TO input, final List actions) { + TO any = input; + + for (LogicActions action : actions) { + any = action.afterCreate(any); + } + + return any; + } + + protected Pair> beforeUpdate(final P input, final String realmPath) { + Realm realm = realmDAO.find(realmPath); + if (realm == null) { + SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm); + sce.getElements().add(realmPath); + throw sce; + } + + P mod = input; + + List actions = getActions(realm); + for (LogicActions action : actions) { + mod = action.beforeUpdate(mod); + } + + LOG.debug("Input: {}\nOutput: {}\n", input, mod); + + return ImmutablePair.of(mod, actions); + } + + protected TO afterUpdate(final TO input, final List actions) { + TO any = input; + + for (LogicActions action : actions) { + any = action.afterUpdate(any); + } + + return any; + } + + protected Pair> beforeDelete(final TO input) { + Realm realm = realmDAO.find(input.getRealm()); + if (realm == null) { + SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm); + sce.getElements().add(input.getRealm()); + throw sce; + } + + TO any = input; + + List actions = getActions(realm); + for (LogicActions action : actions) { + any = action.beforeDelete(any); + } + + LOG.debug("Input: {}\nOutput: {}\n", input, any); + + return ImmutablePair.of(any, actions); + } + + protected TO afterDelete(final TO input, final List actions) { + TO any = input; + + for (LogicActions action : actions) { + any = action.afterDelete(any); + } + + return any; + } + + private static class StartsWithPredicate implements Predicate { + + private final Collection targets; + - public StartsWithPredicate(final Collection targets) { ++ StartsWithPredicate(final Collection targets) { + this.targets = targets; + } + + @Override + public boolean evaluate(final String realm) { + return CollectionUtils.exists(targets, new Predicate() { + + @Override + public boolean evaluate(final String target) { + return realm.startsWith(target); + } + }); + } + + } + + protected Set getEffectiveRealms( + final Set allowedRealms, final Collection requestedRealms) { + + Set allowed = RealmUtils.normalize(allowedRealms); + Set requested = RealmUtils.normalize(requestedRealms); + + Set effective = new HashSet<>(); + CollectionUtils.select(requested, new StartsWithPredicate(allowed), effective); + CollectionUtils.select(allowed, new StartsWithPredicate(requested), effective); + + return effective; + } + + protected void securityChecks(final Set effectiveRealms, final String realm, final Long key) { + if (!CollectionUtils.exists(effectiveRealms, new Predicate() { + + @Override + public boolean evaluate(final String ownedRealm) { + return realm.startsWith(ownedRealm); + } + })) { + + throw new DelegatedAdministrationException( + this instanceof UserLogic + ? AnyTypeKind.USER + : this instanceof GroupLogic + ? AnyTypeKind.GROUP + : AnyTypeKind.ANY_OBJECT, + key); + } + } + + public abstract TO read(Long key); + + public abstract int count(List realms); + + public abstract TO create(TO anyTO); + + public abstract TO update(P anyPatch); + + public abstract TO delete(Long key); + + public abstract List list( + int page, int size, List orderBy, + List realms, + boolean details); + + public abstract List search( + SearchCond searchCondition, + int page, int size, List orderBy, + List realms, + boolean details); + + public abstract int searchCount(SearchCond searchCondition, List realms); +}