001/* 002 * (C) Copyright 2006-2011 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.nuxeo.osgi.util.jar.JarFileCloser; 035import org.nuxeo.osgi.util.jar.URLJarFileIntrospector; 036import org.nuxeo.osgi.util.jar.URLJarFileIntrospectionError; 037import org.osgi.framework.Bundle; 038import org.osgi.framework.BundleEvent; 039import org.osgi.framework.BundleException; 040import org.osgi.framework.BundleListener; 041import org.osgi.framework.Constants; 042import org.osgi.framework.FrameworkEvent; 043import org.osgi.framework.FrameworkListener; 044import org.osgi.framework.ServiceEvent; 045import org.osgi.framework.ServiceListener; 046import org.osgi.framework.ServiceRegistration; 047import org.osgi.service.packageadmin.PackageAdmin; 048 049/** 050 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 051 */ 052public class OSGiAdapter { 053 054 private static final Log log = LogFactory.getLog(OSGiAdapter.class); 055 056 protected final File workingDir; 057 058 protected final File dataDir; 059 060 protected File idTableFile; 061 062 protected BundleIdGenerator bundleIds; 063 064 protected ListenerList frameworkListeners; 065 066 protected ListenerList bundleListeners; 067 068 protected ListenerList serviceListeners; 069 070 protected Map<String, ServiceRegistration> services; 071 072 protected BundleRegistry registry; 073 074 protected Properties properties; 075 076 protected SystemBundle systemBundle; 077 078 protected JarFileCloser uRLJarFileCloser; 079 080 public OSGiAdapter(File workingDir) { 081 this(workingDir, 082 new File(System.getProperty(Environment.NUXEO_DATA_DIR, workingDir + File.separator + "data")), 083 new Properties()); 084 } 085 086 public OSGiAdapter(File workingDir, File dataDir, Properties properties) { 087 services = new ConcurrentHashMap<String, ServiceRegistration>(); 088 this.workingDir = workingDir; 089 this.dataDir = dataDir; 090 this.dataDir.mkdirs(); 091 this.workingDir.mkdirs(); 092 initialize(properties); 093 } 094 095 public void removeService(String clazz) { 096 services.remove(clazz); 097 } 098 099 protected void initialize(Properties properties) { 100 this.properties = properties == null ? new Properties() : properties; 101 registry = new BundleRegistry(); 102 frameworkListeners = new ListenerList(); 103 bundleListeners = new ListenerList(); 104 serviceListeners = new ListenerList(); 105 bundleIds = new BundleIdGenerator(); 106 idTableFile = new File(dataDir, "bundles.ids"); 107 bundleIds.load(idTableFile); 108 // setting up default properties 109 properties.put(Constants.FRAMEWORK_VENDOR, "Nuxeo"); 110 properties.put(Constants.FRAMEWORK_VERSION, "1.0.0"); 111 } 112 113 public void setSystemBundle(SystemBundle systemBundle) throws BundleException { 114 if (this.systemBundle != null) { 115 throw new IllegalStateException("Cannot set system bundle"); 116 } 117 install(systemBundle); 118 registry.addBundleAlias("system.bundle", systemBundle.getSymbolicName()); 119 this.systemBundle = systemBundle; 120 121 systemBundle.getBundleContext().registerService(PackageAdmin.class.getName(), new PackageAdminImpl(this), null); 122 } 123 124 public BundleRegistry getRegistry() { 125 return registry; 126 } 127 128 public String getProperty(String key) { 129 String value = properties.getProperty(key); 130 if (value == null) { 131 value = System.getProperty(key); 132 } 133 return value; 134 } 135 136 public String getProperty(String key, String defvalue) { 137 String val = getProperty(key); 138 if (val == null) { 139 val = defvalue; 140 } 141 return val; 142 } 143 144 /** 145 * @param name the property name. 146 * @param value the property value. 147 */ 148 public void setProperty(String name, String value) { 149 properties.put(name, value); 150 } 151 152 public void shutdown() throws IOException { 153 bundleIds.store(idTableFile); 154 registry.shutdown(); 155 properties.clear(); 156 registry = null; 157 frameworkListeners = null; 158 bundleListeners = null; 159 serviceListeners = null; 160 properties = null; 161 uRLJarFileCloser = null; 162 } 163 164 public long getBundleId(String symbolicName) { 165 return bundleIds.getBundleId(symbolicName); 166 } 167 168 public File getWorkingDir() { 169 return workingDir; 170 } 171 172 public File getDataDir() { 173 return dataDir; 174 } 175 176 public BundleImpl getBundle(String symbolicName) { 177 return registry.getBundle(symbolicName); 178 } 179 180 public BundleImpl[] getInstalledBundles() { 181 return registry.getInstalledBundles(); 182 } 183 184 public void install(BundleImpl bundle) throws BundleException { 185 double s = System.currentTimeMillis(); 186 registry.install(bundle); 187 bundle.startupTime = System.currentTimeMillis() - s; 188 } 189 190 public void uninstall(BundleImpl bundle) throws BundleException { 191 registry.uninstall(bundle); 192 } 193 194 public void addFrameworkListener(FrameworkListener listener) { 195 frameworkListeners.add(listener); 196 } 197 198 public void removeFrameworkListener(FrameworkListener listener) { 199 frameworkListeners.remove(listener); 200 } 201 202 public void addServiceListener(ServiceListener listener) { 203 serviceListeners.add(listener); 204 } 205 206 public void addServiceListener(ServiceListener listener, String filter) { 207 // TODO? 208 throw new UnsupportedOperationException("This method is not implemented"); 209 } 210 211 public void removeServiceListener(ServiceListener listener) { 212 serviceListeners.remove(listener); 213 } 214 215 public void addBundleListener(BundleListener listener) { 216 bundleListeners.add(listener); 217 } 218 219 public void removeBundleListener(BundleListener listener) { 220 bundleListeners.remove(listener); 221 } 222 223 public void fireFrameworkEvent(FrameworkEvent event) { 224 log.debug("Firing FrameworkEvent on " + frameworkListeners.size() + " listeners"); 225 if (event.getType() == FrameworkEvent.STARTED) { 226 uRLJarFileCloser = newJarFileCloser(); 227 } 228 Object[] listeners = frameworkListeners.getListeners(); 229 for (Object listener : listeners) { 230 log.debug("Start execution of " + listener.getClass() + " listener"); 231 try { 232 ((FrameworkListener) listener).frameworkEvent(event); 233 log.debug("End execution of " + listener.getClass() + " listener"); 234 } catch (RuntimeException e) { 235 log.error("Error during Framework Listener execution : " + listener.getClass(), e); 236 } 237 } 238 } 239 240 protected JarFileCloser newJarFileCloser() { 241 try { 242 URLJarFileIntrospector introspector = new URLJarFileIntrospector(); 243 return introspector.newJarFileCloser(systemBundle.loader); 244 } catch (URLJarFileIntrospectionError cause) { 245 log.warn("Cannot put URL jar file closer in place", cause); 246 return JarFileCloser.NOOP; 247 } 248 } 249 250 public void fireServiceEvent(ServiceEvent event) { 251 Object[] listeners = serviceListeners.getListeners(); 252 for (Object listener : listeners) { 253 ((ServiceListener) listener).serviceChanged(event); 254 } 255 } 256 257 public void fireBundleEvent(BundleEvent event) { 258 Object[] listeners = bundleListeners.getListeners(); 259 for (Object listener : listeners) { 260 ((BundleListener) listener).bundleChanged(event); 261 } 262 } 263 264 public Bundle getSystemBundle() { 265 return systemBundle; 266 } 267 268 /** 269 * helper for closing jar files during bundle uninstall 270 * 271 * @since 5.6 272 */ 273 public JarFileCloser getURLJarFileCloser() { 274 if (uRLJarFileCloser == null) { 275 uRLJarFileCloser = newJarFileCloser(); 276 } 277 return uRLJarFileCloser; 278 } 279}