Java tutorial
/* ############################################################################### # # # Copyright 2016, AdeptJ (http://www.adeptj.com) # # # # 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. # # # ############################################################################### */ package io.adeptj.runtime.osgi; import com.typesafe.config.Config; import io.adeptj.runtime.common.BundleContextHolder; import io.adeptj.runtime.common.Environment; import io.adeptj.runtime.common.Servlets; import io.adeptj.runtime.common.Times; import io.adeptj.runtime.config.Configs; import io.adeptj.runtime.servlet.osgi.DefaultErrorHandler; import org.apache.commons.io.IOUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.launch.Framework; import org.osgi.framework.launch.FrameworkFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.Servlet; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; import java.util.ServiceLoader; /** * FrameworkManager: Handles the OSGi Framework(Apache Felix) lifecycle such as startup, shutdown etc. * * @author Rakesh.Kumar, AdeptJ */ public enum FrameworkManager { INSTANCE; private static final Logger LOGGER = LoggerFactory.getLogger(FrameworkManager.class); private static final String FRAMEWORK_PROPERTIES = "/framework.properties"; private static final String FELIX_CM_DIR = "felix.cm.dir"; private static final String CFG_KEY_FELIX_CM_DIR = "felix-cm-dir"; private static final String MEM_DUMP_LOC = "felix.memoryusage.dump.location"; private static final String CFG_KEY_MEM_DUMP_LOC = "memoryusage-dump-loc"; private static final String FELIX_LOG_LEVEL = "felix.log.level"; private ServiceRegistration<Servlet> errorHandler; private Framework framework; private FrameworkLifecycleListener frameworkListener; public void startFramework() { try { long startTime = System.nanoTime(); LOGGER.info("Starting the OSGi Framework!!"); FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next(); this.framework = frameworkFactory.newFramework(this.frameworkConfigs()); long startTimeFramework = System.nanoTime(); this.framework.start(); LOGGER.info("OSGi Framework creation took [{}] ms!!", Times.elapsedMillis(startTimeFramework)); BundleContext systemBundleContext = this.framework.getBundleContext(); this.frameworkListener = new FrameworkLifecycleListener(); systemBundleContext.addFrameworkListener(this.frameworkListener); BundleContextHolder.getInstance().setBundleContext(systemBundleContext); this.provisionBundles(systemBundleContext); List<String> errors = Configs.INSTANCE.undertow().getStringList("common.osgi-error-pages"); this.errorHandler = Servlets.osgiServlet(systemBundleContext, new DefaultErrorHandler(), errors); LOGGER.info("OSGi Framework started in [{}] ms!!", Times.elapsedMillis(startTime)); } catch (Exception ex) { // NOSONAR LOGGER.error("Failed to start OSGi Framework!!", ex); // Stop the Framework if the Bundles throws exception. this.stopFramework(); } } public void stopFramework() { try { if (this.framework != null) { this.removeServicesAndListeners(); this.framework.stop(); // A value of zero will wait indefinitely. FrameworkEvent event = this.framework.waitForStop(0); LOGGER.info("OSGi FrameworkEvent: [{}]", FrameworkEvents.asString(event.getType())); // NOSONAR } else { LOGGER.info("OSGi Framework not started yet, nothing to stop!!"); } } catch (Exception ex) { // NOSONAR LOGGER.error("Error Stopping OSGi Framework!!", ex); } } private void removeServicesAndListeners() { Optional.ofNullable(this.errorHandler).ifPresent(serviceRegistration -> { try { LOGGER.info("Removing OSGi ErrorHandler service!!"); serviceRegistration.unregister(); } catch (Exception ex) { LOGGER.error(ex.getMessage(), ex); } }); Optional.ofNullable(BundleContextHolder.getInstance().getBundleContext()).ifPresent(bundleContext -> { try { LOGGER.info("Removing OSGi FrameworkListener!!"); bundleContext.removeFrameworkListener(this.frameworkListener); } catch (Exception ex) { LOGGER.error(ex.getMessage(), ex); } }); } private void provisionBundles(BundleContext systemBundleContext) throws IOException { // config directory will not yet be created if framework is being provisioned first time. if (!Boolean.getBoolean("provision.bundles.explicitly") && Paths.get(Configs.INSTANCE.felix().getString(CFG_KEY_FELIX_CM_DIR)).toFile().exists()) { LOGGER.info("As per configuration, bundles provisioning is skipped on server restart!!"); } else { Bundles.provisionBundles(systemBundleContext); } } private Map<String, String> frameworkConfigs() { Map<String, String> configs = this.loadFrameworkProperties(); Config felixConf = Configs.of().felix(); configs.put(FELIX_CM_DIR, felixConf.getString(CFG_KEY_FELIX_CM_DIR)); configs.put(MEM_DUMP_LOC, felixConf.getString(CFG_KEY_MEM_DUMP_LOC)); Optional.ofNullable(System.getProperty(FELIX_LOG_LEVEL)) .ifPresent(level -> configs.put(FELIX_LOG_LEVEL, level)); LOGGER.debug("OSGi Framework Configurations: {}", configs); return configs; } private Map<String, String> loadFrameworkProperties() { Properties props = new Properties(); Map<String, String> configs = new HashMap<>(); if (Environment.isFrameworkConfFileExists()) { try (InputStream is = Files.newInputStream(Environment.getFrameworkConfPath())) { props.load(is); props.forEach((key, val) -> configs.put((String) key, (String) val)); } catch (IOException ex) { LOGGER.error("IOException while loading framework.properties from file system!!", ex); // Fallback is try to load the classpath framework.properties this.loadClasspathFrameworkProperties(props, configs); } } else { this.loadClasspathFrameworkProperties(props, configs); this.createFrameworkPropertiesFile(); } return configs; } private void loadClasspathFrameworkProperties(Properties props, Map<String, String> configs) { try (InputStream is = FrameworkManager.class.getResourceAsStream(FRAMEWORK_PROPERTIES)) { props.load(is); props.forEach((key, val) -> configs.put((String) key, (String) val)); } catch (IOException exception) { LOGGER.error("IOException while loading framework.properties from classpath!!", exception); } } private void createFrameworkPropertiesFile() { try (InputStream is = FrameworkManager.class.getResourceAsStream(FRAMEWORK_PROPERTIES)) { Files.write(Environment.getFrameworkConfPath(), IOUtils.toByteArray(is)); } catch (IOException ex) { LOGGER.error("IOException!!", ex); } } public static FrameworkManager getInstance() { return INSTANCE; } }