Start searching of methods for references in the current source class and not in the class the reference is defined in. Start implementing method generation for references.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@570788 13f79535-47bb-0310-9956-ffa450edef68
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 e38859c..9d8be33 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
@@ -41,6 +41,8 @@
 import org.apache.felix.scrplugin.tags.JavaClassDescriptorManager;
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaTag;
+import org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription;
+import org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription.Modification;
 import org.apache.felix.scrplugin.xml.ComponentDescriptorIO;
 import org.apache.felix.scrplugin.xml.MetaTypeIO;
 import org.apache.maven.model.Resource;
@@ -240,7 +242,7 @@
 
         // fields
         do {
-            JavaField[] fields = description.getFields();
+            final JavaField[] fields = description.getFields();
             for (int i=0; fields != null && i < fields.length; i++) {
                 JavaTag tag = fields[i].getTagByName(Constants.REFERENCE);
                 if (tag != null) {
@@ -471,7 +473,8 @@
      * @param defaultName
      * @param component
      */
-    protected void doReference(JavaTag reference, String defaultName, Component component) {
+    protected void doReference(JavaTag reference, String defaultName, Component component)
+    throws MojoExecutionException {
         String name = reference.getNamedParameter(Constants.REFERENCE_NAME);
         if (StringUtils.isEmpty(name)) {
             name = defaultName;
@@ -486,20 +489,56 @@
         }
 
         if (!StringUtils.isEmpty(name)) {
-            final Reference ref = new Reference(reference);
+            final Reference ref = new Reference(reference, component.getJavaClassDescription());
             ref.setName(name);
             ref.setInterfacename(type);
             ref.setCardinality(reference.getNamedParameter(Constants.REFERENCE_CARDINALITY));
             ref.setPolicy(reference.getNamedParameter(Constants.REFERENCE_POLICY));
             ref.setTarget(reference.getNamedParameter(Constants.REFERENCE_TARGET));
-            String value;
-            value = reference.getNamedParameter(Constants.REFERENCE_BIND);
-            if ( value != null ) {
-                ref.setBind(value);
+            final String bindValue = reference.getNamedParameter(Constants.REFERENCE_BIND);
+            if ( bindValue != null ) {
+                ref.setBind(bindValue);
             }
-            value = reference.getNamedParameter(Constants.REFERENCE_UNDBIND);
-            if ( value != null ) {
-                ref.setUnbind(value);
+            final String unbindValue = reference.getNamedParameter(Constants.REFERENCE_UNDBIND);
+            if ( unbindValue != null ) {
+                ref.setUnbind(unbindValue);
+            }
+            // if this is a field we look for the bind/unbind methods
+            // and create them if they are not availabe
+            if ( false ) {
+                if ( reference.getField() != null && component.getJavaClassDescription() instanceof ModifiableJavaClassDescription ) {
+                    String changed = null;
+                    // Only create method if no bind name has been specified
+                    if ( bindValue == null && ref.findMethod(ref.getBind()) == null ) {
+                        // create bind method
+                        final String realMethodName = "bind" + Character.toUpperCase(name.charAt(0))
+                        + name.substring(1);
+                        changed = ((ModifiableJavaClassDescription)component.getJavaClassDescription()).addProtectedMethod(
+                                realMethodName,
+                                type,
+                                "{this." + reference.getField().getName() + "=param;}");
+                    }
+                    if ( unbindValue == null && ref.findMethod(ref.getUnbind()) == null ) {
+                        // create unbind method
+                        final String realMethodName = "unbind" + Character.toUpperCase(name.charAt(0))
+                        + name.substring(1);
+                        final String c = ((ModifiableJavaClassDescription)component.getJavaClassDescription()).addProtectedMethod(
+                                realMethodName,
+                                type,
+                                "{this." + reference.getField().getName() + "=null;}");
+                        if ( changed == null ) {
+                            changed = c;
+                        } else {
+                            changed = changed + c;
+                        }
+                    }
+                    if ( changed != null ) {
+                        Modification mod = new Modification();
+                        mod.lineNumber = 10;
+                        mod.content = changed;
+                        ((ModifiableJavaClassDescription)component.getJavaClassDescription()).writeClassFile(new Modification[] {mod});
+                    }
+                }
             }
             component.addReference(ref);
         }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
index 51c5e91..50d9d9c 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
@@ -79,6 +79,16 @@
     }
 
     /**
+     * Return the associated java class description
+     */
+    public JavaClassDescription getJavaClassDescription() {
+        if ( this.tag != null ) {
+            return this.tag.getJavaClassDescription();
+        }
+        return null;
+    }
+
+    /**
      * @return
      */
     public List getProperties() {
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
index 3ae5e26..fe151f1 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
@@ -40,18 +40,21 @@
     protected String bind;
     protected String unbind;
 
+    protected final JavaClassDescription javaClassDescription;
+
     /**
      * Default constructor.
      */
     public Reference() {
-        this(null);
+        this(null, null);
     }
 
     /**
      * Constructor from java source.
      */
-    public Reference(JavaTag t) {
+    public Reference(JavaTag t, JavaClassDescription desc) {
         super(t);
+        this.javaClassDescription = desc;
         // set default values
         this.setBind("bind");
         this.setUnbind("unbind");
@@ -133,19 +136,14 @@
         }
 
         // validate bind and unbind methods
-        JavaClassDescription javaClass = this.tag.getJavaClassDescription();
-        if (javaClass != null) {
-            this.bind = this.validateMethod(javaClass, this.bind, issues, warnings);
-            this.unbind = this.validateMethod(javaClass, this.unbind, issues, warnings);
-        } else {
-            issues.add(this.getMessage("Cannot find Java class to which the reference belongs"));
-        }
+        this.bind = this.validateMethod(this.bind, issues, warnings);
+        this.unbind = this.validateMethod(this.unbind, issues, warnings);
     }
 
-    protected String validateMethod(JavaClassDescription javaClass, String methodName, List issues, List warnings)
+    protected String validateMethod(String methodName, List issues, List warnings)
     throws MojoExecutionException {
 
-        JavaMethod method = this.findMethod(javaClass, methodName);
+        JavaMethod method = this.findMethod(methodName);
 
         if (method == null) {
             issues.add(this.getMessage("Missing method " + methodName + " for reference " + this.getName()));
@@ -162,17 +160,16 @@
         return method.getName();
     }
 
-    protected JavaMethod findMethod(JavaClassDescription javaClass, String methodName)
+    public JavaMethod findMethod(String methodName)
     throws MojoExecutionException {
-
         String[] sig = new String[]{ this.getInterfacename() };
         String[] sig2 = new String[]{ "org.osgi.framework.ServiceReference" };
 
         // service interface or ServiceReference first
         String realMethodName = methodName;
-        JavaMethod method = javaClass.getMethodBySignature(realMethodName, sig);
+        JavaMethod method = this.javaClassDescription.getMethodBySignature(realMethodName, sig);
         if (method == null) {
-            method = javaClass.getMethodBySignature(realMethodName, sig2);
+            method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
         }
 
         // append reference name with service interface and ServiceReference
@@ -180,10 +177,10 @@
             realMethodName = methodName + Character.toUpperCase(this.name.charAt(0))
             + this.name.substring(1);
 
-            method = javaClass.getMethodBySignature(realMethodName, sig);
+            method = this.javaClassDescription.getMethodBySignature(realMethodName, sig);
         }
         if (method == null) {
-            method = javaClass.getMethodBySignature(realMethodName, sig2);
+            method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
         }
 
         // append type name with service interface and ServiceReference
@@ -191,10 +188,10 @@
             int lastDot = this.getInterfacename().lastIndexOf('.');
             realMethodName = methodName
                 + this.getInterfacename().substring(lastDot + 1);
-            method = javaClass.getMethodBySignature(realMethodName, sig);
+            method = this.javaClassDescription.getMethodBySignature(realMethodName, sig);
         }
         if (method == null) {
-            method = javaClass.getMethodBySignature(realMethodName, sig2);
+            method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
         }
 
         return method;
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.java
new file mode 100644
index 0000000..28986f8
--- /dev/null
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/ModifiableJavaClassDescription.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.felix.scrplugin.tags;
+
+
+public interface ModifiableJavaClassDescription {
+
+    String addProtectedMethod(String name, String paramType, String contents);
+
+    void writeClassFile(Modification[] mods);
+
+    public static final class Modification {
+        public int lineNumber;
+        public String content;
+    }
+}
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
index cf569c9..bccf47d 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/qdox/QDoxJavaClassDescription.java
@@ -18,6 +18,9 @@
  */
 package org.apache.felix.scrplugin.tags.qdox;
 
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -27,10 +30,12 @@
 import org.apache.felix.scrplugin.tags.JavaField;
 import org.apache.felix.scrplugin.tags.JavaMethod;
 import org.apache.felix.scrplugin.tags.JavaTag;
+import org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription;
 import org.apache.maven.plugin.MojoExecutionException;
 
 import com.thoughtworks.qdox.model.DocletTag;
 import com.thoughtworks.qdox.model.JavaClass;
+import com.thoughtworks.qdox.model.JavaParameter;
 import com.thoughtworks.qdox.model.JavaSource;
 import com.thoughtworks.qdox.model.Type;
 
@@ -38,15 +43,19 @@
  * <code>QDoxJavaClassDescription.java</code>...
  *
  */
-public class QDoxJavaClassDescription implements JavaClassDescription {
+public class QDoxJavaClassDescription
+    implements JavaClassDescription, ModifiableJavaClassDescription {
 
     protected final JavaClass javaClass;
 
     protected final JavaClassDescriptorManager manager;
 
+    protected final JavaSource source;
+
     public QDoxJavaClassDescription(JavaSource source, JavaClassDescriptorManager m) {
         this.javaClass = source.getClasses()[0];
         this.manager = m;
+        this.source = source;
     }
 
     /**
@@ -216,4 +225,49 @@
     public boolean isPublic() {
         return this.javaClass.isPublic();
     }
+
+    /**
+     * @see org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription#addProtectedMethod(java.lang.String, java.lang.String, java.lang.String)
+     */
+    public String addProtectedMethod(String name, String paramType, String contents) {
+        final JavaParameter param = new JavaParameter(new Type(paramType), "param");
+        final JavaParameter[] params = new JavaParameter[] {param};
+        final com.thoughtworks.qdox.model.JavaMethod meth = new com.thoughtworks.qdox.model.JavaMethod();
+        meth.setName(name);
+        meth.setSourceCode(contents);
+        meth.setParameters(params);
+        meth.setModifiers(new String[] {"protected"});
+        this.javaClass.addMethod(meth);
+        return "protected void " + name + "(" + paramType + " param)" + contents + " ";
+    }
+
+    /**
+     * @see org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription#writeClassFile(org.apache.felix.scrplugin.tags.ModifiableJavaClassDescription.Modification[])
+     */
+    public void writeClassFile(Modification[] mods) {
+        if ( mods != null && mods.length > 0 ) {
+            try {
+                final LineNumberReader reader = new LineNumberReader(new FileReader(this.source.getFile()));
+                for(int i=0; i<mods.length; i++) {
+                    int lineNumber = mods[i].lineNumber;
+                    while ( reader.getLineNumber() < lineNumber ) {
+                        final String line = reader.readLine();
+                        System.out.println(line);
+                    }
+                    final String line = reader.readLine();
+                    System.out.print(line);
+                    System.out.println(mods[i].content);
+                }
+                String line;
+                while ( (line = reader.readLine()) != null ) {
+                    System.out.println(line);
+                }
+                reader.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
 }