/*******************************************************************************
* 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.internal.communication.core.registry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.log.LogService;
import org.eclipse.core.runtime.Assert;
import org.eclipse.equinox.log.Logger;
import org.eclipse.riena.communication.core.IRemoteServiceReference;
import org.eclipse.riena.communication.core.IRemoteServiceRegistration;
import org.eclipse.riena.communication.core.IRemoteServiceRegistry;
import org.eclipse.riena.communication.core.factory.ProxyAlreadyRegisteredFailure;
import org.eclipse.riena.core.Log4r;
import org.eclipse.riena.internal.communication.core.Activator;
/**
* TODO Documentation
*/
public class RemoteServiceRegistry implements IRemoteServiceRegistry {
// outside start() and stop() this field should only be accessed through the method getRegisteredServices()
private volatile Map<String, IRemoteServiceRegistration> registeredServices;
private final static Logger LOGGER = Log4r.getLogger(Activator.getDefault(), RemoteServiceRegistry.class);
public synchronized void start() {
registeredServices = Collections.synchronizedMap(new HashMap<String, IRemoteServiceRegistration>());
}
public synchronized void stop() {
final Map<String, IRemoteServiceRegistration> tempRegisteredServices = registeredServices;
registeredServices = null;
for (final Map.Entry<String, IRemoteServiceRegistration> entry : tempRegisteredServices.entrySet()) {
unregisterService(entry.getValue().getReference());
}
}
public IRemoteServiceRegistration registerService(final IRemoteServiceReference reference,
final BundleContext context) {
final String url = reference.getDescription().getURL();
final IRemoteServiceRegistration foundRemoteServiceReg = getRegisteredServices().get(url);
if (foundRemoteServiceReg != null) {
throw new ProxyAlreadyRegisteredFailure(
"Cannot register two remote service proxies with the same URL. Proxy for " + url //$NON-NLS-1$
+ " already exists. Registered by bundle " //$NON-NLS-1$
+ foundRemoteServiceReg.getReference().getContext().getBundle().getSymbolicName() + "."); //$NON-NLS-1$
}
// it is a new entry, set properties
final Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put("service.url", url); //$NON-NLS-1$
props.put("service.protocol", reference.getDescription().getProtocol()); //$NON-NLS-1$
final ServiceRegistration serviceRegistration = context.registerService(
reference.getServiceInterfaceClassName(), reference.getServiceInstance(), props);
try {
Activator.getDefault().getContext().addServiceListener(new ServiceListener() {
public void serviceChanged(final ServiceEvent event) {
if (event.getType() == ServiceEvent.UNREGISTERING) {
getRegisteredServices().remove(url);
Activator.getDefault().getContext().removeServiceListener(this);
}
}
}, "(service.id=" + serviceRegistration.getReference().getProperty("service.id") + ")"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
} catch (final InvalidSyntaxException e) {
LOGGER.log(LogService.LOG_WARNING, "Filter is unexpectedly wrong.", e); //$NON-NLS-1$
}
reference.setContext(context);
reference.setServiceRegistration(serviceRegistration);
final RemoteServiceRegistration remoteServiceReg = new RemoteServiceRegistration(reference, this);
registeredServices.put(url, remoteServiceReg);
LOGGER.log(LogService.LOG_DEBUG, "OSGi NEW service registered id: " //$NON-NLS-1$
+ reference.getServiceInterfaceClassName());
return remoteServiceReg;
}
public void unregisterService(final IRemoteServiceReference reference) {
Assert.isNotNull(reference, "RemoteServiceReference must not be null"); //$NON-NLS-1$
getRegisteredServices().remove(reference.getURL());
reference.getServiceRegistration().unregister();
final String serviceClassName = reference.getServiceInterfaceClassName();
reference.dispose();
LOGGER.log(LogService.LOG_DEBUG, "OSGi service removed: " + serviceClassName); //$NON-NLS-1$
}
public List<IRemoteServiceRegistration> registeredServices(final BundleContext context) {
final List<IRemoteServiceRegistration> result = new ArrayList<IRemoteServiceRegistration>();
final List<IRemoteServiceRegistration> all = new ArrayList<IRemoteServiceRegistration>(getRegisteredServices()
.values());
for (final IRemoteServiceRegistration remoteServiceRegistration : all) {
if (context == null || context.equals(remoteServiceRegistration.getReference().getContext())) {
result.add(remoteServiceRegistration);
}
}
return result;
}
/**
* only meant for testcase that directly access the implementation
*
* @param url
* @return
*/
public boolean hasServiceForUrl(final String url) {
return getRegisteredServices().get(url) != null;
}
/**
* Prevents simple NPEs in case that the registry has been stopped or not
* yet started.
*
* @return the registry mapped
*/
private Map<String, IRemoteServiceRegistration> getRegisteredServices() {
final Map<String, IRemoteServiceRegistration> temp = registeredServices;
if (temp == null) {
throw new IllegalStateException("RemoteServiceRegistry is either not started or already stopped!"); //$NON-NLS-1$
}
return temp;
}
}