Save This Page
Home » activemq-parent-5.3.1-source-release » org.apache.activemq.util.osgi » [javadoc | source]
    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   package org.apache.activemq.util.osgi;
   18   
   19   import java.io.IOException;
   20   import java.io.InputStream;
   21   import java.io.InputStreamReader;
   22   import java.io.BufferedReader;
   23   import java.util.Properties;
   24   import java.util.ArrayList;
   25   import java.util.concurrent.ConcurrentHashMap;
   26   import java.util.concurrent.ConcurrentMap;
   27   import java.net.URL;
   28   
   29   import org.apache.activemq.util.FactoryFinder;
   30   import org.apache.activemq.util.FactoryFinder.ObjectFactory;
   31   import org.apache.commons.logging.LogFactory;
   32   import org.apache.commons.logging.Log;
   33   
   34   import org.osgi.framework.Bundle;
   35   import org.osgi.framework.BundleActivator;
   36   import org.osgi.framework.BundleContext;
   37   import org.osgi.framework.BundleEvent;
   38   import org.osgi.framework.SynchronousBundleListener;
   39   
   40   /**
   41    * An OSGi bundle activator for ActiveMQ which adapts the {@link org.apache.activemq.util.FactoryFinder}
   42    * to the OSGi environment.
   43    *
   44    */
   45   public class Activator implements BundleActivator, SynchronousBundleListener, ObjectFactory {
   46   
   47       private static final Log LOG = LogFactory.getLog(Activator.class);
   48   
   49       private final ConcurrentHashMap<String, Class> serviceCache = new ConcurrentHashMap<String, Class>();
   50       private final ConcurrentMap<Long, BundleWrapper> bundleWrappers = new ConcurrentHashMap<Long, BundleWrapper>();
   51       private BundleContext bundleContext;
   52   
   53       // ================================================================
   54       // BundleActivator interface impl
   55       // ================================================================
   56   
   57       public synchronized void start(BundleContext bundleContext) throws Exception {
   58   
   59           // This is how we replace the default FactoryFinder strategy
   60           // with one that is more compatible in an OSGi env.
   61           FactoryFinder.setObjectFactory(this);
   62   
   63           debug("activating");
   64           this.bundleContext = bundleContext;
   65           debug("checking existing bundles");
   66           for (Bundle bundle : bundleContext.getBundles()) {
   67               if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.STARTING ||
   68                   bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STOPPING) {
   69                   register(bundle);
   70               }
   71           }
   72           debug("activated");
   73       }
   74   
   75   
   76       public synchronized void stop(BundleContext bundleContext) throws Exception {
   77           debug("deactivating");
   78           bundleContext.removeBundleListener(this);
   79           while (!bundleWrappers.isEmpty()) {
   80               unregister(bundleWrappers.keySet().iterator().next());
   81           }
   82           debug("deactivated");
   83           this.bundleContext = null;
   84       }
   85   
   86       // ================================================================
   87       // SynchronousBundleListener interface impl
   88       // ================================================================
   89   
   90       public void bundleChanged(BundleEvent event) {
   91           if (event.getType() == BundleEvent.RESOLVED) {
   92               register(event.getBundle());
   93           } else if (event.getType() == BundleEvent.UNRESOLVED || event.getType() == BundleEvent.UNINSTALLED) {
   94               unregister(event.getBundle().getBundleId());
   95           }
   96       }
   97   
   98       protected void register(final Bundle bundle) {
   99           debug("checking bundle " + bundle.getBundleId());
  100           if( !isImportingUs(bundle) ) {
  101               debug("The bundle does not import us: "+ bundle.getBundleId());
  102               return;
  103           }
  104           bundleWrappers.put(bundle.getBundleId(), new BundleWrapper(bundle));
  105       }
  106   
  107       /**
  108        * When bundles unload.. we remove them thier cached Class entries from the
  109        * serviceCache.  Future service lookups for the service will fail.
  110        *
  111        * TODO: consider a way to get the Broker release any references to
  112        * instances of the service.
  113        *
  114        * @param bundleId
  115        */
  116       protected void unregister(long bundleId) {
  117           BundleWrapper bundle = bundleWrappers.remove(bundleId);
  118           if (bundle != null) {
  119               for (String path : bundle.cachedServices) {
  120                   debug("unregistering service for key: " +path );
  121                   serviceCache.remove(path);
  122               }
  123           }
  124       }
  125   
  126       // ================================================================
  127       // ObjectFactory interface impl
  128       // ================================================================
  129   
  130       public Object create(String path) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
  131           Class clazz = serviceCache.get(path);
  132           if (clazz == null) {
  133               StringBuffer warnings = new StringBuffer();
  134               // We need to look for a bundle that has that class.
  135               int wrrningCounter=1;
  136               for (BundleWrapper wrapper : bundleWrappers.values()) {
  137                   URL resource = wrapper.bundle.getResource(path);
  138                   if( resource == null ) {
  139                       continue;
  140                   }
  141   
  142                   Properties properties = loadProperties(resource);
  143   
  144                   String className = properties.getProperty("class");
  145                   if (className == null) {
  146                       warnings.append("("+(wrrningCounter++)+") Invalid sevice file in bundle "+wrapper+": 'class' property not defined.");
  147                       continue;
  148                   }
  149   
  150                   try {
  151                       clazz = wrapper.bundle.loadClass(className);
  152                   } catch (ClassNotFoundException e) {
  153                       warnings.append("("+(wrrningCounter++)+") Bundle "+wrapper+" could not load "+className+": "+e);
  154                       continue;
  155                   }
  156   
  157                   // Yay.. the class was found.  Now cache it.
  158                   serviceCache.put(path, clazz);
  159                   wrapper.cachedServices.add(path);
  160                   break;
  161               }
  162   
  163               if( clazz == null ) {
  164                   // Since OSGi is such a tricky enviorment to work in.. lets give folks the
  165                   // most information we can in the error message.
  166                   String msg = "Service not found: '" + path + "'";
  167                   if (warnings.length()!= 0) {
  168                       msg += ", "+warnings;
  169                   }
  170                   throw new IOException(msg);
  171               }
  172           }
  173           return clazz.newInstance();
  174       }
  175   
  176       // ================================================================
  177       // Internal Helper Methods
  178       // ================================================================
  179   
  180       private void debug(Object msg) {
  181           LOG.debug(msg);
  182       }
  183   
  184       private Properties loadProperties(URL resource) throws IOException {
  185           InputStream in = resource.openStream();
  186           try {
  187               BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
  188               Properties properties = new Properties();
  189               properties.load(in);
  190               return properties;
  191           } finally {
  192               try {
  193                   in.close();
  194               } catch (Exception e) {
  195               }
  196           }
  197       }
  198   
  199       private boolean isImportingUs(Bundle bundle) {
  200           try {
  201               // If that bundle can load our classes.. then it must be importing us.
  202               return bundle.loadClass(Activator.class.getName())==Activator.class;
  203           } catch (ClassNotFoundException e) {
  204               return false;
  205           }
  206       }
  207   
  208       private static class BundleWrapper {
  209           private final Bundle bundle;
  210           private final ArrayList<String> cachedServices = new ArrayList<String>();
  211   
  212           public BundleWrapper(Bundle bundle) {
  213               this.bundle = bundle;
  214           }
  215       }
  216   }

Save This Page
Home » activemq-parent-5.3.1-source-release » org.apache.activemq.util.osgi » [javadoc | source]