/* * 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.tuscany.sca.core.invocation.impl; import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION; import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION_POLICY; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_POLICY; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_TRANSPORT; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_WIREFORMAT; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_INTERFACE; import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_POLICY; import static org.apache.tuscany.sca.invocation.Phase.SERVICE; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_OPERATION_SELECTOR; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_POLICY; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_TRANSPORT; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_WIREFORMAT; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_INTERFACE; import static org.apache.tuscany.sca.invocation.Phase.SERVICE_POLICY; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.UtilityExtensionPoint; import org.apache.tuscany.sca.extensibility.ServiceDeclaration; import org.apache.tuscany.sca.invocation.Phase; import org.oasisopen.sca.ServiceRuntimeException; /** * @version $Rev$ $Date$ */ public class PhaseManager { private static final Logger log = Logger.getLogger(PhaseManager.class.getName()); public static final String STAGE_REFERENCE = "reference"; public static final String STAGE_REFERENCE_BINDING = "reference.binding"; public static final String STAGE_SERVICE_BINDING = "service.binding"; public static final String STAGE_SERVICE = "service"; public static final String STAGE_IMPLEMENTATION = "implementation"; private static final String[] SYSTEM_REFERENCE_PHASES = {REFERENCE, REFERENCE_POLICY, REFERENCE_INTERFACE, REFERENCE_BINDING}; private static final String[] SYSTEM_REFERENCE_BINDING_PHASES = {REFERENCE_BINDING_WIREFORMAT, REFERENCE_BINDING_POLICY, REFERENCE_BINDING_TRANSPORT}; private static final String[] SYSTEM_SERVICE_BINDING_PHASES = {SERVICE_BINDING_TRANSPORT, SERVICE_BINDING_OPERATION_SELECTOR, SERVICE_BINDING_WIREFORMAT, SERVICE_BINDING_POLICY}; private static final String[] SYSTEM_SERVICE_PHASES = {SERVICE_BINDING, SERVICE_INTERFACE, SERVICE_POLICY, SERVICE}; private static final String[] SYSTEM_IMPLEMENTATION_PHASES = {IMPLEMENTATION_POLICY, IMPLEMENTATION}; private ExtensionPointRegistry registry; private String pattern = Phase.class.getName(); private Map<String, Stage> stages; private List<String> phases; public class Stage { private String name; private PhaseSorter<String> sorter = new PhaseSorter<String>(); private Set<String> firstSet = new HashSet<String>(); private Set<String> lastSet = new HashSet<String>(); private List<String> phases = new ArrayList<String>(); public Stage(String name) { super(); this.name = name; } public String getName() { return name; } public PhaseSorter<String> getSorter() { return sorter; } public Set<String> getFirstSet() { return firstSet; } public Set<String> getLastSet() { return lastSet; } public List<String> getPhases() { return phases; } @Override public String toString() { return name + phases; } } /** * @param registry */ public PhaseManager(ExtensionPointRegistry registry) { super(); this.registry = registry; } public static PhaseManager getInstance(ExtensionPointRegistry registry) { UtilityExtensionPoint utilityExtensionPoint = registry.getExtensionPoint(UtilityExtensionPoint.class); return utilityExtensionPoint.getUtility(PhaseManager.class); } // For unit test purpose PhaseManager(String pattern) { super(); this.pattern = pattern; this.registry = new DefaultExtensionPointRegistry(); } private List<String> getPhases(String stage) { Stage s = getStages().get(stage); return s == null ? null : s.getPhases(); } public List<String> getReferencePhases() { return getPhases(STAGE_REFERENCE); } public List<String> getServicePhases() { return getPhases(STAGE_SERVICE); } public List<String> getReferenceBindingPhases() { return getPhases(STAGE_REFERENCE_BINDING); } public List<String> getServiceBindingPhases() { return getPhases(STAGE_SERVICE_BINDING); } public List<String> getImplementationPhases() { return getPhases(STAGE_IMPLEMENTATION); } public synchronized List<String> getAllPhases() { if (phases == null) { phases = new ArrayList<String>(); phases.addAll(getReferencePhases()); phases.addAll(getReferenceBindingPhases()); phases.addAll(getServiceBindingPhases()); phases.addAll(getServicePhases()); phases.addAll(getImplementationPhases()); } return phases; } public synchronized Map<String, Stage> getStages() { if (stages != null) { return stages; } init(); Collection<ServiceDeclaration> services; try { services = registry.getServiceDiscovery().getServiceDeclarations(pattern); } catch (IOException e) { throw new ServiceRuntimeException(e); } for (ServiceDeclaration d : services) { if (log.isLoggable(Level.FINE)) { log.fine(d.getLocation() + ": " + d.getAttributes()); } String name = d.getAttributes().get("name"); if (name == null) { throw new ServiceRuntimeException("Required attribute 'name' is missing."); } String stageName = d.getAttributes().get("stage"); if (stageName == null) { throw new ServiceRuntimeException("Required attribute 'stage' is missing."); } Stage stage = stages.get(stageName); if (stage == null) { throw new ServiceRuntimeException("Invalid stage: " + stageName); } PhaseSorter<String> graph = stage.getSorter(); Set<String> firstSet = stage.getFirstSet(), lastSet = stage.getLastSet(); String before = d.getAttributes().get("before"); String after = d.getAttributes().get("after"); if (before != null) { StringTokenizer tokenizer = new StringTokenizer(before); while (tokenizer.hasMoreTokens()) { String p = tokenizer.nextToken(); if (!"*".equals(p)) { graph.addEdge(name, p); } else { firstSet.add(name); } } } if (after != null) { StringTokenizer tokenizer = new StringTokenizer(after); while (tokenizer.hasMoreTokens()) { String p = tokenizer.nextToken(); if (!"*".equals(p)) { graph.addEdge(p, name); } else { lastSet.add(name); } } } graph.addVertext(name); if(firstSet.size()>1) { log.warning("More than one phases are declared to be first: "+firstSet); } for (String s : firstSet) { for (String v : new HashSet<String>(graph.getVertices().keySet())) { if (!firstSet.contains(v)) { graph.addEdge(s, v); } } } if(lastSet.size()>1) { log.warning("More than one phases are declared to be the last: "+lastSet); } for (String s : lastSet) { for (String v : new HashSet<String>(graph.getVertices().keySet())) { if (!lastSet.contains(v)) { graph.addEdge(v, s); } } } } for (Stage s : stages.values()) { List<String> phases = s.getSorter().topologicalSort(false); s.getPhases().clear(); s.getPhases().addAll(phases); } if (log.isLoggable(Level.FINE)) { log.fine("Stages: " + stages); } return stages; } private void init() { stages = new HashMap<String, Stage>(); Stage referenceStage = new Stage(STAGE_REFERENCE); for (int i = 1; i < SYSTEM_REFERENCE_PHASES.length; i++) { referenceStage.getSorter().addEdge(SYSTEM_REFERENCE_PHASES[i - 1], SYSTEM_REFERENCE_PHASES[i]); } referenceStage.getLastSet().add(REFERENCE_BINDING); stages.put(referenceStage.getName(), referenceStage); Stage referenceBindingStage = new Stage(STAGE_REFERENCE_BINDING); for (int i = 1; i < SYSTEM_REFERENCE_BINDING_PHASES.length; i++) { referenceBindingStage.getSorter().addEdge(SYSTEM_REFERENCE_BINDING_PHASES[i - 1], SYSTEM_REFERENCE_BINDING_PHASES[i]); } stages.put(referenceBindingStage.getName(), referenceBindingStage); Stage serviceBindingStage = new Stage(STAGE_SERVICE_BINDING); for (int i = 1; i < SYSTEM_SERVICE_BINDING_PHASES.length; i++) { serviceBindingStage.getSorter().addEdge(SYSTEM_SERVICE_BINDING_PHASES[i - 1], SYSTEM_SERVICE_BINDING_PHASES[i]); } stages.put(serviceBindingStage.getName(), serviceBindingStage); Stage serviceStage = new Stage(STAGE_SERVICE); for (int i = 1; i < SYSTEM_SERVICE_PHASES.length; i++) { serviceStage.getSorter().addEdge(SYSTEM_SERVICE_PHASES[i - 1], SYSTEM_SERVICE_PHASES[i]); } stages.put(serviceStage.getName(), serviceStage); Stage implementationStage = new Stage(STAGE_IMPLEMENTATION); for (int i = 1; i < SYSTEM_IMPLEMENTATION_PHASES.length; i++) { implementationStage.getSorter().addEdge(SYSTEM_IMPLEMENTATION_PHASES[i - 1], SYSTEM_IMPLEMENTATION_PHASES[i]); } implementationStage.getLastSet().add(IMPLEMENTATION); stages.put(implementationStage.getName(), implementationStage); } }