PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/osgi/service/src/main/java/org/jboss/as/osgi/service/AutoInstallIntegration.java

https://github.com/aminorex/jboss-as
Java | 313 lines | 239 code | 37 blank | 37 comment | 29 complexity | 3419e7a20dcb0a87a6eb3247f8ee8a7c MD5 | raw file
  1. /*
  2. * JBoss, Home of Professional Open Source.
  3. * Copyright 2010, Red Hat, Inc., and individual contributors
  4. * as indicated by the @author tags. See the copyright.txt file in the
  5. * distribution for a full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jboss.as.osgi.service;
  23. import java.io.File;
  24. import java.io.FileInputStream;
  25. import java.io.FilenameFilter;
  26. import java.io.IOException;
  27. import java.net.URL;
  28. import java.util.LinkedHashMap;
  29. import java.util.Map;
  30. import java.util.Observable;
  31. import java.util.Observer;
  32. import java.util.concurrent.atomic.AtomicLong;
  33. import org.jboss.as.osgi.parser.SubsystemState;
  34. import org.jboss.as.osgi.parser.SubsystemState.ChangeEvent;
  35. import org.jboss.as.osgi.parser.SubsystemState.ChangeType;
  36. import org.jboss.as.osgi.parser.SubsystemState.OSGiModule;
  37. import org.jboss.as.server.ServerEnvironment;
  38. import org.jboss.as.server.ServerEnvironmentService;
  39. import org.jboss.modules.Module;
  40. import org.jboss.modules.ModuleIdentifier;
  41. import org.jboss.modules.ModuleLoader;
  42. import org.jboss.msc.service.AbstractService;
  43. import org.jboss.msc.service.ServiceBuilder;
  44. import org.jboss.msc.service.ServiceContainer;
  45. import org.jboss.msc.service.ServiceController;
  46. import org.jboss.msc.service.ServiceController.Mode;
  47. import org.jboss.msc.service.ServiceName;
  48. import org.jboss.msc.service.ServiceTarget;
  49. import org.jboss.msc.service.StartContext;
  50. import org.jboss.msc.service.StartException;
  51. import org.jboss.msc.value.InjectedValue;
  52. import org.jboss.osgi.deployment.deployer.Deployment;
  53. import org.jboss.osgi.deployment.deployer.DeploymentFactory;
  54. import org.jboss.osgi.framework.AutoInstallProvider;
  55. import org.jboss.osgi.framework.BundleManagerService;
  56. import org.jboss.osgi.framework.Services;
  57. import org.jboss.osgi.metadata.OSGiMetaData;
  58. import org.jboss.osgi.metadata.OSGiMetaDataBuilder;
  59. import org.jboss.osgi.spi.util.BundleInfo;
  60. import org.jboss.osgi.vfs.AbstractVFS;
  61. import org.jboss.osgi.vfs.VirtualFile;
  62. import org.osgi.framework.Bundle;
  63. import org.osgi.framework.BundleException;
  64. import org.osgi.service.startlevel.StartLevel;
  65. import static org.jboss.as.osgi.OSGiLogger.ROOT_LOGGER;
  66. import static org.jboss.as.osgi.OSGiMessages.MESSAGES;
  67. /**
  68. * Integration point to auto install bundles at framework startup.
  69. *
  70. * @author Thomas.Diesler@jboss.com
  71. * @since 11-Sep-2010
  72. */
  73. class AutoInstallIntegration extends AbstractService<AutoInstallProvider> implements AutoInstallProvider, Observer {
  74. final InjectedValue<BundleManagerService> injectedBundleManager = new InjectedValue<BundleManagerService>();
  75. final InjectedValue<ServerEnvironment> injectedEnvironment = new InjectedValue<ServerEnvironment>();
  76. final InjectedValue<Bundle> injectedSystemBundle = new InjectedValue<Bundle>();
  77. final InjectedValue<StartLevel> injectedStartLevel = new InjectedValue<StartLevel>();
  78. final InjectedValue<SubsystemState> injectedSubsystemState = new InjectedValue<SubsystemState>();
  79. ServiceController<?> serviceController;
  80. private File modulesDir;
  81. private File bundlesDir;
  82. private ServiceTarget serviceTarget;
  83. private final AtomicLong updateServiceIdCounter = new AtomicLong();
  84. static ServiceController<?> addService(final ServiceTarget target) {
  85. AutoInstallIntegration service = new AutoInstallIntegration();
  86. ServiceBuilder<?> builder = target.addService(Services.AUTOINSTALL_PROVIDER, service);
  87. builder.addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, service.injectedEnvironment);
  88. builder.addDependency(SubsystemState.SERVICE_NAME, SubsystemState.class, service.injectedSubsystemState);
  89. builder.addDependency(Services.BUNDLE_MANAGER, BundleManagerService.class, service.injectedBundleManager);
  90. builder.addDependency(Services.SYSTEM_BUNDLE, Bundle.class, service.injectedSystemBundle);
  91. builder.addDependency(Services.START_LEVEL, StartLevel.class, service.injectedStartLevel);
  92. builder.addDependency(Services.FRAMEWORK_INIT);
  93. builder.setInitialMode(Mode.ON_DEMAND);
  94. return builder.install();
  95. }
  96. AutoInstallIntegration() {
  97. }
  98. @Override
  99. public synchronized void start(StartContext context) throws StartException {
  100. serviceController = context.getController();
  101. ROOT_LOGGER.debugf("Starting: %s in mode %s", serviceController.getName(), serviceController.getMode());
  102. final Map<ServiceName, OSGiModule> pendingServices = new LinkedHashMap<ServiceName, OSGiModule>();
  103. try {
  104. final BundleManagerService bundleManager = injectedBundleManager.getValue();
  105. final ServiceContainer serviceContainer = serviceController.getServiceContainer();
  106. serviceTarget = context.getChildTarget();
  107. modulesDir = injectedEnvironment.getValue().getModulesDir();
  108. bundlesDir = new File(modulesDir.getPath() + "/../bundles").getCanonicalFile();
  109. if (bundlesDir.isDirectory() == false)
  110. throw MESSAGES.cannotFindBundleDir(bundlesDir);
  111. injectedSubsystemState.getValue().addObserver(this);
  112. for (OSGiModule moduleMetaData : injectedSubsystemState.getValue().getModules()) {
  113. ServiceName serviceName = installModule(bundleManager, moduleMetaData);
  114. pendingServices.put(serviceName, moduleMetaData);
  115. }
  116. // Install a service that has a dependency on all pending bundle INSTALLED services
  117. ServiceName servicesInstalled = Services.AUTOINSTALL_PROVIDER.append("INSTALLED");
  118. ServiceBuilder<Void> builder = serviceTarget.addService(servicesInstalled, new AbstractService<Void>() {
  119. public void start(StartContext context) throws StartException {
  120. ROOT_LOGGER.debugf("Auto bundles installed");
  121. }
  122. });
  123. builder.addDependencies(pendingServices.keySet());
  124. builder.install();
  125. // Install a service that starts the bundles
  126. builder = serviceTarget.addService(Services.AUTOINSTALL_PROVIDER_COMPLETE, new AbstractService<Void>() {
  127. public void start(StartContext context) throws StartException {
  128. for (ServiceName serviceName : pendingServices.keySet()) {
  129. OSGiModule moduleMetaData = pendingServices.get(serviceName);
  130. startBundle(serviceContainer, serviceName, moduleMetaData);
  131. }
  132. ROOT_LOGGER.debugf("Auto bundles bundles started");
  133. }
  134. });
  135. builder.addDependencies(servicesInstalled);
  136. builder.install();
  137. } catch (Exception ex) {
  138. throw new StartException(MESSAGES.failedToCreateAutoInstallList(), ex);
  139. }
  140. }
  141. ServiceName installModule(BundleManagerService bundleManager, OSGiModule moduleMetaData) throws Exception {
  142. ModuleIdentifier identifier = moduleMetaData.getIdentifier();
  143. Integer startLevel = moduleMetaData.getStartLevel();
  144. // Attempt to install bundle from the bundles hirarchy
  145. File modulesFile = getRepositoryEntry(bundlesDir, identifier);
  146. if (modulesFile != null) {
  147. URL url = modulesFile.toURI().toURL();
  148. return installBundleFromURL(bundleManager, url, startLevel);
  149. }
  150. // Attempt to install bundle from the modules hirarchy
  151. modulesFile = getRepositoryEntry(modulesDir, identifier);
  152. if (modulesFile != null) {
  153. URL url = modulesFile.toURI().toURL();
  154. VirtualFile virtualFile = AbstractVFS.toVirtualFile(url);
  155. if (BundleInfo.isValidBundle(virtualFile)) {
  156. ROOT_LOGGER.foundOsgiBundle(modulesFile);
  157. return installBundleFromURL(bundleManager, url, startLevel);
  158. }
  159. }
  160. // Register module with the OSGi layer
  161. ModuleLoader moduleLoader = Module.getBootModuleLoader();
  162. Module module = moduleLoader.loadModule(identifier);
  163. OSGiMetaData metadata = getModuleMetadata(module);
  164. return bundleManager.registerModule(serviceTarget, module, metadata);
  165. }
  166. private ServiceName installBundleFromURL(BundleManagerService bundleManager, URL moduleURL, Integer startLevel) throws Exception {
  167. BundleInfo info = BundleInfo.createBundleInfo(moduleURL);
  168. Deployment dep = DeploymentFactory.createDeployment(info);
  169. if (startLevel != null) {
  170. dep.setStartLevel(startLevel.intValue());
  171. }
  172. return bundleManager.installBundle(serviceTarget, dep);
  173. }
  174. void startBundle(final ServiceContainer serviceContainer, ServiceName serviceName, OSGiModule moduleMetaData) {
  175. if (moduleMetaData.getStartLevel() != null) {
  176. @SuppressWarnings("unchecked")
  177. ServiceController<Bundle> controller = (ServiceController<Bundle>) serviceContainer.getRequiredService(serviceName);
  178. Bundle bundle = controller.getValue();
  179. StartLevel startLevel = injectedStartLevel.getValue();
  180. startLevel.setBundleStartLevel(bundle, moduleMetaData.getStartLevel());
  181. try {
  182. bundle.start();
  183. } catch (BundleException ex) {
  184. ROOT_LOGGER.cannotStart(ex, bundle);
  185. }
  186. }
  187. }
  188. @Override
  189. public synchronized AutoInstallIntegration getValue() throws IllegalStateException {
  190. return this;
  191. }
  192. /**
  193. * Get file for the singe jar that corresponds to the given identifier
  194. */
  195. private File getRepositoryEntry(File rootDir, ModuleIdentifier identifier) throws IOException {
  196. String identifierPath = identifier.getName().replace('.', '/') + "/" + identifier.getSlot();
  197. File entryDir = new File(rootDir + "/" + identifierPath);
  198. if (entryDir.isDirectory() == false) {
  199. ROOT_LOGGER.debugf("Cannot obtain directory: %s", entryDir);
  200. return null;
  201. }
  202. String[] files = entryDir.list(new FilenameFilter() {
  203. public boolean accept(File dir, String name) {
  204. return name.endsWith(".jar");
  205. }
  206. });
  207. if (files.length == 0) {
  208. ROOT_LOGGER.debugf("Cannot find jar in: %s", entryDir);
  209. return null;
  210. }
  211. if (files.length > 1) {
  212. ROOT_LOGGER.debugf("Multiple jars in: %s", entryDir);
  213. return null;
  214. }
  215. File entryFile = new File(entryDir + "/" + files[0]);
  216. if (entryFile.exists() == false) {
  217. ROOT_LOGGER.debugf("File does not exist: %s", entryFile);
  218. return null;
  219. }
  220. return entryFile;
  221. }
  222. private OSGiMetaData getModuleMetadata(Module module) throws IOException {
  223. final File modulesDir = injectedEnvironment.getValue().getModulesDir();
  224. final ModuleIdentifier identifier = module.getIdentifier();
  225. String identifierPath = identifier.getName().replace('.', '/') + "/" + identifier.getSlot();
  226. File entryFile = new File(modulesDir + "/" + identifierPath + "/jbosgi-xservice.properties");
  227. if (entryFile.exists() == false) {
  228. ROOT_LOGGER.debugf("Cannot obtain OSGi metadata file: %s", entryFile);
  229. return null;
  230. }
  231. FileInputStream input = new FileInputStream(entryFile);
  232. try {
  233. return OSGiMetaDataBuilder.load(input);
  234. } finally {
  235. input.close();
  236. }
  237. }
  238. // Called when the SubsystemState changes.
  239. @Override
  240. public void update(Observable o, Object arg) {
  241. if (arg instanceof SubsystemState.ChangeEvent == false)
  242. return;
  243. SubsystemState.ChangeEvent event = (ChangeEvent) arg;
  244. if (event.getType() != ChangeType.MODULE)
  245. return;
  246. if (!event.isRemoved()) {
  247. try {
  248. for (final OSGiModule module : injectedSubsystemState.getValue().getModules()) {
  249. if (module.getIdentifier().toString().equals(event.getId())) {
  250. final ServiceName serviceName = installModule(injectedBundleManager.getValue(), module);
  251. ServiceBuilder<Void> builder = serviceController.getServiceContainer().addService(
  252. ServiceName.of(Services.AUTOINSTALL_PROVIDER, "ModuleUpdater", "" + updateServiceIdCounter.incrementAndGet()),
  253. new AbstractService<Void>() {
  254. @Override
  255. public void start(StartContext context) throws StartException {
  256. try {
  257. startBundle(serviceController.getServiceContainer(), serviceName, module);
  258. } finally {
  259. // Remove this temporary service
  260. context.getController().setMode(Mode.REMOVE);
  261. }
  262. }
  263. });
  264. builder.addDependency(serviceName);
  265. builder.install();
  266. return;
  267. }
  268. }
  269. } catch (Exception e) {
  270. ROOT_LOGGER.errorAddingModule(e, event.getId());
  271. return;
  272. }
  273. ROOT_LOGGER.moduleNotFound(event.getId());
  274. }
  275. }
  276. }