You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2013/03/23 19:31:01 UTC

svn commit: r1460203 - in /commons/sandbox/weaver/branches/fields: ./ example/ example/src/main/java/org/apache/commons/weaver/privilizer/example/ example/src/test/java/org/apache/commons/weaver/privilizer/example/ example/src/test/resources/ modules/p...

Author: mbenson
Date: Sat Mar 23 18:31:00 2013
New Revision: 1460203

URL: http://svn.apache.org/r1460203
Log:
brain dump of attempts to handle blueprint methods that reference fields; this yields code with VerifyErrors... HELP\!

Added:
    commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingOACL3Blueprints.java
    commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingOACL3BlueprintsTest.java
    commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java   (with props)
Modified:
    commons/sandbox/weaver/branches/fields/   (props changed)
    commons/sandbox/weaver/branches/fields/example/pom.xml
    commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingBlueprints.java
    commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/Utils.java
    commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingBlueprintsTest.java
    commons/sandbox/weaver/branches/fields/example/src/test/resources/java.policy
    commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/pom.xml
    commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/FilesystemPrivilizer.java
    commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java
    commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java
    commons/sandbox/weaver/branches/fields/pom.xml
    commons/sandbox/weaver/branches/fields/processor/pom.xml

Propchange: commons/sandbox/weaver/branches/fields/
------------------------------------------------------------------------------
  Merged /commons/sandbox/weaver/trunk:r1460197

Modified: commons/sandbox/weaver/branches/fields/example/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/pom.xml?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/pom.xml (original)
+++ commons/sandbox/weaver/branches/fields/example/pom.xml Sat Mar 23 18:31:00 2013
@@ -27,12 +27,18 @@
   <name>Commons Weaver Privilizer Example</name>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <privilizer.policy>ON_INIT</privilizer.policy>
   </properties>
   <dependencies>
     <dependency>
       <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
       <artifactId>commons-weaver-privilizer-api</artifactId>
       <version>${project.version}</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
@@ -49,7 +55,7 @@
         <configuration>
           <weaverConfig>
             <privilizer.accessLevel>PACKAGE</privilizer.accessLevel>
-            <privilizer.policy>ON_INIT</privilizer.policy>
+            <privilizer.policy>${privilizer.policy}</privilizer.policy>
           </weaverConfig>
         </configuration>
         <executions>
@@ -104,6 +110,11 @@
             </lifecycleMappingMetadata>
           </configuration>
         </plugin>
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>exec-maven-plugin</artifactId>
+          <version>1.2.1</version>
+        </plugin>
       </plugins>
     </pluginManagement>
   </build>

