You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2010/05/24 11:25:10 UTC

svn commit: r947576 - in /incubator/river/jtsk/trunk/src: manifest/jsk-resources/META-INF/services/net.jini.config.Configuration net/jini/config/Component.java net/jini/config/GroovyConfig.groovy

Author: peter_firmstone
Date: Mon May 24 09:25:09 2010
New Revision: 947576

URL: http://svn.apache.org/viewvc?rev=947576&view=rev
Log:
River-313 Groovy Config donated by Dennis Reedy

Added:
    incubator/river/jtsk/trunk/src/manifest/jsk-resources/META-INF/services/net.jini.config.Configuration
    incubator/river/jtsk/trunk/src/net/jini/config/Component.java   (with props)
    incubator/river/jtsk/trunk/src/net/jini/config/GroovyConfig.groovy

Added: incubator/river/jtsk/trunk/src/manifest/jsk-resources/META-INF/services/net.jini.config.Configuration
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/manifest/jsk-resources/META-INF/services/net.jini.config.Configuration?rev=947576&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/manifest/jsk-resources/META-INF/services/net.jini.config.Configuration (added)
+++ incubator/river/jtsk/trunk/src/manifest/jsk-resources/META-INF/services/net.jini.config.Configuration Mon May 24 09:25:09 2010
@@ -0,0 +1 @@
+net.jini.config.GroovyConfig
\ No newline at end of file

Added: incubator/river/jtsk/trunk/src/net/jini/config/Component.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/net/jini/config/Component.java?rev=947576&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/net/jini/config/Component.java (added)
+++ incubator/river/jtsk/trunk/src/net/jini/config/Component.java Mon May 24 09:25:09 2010
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed 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 net.jini.config;
+
+import java.lang.annotation.*;
+
+/**
+ * The Component annotation is used in a Groovy class to indicate what
+ * configuration component the class is to be used for.
+ *
+ * <p>The component identifies the object whose behavior will be configured
+ * using the object returned. The value of component must be a
+ * <i>QualifiedIdentifier</i>, as defined in the
+ * <i>Java(TM) Language Specification (JLS)</i>, and is typically the class or
+ * package name of the object being configured.
+ *
+ * @author Dennis Reedy
+ */
+@Documented
+@Retention (RetentionPolicy.RUNTIME)
+@Target (value= ElementType.TYPE)
+public @interface Component {    
+    String value();
+}

