FELIX-680 : Allow variables for reference names and lookup reference interface names in local imports.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@685186 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
index 077c732..92bf0a0 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
@@ -85,6 +85,8 @@
 
     public static final String REFERENCE_NAME = "name";
 
+    public static final String REFERENCE_NAME_REF = "nameRef";
+
     public static final String REFERENCE_INTERFACE = "interface";
 
     public static final String REFERENCE_CARDINALITY = "cardinality";
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
index e21915f..3907392 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
@@ -24,6 +24,7 @@
 import org.apache.felix.scrplugin.om.*;
 import org.apache.felix.scrplugin.om.metatype.*;
 import org.apache.felix.scrplugin.tags.*;
+import org.apache.felix.scrplugin.tags.qdox.QDoxJavaClassDescription;
 import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
 import org.apache.felix.scrplugin.xml.MetaTypeIO;
 import org.apache.maven.model.Resource;
@@ -288,8 +289,9 @@
         while ( refIter.hasNext() ) {
             final Map.Entry entry = (Map.Entry)refIter.next();
             final String refName = entry.getKey().toString();
-            final JavaTag tag = (JavaTag)entry.getValue();
-            this.doReference(tag, refName, component);
+            final Object[] values = (Object[])entry.getValue();
+            final JavaTag tag = (JavaTag)values[0];
+            this.doReference(tag, refName, component, values[1].toString());
         }
 
         // pid handling
@@ -416,14 +418,19 @@
 
                 this.addInterfaces(service, services[i], description);
             } else {
+                String interfaceName = name;
                 // check if the value points to a class/interface
                 // and search through the imports
-                final JavaClassDescription serviceClass = description.getReferencedClass(name);
-                if ( serviceClass == null ) {
-                    throw new MojoExecutionException("Interface '"+ name + "' in class " + description.getName() + " does not point to a valid class/interface.");
+                // but only for local services
+                if ( description instanceof QDoxJavaClassDescription ) {
+                    final JavaClassDescription serviceClass = description.getReferencedClass(name);
+                    if ( serviceClass == null ) {
+                        throw new MojoExecutionException("Interface '"+ name + "' in class " + description.getName() + " does not point to a valid class/interface.");
+                    }
+                    interfaceName = serviceClass.getName();
                 }
                 final Interface interf = new Interface(services[i]);
-                interf.setInterfacename(serviceClass.getName());
+                interf.setInterfacename(interfaceName);
                 service.addInterface(interf);
             }
 
@@ -453,6 +460,14 @@
         }
     }
 
+    /**
+     * Test a newly found reference
+     * @param references
+     * @param reference
+     * @param defaultName
+     * @param isInspectedClass
+     * @throws MojoExecutionException
+     */
     protected void testReference(Map references, JavaTag reference, String defaultName, boolean isInspectedClass)
     throws MojoExecutionException {
         final String refName = this.getReferenceName(reference, defaultName);
@@ -465,21 +480,63 @@
                     throw new MojoExecutionException("Duplicate definition for reference " + refName + " in class " + reference.getJavaClassDescription().getName());
                 }
             } else {
-                references.put(refName, reference);
+                // ensure interface
+                String type = reference.getNamedParameter(Constants.REFERENCE_INTERFACE);
+                if (StringUtils.isEmpty(type)) {
+                    if ( reference.getField() != null ) {
+                        type = reference.getField().getType();
+                    }
+                } else if ( isInspectedClass ) {
+                    // check if the value points to a class/interface
+                    // and search through the imports
+                    final JavaClassDescription serviceClass = reference.getJavaClassDescription().getReferencedClass(type);
+                    if ( serviceClass == null ) {
+                        throw new MojoExecutionException("Interface '"+ type + "' in class " + reference.getJavaClassDescription().getName() + " does not point to a valid class/interface.");
+                    }
+                    type = serviceClass.getName();
+                }
+                references.put(refName, new Object[] {reference, type});
             }
         }
     }
 
-    protected String getReferenceName(JavaTag reference, String defaultName) {
+    protected String getReferenceName(JavaTag reference, String defaultName)
+    throws MojoExecutionException {
         String name = reference.getNamedParameter(Constants.REFERENCE_NAME);
-        if (StringUtils.isEmpty(name)) {
-            name = defaultName;
-        }
-
         if (!StringUtils.isEmpty(name)) {
             return name;
         }
-        return null;
+        name = reference.getNamedParameter(Constants.REFERENCE_NAME_REF);
+        if (!StringUtils.isEmpty(name)) {
+            final JavaField refField = this.getReferencedField(reference, name);
+            final String[] values = refField.getInitializationExpression();
+            if ( values == null || values.length == 0 ) {
+                throw new MojoExecutionException("Referenced field for " + name + " has no values for a reference name.");
+            }
+            if ( values.length > 1 ) {
+                throw new MojoExecutionException("Referenced field " + name + " has more than one value for a reference name.");
+            }
+            name = values[0];
+        }
+
+        return defaultName;
+    }
+
+    protected JavaField getReferencedField(final JavaTag tag, String ref)
+    throws MojoExecutionException {
+        int classSep = ref.lastIndexOf('.');
+        JavaField field = null;
+        if ( classSep == -1 ) {
+            // local variable
+            field = tag.getJavaClassDescription().getFieldByName(ref);
+        }
+        if ( field == null ) {
+            field = tag.getJavaClassDescription().getExternalFieldByName(ref);
+        }
+        if ( field == null ) {
+            throw new MojoExecutionException("Reference references unknown field " + ref + " in class " + tag.getJavaClassDescription().getName());
+        }
+        return field;
     }
 
     /**
@@ -487,16 +544,8 @@
      * @param defaultName
      * @param component
      */
-    protected void doReference(JavaTag reference, String name, Component component)
+    protected void doReference(JavaTag reference, String name, Component component, String type)
     throws MojoExecutionException {
-        // ensure interface
-        String type = reference.getNamedParameter(Constants.REFERENCE_INTERFACE);
-        if (StringUtils.isEmpty(type)) {
-            if ( reference.getField() != null ) {
-                type = reference.getField().getType();
-            }
-        }
-
         final Reference ref = new Reference(reference, component.getJavaClassDescription());
         ref.setName(name);
         ref.setInterfacename(type);
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
index d3a3017..34468a3 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaClassDescription.java
@@ -84,7 +84,7 @@
      */
     public JavaField getExternalFieldByName(String name)
     throws MojoExecutionException {
-        throw new MojoExecutionException("getExternalFieldByName not support for this class.");
+        throw new MojoExecutionException("getExternalFieldByName not supported for this class.");
     }
 
     /**
@@ -92,7 +92,7 @@
      */
     public JavaClassDescription getReferencedClass(String referencedName)
     throws MojoExecutionException {
-        throw new MojoExecutionException("getDescription not support for this class.");
+        throw new MojoExecutionException("getReferencedClass not supported for this class.");
     }
 
     /**