diff --git a/project/pom.xml b/project/pom.xml
index 787c34bb16..a5c95d51c7 100644
--- a/project/pom.xml
+++ b/project/pom.xml
@@ -565,6 +565,7 @@ pageTracker._trackPageview();
BundleActivator.start
+ * method started. There should be no active threads that were started by
+ * this bundle when this bundle returns. A stopped bundle must not call any
+ * Framework objects.
+ *
+ *
+ * This method must complete and return to its caller in a timely manner.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the
+ * bundle is still marked as stopped, and the Framework will remove
+ * the bundle's listeners, unregister all services registered by the
+ * bundle, and release all services used by the bundle.
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (functionLoader != null) {
+ functionLoader.stop();
+ functionLoader = null;
+ }
+ }
+}
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/BundleFunctionLoader.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/BundleFunctionLoader.java
new file mode 100644
index 0000000000..18e2da772e
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/BundleFunctionLoader.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds 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.jclouds.scriptbuilder.osgi;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.CharStreams;
+import com.google.common.io.Resources;
+import org.jclouds.scriptbuilder.FunctionLoader;
+import org.jclouds.scriptbuilder.FunctionNotFoundException;
+import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.scriptbuilder.domain.ShellToken;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * A {@link FunctionLoader} which searches for functions in the {@link Bundle} resources.
+ */
+public class BundleFunctionLoader implements FunctionLoader {
+
+ private final BundleContext bundleContext;
+ private ServiceRegistration registration;
+
+ /**
+ * Constructor
+ *
+ * @param bundleContext
+ */
+ public BundleFunctionLoader(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * Starts the loader.
+ * Looks up for {@link Bundle} resources and registers itself in the service registry.
+ * It adds a property to the service which advertise all the functions found in the local resources.
+ */
+ public void start() {
+ Bundle bundle = bundleContext.getBundle();
+ Enumeration entries = bundle.findEntries("/functions/", "*.*", false);
+ StringBuilder sb = new StringBuilder();
+ while (entries.hasMoreElements()) {
+ URL url = (URL) entries.nextElement();
+ String function = url.getFile();
+ sb.append(function);
+ if (entries.hasMoreElements()) {
+ sb.append(" ");
+ }
+ }
+ String functions = sb.toString();
+ registerFunction(functions);
+ }
+
+ /**
+ * Unregisters itself from the service registry.
+ */
+ public void stop() {
+ registration.unregister();
+ }
+
+
+ /**
+ * Loads the function from the {@link Bundle} resources.
+ * @param function The function name to load.
+ * @param family This operating system family of the function.
+ * @return
+ * @throws FunctionNotFoundException
+ */
+ @Override
+ public String loadFunction(String function, OsFamily family) throws FunctionNotFoundException {
+ try {
+ return CharStreams.toString(Resources.newReaderSupplier(bundleContext.getBundle().getResource(String.format("/functions/%s.%s", function, ShellToken.SH.to(family))), Charsets.UTF_8));
+ } catch (IOException e) {
+ throw new FunctionNotFoundException(function, family, e);
+ }
+ }
+
+ private void registerFunction(String functions) {
+ Properties properties = new Properties();
+ properties.put("function",functions);
+ registration = bundleContext.registerService(FunctionLoader.class.getName(), this,properties);
+ }
+
+}
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/ServiceFunctionLoader.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/ServiceFunctionLoader.java
new file mode 100644
index 0000000000..44ac9c725b
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/osgi/ServiceFunctionLoader.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds 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.jclouds.scriptbuilder.osgi;
+
+import com.google.common.base.Strings;
+import org.jclouds.scriptbuilder.FunctionLoader;
+import org.jclouds.scriptbuilder.FunctionNotFoundException;
+import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.scriptbuilder.domain.ShellToken;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A {@link FunctionLoader} implementation which delegates loading to the OSGi service registry.
+ */
+public class ServiceFunctionLoader implements FunctionLoader {
+
+ private final BundleContext bundleContext;
+
+ public ServiceFunctionLoader(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ /**
+ * Looks up the service registry for an applicable {@link FunctionLoader} and delegates to it.
+ * @param function The function name to load.
+ * @param family This operating system family of the function.
+ * @return The function as {@link String}
+ * @throws FunctionNotFoundException
+ */
+ @Override
+ public String loadFunction(String function, OsFamily family) throws FunctionNotFoundException {
+ ServiceReference[] references = null;
+ String filter = String.format("(function=*%s.%s*)", function, ShellToken.SH.to(family));
+ try {
+ references = bundleContext.getServiceReferences(FunctionLoader.class.getName(), filter);
+ for (ServiceReference reference : references) {
+ FunctionLoader loader = (FunctionLoader) bundleContext.getService(reference);
+ String f = loader.loadFunction(function, family);
+ if (!Strings.isNullOrEmpty(f)) {
+ return f;
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ throw new FunctionNotFoundException(function, family, e);
+ } finally {
+ if (references != null) {
+ for (ServiceReference reference : references) {
+ bundleContext.ungetService(reference);
+ }
+ }
+ }
+ throw new FunctionNotFoundException(function, family);
+ }
+
+}
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/util/Utils.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/util/Utils.java
index 4f11529088..cf76382cdf 100644
--- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/util/Utils.java
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/util/Utils.java
@@ -18,25 +18,22 @@
*/
package org.jclouds.scriptbuilder.util;
-import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.jclouds.scriptbuilder.BasicFunctionLoader;
+import org.jclouds.scriptbuilder.FunctionLoader;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
-import org.jclouds.util.ClassLoadingUtils;
import com.google.common.base.CaseFormat;
-import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
-import com.google.common.io.CharStreams;
-import com.google.common.io.Resources;
/**
* Utilities used to build init scripts.
@@ -47,6 +44,8 @@ public class Utils {
public static final LowerCamelToUpperUnderscore FUNCTION_LOWER_CAMEL_TO_UPPER_UNDERSCORE = new LowerCamelToUpperUnderscore();
+ public static FunctionLoader functionLoader = new BasicFunctionLoader();
+
public static final class LowerCamelToUpperUnderscore implements Function