Commit 988fad57 authored by Loïc Albertin's avatar Loïc Albertin
Browse files

#1034: Allow to prevent installation of bundles in the auto-deploy config file...

#1034: Allow to prevent installation of bundles in the auto-deploy config file using a system property
parent 467d7068
......@@ -39,14 +39,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.osgi.framework.Constants;
import org.ow2.jonas.launcher.jonas.util.FileNamesComparator;
......@@ -95,6 +98,11 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
*/
private SortedMap<Integer, List<String>> autoStartLevelBundlesLocationMap = null;
/**
* Set {@link Pattern}s representing bundles from auto-deploy config file that should be excluded
*/
private Set<Pattern> preventAutoDeployPatterns = null;
/**
* Default constructor.
*/
......@@ -103,6 +111,7 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
this.substitutionEngine = createSubstitutionEngine();
this.autoInstallLevelBundlesLocationMap = new TreeMap<Integer, List<String>>();
this.autoStartLevelBundlesLocationMap = new TreeMap<Integer, List<String>>();
this.preventAutoDeployPatterns = new HashSet<Pattern>();
}
/**
......@@ -167,6 +176,8 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
// Resolve the variables
resolveProperties(gatewayProperties);
initPreventAutoDeploy(gatewayProperties);
// Augment that basic configuration with bundles to be started during gateway start-up
//
Properties autoDeployProperties = null;
......@@ -185,6 +196,20 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
return props2Map(gatewayProperties);
}
/**
* Extract {@link Pattern}s for the <code>jonas.prevent.auto.deploy</code> property from the gateway properties file
* @param gatewayProperties {@link Properties} read from the gateway properties file
*/
private void initPreventAutoDeploy(Properties gatewayProperties) {
String preventAutoDeploy = gatewayProperties.getProperty("jonas.prevent.auto.deploy", "");
for (String pattern : preventAutoDeploy.split(",")) {
pattern = pattern.trim();
if (!pattern.equals("")) {
preventAutoDeployPatterns.add(Pattern.compile(pattern));
}
}
}
/**
* Resolve this set of properties with the given resolver.
* @param properties properties to be resolved
......@@ -332,15 +357,17 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
// The bundle list separator is ','
String[] bundles = value.split(",");
for (int i = 0; i < bundles.length; i++) {
String bundle = bundles[i];
String bundle = bundles[i].trim();
// Only process non-empty parts
if (!"".equals(bundle)) {
if (matchPreventAutoDeployPattern(bundle)) {
continue;
}
String location = "";
// The bundle is specified using the following format:
// <groupId>:<artifactId>[:<version>]
// <groupId>:<artifactId>[:<version>][:{classifier}]
String[] artifact = bundle.split(":");
String groupId = artifact[0].trim();
......@@ -400,6 +427,20 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
return locations;
}
/**
* Check if a bundle name matches a pattern in the jonas.prevent.auto.deploy property
* @param bundle The bundle's name to check
* @return True if bundle matches a {@link Pattern}
*/
private boolean matchPreventAutoDeployPattern(String bundle) {
for (Pattern pattern : preventAutoDeployPatterns) {
if (pattern.matcher(bundle).matches()) {
return true;
}
}
return false;
}
/**
* @param value value from which the classifier will be extracted
* @return the classifier value if this is a valid classifier, null otherwise
......
......@@ -31,6 +31,7 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.rmi.RMISecurityManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
......@@ -55,6 +56,7 @@ import org.ow2.jonas.launcher.jonas.util.JOnASUtils;
/**
* JOnAS Running on OSGi framework.
*
* @author Guillaume Sauthier
*/
public class JOnAS {
......@@ -106,7 +108,9 @@ public class JOnAS {
/**
* Creates a new configured framework instance.
*
* @param forceCleanUp true if cache directory must be deleted.
*
* @throws Exception cannot create the internal gateway.
*/
public JOnAS(final boolean forceCleanUp) throws Exception {
......@@ -174,6 +178,7 @@ public class JOnAS {
/**
* Start JOnAS on the gateway.
*
* @throws Exception Thrown if the start fails
*/
public void start() throws Exception {
......@@ -189,6 +194,7 @@ public class JOnAS {
/**
* Stop JOnAS.
*
* @throws Exception Thrown if the stop fails
*/
public void stop() throws Exception {
......@@ -208,7 +214,9 @@ public class JOnAS {
/**
* Start a new JOnAS.
*
* @param args not used
*
* @throws Exception if something failed
*/
public static void main(final String[] args) throws Exception {
......@@ -252,10 +260,14 @@ public class JOnAS {
// MBeanServerBuilder
System.setProperty("javax.management.builder.initial", "org.ow2.jonas.services.bootstrap.mbeanbuilder.JOnASMBeanServerBuilder");
// Set this property needed by resolvers
setDefaultPropertyIfNotSet("jonas.prevent.auto.deploy", "");
}
/**
* @return a framework factory used to instantiate the framework
*
* @throws Exception if the factory can't be retrieved
*/
private FrameworkFactory getFrameworkFactory() throws Exception {
......@@ -286,6 +298,7 @@ public class JOnAS {
/**
* If the property was already set, do not change its value, otherwise, use
* the default.
*
* @param key property name
* @param def default property value
*/
......@@ -295,9 +308,15 @@ public class JOnAS {
/**
* The bundle start operation is transient for TUI and GUI bundles.
*
* @throws BundleException If bundles startup fails
*/
protected void startTransientBundles() throws BundleException {
boolean startTui = Boolean.getBoolean("jonas.felix.tui.enabled");
boolean startGui = Boolean.getBoolean("jonas.felix.gui.enabled");
if (!startGui && !startTui) {
return;
}
Bundle[] bundles = framework.getBundleContext().getBundles();
for (Bundle bundle : bundles) {
// OSGi R3 bundle may not have the Bundle-SymbolicName manifest header
......@@ -306,14 +325,14 @@ public class JOnAS {
if (symbolicName.equals(tuiBundleName)) {
// Use Text UI ?
if (Boolean.getBoolean("jonas.felix.tui.enabled")) {
if (startTui) {
startTransient(bundle);
}
}
if (symbolicName.startsWith(guiBundleName)) {
// Use GUI ?
if (Boolean.getBoolean("jonas.felix.gui.enabled")) {
if (startGui) {
startTransient(bundle);
}
}
......@@ -342,6 +361,11 @@ public class JOnAS {
List<Bundle> bundlesToStart = new ArrayList<Bundle>();
Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
for (Bundle bundle : bundleContext.getBundles()) {
installedBundles.put(bundle.getLocation(), bundle);
}
// For each level, install the given bundles and specify the start level for these bundles
while (levelIterator.hasNext()) {
Integer level = levelIterator.next();
......@@ -355,11 +379,9 @@ public class JOnAS {
for (String bundleLocation : autoInstallBundleLocations) {
//install the bundle only if it's not already installed in the felix cache
Bundle bundle = isDeploy(bundleLocation);
if (bundle == null) {
if (!installedBundles.containsKey(bundleLocation)) {
try {
bundle = bundleContext.installBundle(bundleLocation);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
installBundle(bundleContext, installedBundles, level, bundleLocation);
} catch (BundleException e) {
LOGGER.log(Level.SEVERE, "Unable to install the bundle with location '" + bundleLocation
+ "' and the startlevel '" + level + "'.", e);
......@@ -371,13 +393,11 @@ public class JOnAS {
// for auto start, install them and add it to the list of bundles to be started
if (autoStartBundleLocations != null && !autoStartBundleLocations.isEmpty()) {
for (String bundleLocation : autoStartBundleLocations) {
//install the bundle only if it's not already installed in the felix cache
Bundle bundle = isDeploy(bundleLocation);
Bundle bundle = installedBundles.get(bundleLocation);
if (bundle == null) {
try {
bundle = bundleContext.installBundle(bundleLocation);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
bundle = installBundle(bundleContext, installedBundles, level, bundleLocation);
} catch (BundleException e) {
LOGGER.log(Level.SEVERE, "Unable to install the bundle with location '" + bundleLocation
+ "' and the startlevel '" + level + "'.", e);
......@@ -403,22 +423,31 @@ public class JOnAS {
}
/**
* @param bundleLocation A bundle location
* @return the Bundle if it's already installed in the felix cache. Null if the bundle is not in the felix cache
* Installs a bundle from its <code>bundleLocation</code> using the <code>bundleContext</code> and sets its startLevel from the given
* <code>level</code> parameter. Finally the bundle is stored in the <code>installedBundles</code> map.
*
* @param bundleContext The {@link BundleContext} used to install the bundle
* @param installedBundles A {@link Map} used to store bundles by location
* @param level The bundle's start level
* @param bundleLocation The location from which a bundle should be installed
*
* @return The installed {@link Bundle}
*
* @throws BundleException Throws if bundle installation fails (see {@link BundleContext#installBundle(String)}
*/
private Bundle isDeploy(final String bundleLocation) {
BundleContext bundleContext = this.framework.getBundleContext();
for (Bundle bundle: bundleContext.getBundles()) {
if (bundle.getLocation().equals(bundleLocation)) {
return bundle;
}
}
return null;
private Bundle installBundle(BundleContext bundleContext, Map<String, Bundle> installedBundles, Integer level, String bundleLocation)
throws BundleException {
Bundle bundle = bundleContext.installBundle(bundleLocation);
installedBundles.put(bundleLocation, bundle);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
return bundle;
}
/**
* The bundle start operation is transient for the given bundle.
*
* @param bundle the given bundle.
*
* @throws BundleException If bundle startup fails
*/
protected void startTransient(final Bundle bundle) throws BundleException {
......
# ---------------------------------------------------------------------------
# JOnAS: Java(TM) Open Application Server
# Copyright (C) 2010-2012 Bull S.A.S.
# Copyright (C) 2010-2013 Bull S.A.S.
# Contact: jonas-team@ow2.org
#
# This library is free software; you can redistribute it and/or
......@@ -106,6 +106,19 @@ felix.fragment.validation warning
#
#felix.bootdelegation.implicit false
## --------------------------------------------- ##
## OW2 JOnAS ##
## --------------------------------------------- ##
jonas-tui org.ow2.shelbie.startup-console
jonas-gui org.apache.felix.shell.gui
# # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Avoid install and start for auto-deployed bundles.
# This variable is a comma separated list of java.util.regex.Pattern
# that should match bundles descriptions in the auto-deploy.properties
# file (in the following format
# <groupId>:<artifactId>[:<version>][:{classifier}] )
#
jonas.prevent.auto.deploy ${jonas.prevent.auto.deploy}
......@@ -39,14 +39,17 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.osgi.framework.Constants;
import org.ow2.jonas.launcher.jonas.util.FileNamesComparator;
......@@ -95,6 +98,11 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
*/
private SortedMap<Integer, List<String>> autoStartLevelBundlesLocationMap = null;
/**
* Set {@link Pattern}s representing bundles from auto-deploy config file that should be excluded
*/
private Set<Pattern> preventAutoDeployPatterns = null;
/**
* Default constructor.
*/
......@@ -103,6 +111,7 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
this.substitutionEngine = createSubstitutionEngine();
this.autoInstallLevelBundlesLocationMap = new TreeMap<Integer, List<String>>();
this.autoStartLevelBundlesLocationMap = new TreeMap<Integer, List<String>>();
this.preventAutoDeployPatterns = new HashSet<Pattern>();
}
/**
......@@ -167,6 +176,8 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
// Resolve the variables
resolveProperties(gatewayProperties);
initPreventAutoDeploy(gatewayProperties);
// Augment that basic configuration with bundles to be started during gateway start-up
//
Properties autoDeployProperties = null;
......@@ -185,6 +196,20 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
return props2Map(gatewayProperties);
}
/**
* Extract {@link Pattern}s for the <code>jonas.prevent.auto.deploy</code> property from the gateway properties file
* @param gatewayProperties {@link Properties} read from the gateway properties file
*/
private void initPreventAutoDeploy(Properties gatewayProperties) {
String preventAutoDeploy = gatewayProperties.getProperty("jonas.prevent.auto.deploy", "");
for (String pattern : preventAutoDeploy.split(",")) {
pattern = pattern.trim();
if (!pattern.equals("")) {
preventAutoDeployPatterns.add(Pattern.compile(pattern));
}
}
}
/**
* Resolve this set of properties with the given resolver.
* @param properties properties to be resolved
......@@ -332,15 +357,17 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
// The bundle list separator is ','
String[] bundles = value.split(",");
for (int i = 0; i < bundles.length; i++) {
String bundle = bundles[i];
String bundle = bundles[i].trim();
// Only process non-empty parts
if (!"".equals(bundle)) {
if (matchPreventAutoDeployPattern(bundle)) {
continue;
}
String location = "";
// The bundle is specified using the following format:
// <groupId>:<artifactId>[:<version>]
// <groupId>:<artifactId>[:<version>][:{classifier}]
String[] artifact = bundle.split(":");
String groupId = artifact[0].trim();
......@@ -390,7 +417,8 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
repository = Maven2Utils.getMaven2InternalRepository();
}
// add path
location = location.concat(Maven2Utils.getBundleMaven2Location(repository.getPath(), groupId, artifactId, version, classifier));
location = location.concat(
Maven2Utils.getBundleMaven2Location(repository.getPath(), groupId, artifactId, version, classifier));
// add to the list
locations.add(location);
......@@ -400,6 +428,20 @@ public class DefaultConfigurationProvider implements IConfigurationProvider {
return locations;
}
/**
* Check if a bundle name matches a pattern in the jonas.prevent.auto.deploy property
* @param bundle The bundle's name to check
* @return True if bundle matches a {@link Pattern}
*/
private boolean matchPreventAutoDeployPattern(String bundle) {
for (Pattern pattern : preventAutoDeployPatterns) {
if (pattern.matcher(bundle).matches()) {
return true;
}
}
return false;
}
/**
* @param value value from which the classifier will be extracted
* @return the classifier value if this is a valid classifier, null otherwise
......
......@@ -31,6 +31,7 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.rmi.RMISecurityManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
......@@ -130,7 +131,7 @@ public class JOnAS {
// Retrieve the configuration
Map<String, String> configProps = provider.getConfiguration();
// Retrieve the bundle names for the shell
tuiBundleName = configProps.get(TUI_BUNDLE_NAME_PROPERTY);
guiBundleName = configProps.get(GUI_BUNDLE_NAME_PROPERTY);
......@@ -252,6 +253,9 @@ public class JOnAS {
// MBeanServerBuilder
System.setProperty("javax.management.builder.initial", "org.ow2.jonas.services.bootstrap.mbeanbuilder.JOnASMBeanServerBuilder");
// Set this property needed by resolvers
setDefaultPropertyIfNotSet("jonas.prevent.auto.deploy", "");
}
/**
......@@ -298,6 +302,11 @@ public class JOnAS {
* @throws BundleException If bundles startup fails
*/
protected void startTransientBundles() throws BundleException {
boolean startTui = Boolean.getBoolean("jonas.felix.tui.enabled");
boolean startGui = Boolean.getBoolean("jonas.felix.gui.enabled");
if (!startGui && !startTui) {
return;
}
Bundle[] bundles = framework.getBundleContext().getBundles();
for (Bundle bundle : bundles) {
// OSGi R3 bundle may not have the Bundle-SymbolicName manifest header
......@@ -306,14 +315,14 @@ public class JOnAS {
if (symbolicName.equals(tuiBundleName)) {
// Use Text UI ?
if (Boolean.getBoolean("jonas.felix.tui.enabled")) {
if (startTui) {
startTransient(bundle);
}
}
if (symbolicName.startsWith(guiBundleName)) {
// Use GUI ?
if (Boolean.getBoolean("jonas.felix.gui.enabled")) {
if (startGui) {
startTransient(bundle);
}
}
......@@ -342,6 +351,11 @@ public class JOnAS {
List<Bundle> bundlesToStart = new ArrayList<Bundle>();
Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
for (Bundle bundle : bundleContext.getBundles()) {
installedBundles.put(bundle.getLocation(), bundle);
}
// For each level, install the given bundles and specify the start level for these bundles
while (levelIterator.hasNext()) {
Integer level = levelIterator.next();
......@@ -355,11 +369,9 @@ public class JOnAS {
for (String bundleLocation : autoInstallBundleLocations) {
//install the bundle only if it's not already installed in the felix cache
Bundle bundle = isDeploy(bundleLocation);
if (bundle == null) {
if (!installedBundles.containsKey(bundleLocation)) {
try {
bundle = bundleContext.installBundle(bundleLocation);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
installBundle(bundleContext, installedBundles, level, bundleLocation);
} catch (BundleException e) {
LOGGER.log(Level.SEVERE, "Unable to install the bundle with location '" + bundleLocation
+ "' and the startlevel '" + level + "'.", e);
......@@ -372,11 +384,10 @@ public class JOnAS {
if (autoStartBundleLocations != null && !autoStartBundleLocations.isEmpty()) {
for (String bundleLocation : autoStartBundleLocations) {
//install the bundle only if it's not already installed in the felix cache
Bundle bundle = isDeploy(bundleLocation);
Bundle bundle = installedBundles.get(bundleLocation);
if (bundle == null) {
try {
bundle = bundleContext.installBundle(bundleLocation);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
bundle = installBundle(bundleContext, installedBundles, level, bundleLocation);
} catch (BundleException e) {
LOGGER.log(Level.SEVERE, "Unable to install the bundle with location '" + bundleLocation
+ "' and the startlevel '" + level + "'.", e);
......@@ -399,23 +410,24 @@ public class JOnAS {
LOGGER.log(Level.SEVERE, "Unable to start the bundle with name '" + bundle.getSymbolicName() + "'", e);
}
}
}
/**
* @param bundleLocation A bundle location
* @return the Bundle if it's already installed in the felix cache. Null if the bundle is not in the felix cache
* Installs a bundle from its <code>bundleLocation</code> using the <code>bundleContext</code> and sets its startLevel from the given
* <code>level</code> parameter. Finally the bundle is stored in the <code>installedBundles</code> map.
* @param bundleContext The {@link BundleContext} used to install the bundle
* @param installedBundles A {@link Map} used to store bundles by location
* @param level The bundle's start level
* @param bundleLocation The location from which a bundle should be installed
* @return The installed {@link Bundle}
* @throws BundleException Throws if bundle installation fails (see {@link BundleContext#installBundle(String)}
*/
private Bundle isDeploy(final String bundleLocation) {
BundleContext bundleContext = this.framework.getBundleContext();
for (Bundle bundle: bundleContext.getBundles()) {
if (bundle.getLocation().equals(bundleLocation)) {
return bundle;
}
}
return null;
private Bundle installBundle(BundleContext bundleContext, Map<String, Bundle> installedBundles, Integer level, String bundleLocation)
throws BundleException {
Bundle bundle = bundleContext.installBundle(bundleLocation);
installedBundles.put(bundleLocation, bundle);
bundle.adapt(BundleStartLevel.class).setStartLevel(level);
return bundle;