Author: simoneg
Date: Fri Nov 20 08:06:23 2009
New Revision: 882441

URL: http://svn.apache.org/viewvc?rev=882441&view=rev
Log:
LABS-365 : implementation for contextualized external configuration

Added:
    labs/magma/trunk/lateconfig-impl/pom.xml
    labs/magma/trunk/lateconfig-impl/src/
    labs/magma/trunk/lateconfig-impl/src/main/
    labs/magma/trunk/lateconfig-impl/src/main/java/
    labs/magma/trunk/lateconfig-impl/src/main/java/org/
    labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/
    labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/
    labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/
    
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurationHook.aj
    
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurator.java
    labs/magma/trunk/lateconfig-impl/src/main/resources/
    labs/magma/trunk/lateconfig-impl/src/test/
    labs/magma/trunk/lateconfig-impl/src/test/java/
    labs/magma/trunk/lateconfig-impl/src/test/java/org/
    labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/
    labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/
    labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/
    
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigBean.java
    
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigTest.java
    
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/OtherTriggerBean.java
    labs/magma/trunk/lateconfig-impl/src/test/resources/
    labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/
    
labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/lateconfig.properties

Added: labs/magma/trunk/lateconfig-impl/pom.xml
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/pom.xml?rev=882441&view=auto
==============================================================================
--- labs/magma/trunk/lateconfig-impl/pom.xml (added)
+++ labs/magma/trunk/lateconfig-impl/pom.xml Fri Nov 20 08:06:23 2009
@@ -0,0 +1,37 @@
+<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/maven-v4_0_0.xsd";>
+  <parent>
+    <artifactId>magma-parent</artifactId>
+    <groupId>org.apache.magma</groupId>
+    <version>3</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.magma</groupId>
+  <artifactId>lateconfig-impl</artifactId>
+  <packaging>magma</packaging>
+  <name>Magma Late Configuration Implementation</name>
+  <version>0.0.3-SNAPSHOT</version>
+  <description>        </description>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.magma</groupId>
+      <artifactId>lateconfig-api</artifactId>
+      <version>0.0.3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.magma</groupId>
+      <artifactId>foundation-beans</artifactId>
+      <version>0.0.3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.magma</groupId>
+      <artifactId>foundation-basics</artifactId>
+      <version>0.0.3-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+       <groupId>junit</groupId>
+       <artifactId>junit</artifactId>
+       <version>4.7</version>
+       <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Added: 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurationHook.aj
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurationHook.aj?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurationHook.aj
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurationHook.aj
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,49 @@
+package org.apache.magma.lateconfig;
+
+import java.util.List;
+
+import org.apache.magma.basics.MagmaException;
+import org.aspectj.lang.reflect.MethodSignature;
+
+
+public aspect LateConfigurationHook {
+
+       public interface LateConfigurationSupport { }
+       
+       declare parents: (@LateConfigurable *) implements 
LateConfigurationSupport;
+               
+       public pointcut methodConfigurationTrigger() : 
+               execution(@LateConfigurationTrigger public * 
LateConfigurationSupport+.*(..));
+       public pointcut constructorConfigurationTrigger() :
+               execution(@LateConfigurationTrigger 
LateConfigurationSupport+.new(..));
+       
+       public pointcut configurableMethod() : execution(@LateConfigurable 
public * LateConfigurationSupport+.*(..));
+               
+       private List<String> LateConfigurationSupport.configured = null;
+       private boolean LateConfigurationSupport.configuring = false;
+
+       after(LateConfigurationSupport bean) : 
constructorConfigurationTrigger() && this(bean) {
+               if (bean.configured != null || bean.configuring) return;
+               bean.configuring = true;
+               bean.configured = LateConfigurator.lateConfigure(bean);
+       }
+       
+       before(LateConfigurationSupport bean) : methodConfigurationTrigger() && 
this(bean) {
+               if (bean.configured != null || bean.configuring) return;
+               bean.configuring = true;
+               bean.configured = LateConfigurator.lateConfigure(bean);
+       }
+       
+       Object around(LateConfigurationSupport bean) : configurableMethod() && 
this(bean) {
+               if (bean.configured == null) return proceed(bean);
+               MethodSignature signature = 
(MethodSignature)thisJoinPoint.getSignature();
+               String methodname = signature.getName();
+               if (!bean.configured.contains(methodname)) return proceed(bean);
+               Class rt = signature.getReturnType();
+               if (rt.equals(Void.TYPE)) return null;
+               if (rt.isAssignableFrom(bean.getClass())) return bean;
+               throw new MagmaException("Don't know what to return after late 
configuration for method {0}, only void or same bean type are supported, not 
{1}", signature.toLongString(), rt);
+       }
+       
+       
+}

Added: 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurator.java
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurator.java?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurator.java
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/main/java/org/apache/magma/lateconfig/LateConfigurator.java
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,172 @@
+package org.apache.magma.lateconfig;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.magma.basics.MagmaException;
+import org.apache.magma.basics.context.RunningContext;
+import org.apache.magma.basics.startup.CycleThreadLocal;
+import org.apache.magma.conversion.Converter;
+import org.apache.magma.conversion.Converters;
+import 
org.apache.magma.lateconfig.LateConfigurationHook.LateConfigurationSupport;
+import org.apache.magma.settings.ContextSettingsHolder;
+import org.apache.magma.settings.Settings;
+
+public class LateConfigurator {
+
+       protected static ContextSettingsHolder prodholder = new 
ContextSettingsHolder();
+       protected static CycleThreadLocal<ContextSettingsHolder> devholder = 
new CycleThreadLocal<ContextSettingsHolder>();
+       
+       public static List<String> lateConfigure(LateConfigurationSupport bean) 
{
+               ContextSettingsHolder holder = initSettings();
+               RunningContext.get().push(bean.getClass());
+               String[] prop = null;
+               try {
+                       List<String> ret = new ArrayList<String>();
+                       Class<? extends LateConfigurationSupport> clazz = 
bean.getClass();
+                       // TODO cache configurable methods
+                       Method[] methods = clazz.getMethods();
+                       for (Method method : methods) {
+                               if 
(method.isAnnotationPresent(LateConfigurable.class)) {
+                                       String keyname = method.getName();
+                                       if (keyname.startsWith("set")) {
+                                               keyname = keyname.substring(3);
+                                       }
+                                       prop = null;
+                                       prop = holder.getEntry(keyname);
+                                       if (prop == null) continue;
+                                       // TODO cache this conversion
+                                       Class<?>[] types = 
method.getParameterTypes();
+                                       Object[] params = new 
Object[types.length];
+                                       if (types.length > 0) {
+                                               // Special case of a single 
string
+                                               if (types.length == 1 && 
types[0].equals(String.class)) {
+                                                       params[0] = 
prop[prop.length - 1];
+                                               } else {
+                                                       String val = 
prop[prop.length - 1];
+                                                       String[] strparams = 
parseArguments(val, prop);
+                                                       // TODO how to handle 
overridden methods?
+                                                       if (strparams.length != 
types.length) throw new MagmaException("Wrong number of parameters for late 
config of {0},{1}, expected {2} but found {3} in {4}", bean.getClass(), 
method.getName(), types.length, strparams.length, Arrays.toString(prop));
+                                                       for (int i = 0; i < 
types.length; i++) {
+                                                               Converter<?> 
converter = Converters.getConverterFor(types[i]);
+                                                               if (converter 
== null) {
+                                                                       throw 
new MagmaException("Cannot find a converter for {0}, needed for late 
configuration of {1}", types[i], Arrays.toString(prop));
+                                                               }
+                                                               params[i] = 
converter.from(strparams[i]);
+                                                       }
+                                               }
+                                       }
+                                       try {
+                                               method.invoke(bean, params);
+                                               ret.add(method.getName());
+                                       } catch (IllegalArgumentException e) {
+                                               throw new MagmaException(e, 
"There has been an error calling {0}.{1} using late configuration {2}", 
method.getDeclaringClass(), method.getName(), Arrays.toString(prop));
+                                       } catch (IllegalAccessException e) {
+                                               throw new MagmaException(e, 
"Method {0}.{1} is not accessible", method.getDeclaringClass(), 
method.getName());
+                                       } catch (InvocationTargetException e) {
+                                               throw new MagmaException(e, 
"There has been an error calling {0}.{1} using late configuration {2}", 
method.getDeclaringClass(), method.getName(), Arrays.toString(prop));           
                            
+                                       }
+                               }
+                       }
+                       return ret;
+               } catch (Exception e) {
+                       if (prop != null) {
+                               throw new MagmaException(e, "Error while 
executing late config for {0}, on line {1}", bean.getClass(), 
Arrays.toString(prop));
+                       } else {
+                               throw new MagmaException(e, "Error while 
executing late config for {0}", bean.getClass());                              
+                       }
+               } finally {
+                       RunningContext.get().popClass();
+               }
+       }
+
+       protected static String[] parseArguments(String val, String[] props) {
+               String[] strparams = val.split(",");
+               // Let's try to handle string in quotes
+               int quoteindex = -1;
+               do {
+                       quoteindex = -1;
+                       int quotedcount = 0;
+                       boolean closed = false;
+                       for (int i = 0; i < strparams.length; i++) {
+                               if (quoteindex == -1) {
+                                       if (strparams[i].startsWith("\"")) {
+                                               strparams[i] = 
strparams[i].substring(1);
+                                               quoteindex = i;
+                                       }
+                               } else {
+                                       if (strparams[i].endsWith("\"")) {
+                                               closed = true;
+                                               strparams[i] = 
strparams[i].substring(0, strparams[i].length() - 1);
+                                       }
+                                       quotedcount++;
+                                       strparams[quoteindex] += "," + 
strparams[i];
+                                       strparams[i] = null;
+                                       if (closed) break;
+                               }
+                       }
+                       if (quoteindex != -1 && !closed) throw new 
MagmaException("Unclosed \" in lateconfig.properties {0}", 
Arrays.toString(props));
+                       String[] nstrparams = new String[strparams.length - 
quotedcount];
+                       int k = 0;
+                       for (int i = 0; i < strparams.length; i++) {
+                               if (strparams[i] != null) nstrparams[k++] = 
strparams[i];
+                       }                                               
+                       strparams = nstrparams;
+               } while (quoteindex > -1);
+               return strparams;
+       }
+       
+       protected static ContextSettingsHolder initSettings() {
+               ContextSettingsHolder holder = null;
+               if (Settings.isDeveloperEnv()) {
+                       holder = devholder.get();
+                       if (holder == null) {
+                               holder = new ContextSettingsHolder();
+                               devholder.set(holder);
+                       }
+                       // No double check, cycle is thread specific
+                       if (holder.isInited()) return holder;
+                       holder.initing();
+                       initHolder(holder);
+               } else {
+                       holder = prodholder;
+                       if (holder.isInited()) return holder;
+                       holder.initing();
+                       if (holder.isInited()) return holder;
+                       initHolder(holder);
+               }
+               return holder;
+       }
+       
+       protected static void initHolder(ContextSettingsHolder holder) {
+               ClassLoader loader = holder.getClass().getClassLoader();
+               Enumeration<URL> resources;
+               try {
+                       resources = 
loader.getResources("META-INF/lateconfig.default.properties");
+                       while (resources.hasMoreElements()) {
+                               holder.overrideWith(resources.nextElement());
+                       }
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+               try {
+                       resources = 
loader.getResources("META-INF/lateconfig.default.properties.xml");
+                       while (resources.hasMoreElements()) {
+                               holder.overrideWith(resources.nextElement());
+                       }
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }
+               
holder.overrideWith(loader.getResource("META-INF/lateconfig.properties"));
+               
holder.overrideWith(loader.getResource("META-INF/lateconfig.properties.xml"));
+               holder.inited();                
+       }
+       
+       
+}

Added: 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigBean.java
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigBean.java?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigBean.java
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigBean.java
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,59 @@
+package org.apache.magma.lateconfig;
+
+import java.lang.annotation.ElementType;
+
+...@lateconfigurable
+public class LateConfigBean {
+
+       private String stringProp;
+       private String chained;
+       private String twostrings;
+       private int exoticInt;
+       private ElementType exoticEnum;
+
+       @LateConfigurationTrigger
+       public LateConfigBean() {
+               
+       }
+               
+       public String getStringProp() {
+               return stringProp;
+       }
+
+       @LateConfigurable
+       public void setStringProp(String stringProp) {
+               this.stringProp = stringProp;
+       }
+
+       public String getChained() {
+               return chained;
+       }
+
+       @LateConfigurable
+       public LateConfigBean setChained(String chained) {
+               this.chained = chained;
+               return this;
+       }
+       
+       @LateConfigurable
+       public void setTwoStrings(String a, String b) {
+               twostrings = a + "-" + b; 
+       }
+       public String getTwostrings() {
+               return twostrings;
+       }
+       
+       @LateConfigurable
+       public void exotic(int i, ElementType ele) {
+               exoticEnum=ele;
+               exoticInt=i;
+       }
+
+       public int getExoticInt() {
+               return exoticInt;
+       }
+
+       public ElementType getExoticEnum() {
+               return exoticEnum;
+       }
+}

Added: 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigTest.java
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigTest.java?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigTest.java
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/LateConfigTest.java
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,101 @@
+package org.apache.magma.lateconfig;
+
+import static org.junit.Assert.*;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+
+import org.apache.magma.basics.MagmaException;
+import org.apache.magma.basics.context.RunningContext;
+import org.apache.magma.basics.context.SubRunningContext;
+import org.junit.After;
+import org.junit.Test;
+
+public class LateConfigTest {
+       
+       @Test
+       public void plainConfigure() throws Exception {
+               LateConfigBean bean = new LateConfigBean();
+               assertEquals("Simple configuration not working", "configured 
correctly", bean.getStringProp());
+       }
+
+       @After
+       public void cleanContext() {
+               RunningContext.cleanup();
+       }
+       
+       @Test
+       public void differentContext() throws Exception {
+               SubRunningContext src = RunningContext.get();
+               src.push("incontext");
+               
+               LateConfigBean bean = new LateConfigBean();
+               assertEquals("in context configuration not working", 
"configured in context", bean.getStringProp());
+       }
+       
+       @Test
+       public void avoidSettingAgain() throws Exception {
+               LateConfigBean bean = new LateConfigBean();
+               assertEquals("Simple configuration not working", "configured 
correctly", bean.getStringProp());
+               bean.setStringProp("should not go");
+               assertEquals("Java set interception not working", "configured 
correctly", bean.getStringProp());
+       }
+       
+       @Test
+       public void chainedSetters() throws Exception {
+               LateConfigBean bean = new LateConfigBean();
+               assertEquals("Simple configuration not working", "configured 
correctly", bean.getStringProp());
+               assertEquals("Simple configuration not working", "Configured 
Correctly", bean.getChained());
+               // If throws exception here it is not chaining
+               bean.setChained("no go").setStringProp("should not go");
+               assertEquals("Java set interception not working", "configured 
correctly", bean.getStringProp());
+               assertEquals("Java set interception not working", "Configured 
Correctly", bean.getChained());
+       }
+       
+       @Test
+       public void otherTrigger() throws Exception {
+               OtherTriggerBean bean = new OtherTriggerBean();
+               assertEquals("Configured during constructor", "empty", 
bean.getStringProp());
+               String compute = bean.compute();
+               assertEquals("Not configured before trigger execution", 
"configured correctly", compute);
+       }
+       
+       @Test
+       public void parseParamsTest() throws Exception {
+               String[] parsed = LateConfigurator.parseArguments("a,b", new 
String[0]);
+               assertEquals(2, parsed.length);
+               assertEquals("a", parsed[0]);
+               assertEquals("b", parsed[1]);
+       }
+       
+       @Test
+       public void quotedParamsTest() throws Exception {
+               String[] parsed = 
LateConfigurator.parseArguments("\"a,b,c\",d", new String[0]);
+               assertEquals(2, parsed.length);
+               assertEquals("a,b,c", parsed[0]);
+               assertEquals("d", parsed[1]);
+       }
+       
+       @Test
+       public void multipleParameters() throws Exception {
+               LateConfigBean bean = new LateConfigBean();
+               assertEquals("Multiple parameters not working correctly", 
"configured-it", bean.getTwostrings());
+       }
+       
+       @Test(expected=MagmaException.class)
+       public void multipleParametersWithFewParameters() throws Exception {
+               SubRunningContext src = RunningContext.get();
+               src.push("wrongmulti");
+               LateConfigBean bean = new LateConfigBean();             
+       }
+       
+       @Test
+       public void exoticSetter() throws Exception {
+               SubRunningContext src = RunningContext.get();
+               src.push("inexotic");
+               LateConfigBean bean = new LateConfigBean();             
+               assertEquals("Exotic set of int failed", 5, 
bean.getExoticInt());
+               assertEquals("Exotic set of enum failed", ElementType.METHOD, 
bean.getExoticEnum());
+       }
+
+}

Added: 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/OtherTriggerBean.java
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/OtherTriggerBean.java?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/OtherTriggerBean.java
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/test/java/org/apache/magma/lateconfig/OtherTriggerBean.java
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,21 @@
+package org.apache.magma.lateconfig;
+
+...@lateconfigurable
+public class OtherTriggerBean {
+       private String stringProp = "empty";
+
+       public String getStringProp() {
+               return stringProp;
+       }
+
+       @LateConfigurable
+       public void setStringProp(String stringProp) {
+               this.stringProp = stringProp;
+       }
+       
+       @LateConfigurationTrigger
+       public String compute() {
+               return this.stringProp;
+       }
+
+}

Added: 
labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/lateconfig.properties
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/lateconfig.properties?rev=882441&view=auto
==============================================================================
--- 
labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/lateconfig.properties
 (added)
+++ 
labs/magma/trunk/lateconfig-impl/src/test/resources/META-INF/lateconfig.properties
 Fri Nov 20 08:06:23 2009
@@ -0,0 +1,6 @@
+stringProp=configured correctly
+incontext.stringProp=configured in context
+chained=Configured Correctly
+twostrings=configured,it
+wrongmulti.twostrings=configured
+inexotic.exotic=5,METHOD
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to