001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and contributors. 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 * bstefanescu, atchertchian, jcarsique 019 */ 020 021package org.nuxeo.osgi; 022 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.LinkedHashMap; 027import java.util.Map; 028import java.util.Set; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.osgi.framework.Bundle; 033import org.osgi.framework.BundleException; 034import org.osgi.framework.Constants; 035 036/** 037 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 038 */ 039public class BundleRegistry { 040 041 private static final Log log = LogFactory.getLog(BundleRegistry.class); 042 043 private final Map<Long, BundleRegistration> bundlesById; 044 045 private final Map<String, BundleRegistration> bundles; 046 047 private final Map<String, Set<BundleRegistration>> pendings; 048 049 public BundleRegistry() { 050 bundlesById = new HashMap<Long, BundleRegistration>(); 051 bundles = new LinkedHashMap<String, BundleRegistration>(); 052 pendings = new HashMap<String, Set<BundleRegistration>>(); 053 } 054 055 public void addBundleAlias(String alias, String symbolicName) { 056 BundleRegistration breg = bundles.get(symbolicName); 057 if (breg != null) { 058 bundles.put(alias, breg); 059 } 060 } 061 062 public synchronized BundleImpl getBundle(long id) { 063 BundleRegistration reg = bundlesById.get(id); 064 return reg == null ? null : reg.bundle; 065 } 066 067 public synchronized BundleImpl getBundle(String symbolicName) { 068 BundleRegistration reg = bundles.get(symbolicName); 069 return reg == null ? null : reg.bundle; 070 } 071 072 /** 073 * @since 5.6 074 */ 075 public synchronized BundleImpl[] getFragments(String symbolicName) { 076 BundleRegistration reg = bundles.get(symbolicName); 077 078 ArrayList<BundleImpl> fragments = new ArrayList<BundleImpl>(); 079 for (String id : reg.extendsMe) { 080 fragments.add(getBundle(id)); 081 } 082 return fragments.toArray(new BundleImpl[fragments.size()]); 083 } 084 085 public synchronized BundleImpl[] getInstalledBundles() { 086 BundleImpl[] bundles = new BundleImpl[this.bundles.size()]; 087 int i = 0; 088 for (BundleRegistration reg : this.bundles.values()) { 089 bundles[i++] = reg.bundle; 090 } 091 return bundles; 092 } 093 094 public synchronized void install(BundleImpl bundle) throws BundleException { 095 if (bundle.getState() == Bundle.UNINSTALLED) { 096 BundleRegistration reg = bundles.get(bundle.getSymbolicName()); 097 if (reg == null) { 098 register(new BundleRegistration(bundle)); 099 } else { 100 register(reg); 101 } 102 } 103 } 104 105 public synchronized void uninstall(BundleImpl bundle) throws BundleException { 106 if (bundle.getState() != Bundle.UNINSTALLED) { 107 BundleRegistration reg = bundles.get(bundle.getSymbolicName()); 108 if (reg != null) { 109 unregister(reg); 110 } 111 } 112 } 113 114 private void register(BundleRegistration reg) throws BundleException { 115 String hostBundleId = getFragmentHost(reg); 116 if (hostBundleId != null) { 117 BundleRegistration host = bundles.get(hostBundleId); 118 if (host == null) { 119 reg.addUnresolvedDependency(hostBundleId); 120 } 121 } 122 if (reg.hasUnresolvedDependencies()) { 123 doPostpone(reg); 124 } else { 125 doRegister(reg); 126 } 127 } 128 129 protected void unregister(BundleRegistration reg) throws BundleException { 130 if (getFragmentHost(reg) == null) { 131 reg.bundle.stop(); 132 } 133 134 reg.bundle.setUnResolved(); 135 bundles.remove(reg.bundle.getSymbolicName()); 136 bundlesById.remove(reg.bundle.getBundleId()); 137 reg.bundle.setUninstalled(); 138 for (String depOnMe : reg.dependsOnMe) { 139 BundleRegistration depReg = bundles.get(depOnMe); 140 if (depReg != null) { // set to unresolved 141 depReg.bundle.setUnResolved(); 142 } 143 } 144 } 145 146 protected void doPostpone(BundleRegistration reg) { 147 String name = reg.bundle.getSymbolicName(); 148 log.info("Registering unresolved bundle: " + name); 149 bundles.put(name, reg); 150 bundlesById.put(reg.bundle.getBundleId(), reg); 151 152 for (String dep : reg.waitingFor) { 153 Set<BundleRegistration> regs = pendings.get(dep); 154 if (regs == null) { 155 regs = new HashSet<BundleRegistration>(); 156 pendings.put(dep, regs); 157 } 158 regs.add(reg); 159 } 160 reg.bundle.setInstalled(); 161 } 162 163 protected void doRegister(BundleRegistration reg) throws BundleException { 164 String name = reg.bundle.getSymbolicName(); 165 log.info("Registering resolved bundle: " + name); 166 bundles.put(name, reg); 167 bundlesById.put(reg.bundle.getBundleId(), reg); 168 reg.bundle.setInstalled(); 169 reg.bundle.setResolved(); 170 171 String hostBundleId = getFragmentHost(reg); 172 if (hostBundleId != null) { 173 BundleRegistration host = bundles.get(hostBundleId); 174 host.addFragment(reg.bundle.getSymbolicName()); 175 } else { 176 // TODO how to lazy start the bundle? 177 reg.bundle.start(); 178 } 179 180 // check if there are objects waiting for me 181 Set<BundleRegistration> regs = pendings.remove(name); 182 if (regs != null) { 183 for (BundleRegistration pendingReg : regs) { 184 pendingReg.removeUnresolvedDependency(name); 185 if (!pendingReg.hasUnresolvedDependencies()) { 186 doRegister(pendingReg); 187 } 188 } 189 } 190 } 191 192 private String getFragmentHost(BundleRegistration reg) { 193 String hostBundleId = reg.bundle.getHeaders().get(Constants.FRAGMENT_HOST); 194 if (hostBundleId == null) { 195 return null; 196 } 197 int p = hostBundleId.indexOf(';'); 198 if (p > -1) { // remove version or other extra information if any 199 hostBundleId = hostBundleId.substring(0, p); 200 } 201 return hostBundleId; 202 } 203 204 public void shutdown() { 205 BundleRegistration[] regs = bundles.values().toArray(new BundleRegistration[bundles.size()]); 206 for (BundleRegistration reg : regs) { 207 try { 208 if (reg.bundle != null) { 209 reg.bundle.shutdown(); 210 } 211 } catch (BundleException e) { 212 log.error("Failed to stop bundle " + reg.bundle.getSymbolicName(), e); 213 } catch (RuntimeException e) { 214 log.error("Failed to stop bundle " + reg.bundle.getSymbolicName(), e); 215 } 216 } 217 } 218 219}