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 * Bogdan Stefanescu 011 * Ian Smith 012 * Florent Guillaume 013 */ 014 015package org.nuxeo.runtime.osgi; 016 017import java.util.IllegalFormatException; 018import java.util.LinkedList; 019import java.util.List; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023import org.nuxeo.common.utils.StringUtils; 024import org.osgi.framework.Bundle; 025import org.osgi.framework.BundleContext; 026import org.osgi.framework.BundleEvent; 027import org.osgi.framework.SynchronousBundleListener; 028 029/** 030 * @author Bogdan Stefanescu 031 * @author Ian Smith 032 * @author Florent Guillaume 033 */ 034public class OSGiComponentLoader implements SynchronousBundleListener { 035 036 private static final Log log = LogFactory.getLog(OSGiComponentLoader.class); 037 038 private final OSGiRuntimeService runtime; 039 040 public OSGiComponentLoader(OSGiRuntimeService runtime) { 041 this.runtime = runtime; 042 install(); 043 } 044 045 public void install() { 046 BundleContext ctx = runtime.getBundleContext(); 047 ctx.addBundleListener(this); 048 Bundle[] bundles = ctx.getBundles(); 049 int mask = Bundle.STARTING | Bundle.ACTIVE; 050 for (Bundle bundle : bundles) { 051 String name = bundle.getSymbolicName(); 052 runtime.bundles.put(name, bundle); 053 int state = bundle.getState(); 054 bundleDebug("Install bundle: %s " + bundleStateAsString(state), name); 055 if ((state & mask) != 0) { // check only resolved bundles 056 if (OSGiRuntimeService.getComponentsList(bundle) != null) { 057 bundleDebug("Install bundle: %s component list: " + OSGiRuntimeService.getComponentsList(bundle), 058 name); 059 // check only bundles containing nuxeo comp. 060 try { 061 runtime.createContext(bundle); 062 } catch (RuntimeException e) { 063 // don't raise this exception, 064 // we want to isolate bundle errors from other bundles 065 log.warn("Failed to load components for bundle: " + name, e); 066 } 067 } else { 068 bundleDebug("Install bundle: %s has no components", name); 069 } 070 } else { 071 bundleDebug("Install bundle: %s is not STARTING " + "or ACTIVE, so no context was created", name); 072 } 073 } 074 } 075 076 public void uninstall() { 077 runtime.getBundleContext().removeBundleListener(this); 078 } 079 080 @Override 081 public void bundleChanged(BundleEvent event) { 082 String name = event.getBundle().getSymbolicName(); 083 int type = event.getType(); 084 085 bundleDebug("Bundle changed: %s " + bundleEventAsString(type), name); 086 try { 087 Bundle bundle = event.getBundle(); 088 String componentsList = OSGiRuntimeService.getComponentsList(bundle); 089 switch (type) { 090 case BundleEvent.INSTALLED: 091 runtime.bundles.put(bundle.getSymbolicName(), bundle); 092 break; 093 case BundleEvent.UNINSTALLED: 094 runtime.bundles.remove(bundle.getSymbolicName()); 095 break; 096 case BundleEvent.STARTING: 097 case BundleEvent.LAZY_ACTIVATION: 098 if (componentsList != null) { 099 bundleDebug("Bundle changed: %s STARTING with components: " + componentsList, name); 100 runtime.createContext(bundle); 101 } else { 102 bundleDebug("Bundle changed: %s STARTING with no components", name); 103 } 104 break; 105 case BundleEvent.STOPPED: 106 case BundleEvent.UNRESOLVED: 107 if (componentsList != null) { 108 bundleDebug("Bundle changed: %s STOPPING with components: " + componentsList, name); 109 runtime.destroyContext(bundle); 110 } else { 111 bundleDebug("Bundle changed: %s STOPPING with no components", name); 112 } 113 break; 114 } 115 } catch (RuntimeException e) { 116 log.error(e, e); 117 } 118 } 119 120 /** 121 * Used for generating good debug info. Convert bit vector into printable string. 122 * 123 * @param state bitwise-or of UNINSTALLED, INSTALLED, RESOLVED, STARTING, STOPPING, and ACTIVE 124 * @return printable version of bits that are on 125 */ 126 public static String bundleStateAsString(int state) { 127 List<String> list = new LinkedList<String>(); 128 if ((state & Bundle.UNINSTALLED) != 0) { 129 list.add("UNINSTALLED"); 130 } 131 if ((state & Bundle.INSTALLED) != 0) { 132 list.add("INSTALLED"); 133 } 134 if ((state & Bundle.RESOLVED) != 0) { 135 list.add("RESOLVED"); 136 } 137 if ((state & Bundle.STARTING) != 0) { 138 list.add("STARTING"); 139 } 140 if ((state & Bundle.STOPPING) != 0) { 141 list.add("STOPPING"); 142 } 143 if ((state & Bundle.ACTIVE) != 0) { 144 list.add("ACTIVE"); 145 } 146 return '[' + StringUtils.join(list, ',') + ']'; 147 } 148 149 /** 150 * Used for generating good debug info. Convert event type into printable string. 151 * 152 * @param eventType INSTALLED, STARTED,STOPPED, UNINSTALLED,UPDATED 153 * @return printable version of event type 154 */ 155 public static String bundleEventAsString(int eventType) { 156 switch (eventType) { 157 case BundleEvent.INSTALLED: 158 return "INSTALLED"; 159 case BundleEvent.STARTED: 160 return "STARTED"; 161 case BundleEvent.STARTING: 162 return "STARTING"; 163 case BundleEvent.STOPPED: 164 return "STOPPED"; 165 case BundleEvent.UNINSTALLED: 166 return "UNINSTALLED"; 167 case BundleEvent.UPDATED: 168 return "UPDATED"; 169 case BundleEvent.LAZY_ACTIVATION: 170 return "LAZY_ACTIVATION"; 171 case BundleEvent.RESOLVED: 172 return "RESOLVED"; 173 case BundleEvent.UNRESOLVED: 174 return "UNRESOLVED"; 175 case BundleEvent.STOPPING: 176 return "STOPPING"; 177 default: 178 return "UNKNOWN_OSGI_EVENT_TYPE_" + eventType; 179 } 180 } 181 182 /** 183 * Prints out a debug message for debugging bundles. 184 * 185 * @param msg the debug message with a %s in it which will be replaced by the component name 186 * @param name the component name 187 */ 188 public static void bundleDebug(String msg, String name) { 189 if (log.isDebugEnabled()) { 190 try { 191 msg = String.format(msg, name); 192 } catch (IllegalFormatException e) { 193 // don't fail for this 194 } 195 log.debug(msg); 196 } 197 } 198 199}