blob: d880718631f29269c7617be4eeded43979e6004d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 Oracle.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* Bob Nettleton (Oracle) - Initial Reference Implementation
******************************************************************************/
package org.eclipse.gemini.naming;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Binding;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
class OSGiServiceListContext extends NotSupportedContext {
private static Logger logger =
Logger.getLogger(OSGiServiceListContext.class.getName());
private final BundleContext m_bundleContext;
private final ServiceReference[] m_serviceReferences;
private final OSGiURLParser m_urlParser;
/* map of service ids (Long) to ServiceReferences */
private final Map m_mapOfServices = new HashMap();
OSGiServiceListContext(BundleContext bundleContext, ServiceReference[] serviceReferences, OSGiURLParser urlParser) {
super("This operation is not supported in an osgi:servicelist context");
m_bundleContext = bundleContext;
m_serviceReferences = serviceReferences;
m_urlParser = urlParser;
buildMapOfServices(m_mapOfServices, m_serviceReferences);
}
@Override
public void close() throws NamingException {
// this operation is a no-op
}
@Override
public NamingEnumeration list(String name) throws NamingException {
if(name.equals("")) {
return new ListNamingEnumeration(m_bundleContext,
m_serviceReferences, m_urlParser.getServiceInterface());
}
throw new OperationNotSupportedException("This NamingEnumeration cannot support list() operations for anything other than the empty string");
}
@Override
public NamingEnumeration listBindings(String name) throws NamingException {
if(name.equals("")) {
return new ListBindingsNamingEnumeration(m_bundleContext,
m_serviceReferences,
m_urlParser);
}
throw new OperationNotSupportedException("This NamingEnumeration cannot support list() operations for anything other than the empty string");
}
@Override
public Object lookup(String name) throws NamingException {
Long serviceId = new Long(name);
if(m_mapOfServices.containsKey(serviceId)) {
ServiceReference serviceReference = (ServiceReference)m_mapOfServices.get(serviceId);
// create a proxy for this service, and return the proxy to handle
// service dynamics
ServiceProxyInfo proxyInfo =
createNoRetryProxiedService(m_bundleContext, m_urlParser, serviceReference);
if(!proxyInfo.isProxied()) {
logger.log(Level.WARNING,
"The service returned could not be proxied, OSGi lifecycle maintenance will not be handled by the Context Manager service");
}
return proxyInfo.getService();
} else {
throw new NameNotFoundException("Service with the name = " + name + " does not exist in this context");
}
}
private static ServiceProxyInfo createNoRetryProxiedService(BundleContext bundleContext, OSGiURLParser urlParser, final ServiceReference serviceReference) {
return ReflectionUtils.getProxyForSingleService(bundleContext,
urlParser,
serviceReference,
new NoRetryInvocationHandlerFactory());
}
/**
* Convenience method for building a lookup map of service id's to services.
* @param mapOfServices
* @param serviceReferences
*/
private static void buildMapOfServices(Map mapOfServices, ServiceReference[] serviceReferences) {
for(int i = 0; i < serviceReferences.length; i++) {
Long serviceId = (Long)serviceReferences[i].getProperty("service.id");
mapOfServices.put(serviceId, serviceReferences[i]);
}
}
/**
* NamingEnumeration that allows for iteration over a list of
* NameClassPair structures. This enumeration should be used
* from the Context.list() operation.
*
*
* @version $Revision$
*/
private static class ListNamingEnumeration extends ServiceBasedNamingEnumeration {
ListNamingEnumeration(BundleContext bundleContext, ServiceReference[] serviceReferences, String interfaceName) {
super(bundleContext, serviceReferences, interfaceName);
// create the NameClassPair structure
m_nameClassPairs = new NameClassPair[m_serviceReferences.length];
for(int i = 0; i < m_serviceReferences.length; i++) {
Long serviceId = (Long)m_serviceReferences[i].getProperty(Constants.SERVICE_ID);
m_nameClassPairs[i] =
new NameClassPair(serviceId.toString(), m_interfaceName);
}
}
}
/**
* NamingEnumeration that supports calls to Context.listBinding()
*
* This enumeration will contain a collection of javax.naming.Binding
* objects.
*
* The Binding for each service reference will contain:
*
* 1. The service ID name
* 2. The service interface type (if specified)
* 3. The service object itself
*
* The responsibility for cleaning up the services obtained by
* this NamingEnumeration lies with the enumeration itself. The close()
* implementation must unget each service reference.
*
* The caller of the NamingEnumeration is responsible for calling close()
* when the caller is finished with the services in the enumeration.
*
*
* @version $Revision$
*/
private static class ListBindingsNamingEnumeration extends ServiceBasedNamingEnumeration {
private final List m_listOfHandlers = new LinkedList();
ListBindingsNamingEnumeration(BundleContext bundleContext, ServiceReference[] serviceReferences, OSGiURLParser urlParser) {
super(bundleContext, serviceReferences, urlParser.getServiceInterface());
// setup a Binding object for each ServiceReference
m_nameClassPairs = new Binding[m_serviceReferences.length];
for(int i = 0; i < m_serviceReferences.length; i++) {
Long serviceId = (Long)m_serviceReferences[i].getProperty(Constants.SERVICE_ID);
final ServiceReference serviceReference = m_serviceReferences[i];
ServiceProxyInfo proxyInfo =
createNoRetryProxiedService(bundleContext, urlParser, serviceReference);
m_listOfHandlers.add(proxyInfo.getHandler());
m_nameClassPairs[i] =
new Binding(serviceId.toString(),
m_interfaceName,
proxyInfo.getService());
}
}
@Override
public void close() throws NamingException {
super.close();
for(int i = 0; i < m_serviceReferences.length; i++) {
m_bundleContext.ungetService(m_serviceReferences[i]);
}
Iterator iterator = m_listOfHandlers.iterator();
while(iterator.hasNext()) {
NoRetryServiceInvocationHandler handler =
(NoRetryServiceInvocationHandler)iterator.next();
handler.close();
}
}
}
private static class NoRetryServiceInvocationHandler extends ServiceInvocationHandler {
NoRetryServiceInvocationHandler(BundleContext callerBundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
super(callerBundleContext, serviceReference, urlParser, osgiService);
}
@Override
protected boolean obtainService() {
m_serviceTracker.close();
// always return false, since servicelist proxies must not rebind to a service
return false;
}
}
private static class NoRetryInvocationHandlerFactory implements InvocationHandlerFactory {
@Override
public InvocationHandler create(BundleContext bundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
return new NoRetryServiceInvocationHandler(bundleContext, serviceReference, urlParser, osgiService);
}
}
}