Propchange: incubator/river/jtsk/trunk/src/net/jini/config/Component.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/river/jtsk/trunk/src/net/jini/config/GroovyConfig.groovy
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/trunk/src/net/jini/config/GroovyConfig.groovy?rev=947576&view=auto
==============================================================================
--- incubator/river/jtsk/trunk/src/net/jini/config/GroovyConfig.groovy (added)
+++ incubator/river/jtsk/trunk/src/net/jini/config/GroovyConfig.groovy Mon May 24 09:25:09 2010
@@ -0,0 +1,360 @@
+/*
+ * Copyright to the original author or authors.
+ *
+ * Licensed 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 net.jini.config;
+
+import net.jini.config.Configuration
+import net.jini.config.ConfigurationException
+import net.jini.config.NoSuchEntryException
+import net.jini.config.ConfigurationNotFoundException
+import net.jini.config.ConfigurationFile
+import java.util.logging.Logger
+import java.util.logging.Level
+import java.lang.reflect.Constructor
+
+/**
+ * Provides support for Groovy based configuration.
+ *
+ * @author Dennis Reedy
+ */
+class GroovyConfig implements Configuration {
+    Map<String, GroovyObject> groovyConfigs = new HashMap<String, GroovyObject>()
+    ConfigurationFile configFile
+    List <String> visited = new ArrayList<String>()
+    static Logger logger = Logger.getLogger(GroovyConfig.class.getPackage().name)
+
+    GroovyConfig(String gFile) {
+        File f = new File(gFile)
+        GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader())
+        parseAndLoad(f.newInputStream(), gcl)
+    }
+
+    /**
+     * Constructor required for Jini Configuration
+     */
+    public GroovyConfig(String[] args, ClassLoader loader) {
+        if(args==null || args.length==0) {
+            configFile = new ConfigurationFile(args, loader)
+        } else {
+            if(!args[0].endsWith(".groovy")) {
+                configFile = new ConfigurationFile(args, loader)
+            } else {
+                /* Make sure we have all groovy files */
+                checkInputs(args)
+                traverseInputs(args, loader)
+            }
+        }
+    }
+
+    def checkInputs(String[] args) {
+        args.each { arg ->
+            if(arg.endsWith(".groovy")) {
+                if(logger.isLoggable(Level.FINE))
+                logger.fine(arg)
+            } else {
+                StringBuffer buffer = new StringBuffer()
+                args.each { a ->
+                    buffer.append(a).append(' ')
+                }
+                throw new ConfigurationException(
+                    'When providing multiple configuration files, '+
+                    'they must all be Groovy configurations '+
+                    '['+buffer.toString()+']');
+            }
+        }
+    }
+
+    def traverseInputs(String[] args, ClassLoader loader) {
+        if(loader==null)
+            loader = Thread.currentThread().getContextClassLoader()
+        GroovyClassLoader gcl = new GroovyClassLoader(loader)
+        args.each { arg ->
+            String groovyFile = arg
+            InputStream is = null
+            long t0 = System.currentTimeMillis()
+            try {
+                try {
+                    URL url = new URL(groovyFile)
+                    is = url.openStream()
+                } catch (MalformedURLException e) {
+                    is = new FileInputStream(groovyFile);
+                }
+                parseAndLoad(is, gcl)
+            } catch (FileNotFoundException e) {
+                throw new ConfigurationNotFoundException("The configuration file "+
+                                                         +"["+groovyFile+"] "+
+                                                         +"does not exist")
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                    }
+                }
+                if(logger.isLoggable(Level.FINE))
+                    logger.fine 'Time to parse '+groovyFile+' : '+
+                                (System.currentTimeMillis()-t0)+' '+
+                                'milliseconds'
+            }
+        }
+
+    }
+
+    def parseAndLoad(InputStream is, GroovyClassLoader gcl) {
+        gcl.parseClass(is)
+        for(Class groovyClass : gcl.loadedClasses) {
+            if(visited.contains(groovyClass.name))
+                continue
+            visited.add(groovyClass.name)
+            for(Constructor c : groovyClass.getConstructors())  {
+                if(c.parameterTypes.length==0) {
+                    c.setAccessible(true)
+                    GroovyObject gO = (GroovyObject)c.newInstance()
+                    String component
+                    if(groovyClass.isAnnotationPresent(Component.class)) {
+                        Component comp = groovyClass.getAnnotation(Component.class)
+                        component = comp.value()
+                    } else {
+                        component = getComponentName(gO.getMetaClass())
+                    }
+                    if (!validQualifiedIdentifier(component)) {
+                        throw new IllegalArgumentException(
+                            "component must be a valid qualified identifier");
+                    }
+                    groovyConfigs.put(component, gO)
+                }
+            }            
+        }
+    }
+
+    def String getComponentName(MetaClass mc) {
+        String component = mc.getTheClass().name
+        component = component.replace("_", ".")
+        return component
+    }
+    
+    def Object getEntry(String component, String name, Class type) {
+        return getEntry(component, name, type, NO_DEFAULT);
+    }
+
+    def Object getEntry(String component, String name, Class type, Object defaultValue) {
+        return getEntry(component, name, type, defaultValue, NO_DATA);
+    }
+
+    def Object getEntry(String component, String name, Class type, Object defaultValue, Object data) {
+        if(configFile!=null)
+            return configFile.getEntry(component, name, type, defaultValue, data)
+
+        if (component == null) {
+            throw new NullPointerException("component cannot be null");
+        } else if (name == null) {
+            throw new NullPointerException("name cannot be null");
+        } else if (type == null) {
+            throw new NullPointerException("type cannot be null");
+        } else if (defaultValue != NO_DEFAULT) {
+            if (type.isPrimitive() ?
+                (defaultValue == null ||
+                 getPrimitiveType(defaultValue.getClass()) != type) :
+                (defaultValue != null && !type.isAssignableFrom(defaultValue.getClass()))) {
+                throw new IllegalArgumentException("defaultValue is of wrong type");
+            }
+        }
+
+        GroovyObject groovyConfig = null;
+        for(Map.Entry<String, GroovyObject> entry : groovyConfigs)  {
+            if(entry.key.equals(component)) {
+                groovyConfig = entry.value;
+                break;
+            }
+        }
+        if(groovyConfig==null) {
+            if(defaultValue==NO_DEFAULT)
+                throw new NoSuchEntryException('component name ['+component+'] '+
+                                               'not found in Groovy files, '+
+                                               'and no default value was given.')
+            else
+                return defaultValue;
+        }
+
+        Object value
+        if(data==NO_DATA) {
+            try {
+                value = groovyConfig.getProperty(name)
+                if(logger.isLoggable(Level.FINER))
+                    logger.finer 'Configuration entry '+
+                                 '['+component+'.'+name+'] found in '+
+                                 'GroovyObject '+groovyConfig+', '+
+                                 'asssign returned value: '+value
+            } catch(MissingPropertyException e) {
+                if(logger.isLoggable(Level.FINEST))
+                    logger.log(Level.FINEST,
+                               'Looking for configuration entry '+
+                               '['+component+'.'+name+'] in GroovyObject '+
+                               groovyConfig,
+                               e)
+                if(defaultValue==NO_DEFAULT) {
+                    throw new NoSuchEntryException("entry not found for "+
+                                                   "component: "+component +", "+
+                                                   "name: " + name, e);
+                } else {
+                    if(logger.isLoggable(Level.FINER))
+                        logger.finer 'Configuration entry '+
+                                     '['+component+'.'+name+'] not found in '+
+                                     'GroovyObject '+groovyConfig+', '+
+                                     'asssign provided default: '+defaultValue
+                    value = defaultValue;
+                }
+            }
+        } else {
+            try {
+                MetaMethod mm = null
+                String methodName = 'get'+name[0].toUpperCase()+name.substring(1, name.length())
+                List<MetaMethod> methods = groovyConfig.metaClass.methods
+                for(MetaMethod m : methods) {
+                    if(m.name==methodName) {
+                        if(logger.isLoggable(Level.FINEST))
+                            logger.finest "Found matching method name [${methodName}], "+
+                                          "check for type match"
+                        Class[] paramTypes = m.nativeParameterTypes
+                        if(paramTypes.length==1 && paramTypes[0].isAssignableFrom(data.class)) {
+                            mm = m;
+                            break;
+                        }
+                    }
+                }
+                if(mm==null) {
+                    if(defaultValue==NO_DEFAULT)
+                        throw new NoSuchEntryException("entry not found for "+
+                                                       "component: "+component+", "+
+                                                       "name: " + name+", "+
+                                                       "data argument: "+data);
+
+                    value = defaultValue;
+                } else {
+                    value = mm.invoke(groovyConfig, data)
+                }
+            } catch(MissingPropertyException e) {
+                throw new NoSuchEntryException("entry not found for component: " +
+                                               component +", name: " + name+", "+
+                                                   "data argument: "+data, e);
+            }
+        }
+
+        if(value!=null) {
+            boolean mismatch = false
+            if(type.isPrimitive()) {
+                if(!type.isAssignableFrom(getPrimitiveType(value.getClass()))) {
+                    mismatch = true
+                }
+            } else if(!type.isAssignableFrom(value.getClass())) {
+                mismatch = true
+            }
+            if(mismatch) {
+                throw new ConfigurationException(
+                    "entry for component " + component + ", name " + name +" "+
+                    "is of wrong type: " +value.getClass().name+", "+
+                    "expected: "+type.name);
+            }
+        }
+        return value
+    }
+
+    /**
+     * Returns the primitive type associated with a wrapper type or null if the
+     * argument is not a wrapper type.
+     *
+     * @param type the wrapper type
+     * @return the associated primitive type or null
+     */
+    def getPrimitiveType(Class type) {
+        if (type == Boolean.class) {
+            return Boolean.TYPE;
+        } else if (type == Byte.class) {
+            return Byte.TYPE;
+        } else if (type == Character.class) {
+            return Character.TYPE;
+        } else if (type == Short.class) {
+            return Short.TYPE;
+        } else if (type == Integer.class) {
+            return Integer.TYPE;
+        } else if (type == Long.class) {
+            return Long.TYPE;
+        } else if (type == Float.class) {
+            return Float.TYPE;
+        } else if (type == Double.class) {
+            return Double.TYPE;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Checks if the argument is a valid <i>Identifier</i>, as defined in the
+     * <i>Java(TM) Language Specification</i>.
+     *
+     * @param name the name to check
+     * @return <code>true</code> if <code>name</code> is a valid
+     * 	       <i>Identifier</i>, else <code>false</code>
+     */
+    boolean validIdentifier(String name) {
+        if (name == null || name.length() == 0 ||
+            !Character.isJavaIdentifierStart(name.charAt(0))) {
+            return false
+        }
+        for (int i = name.length(); --i > 0;) {
+            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
+                return false
+            }
+        }
+        /* Check across the names of all Java programming language keywords, plus
+         * 'null', 'true', and 'false', which are not keywords, but are not
+         * permitted as identifiers. */
+        return !['abstract','continue','for',       'new',      'switch',
+                 'assert',  'default', 'goto',      'package',  'synchronized',
+                 'boolean', 'do',      'if',        'private',  'this',
+                 'break',   'double',  'implements','protected','throw',
+                 'byte',    'else',    'import',    'public',   'throws',
+                 'case',    'enum',    'instanceof','return',   'transient',
+                 'catch',   'extends', 'int',       'short',    'try',
+                 'char',    'final',   'interface', 'static',   'void',
+                 'class',   'finally', 'long',      'strictfp', 'volatile',
+                 'const',   'float',   'native',    'super',    'while',
+                 'null',    'true',    'false'].contains(name)
+    }
+
+
+    /**
+     * Checks if the argument is a valid <i>QualifiedIdentifier</i>, as defined
+     * in the <i>Java Language Specification</i>.
+     *
+     * @param name the name to check
+     * @return <code>true</code> if <code>name</code> is a valid
+     * 	       <i>QualifiedIdentifier</i>, else <code>false</code>
+     */
+    boolean validQualifiedIdentifier(String name) {
+        if (name == null)
+            return false
+        int offset = 0
+        int dot = 0
+        while (dot >= 0) {
+            dot = name.indexOf('.', offset)
+            String id = name.substring(offset, dot < 0 ? name.length() : dot)
+            if (!validIdentifier(id))
+                return false;
+            offset = dot + 1;
+        }
+        return true;
+    }
+}