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;
+ }
+}