PageRenderTime 67ms CodeModel.GetById 42ms app.highlight 13ms RepoModel.GetById 10ms app.codeStats 0ms

/spice-inject/guice-bean/guice-bean-containers/src/main/java/org/sonatype/guice/bean/containers/Activator.java

https://github.com/peterlynch/spice
Java | 244 lines | 137 code | 46 blank | 61 comment | 10 complexity | 84165d6d612b7985da9dea82cd706ef2 MD5 | raw file
  1/**
  2 * Copyright (c) 2010 Sonatype, Inc. All rights reserved.
  3 *
  4 * This program is licensed to you under the Apache License Version 2.0,
  5 * and you may not use this file except in compliance with the Apache License Version 2.0.
  6 * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
  7 *
  8 * Unless required by applicable law or agreed to in writing,
  9 * software distributed under the Apache License Version 2.0 is distributed on an
 10 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 12 */
 13package org.sonatype.guice.bean.containers;
 14
 15import java.util.Dictionary;
 16import java.util.HashMap;
 17import java.util.Hashtable;
 18import java.util.Map;
 19
 20import org.osgi.framework.Bundle;
 21import org.osgi.framework.BundleActivator;
 22import org.osgi.framework.BundleContext;
 23import org.osgi.framework.BundleEvent;
 24import org.osgi.framework.Constants;
 25import org.osgi.framework.ServiceReference;
 26import org.osgi.util.tracker.BundleTracker;
 27import org.osgi.util.tracker.BundleTrackerCustomizer;
 28import org.osgi.util.tracker.ServiceTracker;
 29import org.osgi.util.tracker.ServiceTrackerCustomizer;
 30import org.sonatype.guice.bean.binders.ParameterKeys;
 31import org.sonatype.guice.bean.binders.SpaceModule;
 32import org.sonatype.guice.bean.binders.WireModule;
 33import org.sonatype.guice.bean.locators.DefaultBeanLocator;
 34import org.sonatype.guice.bean.locators.MutableBeanLocator;
 35import org.sonatype.guice.bean.reflect.BundleClassSpace;
 36import org.sonatype.guice.bean.reflect.ClassSpace;
 37
 38import com.google.inject.Binder;
 39import com.google.inject.Guice;
 40import com.google.inject.Injector;
 41import com.google.inject.Module;
 42
 43/**
 44 * {@link BundleActivator} that maintains a dynamic {@link Injector} graph by scanning bundles as they come and go.
 45 */
 46public final class Activator
 47    implements BundleActivator, BundleTrackerCustomizer, ServiceTrackerCustomizer
 48{
 49    // ----------------------------------------------------------------------
 50    // Constants
 51    // ----------------------------------------------------------------------
 52
 53    static final String BUNDLE_INJECTOR_CLASS_NAME = BundleInjector.class.getName();
 54
 55    static final MutableBeanLocator LOCATOR = new DefaultBeanLocator();
 56
 57    // ----------------------------------------------------------------------
 58    // Implementation fields
 59    // ----------------------------------------------------------------------
 60
 61    private BundleContext bundleContext;
 62
 63    private ServiceTracker serviceTracker;
 64
 65    private BundleTracker bundleTracker;
 66
 67    // ----------------------------------------------------------------------
 68    // Public methods
 69    // ----------------------------------------------------------------------
 70
 71    public void start( final BundleContext context )
 72    {
 73        bundleContext = context;
 74        serviceTracker = new ServiceTracker( context, BUNDLE_INJECTOR_CLASS_NAME, this );
 75        serviceTracker.open();
 76        bundleTracker = new BundleTracker( context, Bundle.ACTIVE, this );
 77        bundleTracker.open();
 78    }
 79
 80    public void stop( final BundleContext context )
 81    {
 82        bundleTracker.close();
 83        serviceTracker.close();
 84        LOCATOR.clear();
 85    }
 86
 87    // ----------------------------------------------------------------------
 88    // Bundle tracking
 89    // ----------------------------------------------------------------------
 90
 91    public Object addingBundle( final Bundle bundle, final BundleEvent event )
 92    {
 93        if ( "org.sonatype.inject".equals( bundle.getSymbolicName() ) )
 94        {
 95            return null; // don't bother scanning the primary infrastructure bundle
 96        }
 97
 98        final String imports = (String) bundle.getHeaders().get( Constants.IMPORT_PACKAGE );
 99        if ( null == imports || !imports.contains( "javax.inject" ) )
100        {
101            return null; // bundle doesn't import @Inject, so won't have any beans
102        }
103
104        final ServiceReference[] serviceReferences = bundle.getRegisteredServices();
105        if ( null != serviceReferences )
106        {
107            for ( final ServiceReference ref : serviceReferences )
108            {
109                for ( final String name : (String[]) ref.getProperty( Constants.OBJECTCLASS ) )
110                {
111                    if ( BUNDLE_INJECTOR_CLASS_NAME.equals( name ) )
112                    {
113                        return null; // this bundle already has an injector registered
114                    }
115                }
116            }
117        }
118
119        // bootstrap new injector
120        new BundleInjector( bundle );
121
122        return null;
123    }
124
125    public void modifiedBundle( final Bundle bundle, final BundleEvent event, final Object object )
126    {
127        // nothing to do
128    }
129
130    public void removedBundle( final Bundle bundle, final BundleEvent event, final Object object )
131    {
132        // nothing to do
133    }
134
135    // ----------------------------------------------------------------------
136    // Service tracking
137    // ----------------------------------------------------------------------
138
139    public Object addingService( final ServiceReference reference )
140    {
141        final Object service = bundleContext.getService( reference );
142        LOCATOR.add( ( (BundleInjector) service ).getInjector() );
143        return service;
144    }
145
146    public void modifiedService( final ServiceReference reference, final Object service )
147    {
148        // nothing to do
149    }
150
151    public void removedService( final ServiceReference reference, final Object service )
152    {
153        LOCATOR.remove( ( (BundleInjector) service ).getInjector() );
154    }
155
156    // ----------------------------------------------------------------------
157    // Implementation types
158    // ----------------------------------------------------------------------
159
160    private static final class BundleInjector
161        implements /* TODO:ManagedService, */Module
162    {
163        // ----------------------------------------------------------------------
164        // Constants
165        // ----------------------------------------------------------------------
166
167        private static final String[] API = { BUNDLE_INJECTOR_CLASS_NAME /* TODO:, ManagedService.class.getName() */};
168
169        // ----------------------------------------------------------------------
170        // Implementation fields
171        // ----------------------------------------------------------------------
172
173        private final Map<String, String> properties;
174
175        private final Injector injector;
176
177        // ----------------------------------------------------------------------
178        // Constructors
179        // ----------------------------------------------------------------------
180
181        BundleInjector( final Bundle bundle )
182        {
183            properties = new BundleProperties( bundle.getBundleContext() );
184
185            final ClassSpace space = new BundleClassSpace( bundle );
186            injector = Guice.createInjector( new WireModule( this, new SpaceModule( space ) ) );
187            final Dictionary<Object, Object> metadata = new Hashtable<Object, Object>();
188            metadata.put( Constants.SERVICE_PID, "org.sonatype.inject" );
189
190            bundle.getBundleContext().registerService( API, this, metadata );
191        }
192
193        // ----------------------------------------------------------------------
194        // Public methods
195        // ----------------------------------------------------------------------
196
197        public void configure( final Binder binder )
198        {
199            binder.bind( ParameterKeys.PROPERTIES ).toInstance( properties );
200            binder.bind( MutableBeanLocator.class ).toInstance( LOCATOR );
201        }
202
203        public Injector getInjector()
204        {
205            return injector;
206        }
207    }
208
209    private static final class BundleProperties
210        extends HashMap<String, String>
211    {
212        // ----------------------------------------------------------------------
213        // Constants
214        // ----------------------------------------------------------------------
215
216        private static final long serialVersionUID = 1L;
217
218        // ----------------------------------------------------------------------
219        // Implementation fields
220        // ----------------------------------------------------------------------
221
222        private transient final BundleContext context;
223
224        // ----------------------------------------------------------------------
225        // Constructors
226        // ----------------------------------------------------------------------
227
228        BundleProperties( final BundleContext context )
229        {
230            this.context = context;
231        }
232
233        // ----------------------------------------------------------------------
234        // Public methods
235        // ----------------------------------------------------------------------
236
237        @Override
238        public String get( final Object key )
239        {
240            final String value = super.get( key );
241            return null != value ? value : context.getProperty( String.valueOf( key ) );
242        }
243    }
244}