001/*
002 * (C) Copyright 2006-2018 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 * $Id$
019 */
020
021package org.nuxeo.osgi;
022
023import java.io.File;
024import java.io.IOException;
025import java.util.Map;
026import java.util.Properties;
027import java.util.concurrent.ConcurrentHashMap;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.common.Environment;
032import org.nuxeo.common.collections.ListenerList;
033import org.nuxeo.osgi.services.PackageAdminImpl;
034import org.osgi.framework.Bundle;
035import org.osgi.framework.BundleEvent;
036import org.osgi.framework.BundleException;
037import org.osgi.framework.BundleListener;
038import org.osgi.framework.Constants;
039import org.osgi.framework.FrameworkEvent;
040import org.osgi.framework.FrameworkListener;
041import org.osgi.framework.ServiceEvent;
042import org.osgi.framework.ServiceListener;
043import org.osgi.framework.ServiceRegistration;
044import org.osgi.service.packageadmin.PackageAdmin;
045
046/**
047 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
048 */
049public class OSGiAdapter {
050
051    private static final Log log = LogFactory.getLog(OSGiAdapter.class);
052
053    protected final File workingDir;
054
055    protected final File dataDir;
056
057    protected File idTableFile;
058
059    protected BundleIdGenerator bundleIds;
060
061    protected ListenerList frameworkListeners;
062
063    protected ListenerList bundleListeners;
064
065    protected ListenerList serviceListeners;
066
067    protected Map<String, ServiceRegistration> services;
068
069    protected BundleRegistry registry;
070
071    protected Properties properties;
072
073    protected SystemBundle systemBundle;
074
075    public OSGiAdapter(File workingDir) {
076        this(workingDir,
077                new File(System.getProperty(Environment.NUXEO_DATA_DIR, workingDir + File.separator + "data")),
078                new Properties());
079    }
080
081    public OSGiAdapter(File workingDir, File dataDir, Properties properties) {
082        services = new ConcurrentHashMap<>();
083        this.workingDir = workingDir;
084        this.dataDir = dataDir;
085        this.dataDir.mkdirs();
086        this.workingDir.mkdirs();
087        initialize(properties);
088    }
089
090    public void removeService(String clazz) {
091        services.remove(clazz);
092    }
093
094    protected void initialize(Properties properties) {
095        this.properties = properties;
096        registry = new BundleRegistry();
097        frameworkListeners = new ListenerList();
098        bundleListeners = new ListenerList();
099        serviceListeners = new ListenerList();
100        bundleIds = new BundleIdGenerator();
101        idTableFile = new File(dataDir, "bundles.ids");
102        bundleIds.load(idTableFile);
103        // setting up default properties
104        properties.put(Constants.FRAMEWORK_VENDOR, "Nuxeo");
105        properties.put(Constants.FRAMEWORK_VERSION, "1.0.0");
106    }
107
108    public void setSystemBundle(SystemBundle systemBundle) throws BundleException {
109        if (this.systemBundle != null) {
110            throw new IllegalStateException("Cannot set system bundle");
111        }
112        install(systemBundle);
113        registry.addBundleAlias("system.bundle", systemBundle.getSymbolicName());
114        this.systemBundle = systemBundle;
115
116        systemBundle.getBundleContext().registerService(PackageAdmin.class.getName(), new PackageAdminImpl(this), null);
117    }
118
119    public BundleRegistry getRegistry() {
120        return registry;
121    }
122
123    public String getProperty(String key) {
124        String value = properties.getProperty(key);
125        if (value == null) {
126            value = System.getProperty(key);
127        }
128        return value;
129    }
130
131    public String getProperty(String key, String defvalue) {
132        String val = getProperty(key);
133        if (val == null) {
134            val = defvalue;
135        }
136        return val;
137    }
138
139    /**
140     * @param name the property name.
141     * @param value the property value.
142     */
143    public void setProperty(String name, String value) {
144        properties.put(name, value);
145    }
146
147    public void shutdown() throws IOException {
148        bundleIds.store(idTableFile);
149        registry.shutdown();
150        properties.clear();
151        registry = null;
152        frameworkListeners = null;
153        bundleListeners = null;
154        serviceListeners = null;
155        properties = null;
156    }
157
158    public long getBundleId(String symbolicName) {
159        return bundleIds.getBundleId(symbolicName);
160    }
161
162    public File getWorkingDir() {
163        return workingDir;
164    }
165
166    public File getDataDir() {
167        return dataDir;
168    }
169
170    public BundleImpl getBundle(String symbolicName) {
171        return registry.getBundle(symbolicName);
172    }
173
174    public BundleImpl[] getInstalledBundles() {
175        return registry.getInstalledBundles();
176    }
177
178    public void install(BundleImpl bundle) throws BundleException {
179        double s = System.currentTimeMillis();
180        registry.install(bundle);
181        bundle.startupTime = System.currentTimeMillis() - s;
182    }
183
184    public void uninstall(BundleImpl bundle) throws BundleException {
185        registry.uninstall(bundle);
186    }
187
188    public void addFrameworkListener(FrameworkListener listener) {
189        frameworkListeners.add(listener);
190    }
191
192    public void removeFrameworkListener(FrameworkListener listener) {
193        frameworkListeners.remove(listener);
194    }
195
196    public void addServiceListener(ServiceListener listener) {
197        serviceListeners.add(listener);
198    }
199
200    public void addServiceListener(ServiceListener listener, String filter) {
201        // TODO?
202        throw new UnsupportedOperationException("This method is not implemented");
203    }
204
205    public void removeServiceListener(ServiceListener listener) {
206        serviceListeners.remove(listener);
207    }
208
209    public void addBundleListener(BundleListener listener) {
210        bundleListeners.add(listener);
211    }
212
213    public void removeBundleListener(BundleListener listener) {
214        bundleListeners.remove(listener);
215    }
216
217    public void fireFrameworkEvent(FrameworkEvent event) {
218        log.debug("Firing FrameworkEvent on " + frameworkListeners.size() + " listeners");
219        Object[] listeners = frameworkListeners.getListeners();
220        for (Object listener : listeners) {
221            log.debug("Start execution of " + listener.getClass() + " listener");
222            try {
223                ((FrameworkListener) listener).frameworkEvent(event);
224                log.debug("End execution of " + listener.getClass() + " listener");
225            } catch (RuntimeException e) {
226                if (Boolean.getBoolean("nuxeo.start.strict")) {
227                    throw e;
228                } else {
229                    log.error("Error during Framework Listener execution: " + listener.getClass(), e);
230                }
231            }
232        }
233    }
234
235    public void fireServiceEvent(ServiceEvent event) {
236        Object[] listeners = serviceListeners.getListeners();
237        for (Object listener : listeners) {
238            ((ServiceListener) listener).serviceChanged(event);
239        }
240    }
241
242    public void fireBundleEvent(BundleEvent event) {
243        Object[] listeners = bundleListeners.getListeners();
244        for (Object listener : listeners) {
245            ((BundleListener) listener).bundleChanged(event);
246        }
247    }
248
249    public Bundle getSystemBundle() {
250        return systemBundle;
251    }
252
253}