View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.osgi;
20  
21  import java.util.ArrayList;
22  import java.util.Dictionary;
23  import java.util.Hashtable;
24  import java.util.List;
25  
26  import org.apache.chemistry.opencmis.client.api.SessionFactory;
27  import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
28  import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
29  import org.osgi.framework.Bundle;
30  import org.osgi.framework.BundleActivator;
31  import org.osgi.framework.BundleContext;
32  import org.osgi.framework.BundleEvent;
33  import org.osgi.framework.Constants;
34  import org.osgi.framework.SynchronousBundleListener;
35  import org.osgi.framework.wiring.BundleWiring;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  /**
40   * OSGi Bundle activator for the OpenCMIS client which registers an instance of
41   * the {@link SessionFactory} in the OSGi service registry.
42   */
43  public class Activator implements BundleActivator, SynchronousBundleListener {
44  
45      /**
46       * Represents the manifest header indicating this bundle holds an OpenCMIS
47       * SPI implementation
48       */
49      private static final String OPENCMIS_SPI_HEADER = "OpenCMIS-SPI";
50  
51      private static Logger LOG = LoggerFactory.getLogger(Activator.class);
52  
53      private BundleContext bundleContext;
54  
55      @Override
56      public void start(final BundleContext context) {
57  
58          this.bundleContext = context;
59  
60          // add bundle listener
61          context.addBundleListener(this);
62  
63          try {
64              // check existing bundles in framework for chemistry SPIs
65              for (Bundle bundle : context.getBundles()) {
66                  if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.STARTING
67                          || bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STOPPING) {
68                      register(bundle);
69                  }
70              }
71          } catch (Exception e) {
72              // this catch block is only necessary for broken OSGi
73              // implementations
74              LOG.warn("Could not find and register bundles that contain " + OPENCMIS_SPI_HEADER + " headers: ",
75                      e.toString(), e);
76          }
77  
78          // register the MetaTypeService now, that we are ready
79          Dictionary<String, String> props = new Hashtable<String, String>();
80          props.put(Constants.SERVICE_DESCRIPTION, "Apache Chemistry OpenCMIS Client Session Factory");
81          props.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
82  
83          SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
84          context.registerService(SessionFactory.class.getName(), sessionFactory, props);
85      }
86  
87      @Override
88      public void stop(final BundleContext context) {
89          // remove bundle listener
90          context.removeBundleListener(this);
91  
92          // forget our bundle context
93          bundleContext = null;
94  
95          // unregister all classloaders
96          ClassLoaderUtil.unregisterAllBundleClassLoaders();
97  
98          // The SessionFactory service will be unregistered automatically
99      }
100 
101     @Override
102     public void bundleChanged(final BundleEvent event) {
103         // bundle context might not yet been initialized
104         synchronized (this) {
105             if (bundleContext == null) {
106                 return;
107             }
108         }
109 
110         if (event.getType() == BundleEvent.RESOLVED) {
111             register(event.getBundle());
112         } else if (event.getType() == BundleEvent.UNRESOLVED || event.getType() == BundleEvent.UNINSTALLED) {
113             unregister(event.getBundle().getBundleId());
114         }
115     }
116 
117     private void register(final Bundle bundle) {
118         BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
119         if (bundleWiring == null) {
120             return;
121         }
122 
123         ClassLoader classLoader = bundleWiring.getClassLoader();
124         if (classLoader == null) {
125             return;
126         }
127 
128         List<String> classes = getOpenCmisSpiHeader(bundle);
129         if (classes != null) {
130             ClassLoaderUtil.registerBundleClassLoader(bundle.getBundleId(), classLoader, classes);
131         }
132     }
133 
134     private void unregister(final long bundleId) {
135         ClassLoaderUtil.unregisterBundleClassLoader(bundleId);
136     }
137 
138     private List<String> getOpenCmisSpiHeader(final Bundle bundle) {
139         String spiHeader = bundle.getHeaders().get(OPENCMIS_SPI_HEADER);
140         if (spiHeader == null) {
141             return null;
142         }
143 
144         List<String> headerValues = new ArrayList<String>();
145 
146         String[] split = spiHeader.split(",");
147         for (String className : split) {
148             if (className != null && !className.trim().isEmpty()) {
149                 headerValues.add(className.trim());
150             }
151         }
152 
153         return headerValues;
154     }
155 }