001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 * $Id$
013 */
014
015package org.nuxeo.runtime.osgi;
016
017import java.net.URL;
018
019import org.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021import org.nuxeo.common.Environment;
022import org.nuxeo.runtime.api.Framework;
023import org.osgi.framework.Bundle;
024import org.osgi.framework.BundleActivator;
025import org.osgi.framework.BundleContext;
026import org.osgi.framework.ServiceReference;
027import org.osgi.service.packageadmin.PackageAdmin;
028
029/**
030 * The default BundleActivator for NXRuntime over an OSGi comp. platform.
031 *
032 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
033 */
034public class OSGiRuntimeActivator implements BundleActivator {
035
036    private static final Log log = LogFactory.getLog(OSGiRuntimeActivator.class);
037
038    private static OSGiRuntimeActivator instance;
039
040    protected OSGiRuntimeService runtime;
041
042    protected OSGiComponentLoader componentLoader;
043
044    protected ServiceReference pkgAdmin;
045
046    protected BundleContext context;
047
048    public static OSGiRuntimeActivator getInstance() {
049        return instance;
050    }
051
052    @Override
053    public void start(BundleContext context) {
054        log.info("Starting Runtime Activator");
055        instance = this;
056        this.context = context;
057
058        pkgAdmin = context.getServiceReference(PackageAdmin.class.getName());
059
060        // assert the environment is setup
061        if (Environment.getDefault() == null) {
062            throw new IllegalStateException("Environment is not setup");
063        }
064
065        // create the runtime
066        runtime = new OSGiRuntimeService(context);
067
068        // load main config file if any
069        URL config = context.getBundle().getResource("/OSGI-INF/nuxeo.properties");
070        if (config != null) {
071            System.setProperty(OSGiRuntimeService.PROP_CONFIG_DIR, config.toExternalForm());
072        }
073
074        initialize(runtime);
075        // start it
076        Framework.initialize(runtime);
077        // register bundle component loader
078        componentLoader = new OSGiComponentLoader(runtime);
079        // TODO register osgi services
080    }
081
082    @Override
083    public void stop(BundleContext context) {
084        log.info("Stopping Runtime Activator");
085        instance = null;
086        pkgAdmin = null;
087        // remove component loader
088        componentLoader.uninstall();
089        componentLoader = null;
090        // unregister
091        Framework.shutdown();
092        uninitialize(runtime);
093        runtime = null;
094        context = null;
095    }
096
097    public Bundle getBundle(String name) {
098        if (pkgAdmin == null) {
099            return null;
100        }
101        PackageAdmin pa = (PackageAdmin) context.getService(pkgAdmin);
102        Bundle[] bundles = pa.getBundles(name, null);
103        context.ungetService(pkgAdmin);
104        return bundles == null ? null : bundles[0];
105    }
106
107    /**
108     * Load a class from another bundle given its reference as <code>bundleSymbolicName:className</code> If no
109     * <code>bundleSymbolicName:</code> prefix is given then a classForName will be done
110     *
111     * @param ref
112     * @return
113     */
114    public Class<?> loadClass(String ref) throws ReflectiveOperationException {
115        int i = ref.indexOf(':');
116        if (i == -1) {
117            return Class.forName(ref);
118        }
119        return loadClass(ref.substring(0, i), ref.substring(i + 1));
120    }
121
122    public Class<?> loadClass(String bundleName, String className) throws ReflectiveOperationException {
123        Bundle bundle = getBundle(bundleName);
124        if (bundle == null) {
125            throw new ClassNotFoundException("No bundle found with name: " + bundleName + ". Unable to load class "
126                    + className);
127        }
128        return bundle.loadClass(className);
129    }
130
131    public Object newInstance(String ref) throws ReflectiveOperationException {
132        return loadClass(ref).newInstance();
133    }
134
135    public Object newInstance(String bundleName, String className) throws ReflectiveOperationException {
136        return loadClass(bundleName, className).newInstance();
137    }
138
139    /**
140     * Gives a chance to derived classes to initialize them before the runtime is started.
141     *
142     * @param runtime the current runtime
143     */
144    protected void initialize(OSGiRuntimeService runtime) {
145        // do nothing
146    }
147
148    /**
149     * Gives a chance to derived classes to uninitialize them after the runtime is stopped.
150     *
151     * @param runtime the current runtime
152     */
153    protected void uninitialize(OSGiRuntimeService runtime) {
154        // do nothing
155    }
156
157}