/* * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Nuxeo - initial API and implementation * bstefanescu, atchertchian, jcarsique */ package org.nuxeo.osgi; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public class BundleRegistry { private static final Log log = LogFactory.getLog(BundleRegistry.class); private final Map<Long, BundleRegistration> bundlesById; private final Map<String, BundleRegistration> bundles; private final Map<String, Set<BundleRegistration>> pendings; public BundleRegistry() { bundlesById = new HashMap<Long, BundleRegistration>(); bundles = new LinkedHashMap<String, BundleRegistration>(); pendings = new HashMap<String, Set<BundleRegistration>>(); } public void addBundleAlias(String alias, String symbolicName) { BundleRegistration breg = bundles.get(symbolicName); if (breg != null) { bundles.put(alias, breg); } } public synchronized BundleImpl getBundle(long id) { BundleRegistration reg = bundlesById.get(id); return reg == null ? null : reg.bundle; } public synchronized BundleImpl getBundle(String symbolicName) { BundleRegistration reg = bundles.get(symbolicName); return reg == null ? null : reg.bundle; } /** * @since 5.6 */ public synchronized BundleImpl[] getFragments(String symbolicName) { BundleRegistration reg = bundles.get(symbolicName); ArrayList<BundleImpl> fragments = new ArrayList<BundleImpl>(); for (String id : reg.extendsMe) { fragments.add(getBundle(id)); } return fragments.toArray(new BundleImpl[fragments.size()]); } public synchronized BundleImpl[] getInstalledBundles() { BundleImpl[] bundles = new BundleImpl[this.bundles.size()]; int i = 0; for (BundleRegistration reg : this.bundles.values()) { bundles[i++] = reg.bundle; } return bundles; } public synchronized void install(BundleImpl bundle) throws BundleException { if (bundle.getState() == Bundle.UNINSTALLED) { BundleRegistration reg = bundles.get(bundle.getSymbolicName()); if (reg == null) { register(new BundleRegistration(bundle)); } else { register(reg); } } } public synchronized void uninstall(BundleImpl bundle) throws BundleException { if (bundle.getState() != Bundle.UNINSTALLED) { BundleRegistration reg = bundles.get(bundle.getSymbolicName()); if (reg != null) { unregister(reg); } } } private void register(BundleRegistration reg) throws BundleException { String hostBundleId = getFragmentHost(reg); if (hostBundleId != null) { BundleRegistration host = bundles.get(hostBundleId); if (host == null) { reg.addUnresolvedDependency(hostBundleId); } } if (reg.hasUnresolvedDependencies()) { doPostpone(reg); } else { doRegister(reg); } } protected void unregister(BundleRegistration reg) throws BundleException { if (getFragmentHost(reg) == null) { reg.bundle.stop(); } reg.bundle.setUnResolved(); bundles.remove(reg.bundle.getSymbolicName()); bundlesById.remove(reg.bundle.getBundleId()); reg.bundle.setUninstalled(); for (String depOnMe : reg.dependsOnMe) { BundleRegistration depReg = bundles.get(depOnMe); if (depReg != null) { // set to unresolved depReg.bundle.setUnResolved(); } } } protected void doPostpone(BundleRegistration reg) { String name = reg.bundle.getSymbolicName(); log.info("Registering unresolved bundle: " + name); bundles.put(name, reg); bundlesById.put(reg.bundle.getBundleId(), reg); for (String dep : reg.waitingFor) { Set<BundleRegistration> regs = pendings.get(dep); if (regs == null) { regs = new HashSet<BundleRegistration>(); pendings.put(dep, regs); } regs.add(reg); } reg.bundle.setInstalled(); } protected void doRegister(BundleRegistration reg) throws BundleException { String name = reg.bundle.getSymbolicName(); log.info("Registering resolved bundle: " + name); bundles.put(name, reg); bundlesById.put(reg.bundle.getBundleId(), reg); reg.bundle.setInstalled(); reg.bundle.setResolved(); String hostBundleId = getFragmentHost(reg); if (hostBundleId != null) { BundleRegistration host = bundles.get(hostBundleId); host.addFragment(reg.bundle.getSymbolicName()); } else { // TODO how to lazy start the bundle? reg.bundle.start(); } // check if there are objects waiting for me Set<BundleRegistration> regs = pendings.remove(name); if (regs != null) { for (BundleRegistration pendingReg : regs) { pendingReg.removeUnresolvedDependency(name); if (!pendingReg.hasUnresolvedDependencies()) { doRegister(pendingReg); } } } } private String getFragmentHost(BundleRegistration reg) { String hostBundleId = reg.bundle.getHeaders().get(Constants.FRAGMENT_HOST); if (hostBundleId == null) { return null; } int p = hostBundleId.indexOf(';'); if (p > -1) { // remove version or other extra information if any hostBundleId = hostBundleId.substring(0, p); } return hostBundleId; } public void shutdown() { BundleRegistration[] regs = bundles.values().toArray(new BundleRegistration[bundles.size()]); for (BundleRegistration reg : regs) { try { if (reg.bundle != null) { reg.bundle.shutdown(); } } catch (BundleException e) { log.error("Failed to stop bundle " + reg.bundle.getSymbolicName(), e); } catch (RuntimeException e) { log.error("Failed to stop bundle " + reg.bundle.getSymbolicName(), e); } } } }