Modified: commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingBlueprints.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingBlueprints.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingBlueprints.java (original)
+++ commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingBlueprints.java Sat Mar 23 18:31:00 2013
@@ -21,6 +21,10 @@ import org.apache.commons.weaver.privili
 @Privilizing({ @CallTo(Utils.class), @CallTo(value = Utils.More.class, methods = "getProperty") })
 public class UsingBlueprints {
 
+    public String utilsReadConstant() {
+        return Utils.readConstant();
+    }
+
     public String utilsGetProperty() {
         return Utils.getProperty();
     }

Added: commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingOACL3Blueprints.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingOACL3Blueprints.java?rev=1460203&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingOACL3Blueprints.java (added)
+++ commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/UsingOACL3Blueprints.java Sat Mar 23 18:31:00 2013
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 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 org.apache.commons.weaver.privilizer.example;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+
+@Privilizing(@CallTo(value = ClassUtils.class, methods = "getShortClassName"))
+public class UsingOACL3Blueprints {
+
+    public Class<?> getClass(String className) {
+        try {
+            return ClassUtils.getClass(className);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    public String getShortClassName(String className) {
+        /*
+         * method with field access but does not call other methods:
+         */
+        return ClassUtils.getShortClassName(className);
+    }
+
+    public static void main(String[] args) {
+        final UsingOACL3Blueprints usingOACL3Blueprints = new UsingOACL3Blueprints();
+        for (String arg : args) {
+            System.out.println(usingOACL3Blueprints.getShortClassName(arg));
+        }
+    }
+}

Modified: commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/Utils.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/Utils.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/Utils.java (original)
+++ commons/sandbox/weaver/branches/fields/example/src/main/java/org/apache/commons/weaver/privilizer/example/Utils.java Sat Mar 23 18:31:00 2013
@@ -32,6 +32,12 @@ public class Utils {
     private Utils() {
     }
 
+    private static final String foo = "foo".intern();
+
+    public static String readConstant() {
+        return foo;
+    }
+
     public static String getProperty() {
         return getProperty("foo");
     }

Modified: commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingBlueprintsTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingBlueprintsTest.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingBlueprintsTest.java (original)
+++ commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingBlueprintsTest.java Sat Mar 23 18:31:00 2013
@@ -42,6 +42,11 @@ public class UsingBlueprintsTest {
     }
 
     @Test
+    public void testUtilsReadConstant() {
+        assertEquals("foo", usingBlueprints.utilsReadConstant());
+    }
+
+    @Test
     public void testUtilsGetProperty() {
         assertEquals("foo-value", usingBlueprints.utilsGetProperty());
     }

Added: commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingOACL3BlueprintsTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingOACL3BlueprintsTest.java?rev=1460203&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingOACL3BlueprintsTest.java (added)
+++ commons/sandbox/weaver/branches/fields/example/src/test/java/org/apache/commons/weaver/privilizer/example/UsingOACL3BlueprintsTest.java Sat Mar 23 18:31:00 2013
@@ -0,0 +1,36 @@
+/*
+ *  Copyright 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 org.apache.commons.weaver.privilizer.example;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UsingOACL3BlueprintsTest {
+
+    private UsingOACL3Blueprints usingOACL3Blueprints;
+
+    @Before
+    public void setUp() throws Exception {
+        usingOACL3Blueprints = new UsingOACL3Blueprints();
+    }
+
+//    @Test
+    public void testGetClass() {
+        assertEquals(Utils.class, usingOACL3Blueprints.getClass(Utils.class.getName()));
+    }
+}

Modified: commons/sandbox/weaver/branches/fields/example/src/test/resources/java.policy
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/example/src/test/resources/java.policy?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/example/src/test/resources/java.policy (original)
+++ commons/sandbox/weaver/branches/fields/example/src/test/resources/java.policy Sat Mar 23 18:31:00 2013
@@ -42,4 +42,5 @@ grant codeBase "file:${user.dir}/target/
   permission java.util.PropertyPermission "foo", "read";
   permission java.util.PropertyPermission "bar", "read";
   permission java.util.PropertyPermission "baz", "read";
+  #permission java.lang.RuntimePermission "getClassLoader";
 };

Modified: commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/pom.xml?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/pom.xml (original)
+++ commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/pom.xml Sat Mar 23 18:31:00 2013
@@ -47,7 +47,6 @@
     <dependency>
       <groupId>org.javassist</groupId>
       <artifactId>javassist</artifactId>
-      <version>3.17.1-GA</version>
     </dependency>
   </dependencies>
 

Modified: commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/FilesystemPrivilizer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/FilesystemPrivilizer.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/FilesystemPrivilizer.java (original)
+++ commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/FilesystemPrivilizer.java Sat Mar 23 18:31:00 2013
@@ -30,7 +30,7 @@ import org.apache.commons.lang3.Validate
 /**
  * Handles weaving of methods annotated with {@link Privileged}.
  */
-public class FilesystemPrivilizer extends Privilizer<FilesystemPrivilizer> {
+public class FilesystemPrivilizer extends Privilizer {
 
     private static ClassPool createClassPool(ClassLoader classpath, File target) {
         final ClassPool result = new ClassPool();

Modified: commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java (original)
+++ commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java Sat Mar 23 18:31:00 2013
@@ -41,35 +41,33 @@ import javassist.CtPrimitiveType;
 import javassist.NotFoundException;
 import javassist.bytecode.Descriptor;
 import javassist.expr.ExprEditor;
+import javassist.expr.FieldAccess;
 import javassist.expr.MethodCall;
 
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.mutable.MutableBoolean;
 import org.apache.commons.lang3.text.StrBuilder;
 import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
+import org.apache.commons.weaver.utils.Assistant;
 import org.apache.commons.weaver.utils.Body;
 
 /**
- * Handles weaving of methods annotated with {@link Privileged}.
+ * Handles:
+ * <ul>
+ * <li>weaving of methods annotated with {@link Privileged}</li>
+ * <li>weaving of blueprint annotation methods</li>
+ * </ul>
+ * 
+ * @see Privileged
+ * @see Privilizing
  */
-public abstract class Privilizer<SELF extends Privilizer<SELF>> {
+public abstract class Privilizer {
     public interface ClassFileWriter {
         void write(CtClass type) throws CannotCompileException, IOException;
     }
 
-    public interface Log {
-        void debug(String message);
-
-        void verbose(String message);
-
-        void error(String message);
-
-        void info(String message);
-
-        void warn(String message);
-    }
-
     /**
      * Weaving policy: when to use {@link PrivilegedAction}s.
      */
@@ -162,6 +160,8 @@ public abstract class Privilizer<SELF ex
         return result;
     }
 
+    private final Assistant assistant;
+
     public Privilizer(ClassPool classPool) {
         this(Policy.DYNAMIC, classPool);
     }
@@ -169,10 +169,12 @@ public abstract class Privilizer<SELF ex
     public Privilizer(Policy policy, ClassPool classPool) {
         this.policy = Validate.notNull(policy, "policy");
         this.classPool = Validate.notNull(classPool, "classPool");
+        this.assistant = new Assistant(classPool, "__privilizer_");
     }
 
     /**
-     * Weave all {@link Privileged} methods found.
+     * Weave the specified class. Handles all {@link Privileged} methods as well as calls described by
+     * {@code privilizing}.
      * 
      * @param privilizing
      * 
@@ -217,7 +219,8 @@ public abstract class Privilizer<SELF ex
             }
 
             if (policy == Policy.ON_INIT) {
-                debug("Initializing field %s to %s", policy.condition, HAS_SECURITY_MANAGER_CONDITION);
+                debug("Initializing field %s.%s to %s", type.getName(), policy.condition,
+                    HAS_SECURITY_MANAGER_CONDITION);
 
                 CtField securityManager = new CtField(CtClass.booleanType, policy.condition, type);
                 securityManager.setModifiers(Modifier.STATIC | Modifier.PRIVATE | Modifier.FINAL);
@@ -256,10 +259,9 @@ public abstract class Privilizer<SELF ex
 
     private boolean privilizeBlueprints(final CtClass type, final CtMethod method, final CallTo[] blueprintCalls)
         throws CannotCompileException, ClassNotFoundException, NotFoundException, IOException, IllegalAccessException {
-        boolean result = false;
+        final MutableBoolean result = new MutableBoolean();
 
-        final List<CtMethod> blueprints = new ArrayList<CtMethod>();
-        class CollectBlueprints extends ExprEditor {
+        method.instrument(new ExprEditor() {
             @Override
             public void edit(MethodCall call) throws CannotCompileException {
                 super.edit(call);
@@ -272,37 +274,45 @@ public abstract class Privilizer<SELF ex
                 } catch (NotFoundException e) {
                     return;
                 }
+                boolean found = false;
                 for (CallTo callTo : blueprintCalls) {
                     final Class<?> owner = callTo.value();
                     if (owner.getName().equals(call.getClassName())) {
-                        if (callTo.methods().length > 0) {
-                            boolean found = false;
-                            for (String m : callTo.methods()) {
-                                found = StringUtils.equals(call.getMethodName(), m);
-                                if (found) {
-                                    break;
-                                }
-                            }
-                            if (!found) {
-                                continue;
+                        if (callTo.methods().length == 0) {
+                            found = true;
+                            break;
+                        }
+                        for (String m : callTo.methods()) {
+                            found = StringUtils.equals(call.getMethodName(), m);
+                            if (found) {
+                                break;
                             }
                         }
-                        blueprints.add(called);
-                        break;
                     }
                 }
-            }
-        }
-        method.instrument(new CollectBlueprints());
-
-        for (CtMethod blueprint : blueprints) {
-            final String name = importedMethodName(blueprint);
+                if (found) {
+                    final String name = importedMethodName(called);
 
-            CtMethod copy = copyBlueprintTo(type, name, blueprint, blueprintCalls);
-            method.instrument(redirect(blueprint, copy));
-            result = true;
-        }
-        return result;
+                    CtMethod copy;
+                    try {
+                        copy = copyBlueprintTo(type, name, called, blueprintCalls);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    Body redirect = new Body(Privilizer.this, "call %s", Privilizer.this.toString(called));
+                    if (Privilizer.this.policy.isConditional()) {
+                        redirect.startBlock("if (%s)", Privilizer.this.policy.condition);
+                    }
+                    redirect.appendLine("$_ = %s($$);", copy.getName());
+                    if (Privilizer.this.policy.isConditional()) {
+                        redirect.endBlock().startBlock("else").appendLine("$_ = $proceed($$);").endBlock();
+                    }
+                    call.replace(redirect.complete().toString());
+                    result.setValue(Boolean.TRUE);
+                }
+            }
+        });
+        return result.booleanValue();
     }
 
     private static String importedMethodName(CtMethod blueprint) {
@@ -311,7 +321,7 @@ public abstract class Privilizer<SELF ex
     }
 
     /*
-     * This design is almost certainly non-optimal. Basically, we have:
+     * This design is almost certainly suboptimal. Basically, we have:
      * 
      * for a declared method, look for calls to blueprint methods for each blueprint method, copy it when copying,
      * inspect blueprint method's code and recursively copy in methods from the source class of *that particular method*
@@ -323,7 +333,7 @@ public abstract class Privilizer<SELF ex
      */
     private CtMethod copyBlueprintTo(final CtClass target, final String toName, final CtMethod method,
         final CallTo[] blueprintCalls) throws ClassNotFoundException, NotFoundException, IOException,
-        IllegalAccessException {
+        IllegalAccessException, CannotCompileException {
         if (!Modifier.isStatic(method.getModifiers())) {
             return null;
         }
@@ -335,8 +345,9 @@ public abstract class Privilizer<SELF ex
         }
         final CtClass declaring = method.getDeclaringClass();
 
+        final List<CtField> referencedFields = new ArrayList<CtField>();
         final List<CtMethod> ownBlueprints = new ArrayList<CtMethod>();
-        class CollectBlueprints extends ExprEditor {
+        class CollectOwnReferences extends ExprEditor {
             @Override
             public void edit(MethodCall m) throws CannotCompileException {
                 super.edit(m);
@@ -350,40 +361,55 @@ public abstract class Privilizer<SELF ex
                     ownBlueprints.add(called);
                 }
             }
+
+            @Override
+            public void edit(FieldAccess f) throws CannotCompileException {
+                super.edit(f);
+                try {
+                    referencedFields.add(f.getField());
+                } catch (NotFoundException e) {
+                }
+            }
         }
-        try {
-            method.instrument(new CollectBlueprints());
+        method.instrument(new CollectOwnReferences());
 
-            boolean isRecursive = false;
+        boolean isRecursive = false;
 
-            for (CtMethod blueprint : ownBlueprints) {
-                if (blueprint.equals(method)) {
-                    // recursive method call identified:
-                    isRecursive = true;
-                    continue;
-                }
-                CtMethod local = copyBlueprintTo(target, importedMethodName(blueprint), blueprint, blueprintCalls);
-                if (local != null) {
-                    method.instrument(redirect(blueprint, local));
-                }
-            }
-            final CtMethod result = CtNewMethod.copy(method, toName, target, null);
-            result.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
-            target.addMethod(result);
-            if (isRecursive) {
-                CodeConverter redirect = new CodeConverter();
-                redirect.redirectMethodCall(method.getName(), result);
-                result.instrument(redirect);
-            }
-            // privilize other classes' blueprint methods recursively:
-            privilizeBlueprints(target, result, blueprintCalls);
-            // privilize:
+        for (CtMethod blueprint : ownBlueprints) {
+            if (blueprint.equals(method)) {
+                // recursive method call identified:
+                isRecursive = true;
+                continue;
+            }
+            CtMethod local = copyBlueprintTo(target, importedMethodName(blueprint), blueprint, blueprintCalls);
+            if (local != null) {
+                method.instrument(redirect(blueprint, local));
+            }
+        }
+        final CtMethod result = CtNewMethod.copy(method, toName, target, null);
+        result.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
+        target.addMethod(result);
+
+        if (!referencedFields.isEmpty()) {
+            handleReferencedFields(target, result, method, referencedFields);
+        }
+        if (isRecursive) {
+            CodeConverter redirectRecursive = new CodeConverter();
+            redirectRecursive.redirectMethodCall(method.getName(), result);
+            result.instrument(redirectRecursive);
+        }
+        // privilize other classes' blueprint methods recursively:
+        privilizeBlueprints(target, result, blueprintCalls);
+
+        // not really possible to check for what truly may throw a SecurityException and thus requires privilizing,
+        // but we'll assume any public method must be. As anything else, once copied,
+        // can only be called from something we have already privilized
+        // TODO? only privilize methods the instrumented class called originally, directly
+        if (Modifier.isPublic(method.getModifiers())) {
             weave(target, result);
-
-            return result;
-        } catch (CannotCompileException e) {
-            return null;
         }
+
+        return result;
     }
 
     private static CodeConverter redirect(CtMethod origMethod, CtMethod substMethod) throws CannotCompileException {
@@ -392,6 +418,80 @@ public abstract class Privilizer<SELF ex
         return result;
     }
 
+    private void handleReferencedFields(final CtClass target, final CtMethod method, final CtMethod source,
+        List<CtField> referencedFields) throws CannotCompileException, NotFoundException {
+
+        method.instrument(new ExprEditor() {
+            @Override
+            public void edit(FieldAccess f) throws CannotCompileException {
+                super.edit(f);
+                CtField fld;
+                boolean primitive;
+                try {
+                    fld = f.getField();
+                    primitive = fld.getType().isPrimitive();
+                } catch (NotFoundException e) {
+                    // no such field implies a reference copied such that the field doesn't exist, probably the usual
+                    // case with blueprinted methods containing field refs
+
+                    fld = null;
+                    primitive = false;
+                    CtClass host = source.getDeclaringClass();
+                    while (host != null) {
+                        try {
+                            fld = host.getDeclaredField(f.getFieldName());
+                            primitive = fld.getType().isPrimitive();
+                            break;
+                        } catch (NotFoundException e1) {
+                        }
+                        try {
+                            host = host.getSuperclass();
+                        } catch (NotFoundException e1) {
+                            break;
+                        }
+                    }
+                    if (fld == null) {
+                        throw new RuntimeException(e);
+                    }
+                }
+                if (Modifier.isPublic(fld.getModifiers()) || !Modifier.isStatic(fld.getModifiers())) {
+                    return;
+                }
+
+                final String replacement;
+                if (f.isReader()) {
+                    replacement =
+                        String.format("$_ = ($%s) %s(%s.class, \"%s\", null);", primitive ? "w" : "r", assistant
+                            .fieldReader(target).getName(), fld.getDeclaringClass().getName(), f.getFieldName());
+                } else {
+                    replacement =
+                        String.format("%s(%s.class, \"%s\", null, %s);", assistant.fieldWriter(target).getName(), fld
+                            .getDeclaringClass().getName(), f.getFieldName(), primitive ? "($w) $1" : "$1");
+                }
+                debug("Replacing %s access of %s.%s", f.isReader() ? "read" : "write", fld.getDeclaringClass()
+                    .getName(), f.getFieldName());
+                debug(replacement);
+                f.replace(replacement);
+            }
+        });
+
+        boolean allPublic = true;
+        for (CtField ctField : referencedFields) {
+            Validate.validState(!ctField.getDeclaringClass().equals(target),
+                "Circular reference; cannot blueprint method %s", toString(source));
+            if (!Modifier.isPublic(ctField.getModifiers())) {
+                allPublic = false;
+                break;
+            }
+        }
+        if (!allPublic) {
+            method.insertBefore(assistant.callPushFieldAccess(target, referencedFields));
+            final boolean asFinally = true;
+            method.insertAfter(new StringBuilder(assistant.popFieldAccess(target).getName()).append("();").toString(),
+                asFinally);
+        }
+    }
+
     protected void debug(String message, Object... args) {
         log.fine(String.format(message, args));
     }
@@ -463,12 +563,7 @@ public abstract class Privilizer<SELF ex
                 sig.append(fld.getType().getName()).append(' ').append(fld.getName());
                 body.appendLine("this.%1$s = %1$s;", fld.getName());
             }
-            sig.append(") ").append(body.complete());
-
-            final String c = sig.toString();
-            debug("Creating action constructor:");
-            debug(c);
-            result.addConstructor(CtNewConstructor.make(c, result));
+            result.addConstructor(CtNewConstructor.make(sig.append(") ").append(body.complete()).toString(), result));
         }
         {
             final StrBuilder run = new StrBuilder("public Object run() ");
@@ -495,12 +590,7 @@ public abstract class Privilizer<SELF ex
                 }
             }
 
-            run.append(body.complete());
-
-            final String r = run.toString();
-            debug("Creating run method:");
-            debug(r);
-            result.addMethod(CtNewMethod.make(r, result));
+            result.addMethod(CtNewMethod.make(run.append(body.complete()).toString(), result));
         }
         getClassFileWriter().write(result);
         debug("Returning action type %s", result);
@@ -542,6 +632,7 @@ public abstract class Privilizer<SELF ex
             AccessLevel.PRIVATE, toString(impl));
 
         final Body body = new Body(this, "new body of %s", toString(method));
+
         if (policy.isConditional()) {
             body.startBlock("if (%s)", policy.condition);
         }
@@ -625,9 +716,7 @@ public abstract class Privilizer<SELF ex
             body.appendLine("%s($$);", impl.getName());
         }
 
-        final String block = body.complete().toString();
-        debug("Setting body of %s to:\n%s", toString(method), block);
-        method.setBody(block);
+        method.setBody(body.complete().toString());
         return true;
     }
 

Modified: commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java (original)
+++ commons/sandbox/weaver/branches/fields/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java Sat Mar 23 18:31:00 2013
@@ -23,10 +23,8 @@ public class PrivilizerWeaver implements
     public static final String CONFIG_ACCESS_LEVEL = CONFIG_WEAVER + "accessLevel";
     public static final String CONFIG_POLICY = CONFIG_WEAVER + "policy";
 
-    private Privilizer<FilesystemPrivilizer> privilizer;
-
+    private Privilizer privilizer;
     private Privilizer.Policy policy;
-
     private AccessLevel targetAccessLevel;
 
     @Override

Modified: commons/sandbox/weaver/branches/fields/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/pom.xml?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/pom.xml (original)
+++ commons/sandbox/weaver/branches/fields/pom.xml Sat Mar 23 18:31:00 2013
@@ -25,7 +25,6 @@
     <version>10-SNAPSHOT</version>
   </parent>
 
-  <groupId>org.apache.commons</groupId>
   <artifactId>commons-weaver</artifactId>
   <version>0.1-SNAPSHOT</version>
   <packaging>pom</packaging>
@@ -95,6 +94,11 @@
         <version>3.1</version>
       </dependency>
       <dependency>
+        <groupId>org.javassist</groupId>
+        <artifactId>javassist</artifactId>
+        <version>3.17.1-GA</version>
+      </dependency>
+      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.11</version>

Modified: commons/sandbox/weaver/branches/fields/processor/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/processor/pom.xml?rev=1460203&r1=1460202&r2=1460203&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/fields/processor/pom.xml (original)
+++ commons/sandbox/weaver/branches/fields/processor/pom.xml Sat Mar 23 18:31:00 2013
@@ -43,6 +43,11 @@ under the License.
       <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>

Added: commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java?rev=1460203&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java (added)
+++ commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java Sat Mar 23 18:31:00 2013
@@ -0,0 +1,291 @@
+/*
+ *  Copyright 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 org.apache.commons.weaver.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.CtNewMethod;
+import javassist.NotFoundException;
+
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.weaver.spi.Weaver;
+
+/**
+ * Helper for Javassist-based {@link Weaver} implementations.
+ */
+public class Assistant {
+
+    /**
+     * Default prefix.
+     */
+    public static final String DEFAULT_PREFIX = "_weaver_assisted_";
+
+    private class LazyExceptionsBody extends Body {
+
+        private LazyExceptionsBody(String message, Object... args) {
+            super(prefix, message, args);
+            startBlock("try");
+        }
+
+        @Override
+        public Body complete() {
+            final String e = generateName("lazyException");
+            endBlock()
+                .startBlock("catch (Exception %s)", e)
+                .appendLine(
+                    "throw %1$s instanceof RuntimeException ? (RuntimeException) %1$s : new RuntimeException(%1$s);", e)
+                .endBlock();
+            return super.complete();
+        }
+    }
+
+    private final ClassPool classPool;
+    private final String prefix;
+
+    /**
+     * Create a new {@link Assistant} with the specified {@link ClassPool} and {@code DEFAULT_PREFIX}.
+     * 
+     * @param classPool
+     */
+    public Assistant(ClassPool classPool) {
+        this(classPool, DEFAULT_PREFIX);
+    }
+
+    /**
+     * Create a new {@link Assistant}.
+     * 
+     * @param classPool
+     *            used
+     * @param prefix
+     *            used for generated elements.
+     */
+    public Assistant(ClassPool classPool, String prefix) {
+        super();
+        this.classPool = classPool;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Generate a name.
+     * 
+     * @param name
+     * @return String
+     */
+    public String generateName(String name) {
+        return new StringBuilder(prefix).append(name).toString();
+    }
+
+    /**
+     * Generate a private method to read fields.
+     * 
+     * @param target
+     * @return CtMethod
+     */
+    public CtMethod fieldReader(CtClass target) {
+        final String name = generateName("readField");
+
+        final CtClass[] params = types(Class.class, String.class, Object.class);
+        try {
+            return target.getDeclaredMethod(name, params);
+        } catch (NotFoundException e) {
+        }
+        try {
+            final CtMethod result =
+                CtNewMethod.make(
+                    new StringBuilder("private static Object ")
+                        .append(name)
+                        .append("(Class type, String name, Object instance)")
+                        .append(
+                            new LazyExceptionsBody("fieldReader").appendLine(
+                                "return type.getDeclaredField(name).get(instance);").complete()).toString(), target);
+
+            target.addMethod(result);
+            return result;
+        } catch (CannotCompileException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generate a private method to write fields.
+     * 
+     * @param target
+     * @return CtMethod
+     */
+    public CtMethod fieldWriter(CtClass target) {
+        final String name = generateName("writeField");
+
+        final CtClass[] params = types(Class.class, String.class, Object.class, Object.class);
+        try {
+            return target.getDeclaredMethod(name, params);
+        } catch (NotFoundException e) {
+        }
+        try {
+            final CtMethod result =
+                CtNewMethod.make(
+                    new StringBuilder("private static void ")
+                        .append(name)
+                        .append("(Class type, String name, Object instance, Object value)")
+                        .append(
+                            new LazyExceptionsBody("fieldWriter").appendLine(
+                                "type.getDeclaredField(name).set(instance, value);").complete()).toString(), target);
+            target.addMethod(result);
+            return result;
+        } catch (CannotCompileException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String callPushFieldAccess(CtClass target, Iterable<CtField> fields) {
+        final Body setAccessible = new LazyExceptionsBody("pushFieldAccess");
+
+        final String flds = generateName("flds");
+
+        setAccessible.appendLine("final java.util.List %s = new java.util.ArrayList();", flds);
+
+        final String fld = generateName("fld");
+
+        if (fields != null) {
+            setAccessible.appendLine("java.lang.reflect.Field %s;", fld);
+            final Set<Pair<String, String>> uniqueFields = new HashSet<Pair<String, String>>();
+            for (CtField field : fields) {
+                if (Modifier.isPublic(field.getModifiers())) {
+                    continue;
+                }
+                final Pair<String, String> pair = Pair.of(field.getDeclaringClass().getName(), field.getName());
+                if (uniqueFields.add(pair)) {
+                    setAccessible.appendLine("%s = %s.class.getDeclaredField(\"%s\");", fld, pair.getLeft(),
+                        pair.getRight());
+                    setAccessible.startBlock("if (!%s.isAccessible())", fld).appendLine("%s.add(%s);", flds, fld)
+                        .endBlock();
+                }
+            }
+        }
+
+        final String fieldArray = generateName("fieldArray");
+        setAccessible
+            .appendLine(
+                "final java.lang.reflect.Field[] %1$s = %2$s.toArray(new java.lang.reflect.Field[%2$s.size()]);",
+                fieldArray, flds).appendLine("%s(%s);", pushFieldAccess(target).getName(), fieldArray).complete();
+
+        return setAccessible.toString();
+    }
+
+    public CtMethod pushFieldAccess(CtClass target) {
+        final String name = generateName("pushFieldAccess");
+
+        final CtClass[] params = types(new Field[0].getClass());
+        try {
+            return target.getDeclaredMethod(name, params);
+        } catch (NotFoundException e) {
+        }
+
+        final String stk = generateName("stk");
+        final String fieldAccessStack = getFieldAccessStack(target).getName();
+
+        Body body =
+            new Body(prefix, "pushFieldAccess").appendLine(
+                "java.lang.reflect.AccessibleObject.setAccessible(fields, true);").appendLine(
+                "java.util.Stack %s = (java.util.Stack) %s.get();", stk, fieldAccessStack);
+
+        body.startBlock("if (%s == null)", stk).appendLine("%s = new java.util.Stack();", stk)
+            .appendLine("%s.set(%s);", fieldAccessStack, stk).endBlock();
+
+        body.appendLine("%s.push(fields);", stk).complete();
+
+        try {
+            final CtMethod result =
+                CtNewMethod.make(
+                    new StringBuilder("private static void ").append(name).append("(java.lang.reflect.Field[] fields)")
+                        .append(body).toString(), target);
+            target.addMethod(result);
+            return result;
+        } catch (CannotCompileException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public CtMethod popFieldAccess(CtClass target) {
+        final String name = generateName("popFieldAccess");
+
+        final CtClass[] params = new CtClass[0];
+        try {
+            return target.getDeclaredMethod(name, params);
+        } catch (NotFoundException e) {
+        }
+
+        final String stk = generateName("stk");
+        final String fieldAccessStack = getFieldAccessStack(target).getName();
+        final String fieldArray = generateName("fieldArray");
+
+        final Body body = new Body(prefix, "popFieldAccess");
+        body.appendLine("java.util.Stack %s = (java.util.Stack) %s.get();", stk, fieldAccessStack)
+            .appendLine("java.lang.reflect.Field[] %s = (java.lang.reflect.Field[]) %s.pop();", fieldArray, stk)
+            .appendLine("java.lang.reflect.AccessibleObject.setAccessible(%s, false);", fieldArray);
+        body.startBlock("if (%s.isEmpty())", stk).appendLine("%s.remove();", fieldAccessStack).endBlock().complete();
+
+        try {
+            final CtMethod result =
+                CtNewMethod.make(new StringBuilder("private static void ").append(name).append("()").append(body)
+                    .toString(), target);
+            target.addMethod(result);
+            return result;
+        } catch (CannotCompileException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private CtField getFieldAccessStack(CtClass target) {
+        final String fieldAccessStackName = generateName("fieldAccessStack");
+
+        try {
+            return target.getField(fieldAccessStackName);
+        } catch (Exception e) {
+            final CtField result;
+            try {
+                result = new CtField(classPool.get(ThreadLocal.class.getName()), fieldAccessStackName, target);
+                result.setModifiers(Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL);
+                target.addField(result, "new ThreadLocal()");
+            } catch (Exception e1) {
+                throw new RuntimeException(e1);
+            }
+            return result;
+        }
+    }
+
+    private CtClass[] types(Class<?>... types) {
+        final CtClass[] result = new CtClass[Validate.noNullElements(types).length];
+        int index = 0;
+        for (Class<?> type : types) {
+            try {
+                result[index++] = classPool.get(type.getName());
+            } catch (NotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return result;
+    }
+
+}

Propchange: commons/sandbox/weaver/branches/fields/processor/src/main/java/org/apache/commons/weaver/utils/Assistant.java
------------------------------------------------------------------------------
    svn:executable = *