/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.eclipse.ecr.runtime.api;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.naming.NameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*
*/
public final class ServiceManager implements org.eclipse.ecr.runtime.ServiceManager {
private static final Log log = LogFactory.getLog(ServiceManager.class);
private static final ServiceManager instance = new ServiceManager();
private final Map<String, ServiceDescriptor> services = new HashMap<String, ServiceDescriptor>();
private final List<ServiceHost> servers = new Vector<ServiceHost>();
private final Map<String, ServiceGroup> groups = new HashMap<String, ServiceGroup>();
// Singleton.
private ServiceManager() {
}
public static ServiceManager getInstance() {
return instance;
}
public ServiceDescriptor[] getServiceDescriptors() {
return services.values().toArray(new ServiceDescriptor[services.size()]);
}
public ServiceDescriptor getServiceDescriptor(Class<?> serviceClass) {
return getServiceDescriptor(serviceClass.getName());
}
public ServiceDescriptor getServiceDescriptor(String serviceClass) {
return services.get(serviceClass);
}
public ServiceDescriptor getServiceDescriptor(Class<?> serviceClass,
String name) {
return getServiceDescriptor(serviceClass.getName(), name);
}
public ServiceDescriptor getServiceDescriptor(String serviceClass,
String name) {
return services.get(serviceClass + '#' + name);
}
public void registerService(ServiceDescriptor sd) {
String key = sd.getInstanceName();
synchronized (services) {
if (services.containsKey(key)) {
String msg = "Duplicate service registration: " + key;
log.error(msg);
Framework.getRuntime().getWarnings().add(msg);
return;
}
services.put(key, sd);
sd.getGroup().addService(sd);
log.info("Registered service: " + key);
}
}
public void unregisterService(ServiceDescriptor sd) {
String key = sd.getInstanceName();
synchronized (services) {
sd = services.remove(key);
if (sd == null) {
log.warn(String.format(
"Cannot unregister service '%s': either already"
+ " unregistered or not registered at all", key));
} else {
sd.getGroup().removeService(sd);
log.info("Unregistered service: " + key);
}
}
}
@Override
@SuppressWarnings("unchecked")
public <T> T getService(Class<T> serviceClass) throws Exception {
ServiceDescriptor sd = services.get(serviceClass.getName());
if (sd != null) {
try {
T svc = (T) sd.getGroup().getServer().lookup(sd);
if (svc != null) {
return svc;
}
} catch (NameNotFoundException e) {
// When all facades are deployed (JBoss for now), then lookup
// errors are legitimate. Otherwise it may be just a bad
// packaging issue, so don't log. TODO fix packaging
if (J2EEContainerDescriptor.getSelected() == J2EEContainerDescriptor.JBOSS) {
log.warn("Existing binding but unreachable service for "
+ serviceClass.getName()
+ " ! Fallback on local service...");
log.debug(e.getMessage() + " Check binding declaration: "
+ sd.toString());
}
}
}
return Framework.getLocalService(serviceClass);
}
@Override
@SuppressWarnings("unchecked")
public <T> T getService(Class<T> serviceClass, String name)
throws Exception {
ServiceDescriptor sd = services.get(serviceClass.getName() + '#' + name);
log.trace("Known services" + services.keySet().toString());
if (sd == null) {
return Framework.getLocalService(serviceClass);
}
return (T) sd.getGroup().getServer().lookup(sd);
}
/**
* Dynamically lookup services given a service URI.
* <p>
* This is a dynamic lookup in the sense that the service bindings should
* not be registered through extension points but all the information about
* how to locate the service are passed through the URI.
* <p>
* This method is not portable since the URI depends on the target server
* and configuration. Examples of service URIs:
* <ul>
* <li><code>jboss://localhost:1099/nuxeo/TypeManagerBean/remote</code> -
* locate a service on jboss</li>
* <li><code>glassfish://localhost:1234/org.nuxeo.ecm.platform.types.TypeManager</code> -
* locate a service on glassfish</li>
* </ul>
*
* @param serviceUri the service uri
* @return the service
*/
public Object getService(String serviceUri) throws Exception {
URI uri = new URI(serviceUri);
ServiceLocatorFactory factory = ServiceLocatorFactory.getFactory(uri.getScheme());
if (factory != null) {
ServiceLocator locator = factory.createLocator(uri);
return locator.lookup(uri.getPath().substring(1)); // avoid leading /
}
return null;
}
public ServiceGroup getOrCreateGroup(String name) {
if (name == null || name.length() == 0) {
name = "*";
}
synchronized (groups) {
ServiceGroup group = groups.get(name);
if (group == null) {
group = new ServiceGroup(name);
groups.put(name, group);
}
return group;
}
}
public ServiceGroup getGroup(String name) {
synchronized (groups) {
return groups.get(name);
}
}
public void removeGroup(String name) {
synchronized (groups) {
groups.remove(name);
}
}
public void addGroup(String name) {
if (name == null || name.length() == 0) {
name = "*";
}
ServiceGroup group = new ServiceGroup(name);
synchronized (groups) {
groups.put(name, group);
}
}
public ServiceGroup getRootGroup() {
return getOrCreateGroup("*");
}
public void registerServer(ServiceHost server) {
servers.add(server);
}
public void unregisterServer(ServiceHost server) {
servers.remove(server);
server.dispose();
}
/**
* Removes all registered servers.
*/
public void removeServers() {
for (ServiceHost server : servers) {
server.dispose();
}
servers.clear();
}
public void removeServices() {
services.clear();
}
public void removeGroups() {
groups.clear();
}
public void reset() {
removeServices();
removeGroups();
removeServers();
}
public ServiceHost[] getServers() {
return servers.toArray(new ServiceHost[servers.size()]);
}
}