| /* |
| * 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.tuscany.sca.node.equinox.launcher; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import org.eclipse.osgi.framework.console.CommandProvider; |
| import org.osgi.framework.BundleActivator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.launch.Framework; |
| import org.osgi.framework.launch.FrameworkFactory; |
| |
| /** |
| * Launcher for the OSGi framework using the framework launch APIs |
| */ |
| public class FrameworkLauncher implements BundleActivator { |
| private static final String FACTORY_RESOURCE = "META-INF/services/" + FrameworkFactory.class.getName(); |
| |
| private static final Logger logger = Logger.getLogger(FrameworkLauncher.class.getName()); |
| |
| private FrameworkFactory factory; |
| private boolean isEquinox; |
| |
| @SuppressWarnings("unchecked") |
| private synchronized FrameworkFactory loadFrameworkFactory() { |
| if (factory == null) { |
| try { |
| ClassLoader classLoader = FrameworkFactory.class.getClassLoader(); |
| InputStream is = classLoader.getResourceAsStream(FACTORY_RESOURCE); |
| if (is == null) { |
| classLoader = Thread.currentThread().getContextClassLoader(); |
| is = classLoader.getResourceAsStream(FACTORY_RESOURCE); |
| } |
| if (is == null) { |
| return null; |
| } |
| BufferedReader reader = null; |
| String line = null; |
| try { |
| reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); |
| while (true) { |
| line = reader.readLine(); |
| if (line == null) |
| break; |
| line = line.trim(); |
| if (!line.startsWith("#") && !"".equals(line)) { |
| break; |
| } |
| } |
| } finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException e) { |
| // Ignore |
| } |
| } |
| } |
| if (line != null) { |
| Class<? extends FrameworkFactory> factoryImplClass = |
| (Class<? extends FrameworkFactory>)Class.forName(line, false, classLoader); |
| factory = factoryImplClass.newInstance(); |
| if (factory != null && factory.getClass().getName().startsWith("org.eclipse.osgi.")) { |
| isEquinox = true; |
| } |
| |
| } |
| } catch (Throwable e) { |
| logger.log(Level.SEVERE, e.getMessage(), e); |
| } |
| } |
| return factory; |
| } |
| |
| public Framework newFramework(Map properties) { |
| FrameworkFactory factory = loadFrameworkFactory(); |
| if (factory == null) { |
| return null; |
| } |
| String propertyFile = null; |
| String factoryName = factory.getClass().getName(); |
| if (factoryName.startsWith("org.eclipse.osgi.")) { |
| propertyFile = "equinox.properties"; |
| } else if (factoryName.startsWith("org.apache.felix.")) { |
| propertyFile = "felix.properties"; |
| } |
| Map propMap = new HashMap(); |
| if (propertyFile != null) { |
| InputStream is = getClass().getResourceAsStream(propertyFile); |
| if (is != null) { |
| Properties props = new Properties(); |
| try { |
| props.load(is); |
| } catch (IOException e) { |
| logger.log(Level.WARNING, e.getMessage(), e); |
| } |
| propMap.putAll(props); |
| } |
| } |
| propMap.putAll(properties); |
| return factory.newFramework(propMap); |
| } |
| |
| public boolean isEquinox() { |
| return isEquinox; |
| } |
| |
| public void start(BundleContext context) throws Exception { |
| EquinoxHost.injectedBundleContext = context; |
| if (context.getClass().getName().startsWith("org.eclipse.osgi.")) { |
| isEquinox = true; |
| try { |
| context.registerService(CommandProvider.class.getName(), new NodeLauncherCommand(), new Hashtable()); |
| } catch (NoClassDefFoundError e) { |
| // Ignore it |
| } |
| } |
| } |
| |
| public void stop(BundleContext context) throws Exception { |
| EquinoxHost.injectedBundleContext = null; |
| } |
| |
| private static final String DELIM_START = "${"; |
| private static final String DELIM_STOP = "}"; |
| |
| /** |
| * <p> |
| * This method performs property variable substitution on the |
| * specified value. If the specified value contains the syntax |
| * <tt>${<prop-name>}</tt>, where <tt><prop-name></tt> |
| * refers to either a configuration property or a system property, |
| * then the corresponding property value is substituted for the variable |
| * placeholder. Multiple variable placeholders may exist in the |
| * specified value as well as nested variable placeholders, which |
| * are substituted from inner most to outer most. Configuration |
| * properties override system properties. |
| * </p> |
| * @param val The string on which to perform property substitution. |
| * @param currentKey The key of the property being evaluated used to |
| * detect cycles. |
| * @param cycleMap Map of variable references used to detect nested cycles. |
| * @param configProps Set of configuration properties. |
| * @return The value of the specified string after system property substitution. |
| * @throws IllegalArgumentException If there was a syntax error in the |
| * property placeholder syntax or a recursive variable reference. |
| **/ |
| public static String substVars(String val, String currentKey, Map cycleMap, Properties configProps) |
| throws IllegalArgumentException { |
| // If there is currently no cycle map, then create |
| // one for detecting cycles for this invocation. |
| if (cycleMap == null) { |
| cycleMap = new HashMap(); |
| } |
| |
| // Put the current key in the cycle map. |
| cycleMap.put(currentKey, currentKey); |
| |
| // Assume we have a value that is something like: |
| // "leading ${foo.${bar}} middle ${baz} trailing" |
| |
| // Find the first ending '}' variable delimiter, which |
| // will correspond to the first deepest nested variable |
| // placeholder. |
| int stopDelim = val.indexOf(DELIM_STOP); |
| |
| // Find the matching starting "${" variable delimiter |
| // by looping until we find a start delimiter that is |
| // greater than the stop delimiter we have found. |
| int startDelim = val.indexOf(DELIM_START); |
| while (stopDelim >= 0) { |
| int idx = val.indexOf(DELIM_START, startDelim + DELIM_START.length()); |
| if ((idx < 0) || (idx > stopDelim)) { |
| break; |
| } else if (idx < stopDelim) { |
| startDelim = idx; |
| } |
| } |
| |
| // If we do not have a start or stop delimiter, then just |
| // return the existing value. |
| if ((startDelim < 0) && (stopDelim < 0)) { |
| return val; |
| } |
| // At this point, we found a stop delimiter without a start, |
| // so throw an exception. |
| else if (((startDelim < 0) || (startDelim > stopDelim)) && (stopDelim >= 0)) { |
| throw new IllegalArgumentException("stop delimiter with no start delimiter: " + val); |
| } |
| |
| // At this point, we have found a variable placeholder so |
| // we must perform a variable substitution on it. |
| // Using the start and stop delimiter indices, extract |
| // the first, deepest nested variable placeholder. |
| String variable = val.substring(startDelim + DELIM_START.length(), stopDelim); |
| |
| // Verify that this is not a recursive variable reference. |
| if (cycleMap.get(variable) != null) { |
| throw new IllegalArgumentException("recursive variable reference: " + variable); |
| } |
| |
| // Get the value of the deepest nested variable placeholder. |
| // Try to configuration properties first. |
| String substValue = (configProps != null) ? configProps.getProperty(variable, null) : null; |
| if (substValue == null) { |
| // Ignore unknown property values. |
| substValue = System.getProperty(variable, ""); |
| } |
| |
| // Remove the found variable from the cycle map, since |
| // it may appear more than once in the value and we don't |
| // want such situations to appear as a recursive reference. |
| cycleMap.remove(variable); |
| |
| // Append the leading characters, the substituted value of |
| // the variable, and the trailing characters to get the new |
| // value. |
| val = val.substring(0, startDelim) + substValue + val.substring(stopDelim + DELIM_STOP.length(), val.length()); |
| |
| // Now perform substitution again, since there could still |
| // be substitutions to make. |
| val = substVars(val, currentKey, cycleMap, configProps); |
| |
| // Return the value. |
| return val; |
| } |
| |
| } |