/* Copyright (c) 2006-2009 Jan S. Rellermeyer * Systems Group, * Institute for Pervasive Computing, ETH Zurich. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of ETH Zurich nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package ch.ethz.iks.r_osgi.impl; import java.lang.reflect.Method; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import org.objectweb.asm.Type; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; import ch.ethz.iks.r_osgi.RemoteOSGiService; import ch.ethz.iks.r_osgi.messages.DeliverServiceMessage; /** * Encapsulates a service registered for remote access. * * @author Jan S. Rellermeyer */ final class RemoteServiceRegistration { /** * the local service reference. */ private final ServiceReference reference; /** * the service id. */ private final long serviceID; /** * the interface names. */ private final String[] interfaceNames; /** * the service object. */ private final Object serviceObject; /** * an internal method table, pregenerated to speed up the reflective calls. */ private final HashMap methodTable = new HashMap(0); /** * a prefactored deliver service message. */ private DeliverServiceMessage deliverServiceMessage; /** * creates a new RemoteService object. * * @param ref * the <code>ServiceReference</code> under which the service was * registered. Can be a surrogate. * @param service * the <code>ServiceReference</code> * @throws ClassNotFoundException * if one of the interface classes cannot be found. * @throws ServiceLocationException */ RemoteServiceRegistration(final ServiceReference ref, final ServiceReference service) throws ClassNotFoundException { reference = service; serviceID = ((Long) service.getProperty(Constants.SERVICE_ID)) .longValue(); interfaceNames = (String[]) service.getProperty(Constants.OBJECTCLASS); // get the service object serviceObject = RemoteOSGiActivator.getActivator().getContext().getService(service); if (serviceObject == null) { throw new IllegalStateException("Service is not present."); //$NON-NLS-1$ } // get the interface classes final ClassLoader bundleLoader = serviceObject.getClass() .getClassLoader(); final String[] interfaceNames = (String[]) service .getProperty(Constants.OBJECTCLASS); final int interfaceCount = interfaceNames.length; final Class[] serviceInterfaces = new Class[interfaceCount]; // build up the method table for each interface for (int i = 0; i < interfaceCount; i++) { serviceInterfaces[i] = bundleLoader.loadClass(interfaceNames[i]); final Method[] methods = serviceInterfaces[i].getMethods(); for (int j = 0; j < methods.length; j++) { methodTable.put(methods[j].getName() + Type.getMethodDescriptor(methods[j]), methods[j]); } } final Dictionary headers = service.getBundle().getHeaders(); final CodeAnalyzer analyzer = new CodeAnalyzer(bundleLoader, (String) headers.get(Constants.IMPORT_PACKAGE), (String) headers.get(Constants.EXPORT_PACKAGE)); try { deliverServiceMessage = analyzer.analyze(interfaceNames, (String) ref.getProperty(RemoteOSGiService.SMART_PROXY), (String[]) ref.getProperty(RemoteOSGiService.INJECTIONS), (String) ref.getProperty(RemoteOSGiService.PRESENTATION)); deliverServiceMessage.setServiceID(((Long) ref .getProperty(Constants.SERVICE_ID)).toString()); } catch (final Exception e) { if (RemoteOSGiServiceImpl.log != null) { RemoteOSGiServiceImpl.log.log(LogService.LOG_ERROR, "Error during remote service registration", e); //$NON-NLS-1$ } } } /** * get the service id. * * @return the service id. * @since 0.5 */ long getServiceID() { return serviceID; } ServiceReference getReference() { return reference; } /** * get the service properties. * * @return the properties. */ Dictionary getProperties() { final String[] keys = reference.getPropertyKeys(); final Dictionary props = new Hashtable(keys.length); for (int i = 0; i < keys.length; i++) { props.put(keys[i], reference.getProperty(keys[i])); } return props; } /** * get the service interfaces. * * @return the class names of the service interfaces. */ String[] getInterfaceNames() { return interfaceNames; } /** * check, if the registration equals a service reference. * * @param obj * the object to check. * @return true if the object is equal. * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(final Object obj) { if (obj instanceof ServiceReference) { final ServiceReference ref = (ServiceReference) obj; return ref.equals(reference); } else if (obj instanceof RemoteServiceRegistration) { return ((RemoteServiceRegistration) obj).equals(reference); } return false; } /** * get the hash code. * * @return the hash code. */ public int hashCode() { return (int) (serviceID ^ (serviceID >>> 32)); } /** * get the service object. * * @return the service object. */ Object getServiceObject() { return serviceObject; } /** * get a method from the method table. * * @param signature * the signature of the method. * @return the Method object. */ Method getMethod(final String signature) { Method method = (Method) methodTable.get(signature); // https://bugs.eclipse.org/327029 if (method == null && signature.startsWith("_rosgi")) { final String newsig = signature.substring(6); final String firstChar = newsig.substring(0, 1).toLowerCase(); final String correctedSig = newsig.substring(1); method = (Method) methodTable.get(firstChar + correctedSig); } return method; } /** * get the DeliverServiceMessage. * * @return the message. */ DeliverServiceMessage getDeliverServiceMessage() { return deliverServiceMessage; } public String toString() { return "RemoteServiceRegistration{" + reference.toString() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ } }