/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG 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: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.communication.publisher; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; import org.eclipse.core.runtime.Assert; import org.eclipse.equinox.log.Logger; import org.eclipse.riena.communication.core.RemoteServiceDescription; import org.eclipse.riena.communication.core.publisher.IServicePublishBinder; import org.eclipse.riena.communication.core.publisher.IServicePublisher; import org.eclipse.riena.core.Log4r; import org.eclipse.riena.core.wire.InjectService; import org.eclipse.riena.internal.communication.publisher.Activator; import org.eclipse.riena.internal.communication.publisher.ServiceHooksProxy; /** * The class publishes all services that are existing as life services in the * OSGi Registry as web service endpoints. * */ public class ServicePublishBinder implements IServicePublishBinder { /** * contains a map of available publishers per protocol */ private final Map<String, IServicePublisher> servicePublishers = new HashMap<String, IServicePublisher>(); /** * contains services that are not yet published (due to missing publishers) */ private final List<RemoteServiceDescription> unpublishedServices = new ArrayList<RemoteServiceDescription>(); /** * contains registered published Services */ private final Map<String, RemoteServiceDescription> rsDescs = new HashMap<String, RemoteServiceDescription>(); private final static Logger LOGGER = Log4r.getLogger(Activator.getDefault(), ServicePublishBinder.class); public ServicePublishBinder() { super(); } @InjectService public void bind(final IServicePublisher publisher) { servicePublishers.put(publisher.getProtocol(), publisher); if (unpublishedServices.size() > 0) { LOGGER.log(LogService.LOG_DEBUG, "servicePublish=" + publisher.getProtocol() //$NON-NLS-1$ + " REGISTER...publishing all services that were waiting for him"); //$NON-NLS-1$ } else { LOGGER.log(LogService.LOG_DEBUG, "servicePublish=" + publisher.getProtocol() //$NON-NLS-1$ + " REGISTER...no unpublished services waiting for this protocol"); //$NON-NLS-1$ } // check for services which are missing a publisher checkUnpublishedServices(publisher.getProtocol()); } public void unbind(final IServicePublisher publisher) { final String protocol = publisher.getProtocol(); LOGGER.log(LogService.LOG_DEBUG, "servicePublish=" + publisher.getProtocol() //$NON-NLS-1$ + " UNREGISTER...unpublishing all its services"); //$NON-NLS-1$ // unregister all web services for this type // for (RemoteServiceDescription rsDesc : rsDescs.values()) { // if (protocol.equals(rsDesc.getProtocol())) { // unpublish(rsDesc); // } // } servicePublishers.remove(protocol); } private void checkUnpublishedServices(final String protocol) { final List<RemoteServiceDescription> removedItems = new ArrayList<RemoteServiceDescription>(); for (final RemoteServiceDescription rsd : unpublishedServices) { if (rsd.getProtocol().equals(protocol)) { publish(rsd); removedItems.add(rsd); } } for (final RemoteServiceDescription item : removedItems) { unpublishedServices.remove(item); } } /* * (non-Javadoc) * * @see * org.eclipse.riena.communication.publisher.IServicePublishBinder#publish * (org.osgi.framework.ServiceReference, java.lang.String, java.lang.String) */ public void publish(final ServiceReference ref, final String url, final String protocol) { final String[] interfaces = (String[]) ref.getProperty(Constants.OBJECTCLASS); Assert.isLegal(interfaces.length == 1, "OSGi service registrations only with one interface supported"); //$NON-NLS-1$ final String interfaceName = interfaces[0]; publish(interfaceName, ref, url, protocol); } public void unpublish(final ServiceReference serviceRef) { for (final RemoteServiceDescription rsd : rsDescs.values()) { if (serviceRef.equals(rsd.getServiceRef())) { final IServicePublisher servicePublisher = servicePublishers.get(rsd.getProtocol()); if (servicePublisher != null) { servicePublisher.unpublishService(rsd); } rsDescs.remove(rsd.getProtocol() + "::" + rsd.getPath()); //$NON-NLS-1$ return; } } } public void publish(final String interfaceName, final ServiceReference serviceRef, final String path, final String protocol) { try { publish( new RemoteServiceDescription(interfaceName, serviceRef, path, protocol)); } catch (final ClassNotFoundException e) { LOGGER.log(LogService.LOG_WARNING, "Could not load class for remote service interface for service reference" + serviceRef, e); //$NON-NLS-1$ } } private void publish(final RemoteServiceDescription rsd) { synchronized (rsDescs) { final ServiceHooksProxy handler = new ServiceHooksProxy(rsd.getService()); final Object service = Proxy.newProxyInstance(rsd.getServiceClassLoader(), new Class[] { rsd.getServiceInterfaceClass() }, handler); handler.setRemoteServiceDescription(rsd); final RemoteServiceDescription rsDescFound = rsDescs.get(getRSDKey(rsd)); if (rsDescFound != null) { LOGGER.log(LogService.LOG_WARNING, "A service endpoint with path=[" + rsd.getPath() //$NON-NLS-1$ + "] and remoteType=[" + rsd.getProtocol() + "] already published... ignored"); //$NON-NLS-1$ //$NON-NLS-2$ return; } if (rsd.getPath() == null) { LOGGER.log(LogService.LOG_WARNING, "no path for service: " + service.toString() //$NON-NLS-1$ + " Service not published remote"); //$NON-NLS-1$ return; } final IServicePublisher servicePublisher = servicePublishers.get(rsd.getProtocol()); if (servicePublisher == null) { LOGGER.log(LogService.LOG_INFO, "no publisher found for protocol " + rsd.getProtocol()); //$NON-NLS-1$ unpublishedServices.add(rsd); return; } rsd.setService(service); String url = null; try { url = servicePublisher.publishService(rsd); } catch (final RuntimeException e) { LOGGER.log(LogService.LOG_ERROR, e.getMessage()); return; } // set full URL under which the service is available rsd.setURL(url); handler.setMessageContextAccessor(servicePublisher.getMessageContextAccessor()); rsDescs.put(getRSDKey(rsd), rsd); LOGGER.log(LogService.LOG_DEBUG, "service endpoints count: " + rsDescs.size()); //$NON-NLS-1$ } } private String getRSDKey(final RemoteServiceDescription rsd) { return rsd.getProtocol() + "::" + rsd.getPath(); //$NON-NLS-1$ } public RemoteServiceDescription[] getAllServices() { final RemoteServiceDescription[] result = new RemoteServiceDescription[rsDescs.size()]; synchronized (rsDescs) { rsDescs.values().toArray(result); } return result; } }