/*** * 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