blob: 2f339d740332cdb7e4971dbe0705a55fb3b2bb91 [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 org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.felix.shell.ShellService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleReference;
import javax.servlet.ServletContext;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A glassfish implementation of an OsgiHost
*/
public class GlassfishOSGiHost extends BaseOsgiHost implements OsgiHost {
private static final Logger LOG = LogManager.getLogger(GlassfishOSGiHost.class);
/**
* Location inside the WAR where initial bundles are located.
*/
private static final String BUNDLES_DIR = "/WEB-INF/classes/bundles/2/";
private BundleContext bctx = null;
@Override
public void init(ServletContext servletContext) {
this.servletContext = servletContext;
installManagedBundles();
addSpringOSGiSupport();
// add the bundle context to the ServletContext
servletContext.setAttribute(OSGI_BUNDLE_CONTEXT, bctx);
}
private void installManagedBundles() {
try {
// Obtaining BundleContext from ServletContext class which is loaded
// by bundle class loader
BundleReference ref = (BundleReference) servletContext.getClass()
.getClassLoader();
bctx = ref.getBundle().getBundleContext();
// installing managed bundles
installBundles();
} catch (Exception ex) {
LOG.error("Installing Managed Bundles met a problem", ex);
}
}
private void installBundles() throws Exception {
ArrayList<Bundle> installed = new ArrayList<>();
for (URL url : findBundles()) {
if (LOG.isDebugEnabled()) { // Avoid repeated cost of URL string transform, except when debug level logging is enabled.
LOG.debug("Installing bundle [{}]", url);
}
Bundle bundle = bctx.installBundle(url.toExternalForm());
installed.add(bundle);
}
installed.forEach(bundle -> {
try {
bundle.start();
} catch (BundleException e) {
// Use logging to print the stacktrace (no direct stacktrace print to stdout/stderr).
LOG.error("Failed to start [{}]", bundle, e);
}
});
}
private List<URL> findBundles() throws Exception {
ArrayList<URL> list = new ArrayList<>();
for (Object o : this.servletContext.getResourcePaths(BUNDLES_DIR)) {
String name = (String) o;
if (name.endsWith(".jar")) {
URL url = this.servletContext.getResource(name);
if (url != null) {
list.add(url);
}
}
}
ProtectionDomain protectionDomain = ShellService.class.getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
URL loc = codeSource.getLocation();
list.add(loc);
return list;
}
@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, bctx);
} catch (ClassNotFoundException e) {
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);
}
}
/**
* This bundle map will not change, but the status of the bundles can change
* over time. Use getActiveBundles() for active bundles
*/
@Override
public Map<String, Bundle> getBundles() {
Map<String, Bundle> bundles = new HashMap<>();
for (Bundle bundle : bctx.getBundles()) {
bundles.put(bundle.getSymbolicName(), bundle);
}
return Collections.unmodifiableMap(bundles);
}
@Override
public Map<String, Bundle> getActiveBundles() {
Map<String, Bundle> bundles = new HashMap<>();
for (Bundle bundle : bctx.getBundles()) {
if (bundle.getState() == Bundle.ACTIVE)
bundles.put(bundle.getSymbolicName(), bundle);
}
return Collections.unmodifiableMap(bundles);
}
@Override
public BundleContext getBundleContext() {
return bctx;
}
@Override
public void destroy() throws Exception {
}
}