/*******************************************************************************
* Copyright (c) 2013 Olivier Moises
*
* 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:
* Olivier Moises- initial API and implementation
*******************************************************************************/
package org.eclipse.wazaabi.engine.edp.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.wazaabi.engine.edp.AdapterFactory;
import org.eclipse.wazaabi.engine.edp.ComponentFactory;
import org.eclipse.wazaabi.engine.edp.IdentifiableFactory;
import org.eclipse.wazaabi.engine.edp.Registry;
import org.eclipse.wazaabi.engine.edp.adapters.EventAdapter;
import org.eclipse.wazaabi.engine.edp.adapters.EventHandlerAdapter;
import org.eclipse.wazaabi.engine.edp.coderesolution.AbstractCodeDescriptor;
import org.eclipse.wazaabi.engine.edp.coderesolution.ExecutableAdapter;
import org.eclipse.wazaabi.engine.edp.coderesolution.ICodeLocator;
import org.eclipse.wazaabi.engine.edp.converters.BundledConverter;
import org.eclipse.wazaabi.engine.edp.converters.BundledConverterFactory;
import org.eclipse.wazaabi.engine.edp.events.EventAdapterFactory;
import org.eclipse.wazaabi.engine.edp.events.EventHandlerAdapterFactory;
import org.eclipse.wazaabi.engine.edp.executables.ExecutableAdapterFactory;
import org.eclipse.wazaabi.engine.edp.internal.osgi.Activator;
import org.eclipse.wazaabi.engine.edp.validators.BundledValidator;
import org.eclipse.wazaabi.engine.edp.validators.BundledValidatorFactory;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EDPRegistryImpl implements Registry, ServiceListener {
private final Logger logger = LoggerFactory
.getLogger(EDPRegistryImpl.class);
private final HashMap<Class<?>, List<Object>> activatedServices = new HashMap<Class<?>, List<Object>>();
private HashMap<Object, ServiceReference<?>> serviceToServiceReference = new HashMap<Object, ServiceReference<?>>();
private HashMap<ServiceReference<?>, Object> serviceReferenceToService = new HashMap<ServiceReference<?>, Object>();
private HashMap<Class<?>, Boolean> blockedServices = new HashMap<Class<?>, Boolean>();
private boolean isDisposed = false;
public static final String PLACE_BEFORE = "place-before"; //$NON-NLS-1$
public EDPRegistryImpl() {
logger.debug("Registry created");
if (Activator.getDefault() != null
&& Activator.getDefault().getContext() != null) {
Activator.getDefault().getContext().addServiceListener(this);
}
}
public Adapter createAdapter(Object callingContext, EObject model,
Object creationHint, Class<?> returnedType) {
if (isDisposed || returnedType == null || model == null)
return null;
Class<?> interfaze = getServiceInterfacerFor(returnedType);
if (interfaze == null) {
logger.error("No factory interface found for {}", returnedType); //$NON-NLS-1$
return null;
}
IdentifiableFactory f = getFactoryFor(callingContext, model,
creationHint, interfaze);
if (f instanceof AdapterFactory) {
return ((AdapterFactory) f).createAdapter(callingContext, model,
creationHint);
}
return null;
}
/**
* Given an interface, returns a copy of services implementing this
* interface by looking up into OSGI declarative services if running. Each
* time service is found, it is stored in a cache.
*
* @param interfaze
* The interface the returned services implement
* @return a list of services A unmodifiable, not null, copy of the services
* implementing the interface
*/
public List<Object> getServices(Class<?> interfaze) {
// logger.debug("seeking service for {}", interfaze); //$NON-NLS-1$
if (isDisposed || interfaze == null)
return null;
synchronized (activatedServices) {
// first we lookup into activatedServices
List<Object> services = activatedServices.get(interfaze);
if (services == null) {
services = new ArrayList<Object>();
activatedServices.put(interfaze, services);
}
// if running from within a OSGI container
if (Activator.getDefault() != null
&& Activator.getDefault().getContext() != null
&& !blockedServices.containsKey(interfaze)) {
List<Object> declaratedServices = new ArrayList<Object>();
try {
for (ServiceReference<?> sr : Activator.getDefault()
.getContext().getServiceReferences(interfaze, null)) {
// did we already meet this service reference ?
if (serviceReferenceToService.containsKey(sr))
continue;
Object service = Activator.getDefault().getContext()
.getService(sr);
if (service == null)
continue;
serviceToServiceReference.put(service, sr);
serviceReferenceToService.put(sr, service);
// do we need to insert the factory before or just
// append it?
Object placeBefore = sr.getProperty(PLACE_BEFORE);
if (placeBefore instanceof String[]
&& ((String[]) placeBefore)[0] != null
&& !((String[]) placeBefore)[0].isEmpty()) {
String id = ((String[]) placeBefore)[0];
int i = -1;
for (i = 0; i < declaratedServices.size(); i++)
if (declaratedServices.get(i) instanceof IdentifiableFactory
&& id.equals(((IdentifiableFactory) declaratedServices
.get(i)).getFactoryID()))
break;
if (i != -1)
declaratedServices.add(i, service);
} else
declaratedServices.add(service);
logger.debug("Discovered : {} from OSGI DS", //$NON-NLS-1$
service);
}
} catch (InvalidSyntaxException e) {
logger.error("{}", e);
}
if (!declaratedServices.isEmpty())
services.addAll(declaratedServices);
}
return Collections.unmodifiableList(services);
}
}
/**
* Returns the service class name of the factory returning the given
* returned type. Factories are registered by osgi framework using the
* service class name.
*
* @param returnedType
* @return
*/
protected Class<?> getServiceInterfacerFor(Class<?> returnedType) {
if (EventAdapter.class.equals(returnedType))
return EventAdapterFactory.class;
if (EventHandlerAdapter.class.equals(returnedType))
return EventHandlerAdapterFactory.class;
if (ExecutableAdapter.class.equals(returnedType))
return ExecutableAdapterFactory.class;
if (AbstractCodeDescriptor.class.equals(returnedType))
return ICodeLocator.class;
if (BundledConverter.class.equals(returnedType))
return BundledConverterFactory.class;
if (BundledValidator.class.equals(returnedType))
return BundledValidatorFactory.class;
return null;
}
public IdentifiableFactory getFactoryFor(Object callingContext,
Object model, Object creationHint, Class<?> interfaze) {
if (isDisposed || model == null || interfaze == null)
return null;
List<Object> services = getServices(interfaze);
for (Object service : services)
if (service instanceof IdentifiableFactory
&& ((IdentifiableFactory) service).isFactoryFor(
callingContext, model, creationHint)) {
// logger.debug("found DeclaratedFactory : {}", service); //$NON-NLS-1$
return (IdentifiableFactory) service;
}
return null;
}
public Object createComponent(Object callingContext, Object model,
Object creationHint, Class<?> returnedType) {
if (isDisposed || returnedType == null || model == null)
return null;
Class<?> interfaze = getServiceInterfacerFor(returnedType);
if (interfaze == null) {
logger.error("No factory interface found for {}", returnedType); //$NON-NLS-1$
return null;
}
IdentifiableFactory f = getFactoryFor(callingContext, model,
creationHint, interfaze);
if (f instanceof ComponentFactory) {
return ((ComponentFactory) f).createComponent(callingContext,
model, creationHint);
}
return null;
}
@Override
public void startBatchOptimization() {
// TODO Auto-generated method stub
}
@Override
public void endBatchOptimization() {
// TODO Auto-generated method stub
}
@Override
public void setServices(Class<?> interfaze, List<Object> services,
boolean blockOSGI) {
List<Object> servicesToRemove = new ArrayList<Object>();
if (services != null && Activator.getDefault() != null
&& Activator.getDefault().getContext() != null) {
List<Object> existingServices = activatedServices.get(interfaze);
if (existingServices != null)
for (Object existingService : existingServices)
if (!services.contains(existingService))
servicesToRemove.add(existingService);
}
activatedServices.put(interfaze,
services != null ? new ArrayList<Object>(services)
: new ArrayList<Object>());
blockedServices.put(interfaze, blockOSGI);
if (Activator.getDefault() != null
&& Activator.getDefault().getContext() != null)
for (Object service : servicesToRemove) {
ServiceReference<?> sr = serviceToServiceReference.get(service);
if (sr != null) {
Activator.getDefault().getContext().ungetService(sr);
serviceToServiceReference.remove(service);
serviceReferenceToService.remove(sr);
}
}
}
@Override
public void dispose() {
logger.debug("Registry disposed");
if (Activator.getDefault() != null
&& Activator.getDefault().getContext() != null) {
Activator.getDefault().getContext().removeServiceListener(this);
}
isDisposed = true;
}
@Override
public void initialize(Registry otherRegistry) {
if (otherRegistry == null)
return;
activatedServices
.putAll(((EDPRegistryImpl) otherRegistry).activatedServices);
serviceReferenceToService
.putAll(((EDPRegistryImpl) otherRegistry).serviceReferenceToService);
serviceToServiceReference
.putAll(((EDPRegistryImpl) otherRegistry).serviceToServiceReference);
}
@Override
public boolean isDisposed() {
return isDisposed;
}
@Override
public void serviceChanged(ServiceEvent event) {
if (event.getType() == ServiceEvent.UNREGISTERING) {
ServiceReference<?> sr = event.getServiceReference();
Object service = serviceReferenceToService.get(sr);
if (service != null) {
serviceReferenceToService.remove(sr);
serviceToServiceReference.remove(service);
List<Class<?>> foundInterfaces = new ArrayList<Class<?>>();
for (Class<?> i : activatedServices.keySet())
if (i.isAssignableFrom(service.getClass()))
foundInterfaces.add(i);
for (Class<?> i : foundInterfaces) {
List<Object> services = activatedServices.get(i);
services.remove(service);
blockedServices.remove(i);
}
}
}
}
}