diff options
Diffstat (limited to '')
-rw-r--r-- | sca-java-2.x/branches/2.0-Beta1/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java b/sca-java-2.x/branches/2.0-Beta1/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java new file mode 100644 index 0000000000..f99f682e07 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/extensibility/src/main/java/org/apache/tuscany/sca/extensibility/ServiceDiscovery.java @@ -0,0 +1,288 @@ +/* + * 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.extensibility; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.extensibility.impl.LDAPFilter; + +/** + * Service discovery for Tuscany based on J2SE Jar service provider spec. + * Services are described using configuration files in META-INF/services. + * Service description specifies a class name followed by optional properties. + * + * TODO: this is broken as it uses a static INSTANCE but non-static serviceAttributes + * and discoverer so the same INSTANCE gets used across NodeFactories and picks up + * old values + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public final class ServiceDiscovery implements ServiceDiscoverer { + private final static Logger logger = Logger.getLogger(ServiceDiscovery.class.getName()); + private final static ServiceDiscovery INSTANCE = new ServiceDiscovery(); + + private final Map<String, Map<String, String>> serviceAttributes = new HashMap<String, Map<String, String>>(); + private ServiceDiscoverer discoverer; + + private ServiceDiscovery() { + super(); + } + + private ServiceDiscovery(ServiceDiscoverer discoverer) { + super(); + this.discoverer = discoverer; + } + + /** + * Get an instance of Service discovery, one instance is created per + * ClassLoader that this class is loaded from + * + * @return + */ + public static ServiceDiscovery getInstance() { + return INSTANCE; + } + + public static ServiceDiscovery getInstance(ServiceDiscoverer discoverer) { + return new ServiceDiscovery(discoverer); + } + + public ServiceDiscoverer getServiceDiscoverer() { + if (discoverer != null) { + return discoverer; + } + try { + // FIXME: This is a hack to trigger the activation of the extensibility-equinox bundle in OSGi + Class.forName("org.apache.tuscany.sca.extensibility.equinox.EquinoxServiceDiscoverer"); + if (discoverer != null) { + return discoverer; + } + } catch (Throwable e) { + } + discoverer = new ContextClassLoaderServiceDiscoverer(getClass().getClassLoader()); + return discoverer; + } + + public void setServiceDiscoverer(ServiceDiscoverer sd) { + if (discoverer != null && sd != null) { + logger.warning("ServiceDiscoverer is reset to " + sd); + } + discoverer = sd; + } + + public Collection<ServiceDeclaration> getServiceDeclarations(String name) throws IOException { + return getServiceDeclarations(name, false); + } + + public Collection<ServiceDeclaration> getServiceDeclarations(String name, boolean byRanking) throws IOException { + Collection<ServiceDeclaration> declarations = getServiceDiscoverer().getServiceDeclarations(name); + // Check if any of the service declarations has attributes that are overrided + if (!serviceAttributes.isEmpty()) { + for (ServiceDeclaration declaration : declarations) { + Map<String, String> attrs = getAttributes(name); + if (attrs != null) { + declaration.getAttributes().putAll(attrs); + } + } + } + if (!byRanking) { + return declarations; + } + if (!declarations.isEmpty()) { + List<ServiceDeclaration> declarationList = new ArrayList<ServiceDeclaration>(declarations); + /* + for (ServiceDeclaration sd1 : declarations) { + for (Iterator<ServiceDeclaration> i = declarationList.iterator(); i.hasNext();) { + ServiceDeclaration sd2 = i.next(); + if (sd1 != sd2 && sd1.getAttributes().equals(sd2.getAttributes())) { + logger + .warning("Duplicate service declarations: " + sd1.getLocation() + "," + sd2.getLocation()); + i.remove(); + } + } + } + */ + Collections.sort(declarationList, ServiceComparator.DESCENDING_ORDER); + return declarationList; + } else { + return Collections.emptyList(); + } + } + + /** + * Get the service declaration. If there are more than one services, the one with highest ranking will + * be returned. + */ + public ServiceDeclaration getServiceDeclaration(final String name) throws IOException { + Collection<ServiceDeclaration> declarations = getServiceDeclarations(name, true); + if (!declarations.isEmpty()) { + // List<ServiceDeclaration> declarationList = new ArrayList<ServiceDeclaration>(declarations); + // Collections.sort(declarationList, ServiceComparator.DESCENDING_ORDER); + return declarations.iterator().next(); + } else { + return null; + } + } + + /** + * Get service declarations that are filtered by the service type. In an OSGi runtime, there + * might be different versions of the services + * @param serviceType + * @return + * @throws IOException + */ + public Collection<ServiceDeclaration> getServiceDeclarations(Class<?> serviceType, boolean byRanking) + throws IOException { + Collection<ServiceDeclaration> sds = getServiceDeclarations(serviceType.getName(), byRanking); + for (Iterator<ServiceDeclaration> i = sds.iterator(); i.hasNext();) { + ServiceDeclaration sd = i.next(); + if (!sd.isAssignableTo(serviceType)) { + logger.log(Level.WARNING, "Service provider {0} is not a type of {1}", new Object[] {sd,serviceType.getName()}); + i.remove(); + } + } + return sds; + } + + /** + * Discover all service providers that are compatible with the service type + * @param serviceType + * @return + * @throws IOException + */ + public Collection<ServiceDeclaration> getServiceDeclarations(Class<?> serviceType) throws IOException { + return getServiceDeclarations(serviceType, false); + } + + /** + * Discover all service providers that are compatible with the service type and match the filter + * @param serviceType + * @param filter + * @return + * @throws IOException + */ + public Collection<ServiceDeclaration> getServiceDeclarations(Class<?> serviceType, String filter) throws IOException { + Collection<ServiceDeclaration> sds = getServiceDeclarations(serviceType, false); + Collection<ServiceDeclaration> filtered = new ArrayList<ServiceDeclaration>(); + LDAPFilter filterImpl = LDAPFilter.newInstance(filter); + for(ServiceDeclaration sd: sds) { + if(filterImpl.match(sd.getAttributes())) { + filtered.add(sd); + } + } + return filtered; + } + + /** + * @param serviceName + * @param filter + * @return + * @throws IOException + */ + public Collection<ServiceDeclaration> getServiceDeclarations(String serviceName, String filter) throws IOException { + Collection<ServiceDeclaration> sds = getServiceDeclarations(serviceName, false); + Collection<ServiceDeclaration> filtered = new ArrayList<ServiceDeclaration>(); + LDAPFilter filterImpl = LDAPFilter.newInstance(filter); + for(ServiceDeclaration sd: sds) { + if(filterImpl.match(sd.getAttributes())) { + filtered.add(sd); + } + } + return filtered; + } + + public ServiceDeclaration getServiceDeclaration(Class<?> serviceType) throws IOException { + Collection<ServiceDeclaration> sds = getServiceDeclarations(serviceType, true); + if (sds.isEmpty()) { + return null; + } else { + return sds.iterator().next(); + } + } + + /** + * Compare service declarations by ranking + */ + private static class ServiceComparator implements Comparator<ServiceDeclaration> { + private final static Comparator<ServiceDeclaration> DESCENDING_ORDER = new ServiceComparator(); + + public int compare(ServiceDeclaration o1, ServiceDeclaration o2) { + int rank1 = 0; + String r1 = o1.getAttributes().get("ranking"); + if (r1 != null) { + rank1 = Integer.parseInt(r1); + } + int rank2 = 0; + String r2 = o2.getAttributes().get("ranking"); + if (r2 != null) { + rank2 = Integer.parseInt(r2); + } + return rank2 - rank1; // descending + } + } + + public ClassLoader getContextClassLoader() { + return discoverer.getContextClassLoader(); + } + + /** + * Set the attributes for a given service type + * @param serviceType + * @param attributes + */ + public void setAttribute(String serviceType, Map<String, String> attributes) { + serviceAttributes.put(serviceType, attributes); + } + + /** + * Set an attribute to the given value for a service type + * @param serviceType The service type + * @param attribute The attribute name + * @param value The attribute value + */ + public void setAttribute(String serviceType, String attribute, String value) { + Map<String, String> attributes = serviceAttributes.get(serviceType); + if (attributes == null) { + attributes = new HashMap<String, String>(); + serviceAttributes.put(serviceType, attributes); + } + attributes.put(attribute, value); + } + + /** + * Return a map of attributes for a given service type + * @param serviceType + * @return + */ + public Map<String, String> getAttributes(String serviceType) { + return serviceAttributes.get(serviceType); + } +} |