/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openengsb.core.common.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Iterator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.openengsb.core.api.ConnectorInstanceFactory;
import org.openengsb.core.api.ConnectorProvider;
import org.openengsb.core.api.DomainProvider;
import org.openengsb.core.api.VirtualConnectorProvider;
import org.openengsb.core.util.FilterUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
/**
* This class is used to automatically register {@link ConnectorProvider}s for Virtual connectors. With every
* {@link VirtualConnectorProvider} or {@link DomainProvider} registered or removed the {@link ConnectorProvider}s for
* the virtual connectors are managed accordingly.
*/
public class VirtualConnectorManager {
private static class Registration {
protected Registration(VirtualConnectorProvider virtualConnector, DomainProvider domainProvider,
ServiceRegistration factoryService, ServiceRegistration connectorProvider) {
this.virtualConnector = virtualConnector;
this.domainProvider = domainProvider;
this.factoryService = factoryService;
this.connectorProvider = connectorProvider;
}
private VirtualConnectorProvider virtualConnector;
private DomainProvider domainProvider;
private ServiceRegistration factoryService;
private ServiceRegistration connectorProvider;
}
private Collection<Registration> registeredFactories = Sets.newHashSet();
private ServiceTracker virtualConnectorProviderTracker;
private ServiceTracker domainProviderTracker;
private final BundleContext bundleContext;
public VirtualConnectorManager(BundleContext bundleContext) {
this.bundleContext = bundleContext;
init();
}
private void init() {
Filter virtualConnectorFilter = FilterUtils.makeFilterForClass(VirtualConnectorProvider.class);
virtualConnectorProviderTracker =
new ServiceTracker(bundleContext, virtualConnectorFilter, new ServiceTrackerCustomizer() {
@Override
public void removedService(ServiceReference reference, Object service) {
VirtualConnectorProvider provider = (VirtualConnectorProvider) service;
Iterator<Registration> factoryServices = getFactoriesForVirtualConnectorForRemoval(provider);
unregisterAllRegistrations(factoryServices);
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
// do nothing
}
@Override
public Object addingService(ServiceReference reference) {
createNewFactoryForVirtualConnectorProvider(reference);
return bundleContext.getService(reference);
}
});
Filter domainProviderFilter = FilterUtils.makeFilterForClass(DomainProvider.class);
domainProviderTracker =
new ServiceTracker(bundleContext, domainProviderFilter, new ServiceTrackerCustomizer() {
@Override
public void removedService(ServiceReference reference, Object service) {
Iterator<Registration> factoryServices =
getFactoriesForDomainProviderForRemoval((DomainProvider) service);
unregisterAllRegistrations(factoryServices);
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
// do nothing
}
@Override
public Object addingService(ServiceReference reference) {
DomainProvider newProvider = (DomainProvider) bundleContext.getService(reference);
createNewFactoryForDomainProvider(newProvider);
return newProvider;
}
});
}
public void start() {
virtualConnectorProviderTracker.open();
domainProviderTracker.open();
Object[] services = domainProviderTracker.getServices();
if (services != null) {
for (Object service : services) {
createNewFactoryForDomainProvider((DomainProvider) service);
}
}
}
public void stop() {
virtualConnectorProviderTracker.close();
domainProviderTracker.close();
}
protected static <T> Collection<T> getServicesFromTracker(ServiceTracker tracker, Class<T> serviceClass) {
Collection<T> result = new ArrayList<T>();
if (tracker == null) {
return result;
}
Object[] services = tracker.getServices();
if (services != null) {
CollectionUtils.addAll(result, services);
}
return result;
}
private Iterator<Registration> getFactoriesForVirtualConnectorForRemoval(final VirtualConnectorProvider provider) {
Iterator<Registration> consumingIterator = Iterators.consumingIterator(registeredFactories.iterator());
return Iterators.filter(consumingIterator, new Predicate<Registration>() {
@Override
public boolean apply(Registration input) {
return ObjectUtils.equals(input.virtualConnector, provider);
}
});
}
private Iterator<Registration> getFactoriesForDomainProviderForRemoval(final DomainProvider provider) {
Iterator<Registration> consumingIterator = Iterators.consumingIterator(registeredFactories.iterator());
return Iterators.filter(consumingIterator, new Predicate<Registration>() {
@Override
public boolean apply(Registration input) {
return ObjectUtils.equals(input.domainProvider, provider);
}
});
}
private void createNewFactoryForVirtualConnectorProvider(ServiceReference reference) {
VirtualConnectorProvider virtualConnectorProvider =
(VirtualConnectorProvider) bundleContext.getService(reference);
for (DomainProvider p : getServicesFromTracker(domainProviderTracker, DomainProvider.class)) {
ServiceRegistration factoryService = registerConnectorFactoryService(virtualConnectorProvider, p);
ServiceRegistration providerService = registerConnectorProviderService(virtualConnectorProvider, p);
registeredFactories.add(new Registration(virtualConnectorProvider, p, factoryService, providerService));
}
}
private ServiceRegistration registerConnectorProviderService(VirtualConnectorProvider virtualConnectorProvider,
DomainProvider p) {
Dictionary<String, Object> properties = new Hashtable<String, Object>();
properties.put(org.openengsb.core.api.Constants.DOMAIN_KEY, p.getId());
properties.put(org.openengsb.core.api.Constants.CONNECTOR_KEY, virtualConnectorProvider.getId());
return bundleContext.registerService(ConnectorProvider.class.getCanonicalName(), virtualConnectorProvider,
properties);
}
private void createNewFactoryForDomainProvider(DomainProvider newProvider) {
Collection<VirtualConnectorProvider> virtualProviders =
getServicesFromTracker(virtualConnectorProviderTracker, VirtualConnectorProvider.class);
for (VirtualConnectorProvider p : virtualProviders) {
registerConnectorFactoryService(p, newProvider);
ServiceRegistration factoryService = registerConnectorFactoryService(p, newProvider);
ServiceRegistration providerService = registerConnectorProviderService(p, newProvider);
registeredFactories.add(new Registration(p, newProvider, factoryService, providerService));
}
}
protected ServiceRegistration registerConnectorFactoryService(VirtualConnectorProvider virtualConnectorProvider,
DomainProvider p) {
ConnectorInstanceFactory factory = virtualConnectorProvider.createFactory(p);
Dictionary<String, Object> properties = new Hashtable<String, Object>();
properties.put(org.openengsb.core.api.Constants.DOMAIN_KEY, p.getId());
properties.put(org.openengsb.core.api.Constants.CONNECTOR_KEY, virtualConnectorProvider.getId());
return bundleContext.registerService(ConnectorInstanceFactory.class.getName(), factory, properties);
}
private void unregisterAllRegistrations(Iterator<Registration> factoryServices) {
while (factoryServices.hasNext()) {
Registration r = factoryServices.next();
r.factoryService.unregister();
r.connectorProvider.unregister();
}
}
}