/***
* Coalevo Project
* http://www.coalevo.net
*
* (c) Verein zur Foerderung der Internetkommunikation, Austria
* http://www.vfi.or.at
*
* Licensed 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 net.coalevo.datasource.impl;
import org.osgi.framework.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import net.coalevo.datasource.model.DataSourceProvider;
/**
* This class implements a manager for {@link DataSourceProvider}
* implementations registered with the container.
*
* The instances are handled according to the OSGi white-board model.
* All registered instances of the {@link DataSourceProvider} class will be
* handled here to make them available to the {@link DataSourceProvider}.
*
* @author Dieter Wimberger (wimpi)
* @version @version@ (@date@)
*/
class DataSourceProviderManager {
private BundleContext m_BundleContext;
private Map m_DataSourceProviders;
private DataSourceProviderListener m_DataSourceProviderListener;
private Map m_DSPWaits;
private String m_Default;
public DataSourceProviderManager() {
m_DataSourceProviders = new ConcurrentHashMap();
m_DSPWaits = new ConcurrentHashMap();
m_Default = System.getProperty("coalevo.datasource.default","derby");
}//DataSourceProviderManager
/**
* Activates this DataSourceProviderManager.
* The logic will automatically detect all {@link DataSourceProvider}
* class objects in the container, whether registered before or after
* the activation (i.e. white board model implementation).
*
* @param bc the BundleContext.
*/
public void activate(BundleContext bc) {
//get the context
m_BundleContext = bc;
//prepare listener
m_DataSourceProviderListener = new DataSourceProviderListener();
//prepare the filter
String filter = "(objectclass=" + DataSourceProvider.class.getName() + ")";
try {
//add the listener to the bundle context.
bc.addServiceListener(m_DataSourceProviderListener, filter);
//ensure that already registered Provider instances are registered with
//the manager
ServiceReference[] srl = bc.getServiceReferences(null, filter);
for (int i = 0; srl != null && i < srl.length; i++) {
m_DataSourceProviderListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, srl[i]));
}
} catch (InvalidSyntaxException ex) {
Activator.log().error("activate()", ex);
}
}//activate
/**
* Deactivates this ShellCommandProviderManagerImpl.
* The logic will remove the listener and release all
* references.
*/
public void deactivate() {
//remove the listener
m_BundleContext.removeServiceListener(m_DataSourceProviderListener);
m_DataSourceProviders.clear();
//null out the references
m_DataSourceProviders = null;
m_DataSourceProviderListener = null;
m_BundleContext = null;
}//deactivate
/**
* Returns the DataSourceProvider mapped to the given
* identifier.
*
* @param identifier an identifier.
* @return the mapped {@link DataSourceProvider}.
*/
public DataSourceProvider get(String identifier) {
return m_DataSourceProviders.get(identifier);
}//get
/**
* Tests if a {@link DataSourceProvider} with the given identifier
* is available.
*
* @param identifier a {@link DataSourceProvider} identifier.
* @return true if available, false otherwise.
*/
public boolean isAvailable(String identifier) {
return m_DataSourceProviders.containsKey(identifier);
}//isAvailable
/**
* Waits for a {@link DataSourceProvider} with the given identifier
* for the given max. waiting time.
*
* If the waiting time is -1, the thread will wait unlimited.
*
* @param identifier the identifier of the {@link DataSourceProvider}.
* @param time the maximum waiting time, or -1 if unlimited.
* @return the {@link DataSourceProvider} mapped to the given identifier of null
* if none maps.
*
*/
public DataSourceProvider waitFor(String identifier, long time) {
if(m_DataSourceProviders.containsKey(identifier)) {
return get(identifier);
}
//1. Wait latch
CountDownLatch cdl = null;
if(m_DSPWaits.containsKey(identifier)) {
cdl = m_DSPWaits.get(identifier);
} else {
cdl = new CountDownLatch(1);
m_DSPWaits.put(identifier,cdl);
}
//2. wait
try {
if(time >=0) {
cdl.await(time, TimeUnit.MILLISECONDS);
} else {
cdl.await();
}
} catch (Exception ex) {
Activator.log().error("waitFor()",ex);
}
return get(identifier);
}//waitFor
/**
* Registers a {@link DataSourceProvider} implementation.
*
* @param dsp a {@link DataSourceProvider}.
* @return true if registered, false otherwise.
*/
public boolean register(DataSourceProvider dsp) {
final String id = dsp.getIdentifier();
boolean c = m_DataSourceProviders.containsKey(id);
if(!c) {
m_DataSourceProviders.put(id,dsp);
notifyWaits(id);
if(m_Default.equals(id)) {
m_DataSourceProviders.put("default",dsp);
notifyWaits("default");
}
Activator.log().info(
Activator.getMessages().get("DataSourceProviderManager.registered","id",id)
);
}
return c;
}//register
private void notifyWaits(String id) {
CountDownLatch cdl = m_DSPWaits.remove(id);
if(cdl != null) {
cdl.countDown();
}
}//notifyWaits
/**
* Unregisters a {@link DataSourceProvider} implementation.
*
* @param dsp a{@link DataSourceProvider}.
* @return true if unregistered, false otherwise.
*/
public boolean unregister(DataSourceProvider dsp) {
boolean c = m_DataSourceProviders.containsValue(dsp);
final String id = dsp.getIdentifier();
if(c) {
m_DataSourceProviders.remove(id);
Activator.log().info(
Activator.getMessages().get("DataSourceProviderManager.unregistered","id",dsp.getIdentifier())
);
}
return c;
}//unregister
private class DataSourceProviderListener
implements ServiceListener {
public void serviceChanged(ServiceEvent ev) {
ServiceReference sr = ev.getServiceReference();
Object o = null;
switch (ev.getType()) {
case ServiceEvent.REGISTERED:
o = m_BundleContext.getService(sr);
if (o == null) {
Activator.log().error("ServiceListener:serviceChanged:registered:null");
} else if (!(o instanceof DataSourceProvider)) {
Activator.log().error("ServiceListener:serviceChanged:registered:Reference not a DataSourceProvider instance.");
} else {
register((DataSourceProvider) o);
}
break;
case ServiceEvent.UNREGISTERING:
o = m_BundleContext.getService(sr);
if (o == null) {
Activator.log().error("ServiceListener:serviceChanged:unregistering:null");
} else if (!(o instanceof DataSourceProvider)) {
Activator.log().error("ServiceListener:serviceChanged:unregistering:Reference not a DataSourceProvider instance.");
} else {
unregister((DataSourceProvider) o);
}
break;
}
}
}//inner class DataSourceProviderListener
}//class DataSourceProviderManager