cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dar...@apache.org
Subject [05/47] Spring Modularization
Date Wed, 23 Oct 2013 19:43:22 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/pom.xml
----------------------------------------------------------------------
diff --git a/framework/pom.xml b/framework/pom.xml
index 4ea2df1..14e3368 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -38,5 +38,7 @@
     <module>db</module>
     <module>config</module>
     <module>managed-context</module>
+    <module>spring/lifecycle</module>
+    <module>spring/module</module>
   </modules>
 </project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/pom.xml
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml
new file mode 100644
index 0000000..647101c
--- /dev/null
+++ b/framework/spring/lifecycle/pom.xml
@@ -0,0 +1,34 @@
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cloud-framework-spring-lifecycle</artifactId>
+    <name>Apache CloudStack Framework - Spring Life Cycle</name>
+    <parent>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-maven-standard</artifactId>
+        <version>4.3.0-SNAPSHOT</version>
+        <relativePath>../../../maven-standard/pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-framework-config</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractBeanCollector.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractBeanCollector.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractBeanCollector.java
new file mode 100644
index 0000000..a3c0d60
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractBeanCollector.java
@@ -0,0 +1,113 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * This class provides a method to do basically the same as @Inject of a type, but
+ * it will only find the types in the current context and not the parent.  This class 
+ * should only be used for very specific Spring bootstrap logic.  In general @Inject 
+ * is infinitely better.  Basically you need a very good reason to use this.
+ *
+ */
+public abstract class AbstractBeanCollector extends AbstractSmartLifeCycle implements BeanPostProcessor {
+
+    Class<?>[] typeClasses = new Class<?>[] {};
+    Map<Class<?>, Set<Object>> beans = new HashMap<Class<?>, Set<Object>>();
+    
+    @Override
+    public int getPhase() {
+        return 2000;
+    }
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+        for ( Class<?> typeClass : typeClasses ) {
+            if ( typeClass.isAssignableFrom(bean.getClass()) ) {
+                doPostProcessBeforeInitialization(bean, beanName);
+                break;
+            }
+        }
+        
+        return bean;
+    }
+    
+    protected void doPostProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+    }
+
+    protected void doPostProcessAfterInitialization(Object bean, Class<?> typeClass, String beanName) throws BeansException {
+        Set<Object> beansOfType = beans.get(typeClass);
+        
+        if ( beansOfType == null ) {
+            beansOfType = new HashSet<Object>();
+            beans.put(typeClass, beansOfType);
+        }
+        
+        beansOfType.add(bean);
+    }
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        for ( Class<?> typeClass : typeClasses ) {
+            if ( typeClass.isAssignableFrom(bean.getClass()) ) {
+                doPostProcessAfterInitialization(bean, typeClass, beanName);
+            }
+        }
+        
+        return bean;
+    }
+
+    protected <T> Set<T> getBeans(Class<T> typeClass) {
+        @SuppressWarnings("unchecked")
+        Set<T> result = (Set<T>) beans.get(typeClass);
+        
+        if ( result == null )
+            return Collections.emptySet();
+        
+        return result;
+    }
+    
+    public Class<?> getTypeClass() {
+        if ( typeClasses == null || typeClasses.length == 0 )
+            return null;
+        
+        return typeClasses[0];
+    }
+
+    public void setTypeClass(Class<?> typeClass) {
+        this.typeClasses = new Class<?>[] { typeClass };
+    }
+
+    public Class<?>[] getTypeClasses() {
+        return typeClasses;
+    }
+
+    public void setTypeClasses(Class<?>[] typeClasses) {
+        this.typeClasses = typeClasses;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractSmartLifeCycle.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractSmartLifeCycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractSmartLifeCycle.java
new file mode 100644
index 0000000..071817b
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/AbstractSmartLifeCycle.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+import org.springframework.context.SmartLifecycle;
+
+public abstract class AbstractSmartLifeCycle implements SmartLifecycle {
+
+    boolean running = false;
+    
+    @Override
+    public void start() {
+        running = true;
+    }
+
+    @Override
+    public void stop() {
+        running = false;
+    }
+
+    @Override
+    public boolean isRunning() {
+        return running;
+    }
+
+    @Override
+    public boolean isAutoStartup() {
+        return true;
+    }
+
+    @Override
+    public void stop(Runnable callback) {
+        stop();
+        callback.run();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java
new file mode 100644
index 0000000..1b7ea51
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java
@@ -0,0 +1,169 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.naming.ConfigurationException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.cloud.utils.component.ComponentLifecycle;
+import com.cloud.utils.component.SystemIntegrityChecker;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.mgmt.JmxUtil;
+import com.cloud.utils.mgmt.ManagementBean;
+
+public class CloudStackExtendedLifeCycle extends AbstractBeanCollector {
+
+    private static final Logger log = LoggerFactory.getLogger(CloudStackExtendedLifeCycle.class);
+    
+    Map<Integer, Set<ComponentLifecycle>> sorted = new TreeMap<Integer, Set<ComponentLifecycle>>();
+    
+    public CloudStackExtendedLifeCycle() {
+        super();
+        setTypeClasses(new Class<?>[] {
+            ComponentLifecycle.class,
+            SystemIntegrityChecker.class
+        });
+    }
+    
+    @Override
+    public void start() {
+        sortBeans();
+        checkIntegrity();
+        configure();
+        
+        super.start();
+    }
+
+    protected void checkIntegrity() {
+        for ( SystemIntegrityChecker checker : getBeans(SystemIntegrityChecker.class) ) {
+            log.info("Running system integrity checker {}", checker);
+            
+            checker.check();
+        }
+    }
+    
+    public void startBeans() {
+        log.info("Starting CloudStack Components");
+
+        with(new WithComponentLifeCycle() {
+            @Override
+            public void with(ComponentLifecycle lifecycle) {
+                lifecycle.start();
+                
+                if ( lifecycle instanceof ManagementBean ) {
+                    ManagementBean mbean = (ManagementBean)lifecycle;
+                    try {
+                        JmxUtil.registerMBean(mbean);
+                    } catch (MalformedObjectNameException e) {
+                        log.warn("Unable to register MBean: " + mbean.getName(), e);
+                    } catch (InstanceAlreadyExistsException e) {
+                        log.warn("Unable to register MBean: " + mbean.getName(), e);
+                    } catch (MBeanRegistrationException e) {
+                        log.warn("Unable to register MBean: " + mbean.getName(), e);
+                    } catch (NotCompliantMBeanException e) {
+                        log.warn("Unable to register MBean: " + mbean.getName(), e);
+                    }
+                    log.info("Registered MBean: " + mbean.getName());
+                }
+            }
+        });
+
+        log.info("Done Starting CloudStack Components");
+    }
+    
+    public void stopBeans() {
+        with(new WithComponentLifeCycle() {
+            @Override
+            public void with(ComponentLifecycle lifecycle) {
+                lifecycle.stop();
+            }
+        });
+    }
+
+    private void configure() {
+        log.info("Configuring CloudStack Components");
+        
+        with(new WithComponentLifeCycle() {
+            @Override
+            public void with(ComponentLifecycle lifecycle) {
+                try {
+                    lifecycle.configure(lifecycle.getName(), lifecycle.getConfigParams());
+                } catch (ConfigurationException e) {
+                    log.error("Failed to configure {}", lifecycle.getName(), e);
+                    throw new CloudRuntimeException(e);
+                }
+            }
+        });
+        
+        log.info("Done Configuring CloudStack Components");
+    }
+
+    private void sortBeans() {
+        for ( ComponentLifecycle lifecycle : getBeans(ComponentLifecycle.class) ) {
+            Set<ComponentLifecycle> set = sorted.get(lifecycle.getRunLevel());
+            
+            if ( set == null ) {
+                set = new HashSet<ComponentLifecycle>();
+                sorted.put(lifecycle.getRunLevel(), set);
+            }
+            
+            set.add(lifecycle);
+        }
+    }
+
+    @Override
+    public void stop() {
+        with(new WithComponentLifeCycle() {
+            @Override
+            public void with(ComponentLifecycle lifecycle) {
+                lifecycle.stop();
+            }
+        });
+        
+        super.stop();
+    }
+
+    protected void with(WithComponentLifeCycle with) {
+        for ( Set<ComponentLifecycle> lifecycles : sorted.values() ) {
+            for ( ComponentLifecycle lifecycle : lifecycles ) {
+                with.with(lifecycle);
+            }
+        }
+    }
+    
+    @Override
+    public int getPhase() {
+        return 2000;
+    }
+
+    private static interface WithComponentLifeCycle {
+       public void with(ComponentLifecycle lifecycle);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycleStart.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycleStart.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycleStart.java
new file mode 100644
index 0000000..33d4aea
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycleStart.java
@@ -0,0 +1,49 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+public class CloudStackExtendedLifeCycleStart extends AbstractSmartLifeCycle implements Runnable {
+
+    CloudStackExtendedLifeCycle lifeCycle;
+    
+    @Override
+    public void stop() {
+        lifeCycle.stopBeans();
+        super.stop();
+    }
+
+    @Override
+    public int getPhase() {
+        return 3000;
+    }
+
+    public CloudStackExtendedLifeCycle getLifeCycle() {
+        return lifeCycle;
+    }
+
+    public void setLifeCycle(CloudStackExtendedLifeCycle lifeCycle) {
+        this.lifeCycle = lifeCycle;
+    }
+
+    @Override
+    public void run() {
+        lifeCycle.startBeans();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackLog4jSetup.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackLog4jSetup.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackLog4jSetup.java
new file mode 100644
index 0000000..163703d
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackLog4jSetup.java
@@ -0,0 +1,56 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+import org.springframework.context.SmartLifecycle;
+
+import com.cloud.utils.LogUtils;
+
+public class CloudStackLog4jSetup implements SmartLifecycle {
+
+    @Override
+    public void start() {
+        LogUtils.initLog4j("log4j-cloud.xml");
+    }
+
+    @Override
+    public void stop() {
+    }
+
+    @Override
+    public boolean isRunning() {
+        return false;
+    }
+
+    @Override
+    public int getPhase() {
+        return 0;
+    }
+
+    @Override
+    public boolean isAutoStartup() {
+        return true;
+    }
+
+    @Override
+    public void stop(Runnable callback) {
+        callback.run();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/ConfigDepotLifeCycle.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/ConfigDepotLifeCycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/ConfigDepotLifeCycle.java
new file mode 100644
index 0000000..b380028
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/ConfigDepotLifeCycle.java
@@ -0,0 +1,47 @@
+/*
+ * 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.cloudstack.spring.lifecycle;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.framework.config.ConfigDepotAdmin;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+public class ConfigDepotLifeCycle implements BeanPostProcessor {
+
+    @Inject
+    ConfigDepotAdmin configDepotAdmin;
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+        if ( bean instanceof Configurable ) {
+            configDepotAdmin.populateConfiguration((Configurable)bean);
+        }
+        
+        return bean;
+    }
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        return bean;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/DumpRegistry.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/DumpRegistry.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/DumpRegistry.java
new file mode 100644
index 0000000..5614a32
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/DumpRegistry.java
@@ -0,0 +1,77 @@
+/*
+ * 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.cloudstack.spring.lifecycle.registry;
+
+import java.util.List;
+
+import com.cloud.utils.component.ComponentLifecycleBase;
+import com.cloud.utils.component.Named;
+import com.cloud.utils.component.Registry;
+
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DumpRegistry extends ComponentLifecycleBase {
+
+    private static final Logger log = LoggerFactory.getLogger(DumpRegistry.class);
+    
+    List<Registry<?>> registries;
+
+    public List<Registry<?>> getRegistries() {
+        return registries;
+    }
+    
+    @Inject
+    public void setRegistries(List<Registry<?>> registries) {
+        this.registries = registries;
+    }
+
+    @Override
+    public boolean start() {
+        for ( Registry<?> registry : registries ) {
+            StringBuilder buffer = new StringBuilder();
+            
+            for ( Object o : registry.getRegistered() ) {
+                if ( buffer.length() > 0 )
+                    buffer.append(", ");
+                
+                buffer.append(getName(o));
+            }
+            
+            log.info("Registry [{}] contains [{}]", registry.getName(), buffer);
+        }
+        
+        return super.start();
+    }
+    
+    protected String getName(Object o) {
+        String name = null;
+        if (o instanceof Named) {
+            name = ((Named) o).getName();
+        }
+
+        if (name == null) {
+            name = o.getClass().getSimpleName();
+        }
+
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/ExtensionRegistry.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/ExtensionRegistry.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/ExtensionRegistry.java
new file mode 100644
index 0000000..2bd362e
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/ExtensionRegistry.java
@@ -0,0 +1,245 @@
+/*
+ * 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.cloudstack.spring.lifecycle.registry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanNameAware;
+
+import com.cloud.utils.component.Named;
+import com.cloud.utils.component.Registry;
+
+public class ExtensionRegistry implements Registry<Object>, Configurable, BeanNameAware {
+
+    private static final Logger log = LoggerFactory.getLogger(ExtensionRegistry.class);
+    
+    String name;
+    String beanName;
+    
+    String orderConfigKey;
+    String orderConfigDefault;
+    ConfigKey<String> orderConfigKeyObj;
+    
+    String excludeKey;
+    String excludeDefault;
+    ConfigKey<String> excludeKeyObj;
+    
+    String configComponentName;
+    List<Object> preRegistered;
+    List<Object> registered = new CopyOnWriteArrayList<Object>();
+    List<Object> readOnly = Collections.unmodifiableList(registered);
+    
+    @Override
+    public boolean register(Object item) {
+        if ( registered.contains(item) )
+            return false;
+        
+        String[] order = new String[] {};
+        Set<String> exclude = new HashSet<String>();
+        
+        if ( orderConfigKeyObj != null ) {
+            Object value = orderConfigKeyObj.value();
+            if ( value != null && value.toString().trim().length() > 0 ) {
+                order = value.toString().trim().split("\\s*,\\s*");
+            }
+        }
+        
+        if ( excludeKeyObj != null ) {
+            Object value = excludeKeyObj.value();
+            if ( value != null && value.toString().trim().length() > 0 ) {
+                for ( String e : value.toString().trim().split("\\s*,\\s*") ) {
+                    exclude.add(e);
+                }
+            }
+        }
+        
+        String name = getName(item);
+        
+        if ( name != null && exclude.size() > 0 && exclude.contains(name) ) {
+            return false;
+        }
+        
+        if ( name == null && order.length > 0 ) {
+            throw new RuntimeException("getName() is null for [" + item + "]");
+        }
+        
+        int i = 0;
+        for ( String orderTest : order ) {
+            if ( orderTest.equals(name) ) {
+                registered.add(i, item);
+                i = -1;
+                break;
+            }
+            
+            if ( registered.size() <= i ) {
+                break;
+            }
+            
+            if ( getName(registered.get(i)).equals(orderTest) ) {
+                i++;
+            }
+        }
+        
+        if ( i != -1 ) {
+            registered.add(item);
+        }
+
+        log.debug("Registering extension [{}] in [{}]", name, this.name);
+        
+        return true;
+    }
+    
+    protected String getName(Object object) {
+        if ( object instanceof Named ) {
+            String name = ((Named)object).getName();
+            if ( name != null )
+                return name;
+        }
+        
+        return object == null ? null : object.getClass().getSimpleName();
+    }
+
+    @Override
+    public void unregister(Object type) {
+        registered.remove(type);
+    }
+
+    @Override
+    public List<Object> getRegistered() {
+        return readOnly;
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return configComponentName == null ? this.getClass().getSimpleName() : configComponentName;
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        List<ConfigKey<String>> result = new ArrayList<ConfigKey<String>>();
+        
+        if ( orderConfigKey != null && orderConfigKeyObj == null ) {
+            orderConfigKeyObj = new ConfigKey<String>("Advanced", String.class, orderConfigKey, orderConfigDefault, 
+                    "The order of precedence for the extensions", false);
+        }
+
+        if ( orderConfigKeyObj != null )
+            result.add(orderConfigKeyObj);
+        
+        if ( excludeKey != null && excludeKeyObj == null ) {
+            excludeKeyObj = new ConfigKey<String>("Advanced", String.class, excludeKey, excludeDefault, 
+                    "Extensions to exclude from being registered", false);
+        }
+        
+        if ( excludeKeyObj != null ) {
+            result.add(excludeKeyObj);
+        }
+        
+        return result.toArray(new ConfigKey[result.size()]);
+    }
+
+    @PostConstruct
+    public void init() {
+        if ( name == null ) {
+            for ( String part : beanName.replaceAll("([A-Z])", " $1").split("\\s+") ) {
+                part = StringUtils.capitalize(part.toLowerCase());;
+                
+                name = name == null ? part : name + " " + part;
+            }
+        }
+        
+        if ( preRegistered != null ) {
+            for ( Object o : preRegistered ) {
+                register(o);
+            }
+        }
+    }
+
+
+    public String getOrderConfigKey() {
+        return orderConfigKey;
+    }
+
+    public void setOrderConfigKey(String orderConfigKey) {
+        this.orderConfigKey = orderConfigKey;
+    }
+
+    public void setConfigComponentName(String configComponentName) {
+        this.configComponentName = configComponentName;
+    }
+
+    public String getOrderConfigDefault() {
+        return orderConfigDefault;
+    }
+
+    public void setOrderConfigDefault(String orderConfigDefault) {
+        this.orderConfigDefault = orderConfigDefault;
+    }
+
+    public String getExcludeKey() {
+        return excludeKey;
+    }
+
+    public void setExcludeKey(String excludeKey) {
+        this.excludeKey = excludeKey;
+    }
+
+    public String getExcludeDefault() {
+        return excludeDefault;
+    }
+
+    public void setExcludeDefault(String excludeDefault) {
+        this.excludeDefault = excludeDefault;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void setBeanName(String name) {
+        this.beanName = name;
+    }
+
+    public List<Object> getPreRegistered() {
+        return preRegistered;
+    }
+
+    public void setPreRegistered(List<Object> preRegistered) {
+        this.preRegistered = preRegistered;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/PluggableServiceLifecycle.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/PluggableServiceLifecycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/PluggableServiceLifecycle.java
new file mode 100644
index 0000000..3eeeed8
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/PluggableServiceLifecycle.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cloudstack.spring.lifecycle.registry;
+
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.utils.component.PluggableService;
+
+public class PluggableServiceLifecycle extends RegistryLifecycle {
+
+    @Override
+    public void start() {
+        super.start();
+
+        for (Object obj : beans) {
+            if (obj instanceof PluggableService) {
+                for (Class<?> cmd : ((PluggableService) obj).getCommands()) {
+                    ComponentContext.addDelegateContext(cmd, applicationContext);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void stop() {
+        for (Object obj : beans) {
+            if (obj instanceof PluggableService) {
+                for (Class<?> cmd : ((PluggableService) obj).getCommands()) {
+                    ComponentContext.removeDelegateContext(cmd);
+                }
+            }
+        }
+
+        super.stop();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/RegistryLifecycle.java
----------------------------------------------------------------------
diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/RegistryLifecycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/RegistryLifecycle.java
new file mode 100644
index 0000000..bd7a033
--- /dev/null
+++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/registry/RegistryLifecycle.java
@@ -0,0 +1,144 @@
+/*
+ * 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.cloudstack.spring.lifecycle.registry;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.SmartLifecycle;
+
+import com.cloud.utils.component.Registry;
+
+public class RegistryLifecycle implements BeanPostProcessor, SmartLifecycle, ApplicationContextAware {
+
+    private static final Logger log = LoggerFactory.getLogger(RegistryLifecycle.class);
+    
+    Registry<Object> registry;
+    
+    /* The bean name works around circular dependency issues in Spring.  This shouldn't be
+     * needed if your beans are already nicely organized.  If they look like spaghetti, then you
+     * can use this.
+     */
+    String registryBeanName;
+    Set<Object> beans = new HashSet<Object>();
+    Class<?> typeClass;
+    ApplicationContext applicationContext;
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+        if ( typeClass.isAssignableFrom(bean.getClass()) )
+            beans.add(bean);
+        
+        return bean;
+    }
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        return bean;
+    }
+
+    @Override
+    public void start() {
+        Iterator<Object> iter = beans.iterator();
+        Registry<Object> registry = lookupRegistry();
+        
+        while ( iter.hasNext() ) {
+            Object next = iter.next();
+            if ( registry.register(next) ) {
+                log.debug("Registered {}", next);
+            } else {
+                iter.remove();
+            }
+        }
+    }
+
+    @Override
+    public void stop() {
+        Registry<Object> registry = lookupRegistry();
+        
+        for ( Object bean : beans ) {
+            registry.unregister(bean);
+        }
+        
+        beans.clear();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return false;
+    }
+
+    @Override
+    public int getPhase() {
+        return 2000;
+    }
+
+    @Override
+    public boolean isAutoStartup() {
+        return true;
+    }
+
+    @Override
+    public void stop(Runnable callback) {
+        stop();
+        callback.run();
+    }
+    
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected Registry<Object> lookupRegistry() {
+        return registry == null ? applicationContext.getBean(registryBeanName, Registry.class) : registry;
+    }
+
+    public Registry<Object> getRegistry() {
+        return registry;
+    }
+
+    public void setRegistry(Registry<Object> registry) {
+        this.registry = registry;
+    }
+
+    public Class<?> getTypeClass() {
+        return typeClass;
+    }
+
+    public void setTypeClass(Class<?> typeClass) {
+        this.typeClass = typeClass;
+    }
+
+    public String getRegistryBeanName() {
+        return registryBeanName;
+    }
+
+    public void setRegistryBeanName(String registryBeanName) {
+        this.registryBeanName = registryBeanName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/pom.xml
----------------------------------------------------------------------
diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml
new file mode 100644
index 0000000..b9d95a8
--- /dev/null
+++ b/framework/spring/module/pom.xml
@@ -0,0 +1,50 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cloud-framework-spring-module</artifactId>
+    <parent>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-maven-standard</artifactId>
+        <version>4.3.0-SNAPSHOT</version>
+        <relativePath>../../../maven-standard/pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/context/ResourceApplicationContext.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/context/ResourceApplicationContext.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/context/ResourceApplicationContext.java
new file mode 100644
index 0000000..60d0262
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/context/ResourceApplicationContext.java
@@ -0,0 +1,55 @@
+/*
+ * 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.cloudstack.spring.module.context;
+
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.core.io.Resource;
+
+public class ResourceApplicationContext extends AbstractXmlApplicationContext {
+
+    Resource[] configResources;
+    String applicationName = "";
+
+    public ResourceApplicationContext() {
+    }
+
+    public ResourceApplicationContext(Resource... configResources) {
+        super();
+        this.configResources = configResources;
+    }
+
+    @Override
+    protected Resource[] getConfigResources() {
+        return configResources;
+    }
+
+    public void setConfigResources(Resource[] configResources) {
+        this.configResources = configResources;
+    }
+
+    @Override
+    public String getApplicationName() {
+        return applicationName;
+    }
+
+    public void setApplicationName(String applicationName) {
+        this.applicationName = applicationName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/CloudStackSpringContext.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/CloudStackSpringContext.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/CloudStackSpringContext.java
new file mode 100644
index 0000000..e624a5b
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/CloudStackSpringContext.java
@@ -0,0 +1,137 @@
+/*
+ * 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.cloudstack.spring.module.factory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.cloudstack.spring.module.locator.ModuleDefinitionLocator;
+import org.apache.cloudstack.spring.module.locator.impl.ClasspathModuleDefinitionLocator;
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+import org.apache.cloudstack.spring.module.model.ModuleDefinitionSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.io.Resource;
+
+public class CloudStackSpringContext {
+
+    private static final Logger log = LoggerFactory.getLogger(CloudStackSpringContext.class);
+    
+    public static final String CLOUDSTACK_CONTEXT = "META-INF/cloudstack";
+    public static final String CLOUDSTACK_BASE = "bootstrap";
+    
+    ModuleBasedContextFactory factory = new ModuleBasedContextFactory();
+    ModuleDefinitionLocator loader = new ClasspathModuleDefinitionLocator();
+    ModuleDefinitionSet moduleDefinitionSet;
+    String baseName;
+    String contextName;
+    
+    public CloudStackSpringContext(String context, String base) throws IOException {
+        this.baseName = base;
+        this.contextName = context;
+        
+        factory = new ModuleBasedContextFactory();
+        loader = new ClasspathModuleDefinitionLocator();
+        init();
+    }
+    
+    public CloudStackSpringContext() throws IOException {
+        this(CLOUDSTACK_CONTEXT, CLOUDSTACK_BASE);
+    }
+    
+    public void init() throws IOException {
+        Collection<ModuleDefinition> defs = loader.locateModules(contextName);
+        
+        if ( defs.size() == 0 )
+            throw new RuntimeException("No modules found to load for Spring");
+        
+        moduleDefinitionSet = factory.loadModules(defs, baseName);
+    }
+    
+    public void registerShutdownHook() {
+        ApplicationContext base = moduleDefinitionSet.getApplicationContext(baseName);
+        
+        if ( base instanceof ConfigurableApplicationContext ) {
+            ((ConfigurableApplicationContext)base).registerShutdownHook();
+        }
+    }
+    
+    public ModuleDefinition getModuleDefinitionForWeb(String name) {
+        ModuleDefinition def = moduleDefinitionSet.getModuleDefinition(name);
+        
+        if ( def != null ) {
+            return def;
+        }
+        
+        /* Grab farthest descendant that is deterministic */
+        def = moduleDefinitionSet.getModuleDefinition(baseName);
+        
+        if ( def == null ) {
+            throw new RuntimeException("Failed to find base spring module to extend for web");
+        }
+        
+        while ( def.getChildren().size() == 1 ) {
+            def = def.getChildren().iterator().next();
+        }
+        
+        return def;
+    }
+    
+    public ApplicationContext getApplicationContextForWeb(String name) {
+        ModuleDefinition def = getModuleDefinitionForWeb(name);
+        
+        return moduleDefinitionSet.getApplicationContext(def.getName());
+    }
+    
+    public String[] getConfigLocationsForWeb(String name, String[] configured) {
+        if ( configured == null )
+            configured = new String[] {};
+        
+        ModuleDefinition def = getModuleDefinitionForWeb(name);
+        
+        List<Resource> inherited = new ArrayList<Resource>();
+        
+        while ( def != null ) {
+            inherited.addAll(def.getInheritableContextLocations());
+            def = moduleDefinitionSet.getModuleDefinition(def.getParentName());
+        }
+
+        List<String> urlList = new ArrayList<String>();
+        
+        for ( Resource r : inherited ) {
+            try {
+                String urlString = r.getURL().toExternalForm();
+                urlList.add(urlString);
+            } catch (IOException e) {
+                log.error("Failed to create URL for {}", r.getDescription(), e);
+            }
+        }
+        
+        String[] result = new String[urlList.size() + configured.length];
+        result = urlList.toArray(result);
+        
+        System.arraycopy(configured, 0, result, urlList.size(), configured.length);
+        
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/ModuleBasedContextFactory.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/ModuleBasedContextFactory.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/ModuleBasedContextFactory.java
new file mode 100644
index 0000000..3f89d3a
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/factory/ModuleBasedContextFactory.java
@@ -0,0 +1,84 @@
+/*
+ * 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.cloudstack.spring.module.factory;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+import org.apache.cloudstack.spring.module.model.ModuleDefinitionSet;
+import org.apache.cloudstack.spring.module.model.impl.DefaultModuleDefinitionSet;
+
+public class ModuleBasedContextFactory {
+
+    public ModuleDefinitionSet loadModules(Collection<ModuleDefinition> defs, String root) throws IOException {
+        
+        Map<String, ModuleDefinition> modules = wireUpModules(root, defs);
+        
+        DefaultModuleDefinitionSet moduleSet = new DefaultModuleDefinitionSet(modules, root);
+        moduleSet.load();
+        
+        return moduleSet;
+    }
+    
+    protected Map<String, ModuleDefinition> wireUpModules(String root, Collection<ModuleDefinition> defs) throws IOException {
+        Map<String, ModuleDefinition> modules = new HashMap<String, ModuleDefinition>();
+        
+        for ( ModuleDefinition def : defs ) {
+            modules.put(def.getName(), def);
+        }
+        
+        ModuleDefinition rootDef = null;
+        Map<String, ModuleDefinition> result = new HashMap<String, ModuleDefinition>();
+        
+        for ( ModuleDefinition def : modules.values() ) {
+            if ( def.getName().equals(root) ) {
+                rootDef = def;
+            }
+            
+            if ( def.getParentName() != null ) {
+                ModuleDefinition parentDef = modules.get(def.getParentName());
+                
+                if ( parentDef != null )
+                    parentDef.addChild(def);
+            }
+        }
+        
+        return traverse(rootDef, result);
+    }
+    
+    protected Map<String, ModuleDefinition> traverse(ModuleDefinition base, Map<String, ModuleDefinition> result) {
+        if ( base == null )
+            return result;
+        
+        if ( result.containsKey(base.getName()) ) {
+            throw new RuntimeException("Circular dependency to [" + base.getName() + "] from current set " +
+                    result.keySet());
+        }
+        
+        result.put(base.getName(), base);
+        
+        for ( ModuleDefinition childDef : base.getChildren() )
+            traverse(childDef, result);
+        
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/ModuleDefinitionLocator.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/ModuleDefinitionLocator.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/ModuleDefinitionLocator.java
new file mode 100644
index 0000000..6b14e0a
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/ModuleDefinitionLocator.java
@@ -0,0 +1,36 @@
+/*
+ * 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.cloudstack.spring.module.locator;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+
+/**
+ * Responsible for locating the ModuleDefinition for a given context.  The implementation
+ * of this class should take extra care to set the ClassLoader of the ModuleDefinition
+ * properly.
+ *
+ */
+public interface ModuleDefinitionLocator {
+
+    Collection<ModuleDefinition> locateModules(String context) throws IOException;
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/impl/ClasspathModuleDefinitionLocator.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/impl/ClasspathModuleDefinitionLocator.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/impl/ClasspathModuleDefinitionLocator.java
new file mode 100644
index 0000000..c9deacc
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/locator/impl/ClasspathModuleDefinitionLocator.java
@@ -0,0 +1,62 @@
+/*
+ * 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.cloudstack.spring.module.locator.impl;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cloudstack.spring.module.locator.ModuleDefinitionLocator;
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+import org.apache.cloudstack.spring.module.model.impl.DefaultModuleDefinition;
+import org.apache.cloudstack.spring.module.util.ModuleLocationUtils;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+public class ClasspathModuleDefinitionLocator implements ModuleDefinitionLocator {
+    
+    protected ResourcePatternResolver getResolver() {
+        return new PathMatchingResourcePatternResolver();
+    }
+    
+    public Collection<ModuleDefinition> locateModules(String context) throws IOException {
+        ResourcePatternResolver resolver = getResolver();
+        
+        Map<String, ModuleDefinition> allModules = discoverModules(context, resolver);
+        
+        return allModules.values();
+    }
+    
+    protected Map<String, ModuleDefinition> discoverModules(String baseDir, ResourcePatternResolver resolver) throws IOException {
+        Map<String, ModuleDefinition> result = new HashMap<String, ModuleDefinition>();
+        
+        for ( Resource r : resolver.getResources(ModuleLocationUtils.getModulesLocation(baseDir)) ) {
+            DefaultModuleDefinition def = new DefaultModuleDefinition(baseDir, r, resolver);
+            def.init();
+            
+            if ( def.isValid() )
+                result.put(def.getName(), def);
+        }
+        
+        return result;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinition.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinition.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinition.java
new file mode 100644
index 0000000..b3c4647
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinition.java
@@ -0,0 +1,48 @@
+/*
+ * 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.cloudstack.spring.module.model;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.core.io.Resource;
+
+public interface ModuleDefinition {
+    
+    ClassLoader getClassLoader();
+    
+    String getName();
+    
+    String getParentName();
+    
+    List<Resource> getConfigLocations();
+    
+    List<Resource> getContextLocations();
+    
+    List<Resource> getInheritableContextLocations();
+    
+    List<Resource> getOverrideContextLocations();
+    
+    boolean isValid();
+    
+    Collection<ModuleDefinition> getChildren();
+    
+    void addChild(ModuleDefinition childDef);
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinitionSet.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinitionSet.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinitionSet.java
new file mode 100644
index 0000000..635a7a1
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/ModuleDefinitionSet.java
@@ -0,0 +1,32 @@
+/*
+ * 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.cloudstack.spring.module.model;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+
+public interface ModuleDefinitionSet {
+
+    ModuleDefinition getModuleDefinition(String name);
+    
+    ApplicationContext getApplicationContext(String name);
+    
+    Resource[] getConfigResources(String name);
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinition.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinition.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinition.java
new file mode 100644
index 0000000..6c51808
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinition.java
@@ -0,0 +1,167 @@
+/*
+ * 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.cloudstack.spring.module.model.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+import org.apache.cloudstack.spring.module.util.ModuleLocationUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.util.StringUtils;
+
+public class DefaultModuleDefinition implements ModuleDefinition {
+
+    public static final String NAME = "name";
+    public static final String PARENT = "parent";
+        
+    String name;
+    String baseDir;
+    String parent;
+    Resource moduleProperties;
+    ResourcePatternResolver resolver;
+    boolean valid;
+    
+    List<Resource> configLocations;
+    List<Resource> contextLocations;
+    List<Resource> inheritableContextLocations;
+    List<Resource> overrideContextLocations;
+    Map<String, ModuleDefinition> children = new TreeMap<String, ModuleDefinition>();
+    
+    public DefaultModuleDefinition(String baseDir, Resource moduleProperties, ResourcePatternResolver resolver) {
+        this.baseDir = baseDir;
+        this.resolver = resolver;
+        this.moduleProperties = moduleProperties;
+    }
+    
+    public void init() throws IOException {
+        
+        if ( ! moduleProperties.exists() ) {
+            return;
+        }
+        
+        resolveNameAndParent();
+        
+        contextLocations = Arrays.asList(resolver.getResources(ModuleLocationUtils.getContextLocation(baseDir, name)));
+        configLocations = Arrays.asList(resolver.getResources(ModuleLocationUtils.getDefaultsLocation(baseDir, name)));
+        inheritableContextLocations = Arrays.asList(resolver.getResources(ModuleLocationUtils.getInheritableContextLocation(baseDir, name)));
+        overrideContextLocations = Arrays.asList(resolver.getResources(ModuleLocationUtils.getOverrideContextLocation(baseDir, name)));
+
+        valid = true;
+    }
+    
+    protected void resolveNameAndParent() throws IOException {
+        InputStream is = null;
+        
+        try {
+            is = moduleProperties.getInputStream();
+            Properties props = new Properties();
+            props.load(is);
+            
+            name = props.getProperty(NAME);
+            parent = props.getProperty(PARENT);
+            
+            if ( ! StringUtils.hasText(name) ) {
+                throw new IOException("Missing name property in [" + location() + "]");
+            }
+            
+            if ( ! StringUtils.hasText(parent) ) {
+                parent = null;
+            }
+            
+            checkNameMatchesSelf();
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+    }
+    
+    protected void checkNameMatchesSelf() throws IOException {
+        String expectedLocation = ModuleLocationUtils.getModuleLocation(baseDir, name);
+        Resource self = resolver.getResource(expectedLocation);
+        
+        if ( ! self.exists() ) {
+            throw new IOException("Resource [" + location() + "] is expected to exist at [" +
+                    expectedLocation + "] please ensure the name property is correct");
+        }
+        
+        String moduleUrl = moduleProperties.getURL().toExternalForm();
+        String selfUrl = self.getURL().toExternalForm();
+            
+        if ( ! moduleUrl.equals(selfUrl) ) {
+            throw new IOException("Resource [" + location() + "] and [" +
+                    self.getURL() + "] do not appear to be the same resource, " + 
+                    "please ensure the name property is correct");
+        }
+    }
+    
+    private String location() throws IOException {
+        return moduleProperties.getURL().toString();
+    }
+    
+    public void addChild(ModuleDefinition def) {
+        children.put(def.getName(), def);
+    }
+    
+    public Collection<ModuleDefinition> getChildren() {
+        return children.values();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getParentName() {
+        return parent;
+    }
+
+    public List<Resource> getConfigLocations() {
+        return configLocations;
+    }
+
+    public List<Resource> getContextLocations() {
+        return contextLocations;
+    }
+
+    public List<Resource> getInheritableContextLocations() {
+        return inheritableContextLocations;
+    }
+
+    @Override
+    public List<Resource> getOverrideContextLocations() {
+        return overrideContextLocations;
+    }
+
+    public boolean isValid() {
+        return valid;
+    }
+
+    public ClassLoader getClassLoader() {
+        return resolver.getClassLoader();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java
new file mode 100644
index 0000000..15df839
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java
@@ -0,0 +1,243 @@
+/*
+ * 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.cloudstack.spring.module.model.impl;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.apache.cloudstack.spring.module.context.ResourceApplicationContext;
+import org.apache.cloudstack.spring.module.model.ModuleDefinition;
+import org.apache.cloudstack.spring.module.model.ModuleDefinitionSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+
+public class DefaultModuleDefinitionSet implements ModuleDefinitionSet {
+
+    private static final Logger log = LoggerFactory.getLogger(DefaultModuleDefinitionSet.class);
+    
+    public static final String DEFAULT_CONFIG_RESOURCES = "DefaultConfigResources";
+    public static final String DEFAULT_CONFIG_XML = "defaults-context.xml";
+    
+    String root;
+    Map<String, ModuleDefinition> modules;
+    Map<String, ApplicationContext> contexts = new HashMap<String, ApplicationContext>();
+    ApplicationContext rootContext = null;
+
+    public DefaultModuleDefinitionSet(Map<String, ModuleDefinition> modules, String root) {
+        super();
+        this.root = root;
+        this.modules = modules;
+    }
+
+    public void load() throws IOException {
+        if ( ! loadRootContext() )
+            return;
+        
+        printHierarchy();
+        loadContexts();
+        startContexts();
+    }
+    
+    protected boolean loadRootContext() {
+        ModuleDefinition def = modules.get(root);
+        
+        if ( def == null )
+            return false;
+        
+        ApplicationContext defaultsContext = getDefaultsContext();
+        
+        rootContext = loadContext(def, defaultsContext);
+        
+        return true;
+    }
+    
+    protected void startContexts() {
+        withModule(new WithModule() {
+            public void with(ModuleDefinition def, Stack<ModuleDefinition> parents) {
+                try {
+                    ApplicationContext context = getApplicationContext(def.getName());
+                    try {
+                        Runnable runnable = context.getBean("moduleStartup", Runnable.class);
+                        log.info("Starting module [{}]", def.getName());
+                        runnable.run();
+                    } catch ( BeansException e ) {
+                       // Ignore 
+                    }
+                } catch ( EmptyStackException e ) {
+                    // The root context is already loaded, so ignore the exception
+                }
+            }
+        });
+    }
+    
+    protected void loadContexts() {
+        withModule(new WithModule() {
+            public void with(ModuleDefinition def, Stack<ModuleDefinition> parents) {
+                try {
+                    ApplicationContext parent = getApplicationContext(parents.peek().getName());
+                    loadContext(def, parent);
+                } catch ( EmptyStackException e ) {
+                    // The root context is already loaded, so ignore the exception
+                }
+            }
+        });
+    }
+    protected ApplicationContext loadContext(ModuleDefinition def, ApplicationContext parent) {
+        ResourceApplicationContext context = new ResourceApplicationContext();
+        context.setApplicationName("/" + def.getName());
+        
+        Resource[] resources = getConfigResources(def.getName());
+        context.setConfigResources(resources);
+        context.setParent(parent);
+        context.setClassLoader(def.getClassLoader());
+
+        long start = System.currentTimeMillis();
+        if ( log.isInfoEnabled() ) {
+            for ( Resource resource : resources ) {
+                log.info("Loading module context [{}] from {}", def.getName(), resource);
+            }
+        }
+        context.refresh();
+        log.info("Loaded module context [{}] in {} ms", def.getName(), (System.currentTimeMillis() - start));
+        
+        contexts.put(def.getName(), context);
+        
+        return context;
+    }
+    
+    protected boolean shouldLoad(ModuleDefinition def) {
+        return true;
+    }
+    
+    protected ApplicationContext getDefaultsContext() {
+        URL config = DefaultModuleDefinitionSet.class.getResource(DEFAULT_CONFIG_XML);
+        
+        ResourceApplicationContext context = new ResourceApplicationContext(new UrlResource(config));
+        context.setApplicationName("/defaults");
+        context.refresh();
+        
+        @SuppressWarnings("unchecked")
+        final List<Resource> resources = (List<Resource>) context.getBean(DEFAULT_CONFIG_RESOURCES);
+        
+        withModule(new WithModule() {
+            public void with(ModuleDefinition def, Stack<ModuleDefinition> parents) {
+                for ( Resource defaults : def.getConfigLocations() ) {
+                    resources.add(defaults);
+                }
+            }
+        });
+        
+        return context;
+    }
+    
+    protected void printHierarchy() {
+        withModule(new WithModule() {
+            public void with(ModuleDefinition def, Stack<ModuleDefinition> parents) {
+                log.info(String.format("Module Hierarchy:%" + ((parents.size() * 2) + 1) + "s%s", "", def.getName()));
+            }
+        });
+    }
+    
+    protected void withModule(WithModule with) {
+        ModuleDefinition rootDef = modules.get(root);
+        withModule(rootDef, new Stack<ModuleDefinition>(), with);
+    }
+    
+    protected void withModule(ModuleDefinition def, Stack<ModuleDefinition> parents, WithModule with) {
+        if ( def == null )
+            return;
+        
+        if ( ! shouldLoad(def) ) {
+            return;
+        }
+        
+        with.with(def, parents);
+        
+        parents.push(def);
+        
+        for ( ModuleDefinition child : def.getChildren() ) {
+            withModule(child, parents, with);
+        }
+        
+        parents.pop();
+    }
+    
+    private static interface WithModule {
+        public void with(ModuleDefinition def, Stack<ModuleDefinition> parents);
+    }
+    
+    @Configuration
+    public static class ConfigContext {
+        
+        List<Resource> resources;
+        
+        public ConfigContext(List<Resource> resources) {
+            super();
+            this.resources = resources;
+        }
+
+        @Bean(name = DEFAULT_CONFIG_RESOURCES)
+        public List<Resource> defaultConfigResources() {
+            return new ArrayList<Resource>();
+        }
+    }
+
+    public ApplicationContext getApplicationContext(String name) {
+        return contexts.get(name);
+    }
+
+    public Resource[] getConfigResources(String name) {
+        Set<Resource> resources = new LinkedHashSet<Resource>();
+        
+        ModuleDefinition original = null;
+        ModuleDefinition def = original = modules.get(name);
+        
+        if ( def == null )
+            return new Resource[] {};
+        
+        resources.addAll(def.getContextLocations());
+        
+        while ( def != null ) {
+            resources.addAll(def.getInheritableContextLocations());
+            def = modules.get(def.getParentName());
+        }
+        
+        resources.addAll(original.getOverrideContextLocations());
+        
+        return resources.toArray(new Resource[resources.size()]);
+    }
+
+    public ModuleDefinition getModuleDefinition(String name) {
+        return modules.get(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/Main.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/Main.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/Main.java
new file mode 100644
index 0000000..3a9660c
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/Main.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cloudstack.spring.module.util;
+
+import org.apache.cloudstack.spring.module.factory.CloudStackSpringContext;
+
+public class Main {
+
+    long start = System.currentTimeMillis();
+    
+    public Main() {
+        
+    }
+    
+    public void start() throws Exception {
+        CloudStackSpringContext context = new CloudStackSpringContext();
+        context.registerShutdownHook();
+        
+        if ( Boolean.getBoolean("force.exit") ) {
+            System.exit(0);
+        }
+    }
+    
+    public long getTime() {
+        return System.currentTimeMillis() - start;
+    }
+    
+    
+    public static void main(String... args) {
+        Main main = new Main();
+
+        try {
+            main.start();
+            System.out.println("STARTUP COMPLETE [" + main.getTime() + "] ms");
+        } catch ( Exception e ) {
+            e.printStackTrace();
+            System.out.println("STARTUP FAILED [" + main.getTime() + "] ms");
+            System.err.println("STARTUP FAILED [" + main.getTime() + "] ms");
+            System.exit(1);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/67186429/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/ModuleLocationUtils.java
----------------------------------------------------------------------
diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/ModuleLocationUtils.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/ModuleLocationUtils.java
new file mode 100644
index 0000000..eeab154
--- /dev/null
+++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/util/ModuleLocationUtils.java
@@ -0,0 +1,53 @@
+/*
+ * 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.cloudstack.spring.module.util;
+
+public class ModuleLocationUtils {
+
+    private static final String ALL_MODULE_PROPERTIES = "classpath*:%s/*/module.properties";
+    private static final String MODULE_PROPERTIES = "classpath:%s/%s/module.properties";
+    private static final String CONTEXT_LOCATION = "classpath*:%s/%s/*context.xml";
+    private static final String INHERTIABLE_CONTEXT_LOCATION = "classpath*:%s/%s/*context-inheritable.xml";
+    private static final String OVERRIDE_CONTEXT_LOCATION = "classpath*:%s/%s/*context-override.xml";
+    private static final String DEFAULTS_LOCATION = "classpath*:%s/%s/*defaults.properties";
+
+    public static String getModulesLocation(String baseDir) {
+        return String.format(ALL_MODULE_PROPERTIES, baseDir);
+    }
+    
+    public static String getModuleLocation(String baseDir, String name) {
+        return String.format(MODULE_PROPERTIES, baseDir, name);
+    }
+    
+    public static String getContextLocation(String baseDir, String name) {
+        return String.format(CONTEXT_LOCATION, baseDir, name);
+    }
+    
+    public static String getInheritableContextLocation(String baseDir, String name) {
+        return String.format(INHERTIABLE_CONTEXT_LOCATION, baseDir, name);
+    }
+    
+    public static String getOverrideContextLocation(String baseDir, String name) {
+        return String.format(OVERRIDE_CONTEXT_LOCATION, baseDir, name);
+    }
+    
+    public static String getDefaultsLocation(String baseDir, String name) {
+        return String.format(DEFAULTS_LOCATION, baseDir, name);
+    }
+}


Mime
View raw message