blob: f31a94fde361cbb1e1fff9cd1332ffac05bda762 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.struts2.osgi.host;
import com.opensymphony.xwork2.config.ConfigurationException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.felix.framework.Felix;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.main.AutoProcessor;
import org.apache.felix.main.Main;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import javax.servlet.ServletContext;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Apache felix implementation of an OsgiHost
* See http://felix.apache.org/site/apache-felix-framework-launching-and-embedding.html
* <br>
* Servlet config params:
* <p>struts.osgi.clearBundleCache: Defaults to "true" delete installed bundles when the comntainer starts</p>
* <p>struts.osgi.logLevel: Defaults to "1". Felix log level. 1 = error, 2 = warning, 3 = information, and 4 = debug </p>
* <p>struts.osgi.runLevel: Defaults to "3". Run level to start the container.</p>
*/
public class FelixOsgiHost extends BaseOsgiHost {
private static final Logger LOG = LogManager.getLogger(FelixOsgiHost.class);
protected Felix felix;
protected void startFelix() {
//load properties from felix embedded file
Properties configProps = getProperties("default.properties");
// Copy framework properties from the system properties.
Main.copySystemProperties(configProps);
replaceSystemPackages(configProps);
//struts, xwork and felix exported packages
Properties strutsConfigProps = getProperties("struts-osgi.properties");
addExportedPackages(strutsConfigProps, configProps);
//find bundles and adde em to autostart property
addAutoStartBundles(configProps);
// Bundle cache
String storageDir = System.getProperty("java.io.tmpdir") + ".felix-cache";
configProps.setProperty(Constants.FRAMEWORK_STORAGE, storageDir);
LOG.debug("Storing bundles at [{}]", storageDir);
String cleanBundleCache = getServletContextParam("struts.osgi.clearBundleCache", "true");
if ("true".equalsIgnoreCase(cleanBundleCache)) {
LOG.debug("Clearing bundle cache");
configProps.put(FelixConstants.FRAMEWORK_STORAGE_CLEAN, FelixConstants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
}
//other properties
configProps.put(FelixConstants.SERVICE_URLHANDLERS_PROP, "false");
configProps.put(FelixConstants.LOG_LEVEL_PROP, getServletContextParam("struts.osgi.logLevel", "1"));
configProps.put(FelixConstants.BUNDLE_CLASSPATH, ".");
configProps.put(FelixConstants.FRAMEWORK_BEGINNING_STARTLEVEL, getServletContextParam("struts.osgi.runLevel", "3"));
try {
felix = new Felix(configProps);
felix.init();
AutoProcessor.process(configProps, felix.getBundleContext());
felix.start();
LOG.trace("Apache Felix is running");
}
catch (Exception ex) {
throw new ConfigurationException("Couldn't start Apache Felix", ex);
}
addSpringOSGiSupport();
//add the bundle context to the ServletContext
servletContext.setAttribute(OSGI_BUNDLE_CONTEXT, felix.getBundleContext());
}
@Override
public void init(ServletContext servletContext) {
this.servletContext = servletContext;
startFelix();
}
@Override
public Map<String, Bundle> getBundles() {
Map<String, Bundle> bundles = new HashMap<String, Bundle>();
for (Bundle bundle : felix.getBundleContext().getBundles()) {
bundles.put(bundle.getSymbolicName(), bundle);
}
return Collections.unmodifiableMap(bundles);
}
@Override
public Map<String, Bundle> getActiveBundles() {
Map<String, Bundle> bundles = new HashMap<String, Bundle>();
for (Bundle bundle : felix.getBundleContext().getBundles()) {
if (bundle.getState() == Bundle.ACTIVE) {
bundles.put(bundle.getSymbolicName(), bundle);
}
}
return Collections.unmodifiableMap(bundles);
}
@Override
public BundleContext getBundleContext() {
return felix.getBundleContext();
}
@Override
public void destroy() throws Exception {
felix.stop();
LOG.trace("Apache Felix has stopped");
}
@Override
protected void addSpringOSGiSupport() {
// see the javadoc for org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext for more details
// OsgiBundleXmlWebApplicationContext expects the the BundleContext to be set in the ServletContext under the attribute
// OsgiBundleXmlWebApplicationContext.BUNDLE_CONTEXT_ATTRIBUTE
try {
Class clazz = Class.forName("org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext");
String key = (String) clazz.getDeclaredField("BUNDLE_CONTEXT_ATTRIBUTE").get(null);
servletContext.setAttribute(key, felix.getBundleContext());
} catch (ClassNotFoundException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Spring OSGi support is not enabled");
}
} catch (Exception e) {
LOG.error("The API of Spring OSGi has changed and the field [{}] is no longer available. The OSGi plugin needs to be updated",
"org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext.BUNDLE_CONTEXT_ATTRIBUTE", e);
}
}
}