/* * 2012-3 Red Hat Inc. and/or its affiliates and other contributors. * * 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.overlord.rtgov.service.dependency.layout; import java.util.Collections; import java.util.Comparator; import org.overlord.rtgov.service.dependency.OperationNode; import org.overlord.rtgov.service.dependency.ServiceGraph; import org.overlord.rtgov.service.dependency.ServiceNode; import org.overlord.rtgov.service.dependency.UsageLink; /** * This class represents the default service graph layout * algorithm implementation. * */ public class ServiceGraphLayoutImpl implements ServiceGraphLayout { /** * This definition represents the width of an operation node. */ protected static final int OPERATION_WIDTH=160; /** * This definition represents the height of an operation node. */ protected static final int OPERATION_HEIGHT=20; /** * This definition represents the padding gap around the service inside. */ protected static final int SERVICE_BORDER_PADDING=10; /** * This definition represents the width of a service node. */ protected static final int SERVICE_WIDTH=OPERATION_WIDTH+(2 * SERVICE_BORDER_PADDING); /** * This definition represents the padding for the service node header. */ protected static final int SERVICE_HEADER_PADDING=20; /** * This definition represents the initial horizontal padding for the * root service nodes. */ protected static final int SERVICE_INITIAL_HORIZONTAL_PADDING=50; /** * This definition represents the horizontal padding between service nodes. */ protected static final int SERVICE_HORIZONTAL_PADDING=200; /** * This definition represents the vertical padding between service nodes. */ protected static final int SERVICE_VERTICAL_PADDING=50; private int _height=0; private int _width=0; /** * {@inheritDoc} */ public void layout(ServiceGraph sg) { // Find initial service nodes java.util.List<ServiceNode> initialNodes=new java.util.ArrayList<ServiceNode>(); for (ServiceNode sn : sg.getServiceNodes()) { if (sn.getProperties().get(ServiceNode.INITIAL_NODE) == Boolean.TRUE) { initialNodes.add(sn); } } // Sort initial node list Collections.sort(initialNodes, new Comparator<ServiceNode>() { public int compare(ServiceNode o1, ServiceNode o2) { // TODO: May need to sort based on interface's localpart, if a fully qualified name return (o1.getService().getServiceType().compareTo(o2.getService().getServiceType())); } }); // Layout service nodes for (ServiceNode sn : initialNodes) { layoutService(sg, sn, SERVICE_INITIAL_HORIZONTAL_PADDING, _height+SERVICE_VERTICAL_PADDING); } // Record the overall height and width sg.getProperties().put(ServiceGraphLayout.HEIGHT, _height); sg.getProperties().put(ServiceGraphLayout.WIDTH, _width); } /** * This method determines whether the supplied service node * requires layout. * * @param sn The service node * @return Whether the service node requires layout */ protected boolean requiresLayout(ServiceNode sn) { return (sn.getProperties().get(ServiceGraphLayout.X_POSITION) == null); } /** * This method performs the layout of the supplied service * node. * * @param sg The service graph * @param sn The service node * @param x The x position * @param y The y position */ protected void layoutService(ServiceGraph sg, ServiceNode sn, int x, int y) { // Ensure service has not already been processed if (requiresLayout(sn)) { sn.getProperties().put(ServiceGraphLayout.X_POSITION, x); sn.getProperties().put(ServiceGraphLayout.Y_POSITION, y); sn.getProperties().put(ServiceGraphLayout.WIDTH, SERVICE_WIDTH); sn.getProperties().put(ServiceGraphLayout.HEIGHT, SERVICE_HEADER_PADDING+((OPERATION_HEIGHT + SERVICE_BORDER_PADDING) * sn.getOperations().size())); int opX=x+SERVICE_BORDER_PADDING; int opY=y+SERVICE_HEADER_PADDING; // Build list of operations java.util.List<OperationNode> oplist=new java.util.ArrayList<OperationNode>(sn.getOperations()); // Sort list of operations Collections.sort(oplist, new Comparator<OperationNode>() { public int compare(OperationNode o1, OperationNode o2) { return (o1.getOperation().getName().compareTo(o2.getOperation().getName())); } }); // Layout the operations for (OperationNode opn : oplist) { opn.getProperties().put(ServiceGraphLayout.X_POSITION, opX); opn.getProperties().put(ServiceGraphLayout.Y_POSITION, opY); opn.getProperties().put(ServiceGraphLayout.WIDTH, OPERATION_WIDTH); opn.getProperties().put(ServiceGraphLayout.HEIGHT, OPERATION_HEIGHT); opY += OPERATION_HEIGHT + SERVICE_BORDER_PADDING; } // Check if width and/or height needs to be updated int maxX=(Integer)sn.getProperties().get(ServiceGraphLayout.X_POSITION) +(Integer)sn.getProperties().get(ServiceGraphLayout.WIDTH); int maxY=(Integer)sn.getProperties().get(ServiceGraphLayout.Y_POSITION) +(Integer)sn.getProperties().get(ServiceGraphLayout.HEIGHT); if (maxX > _width) { _width = maxX; } if (maxY > _height) { _height = maxY; } // Identify the 'used' services to layout int newX=maxX + SERVICE_HORIZONTAL_PADDING; int newY=y; // Identify links to be laid out java.util.List<UsageLink> links=new java.util.ArrayList<UsageLink>(); for (UsageLink ul : sg.getUsageLinks()) { if (ul.getSource() == sn && requiresLayout(ul.getTarget())) { links.add(ul); } } // Sort links Collections.sort(links, new Comparator<UsageLink>() { public int compare(UsageLink o1, UsageLink o2) { // TODO: May need to sort based on interface's localpart, if a fully qualified name return (o1.getTarget().getService().getServiceType().compareTo( o2.getTarget().getService().getServiceType())); } }); // Layout sorted links for (UsageLink ul : links) { layoutService(sg, ul.getTarget(), newX, newY); newY += (Integer)ul.getTarget().getProperties().get(ServiceGraphLayout.HEIGHT) +SERVICE_VERTICAL_PADDING; } } } }