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/07/30 17:18:02 UTC

svn commit: r1508483 - in /commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver: ./ src/main/java/org/apache/commons/weaver/privilizer/ src/main/java/org/apache/commons/weaver/privilizer/asm/ src/main/resources/META-INF/services/

Author: mbenson
Date: Tue Jul 30 15:18:01 2013
New Revision: 1508483

URL: http://svn.apache.org/r1508483
Log:
privilizer with ASM working

Added:
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java   (with props)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java   (with props)
Removed:
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java
Modified:
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/   (props changed)
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner
    commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver

Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml Tue Jul 30 15:18:01 2013
@@ -52,15 +52,10 @@
       <groupId>org.javassist</groupId>
       <artifactId>javassist</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.ow2.asm</groupId>
-      <artifactId>asm</artifactId>
-    </dependency>
   </dependencies>
-
   <build>
     <plugins>
-      <plugin>
+      <!--plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-invoker-plugin</artifactId>
         <configuration>
@@ -83,7 +78,42 @@
             </goals>
           </execution>
         </executions>
-      </plugin>
+      </plugin-->
     </plugins>
   </build>
+  <profiles>
+    <profile>
+      <id>basic</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm-commons</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm-tree</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm-util</artifactId>
+        </dependency>
+      </dependencies>
+    </profile>
+    <profile>
+      <id>dev</id>
+      <dependencies>
+        <dependency>
+          <groupId>org.ow2.asm</groupId>
+          <artifactId>asm-debug-all</artifactId>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
 </project>

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Jul 30 15:18:01 2013
@@ -0,0 +1 @@
+bytecode

Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java Tue Jul 30 15:18:01 2013
@@ -18,6 +18,10 @@ package org.apache.commons.weaver.privil
 import java.lang.reflect.Modifier;
 import java.util.EnumSet;
 import java.util.Locale;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
 
 public enum AccessLevel {
     PUBLIC(Modifier.PUBLIC), PROTECTED(Modifier.PROTECTED), PACKAGE(0), PRIVATE(Modifier.PRIVATE);
@@ -29,16 +33,21 @@ public enum AccessLevel {
     }
 
     public static AccessLevel of(int mod) {
+        final Set<AccessLevel> matched = EnumSet.noneOf(AccessLevel.class);
         if (Modifier.isPublic(mod)) {
-            return PUBLIC;
+            matched.add(PUBLIC);
         }
         if (Modifier.isProtected(mod)) {
-            return PROTECTED;
+            matched.add(PROTECTED);
         }
         if (Modifier.isPrivate(mod)) {
-            return PRIVATE;
+            matched.add(PRIVATE);
+        }
+        if (matched.isEmpty()) {
+            return PACKAGE;
         }
-        return PACKAGE;
+        Validate.isTrue(matched.size() == 1, "%s seems to declare multiple access modifiers: %s", mod, matched);
+        return matched.iterator().next();
     }
 
     public int merge(int mod) {
@@ -62,4 +71,17 @@ public enum AccessLevel {
     public static AccessLevel defaultValue() {
         return AccessLevel.PRIVATE;
     }
+
+    /**
+     * Parse from a {@link String} returning {@link #defaultValue()} for blank/null input.
+     * 
+     * @param s
+     * @return {@link AccessLevel}
+     */
+    public static AccessLevel parse(String s) {
+        if (StringUtils.isBlank(s)) {
+            return defaultValue();
+        }
+        return valueOf(s.trim().toUpperCase(Locale.US));
+    }
 }

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,77 @@
+/*
+ * 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.commons.weaver.privilizer;
+
+import java.security.PrivilegedAction;
+import java.util.Locale;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Weaving policy: when to use {@link PrivilegedAction}s.
+ */
+public enum Policy {
+    /**
+     * Disables weaving.
+     */
+    NEVER,
+
+    /**
+     * Weaves such that the check for an active {@link SecurityManager} is done once only.
+     */
+    ON_INIT,
+
+    /**
+     * Weaves such that the check for an active {@link SecurityManager} is done for each {@link Privileged} method
+     * execution.
+     */
+    DYNAMIC,
+
+    /**
+     * Weaves such that {@link Privileged} methods are always executed as such.
+     */
+    ALWAYS;
+
+    /**
+     * Get the {@link Policy} value that should be used as a default.
+     * 
+     * @return {@link Policy#DYNAMIC}
+     */
+    public static Policy defaultValue() {
+        return DYNAMIC;
+    }
+
+    /**
+     * Parse from a {@link String} returning {@link #defaultValue()} for blank/null input.
+     * 
+     * @param s
+     * @return {@link Policy}
+     */
+    public static Policy parse(String s) {
+        if (StringUtils.isBlank(s)) {
+            return defaultValue();
+        }
+        return valueOf(s.trim().toUpperCase(Locale.US));
+    }
+
+    public boolean isConditional() {
+        return this == ON_INIT || this == DYNAMIC;
+    }
+
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,30 @@
+/*
+ * 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.commons.weaver.privilizer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Class-retention annotation to mark privilized classes.
+ */
+@Target(ElementType.TYPE)
+public @interface Privilized {
+    Policy value();
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java Tue Jul 30 15:18:01 2013
@@ -17,23 +17,18 @@ package org.apache.commons.weaver.privil
 
 import java.io.File;
 import java.lang.annotation.ElementType;
-import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.weaver.model.ScanRequest;
 import org.apache.commons.weaver.model.Scanner;
 import org.apache.commons.weaver.model.WeavableClass;
 import org.apache.commons.weaver.model.WeaveEnvironment;
 import org.apache.commons.weaver.model.WeaveInterest;
-import org.apache.commons.weaver.privilizer.Privilizer.Policy;
-import org.apache.commons.weaver.privilizer.Privilizer.Privilized;
+import org.apache.commons.weaver.privilizer.asm.Privilizer;
 import org.apache.commons.weaver.spi.Cleaner;
-import org.apache.commons.weaver.utils.URLArray;
-import org.apache.xbean.finder.archive.FileArchive;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.Opcodes;
@@ -41,30 +36,22 @@ import org.objectweb.asm.Opcodes;
 /**
  * Removes classes privilized with a different policy.
  */
-/*
- * Implemented with ASM in anticipation of the rest of the privilizer being rewritten :P
- */
 public class PrivilizerCleaner implements Cleaner {
     private static final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
     private static final Logger LOG = Logger.getLogger(PrivilizerCleaner.class.getName());
 
     @Override
     public boolean clean(WeaveEnvironment environment, Scanner scanner) {
-        final ClassLoader classLoader = new URLClassLoader(URLArray.fromPaths(environment.classpath));
-        final FileArchive fileArchive = new FileArchive(classLoader, environment.target);
+        final Privilizer privilizer = new Privilizer(environment);
 
-        final String policyConfig = environment.config.getProperty(PrivilizerWeaver.CONFIG_POLICY);
-        final Privilizer.Policy policy =
-            StringUtils.isEmpty(policyConfig) ? Privilizer.Policy.defaultValue() : Privilizer.Policy
-                .valueOf(policyConfig);
         final List<String> toDelete = new ArrayList<String>();
 
         final ScanRequest scanRequest = new ScanRequest().add(WeaveInterest.of(Privilized.class, ElementType.TYPE));
 
-        LOG.log(Level.FINE, "Cleaning classes privilized with policy other than {0}", policy);
+        LOG.log(Level.FINE, "Cleaning classes privilized with policy other than {0}", privilizer.policy);
         for (WeavableClass<?> weavableClass : scanner.scan(scanRequest).getClasses().with(Privilized.class)) {
             final Policy privilizedPolicy = weavableClass.getAnnotation(Privilized.class).value();
-            if (privilizedPolicy == policy) {
+            if (privilizedPolicy == privilizer.policy) {
                 continue;
             }
             final String className = weavableClass.getTarget().getName();
@@ -72,7 +59,7 @@ public class PrivilizerCleaner implement
                 new Object[] { className, privilizedPolicy });
 
             try {
-                final ClassReader classReader = new ClassReader(fileArchive.getBytecode(className));
+                final ClassReader classReader = new ClassReader(privilizer.fileArchive.getBytecode(className));
                 classReader.accept(new ClassVisitor(Opcodes.ASM4) {
                     @Override
                     public void visit(int version, int access, String name, String signature, String superName,

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,229 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+
+import javassist.Modifier;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.builder.Builder;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.signature.SignatureWriter;
+
+/**
+ * Generates the Privileged[Exception?]Action class to privilize a given Method.
+ */
+class ActionGenerator extends Privilizer.WriteClass implements Builder<Type> {
+    final PrivilizingVisitor owner;
+    final Method m;
+    final boolean exc;
+    final Type[] exceptions;
+    final String simpleName;
+    final Type action;
+    final Method impl;
+    final int index;
+    final boolean implIsStatic;
+    final Method helper;
+    final Type result;
+    final Field[] fields;
+    private final Type actionInterface;
+
+    ActionGenerator(final int access, final Method m, final String[] exceptions, PrivilizingVisitor owner) {
+        owner.privilizer().super(new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES));
+        this.m = m;
+        this.exc = ArrayUtils.isNotEmpty(exceptions);
+        this.exceptions = exc ? new Type[] { Type.getType(Exception.class) } : null;
+        this.owner = owner;
+        this.simpleName = generateName(m);
+        this.action = Type.getObjectType(owner.className + '$' + simpleName);
+
+        int privilegedAccessIndex = -1;
+        String implName = null;
+        for (Map.Entry<Method, String> e : owner.privilegedMethods.entrySet()) {
+            privilegedAccessIndex++;
+            if (e.getKey().equals(m)) {
+                implName = e.getValue();
+                break;
+            }
+        }
+        Validate.validState(implName != null);
+
+        this.index = privilegedAccessIndex;
+
+        this.impl = new Method(implName, m.getDescriptor());
+        this.implIsStatic = Modifier.isStatic(access);
+        final Type[] args = implIsStatic ? m.getArgumentTypes() : ArrayUtils.add(m.getArgumentTypes(), 0, owner.target);
+        this.helper = new Method(privilizer().generateName("access$" + index), m.getReturnType(), args);
+        this.result = privilizer().wrap(m.getReturnType());
+        this.fields = fields(args);
+        this.actionInterface = Type.getType(exc ? PrivilegedExceptionAction.class : PrivilegedAction.class);
+    }
+
+    private static String generateName(Method m) {
+        final StringBuilder b = new StringBuilder(m.getName());
+        if (m.getArgumentTypes().length > 0) {
+            b.append("$$");
+            for (Type arg : m.getArgumentTypes()) {
+                b.append(arg.getDescriptor().replace("[", "arrayOf").replace('/', '_').replace(';', '$'));
+            }
+        }
+        return b.append("_ACTION").toString();
+    }
+
+    private static Field[] fields(Type[] args) {
+        final Field[] result = new Field[args.length];
+
+        for (int i = 0; i < args.length; i++) {
+            final String name = new StringBuilder("f").append(i + 1).toString();
+            result[i] = new Field(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, name, args[i]);
+        }
+        return result;
+    }
+
+    @Override
+    public Type build() {
+        generateHelper();
+        begin();
+        init();
+        impl();
+        visitEnd();
+        owner.privilizer().debug("Generated %s implementation %s to call %s#%s", actionInterface.getClassName(),
+            action.getClassName(), owner.target.getClassName(), helper);
+        return action;
+    }
+
+    /**
+     * We must add special methods for inner classes to invoke their owners' methods, according to the scheme "access$n"
+     * where n is the index into this (ordered) map. Additionally we will prefix the whole thing like we usually do
+     * (__privileged_):
+     */
+    private void generateHelper() {
+        owner.privilizer().debug("Generating static helper method %s.%s to call %s", owner.target.getClassName(),
+            helper, impl);
+        final GeneratorAdapter mg =
+            new GeneratorAdapter(Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, helper, null, exceptions, owner);
+
+        mg.visitCode();
+        mg.loadArgs();
+        if (implIsStatic) {
+            mg.invokeStatic(owner.target, impl);
+        } else {
+            mg.invokeVirtual(owner.target, impl);
+        }
+        mg.returnValue();
+        mg.endMethod();
+    }
+
+    private void begin() {
+        owner.visitInnerClass(action.getInternalName(), owner.className, simpleName, Opcodes.ACC_PRIVATE
+            | Opcodes.ACC_STATIC);
+
+        final SignatureWriter type = new SignatureWriter();
+        final SignatureVisitor actionImplemented = type.visitInterface();
+        actionImplemented.visitClassType(actionInterface.getInternalName());
+        final SignatureVisitor visitTypeArgument = actionImplemented.visitTypeArgument('=');
+        final SignatureReader result = new SignatureReader(privilizer().wrap(m.getReturnType()).getDescriptor());
+        result.accept(visitTypeArgument);
+        actionImplemented.visitEnd();
+
+        final String signature = type.toString();
+
+        visit(Opcodes.V1_5, Opcodes.ACC_SUPER | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL, action.getInternalName(),
+            signature, Type.getType(Object.class).getInternalName(), new String[] { actionInterface.getInternalName() });
+    }
+
+    /**
+     * Add fields and generate constructor.
+     * 
+     * @param cv
+     */
+    private void init() {
+        for (Field field : fields) {
+            visitField(field.access, field.name, field.type.getDescriptor(), null, null).visitEnd();
+        }
+        final Method init = new Method("<init>", Type.VOID_TYPE, helper.getArgumentTypes());
+
+        final GeneratorAdapter mg =
+            new GeneratorAdapter(Opcodes.ACC_PRIVATE, init, null, Privilizer.EMPTY_TYPE_ARRAY, this);
+
+        mg.visitCode();
+        final Label begin = mg.mark();
+
+        // invoke super constructor
+        mg.loadThis();
+        mg.invokeConstructor(Type.getType(Object.class), Method.getMethod("void <init> ()"));
+        // assign remaining fields
+
+        int arg = 0;
+        for (Field field : fields) {
+            mg.loadThis();
+            mg.loadArg(arg++);
+            mg.putField(action, field.name, field.type);
+        }
+
+        mg.returnValue();
+        final Label end = mg.mark();
+
+        // declare local vars
+        mg.visitLocalVariable("this", action.getDescriptor(), null, begin, end, 0);
+        arg = 1;
+        for (Field field : fields) {
+            mg.visitLocalVariable("arg" + arg, field.type.getDescriptor(), null, begin, end, arg++);
+        }
+        mg.endMethod();
+    }
+
+    /**
+     * Generate impl method.
+     * 
+     * @param cv
+     */
+    private void impl() {
+        final Method run = new Method("run", result, Privilizer.EMPTY_TYPE_ARRAY);
+
+        final GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, run, null, exceptions, this);
+
+        for (Field field : fields) {
+            mg.loadThis();
+            mg.getField(action, field.name, field.type);
+        }
+
+        mg.invokeStatic(owner.target, helper);
+
+        if (m.getReturnType().getSort() < Type.ARRAY) {
+            mg.valueOf(m.getReturnType());
+        }
+
+        mg.returnValue();
+
+        mg.endMethod();
+    }
+
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,489 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+class BlueprintingVisitor extends Privilizer.PrivilizerClassVisitor {
+
+    private final Set<Type> blueprintTypes = new HashSet<Type>();
+    private final Map<Pair<Type, Method>, MethodNode> blueprintRegistry = new HashMap<Pair<Type, Method>, MethodNode>();
+
+    private final Map<Pair<Type, Method>, String> importedMethods = new HashMap<Pair<Type, Method>, String>();
+
+    private final Map<Type, Map<Method, MethodNode>> methodCache = new HashMap<Type, Map<Method, MethodNode>>();
+    private final Map<Pair<Type, String>, FieldAccess> fieldAccessMap = new HashMap<Pair<Type, String>, FieldAccess>();
+
+    private final ClassVisitor next;
+
+    BlueprintingVisitor(Privilizer privilizer, ClassVisitor cv, Privilizing config) {
+        privilizer.super(new ClassNode(Opcodes.ASM4));
+        this.next = cv;
+
+        // load up blueprint methods:
+        for (Privilizing.CallTo callTo : config.value()) {
+            final Type blueprintType = Type.getType(callTo.value());
+            blueprintTypes.add(blueprintType);
+            for (Map.Entry<Method, MethodNode> e : getMethods(blueprintType).entrySet()) {
+                boolean found = false;
+                if (callTo.methods().length == 0) {
+                    found = true;
+                } else {
+                    for (String name : callTo.methods()) {
+                        if (e.getKey().getName().equals(name)) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                if (found) {
+                    blueprintRegistry.put(Pair.of(blueprintType, e.getKey()), e.getValue());
+                }
+            }
+        }
+    }
+
+    private Map<Method, MethodNode> getMethods(final Type type) {
+        if (methodCache.containsKey(type)) {
+            return methodCache.get(type);
+        }
+        final ClassNode classNode = read(type.getClassName());
+        final Map<Method, MethodNode> result = new HashMap<Method, MethodNode>();
+
+        @SuppressWarnings("unchecked")
+        final List<MethodNode> methods = classNode.methods;
+
+        for (MethodNode methodNode : methods) {
+            if (Modifier.isStatic(methodNode.access) && !"<clinit>".equals(methodNode.name)) {
+                result.put(new Method(methodNode.name, methodNode.desc), methodNode);
+            }
+        }
+        methodCache.put(type, result);
+        return result;
+    }
+
+    private ClassNode read(String className) {
+        final ClassNode result = new ClassNode(Opcodes.ASM4);
+        try {
+            new ClassReader(privilizer().fileArchive.getBytecode(className)).accept(result, ClassReader.SKIP_DEBUG
+                | ClassReader.EXPAND_FRAMES);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return result;
+    }
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+        Validate.isTrue(!blueprintTypes.contains(Type.getObjectType(name)),
+            "Class %s cannot declare itself as a blueprint!", name);
+        super.visit(version, access, name, signature, superName, interfaces);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        return new MethodInvocationHandler(mv) {
+            @Override
+            boolean shouldImport(Pair<Type, Method> methodKey) {
+                return blueprintRegistry.containsKey(methodKey);
+            }
+        };
+    }
+
+    private String importMethod(Pair<Type, Method> key) {
+        if (importedMethods.containsKey(key)) {
+            return importedMethods.get(key);
+        }
+        final String result =
+            new StringBuilder(key.getLeft().getInternalName().replace('/', '_')).append("$$")
+                .append(key.getRight().getName()).toString();
+        importedMethods.put(key, result);
+
+        privilizer().debug("importing %s#%s as %s", key.getLeft().getClassName(), key.getRight(), result);
+        final int access = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC;
+
+        final MethodNode source = getMethods(key.getLeft()).get(key.getRight());
+
+        @SuppressWarnings("unchecked")
+        final String[] exceptions = (String[]) source.exceptions.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
+
+        // non-public fields accessed
+        final Set<FieldAccess> fieldAccesses = new LinkedHashSet<FieldAccess>();
+
+        source.accept(new FieldAccessAccumulator(fieldAccesses));
+
+        final MethodNode withAccessibleAdvice =
+            new MethodNode(access, result, source.desc, source.signature, exceptions);
+
+        // spider own methods:
+        MethodVisitor mv = new NestedMethodInvocationHandler(withAccessibleAdvice, key.getLeft());
+
+        if (!fieldAccesses.isEmpty()) {
+            // accessesNonPublicFields = true;
+            mv = new AccessibleAdvisor(mv, access, result, source.desc, new ArrayList<FieldAccess>(fieldAccesses));
+        }
+
+        source.accept(mv);
+
+        if (Modifier.isPrivate(source.access)) {
+            // can only be called by other privileged methods, so no need to mark as privileged
+        } else {
+            withAccessibleAdvice.visitAnnotation(Type.getType(Privileged.class).getDescriptor(), false).visitEnd();
+        }
+
+        withAccessibleAdvice.accept(this.cv);
+
+        return result;
+    }
+
+    private FieldAccess fieldAccess(final Type owner, String name, Type desc) {
+        final Pair<Type, String> key = Pair.of(owner, name);
+        if (!fieldAccessMap.containsKey(key)) {
+            try {
+                final MutableObject<Type> next = new MutableObject<Type>(owner);
+                final Deque<Type> stk = new ArrayDeque<Type>();
+                while (next.getValue() != null) {
+                    stk.push(next.getValue());
+                    new ClassReader(privilizer().fileArchive.getBytecode(next.getValue().getInternalName())).accept(
+                        privilizer().new PrivilizerClassVisitor() {
+                            @Override
+                            public void visit(int version, int access, String name, String signature, String superName,
+                                String[] interfaces) {
+                                super.visit(version, access, name, signature, superName, interfaces);
+                                next.setValue(Type.getObjectType(superName));
+                            }
+
+                            @Override
+                            public FieldVisitor visitField(int access, String name, String desc, String signature,
+                                Object value) {
+                                for (Type type : stk) {
+                                    final Pair<Type, String> k = Pair.of(type, name);
+                                    // skip shadowed fields:
+                                    if (!fieldAccessMap.containsKey(k)) {
+                                        fieldAccessMap.put(k, new FieldAccess(access, target, name, Type.getType(desc)));
+                                    }
+                                }
+                                return null;
+                            }
+                        }, ClassReader.SKIP_CODE);
+                    if (fieldAccessMap.containsKey(key)) {
+                        break;
+                    }
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            } finally {
+
+            }
+            Validate.isTrue(fieldAccessMap.containsKey(key), "Could not locate %s.%s", owner.getClassName(), name);
+        }
+        return fieldAccessMap.get(key);
+    }
+
+    @Override
+    public void visitEnd() {
+        super.visitEnd();
+//        if (privilizer().verify) {
+//            final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+//            ((ClassNode) cv).accept(classWriter);
+//            privilizer().verify(target, classWriter.toByteArray());
+//        }
+        ((ClassNode) cv).accept(next);
+    }
+
+    private abstract class MethodInvocationHandler extends MethodVisitor {
+        MethodInvocationHandler(MethodVisitor mv) {
+            super(Opcodes.ASM4, mv);
+        }
+
+        @Override
+        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+            if (opcode == Opcodes.INVOKESTATIC) {
+                final Method m = new Method(name, desc);
+                final Pair<Type, Method> methodKey = Pair.of(Type.getObjectType(owner), m);
+                if (shouldImport(methodKey)) {
+                    final String importedName = importMethod(methodKey);
+                    super.visitMethodInsn(opcode, className, importedName, desc);
+                    return;
+                }
+            }
+            super.visitMethodInsn(opcode, owner, name, desc);
+        }
+
+        abstract boolean shouldImport(Pair<Type, Method> methodKey);
+    }
+
+    class NestedMethodInvocationHandler extends MethodInvocationHandler {
+        final Type owner;
+
+        NestedMethodInvocationHandler(MethodVisitor mv, Type owner) {
+            super(mv);
+            this.owner = owner;
+        }
+
+        @Override
+        boolean shouldImport(Pair<Type, Method> methodKey) {
+            // call anything called within a class hierarchy:
+            final Type called = methodKey.getLeft();
+            // "I prefer the short cut":
+            if (called.equals(owner)) {
+                return true;
+            }
+            try {
+                final Class<?> inner = load(called);
+                final Class<?> outer = load(owner);
+                return inner.isAssignableFrom(outer);
+            } catch (ClassNotFoundException e) {
+                return false;
+            }
+        }
+
+        private Class<?> load(Type t) throws ClassNotFoundException {
+            return privilizer().classLoader.loadClass(t.getClassName());
+        }
+    }
+
+    private class FieldAccessAccumulator extends MethodVisitor {
+        final Set<FieldAccess> fieldAccesses;
+
+        FieldAccessAccumulator(Set<FieldAccess> fieldAccesses) {
+            super(Opcodes.ASM4);
+            this.fieldAccesses = fieldAccesses;
+        }
+
+        @Override
+        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+            final FieldAccess fieldAccess = fieldAccess(Type.getObjectType(owner), name, Type.getType(desc));
+
+            super.visitFieldInsn(opcode, owner, name, desc);
+            if (!Modifier.isPublic(fieldAccess.access)) {
+                fieldAccesses.add(fieldAccess);
+            }
+        }
+
+    }
+
+    private class AccessibleAdvisor extends AdviceAdapter {
+        final Type bitSetType = Type.getType(BitSet.class);
+        final Type classType = Type.getType(Class.class);
+        final Type fieldType = Type.getType(java.lang.reflect.Field.class);
+        final Type fieldArrayType = Type.getType(java.lang.reflect.Field[].class);
+        final Type stringType = Type.getType(String.class);
+
+        final List<FieldAccess> fieldAccesses;
+        final Label begin = new Label();
+        int localFieldArray;
+        int bitSet;
+        int fieldCounter;
+
+        AccessibleAdvisor(MethodVisitor mv, int access, String name, String desc, List<FieldAccess> fieldAccesses) {
+            super(ASM4, mv, access, name, desc);
+            this.fieldAccesses = fieldAccesses;
+        }
+
+        @Override
+        protected void onMethodEnter() {
+            localFieldArray = newLocal(fieldArrayType);
+            bitSet = newLocal(bitSetType);
+            fieldCounter = newLocal(Type.INT_TYPE);
+
+            // create localFieldArray
+            push(fieldAccesses.size());
+            newArray(fieldArrayType.getElementType());
+            storeLocal(localFieldArray);
+
+            // create bitSet
+            newInstance(bitSetType);
+            dup();
+            push(fieldAccesses.size());
+            invokeConstructor(bitSetType, Method.getMethod("void <init>(int)"));
+            storeLocal(bitSet);
+
+            // populate localFieldArray
+            push(0);
+            storeLocal(fieldCounter);
+            for (FieldAccess access : fieldAccesses) {
+                prehandle(access);
+                iinc(fieldCounter, 1);
+            }
+            mark(begin);
+        }
+
+        private void prehandle(FieldAccess access) {
+            // push owner.class literal
+            visitLdcInsn(access.owner);
+            push(access.name);
+            final Label next = new Label();
+            invokeVirtual(classType, new Method("getDeclaredField", fieldType, new Type[] { stringType }));
+
+            dup();
+            // store the field at localFieldArray[fieldCounter]:
+            loadLocal(localFieldArray);
+            swap();
+            loadLocal(fieldCounter);
+            swap();
+            arrayStore(fieldArrayType.getElementType());
+
+            dup();
+            invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("boolean isAccessible()"));
+
+            final Label setAccessible = new Label();
+            // if false, setAccessible:
+            ifZCmp(EQ, setAccessible);
+
+            // else pop field instance
+            pop();
+            // and record that he was already accessible:
+            loadLocal(bitSet);
+            loadLocal(fieldCounter);
+            invokeVirtual(bitSetType, Method.getMethod("void set(int)"));
+            goTo(next);
+
+            mark(setAccessible);
+            push(true);
+            invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("void setAccessible(boolean)"));
+
+            mark(next);
+        }
+
+        @Override
+        public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+            final Pair<Type, String> key = Pair.of(Type.getObjectType(owner), name);
+            final FieldAccess fieldAccess = fieldAccessMap.get(key);
+            Validate.isTrue(fieldAccesses.contains(fieldAccess), "Cannot find field %s", key);
+            final int fieldIndex = fieldAccesses.indexOf(fieldAccess);
+
+            privilizer().debug("accessing field %s with opcode %s", fieldIndex, opcode);
+            visitInsn(NOP);
+            loadLocal(localFieldArray);
+            push(fieldIndex);
+            arrayLoad(fieldArrayType.getElementType());
+            checkCast(fieldType);
+
+            final Method access;
+            if (opcode == PUTSTATIC) {
+                // value should have been at top of stack on entry; position the field under the value:
+                swap();
+                // add null object for static field deref and swap under value:
+                push((String) null);
+                swap();
+                if (fieldAccess.type.getSort() < Type.ARRAY) {
+                    // box value:
+                    valueOf(fieldAccess.type);
+                }
+                access = Method.getMethod("void set(Object, Object)");
+            } else {
+                access = Method.getMethod("Object get(Object)");
+                // add null object for static field deref:
+                push((String) null);
+            }
+
+            invokeVirtual(fieldType, access);
+
+            if (opcode == GETSTATIC) {
+                checkCast(privilizer().wrap(fieldAccess.type));
+                if (fieldAccess.type.getSort() < Type.ARRAY) {
+                    unbox(fieldAccess.type);
+                }
+            }
+        }
+
+        @Override
+        public void visitMaxs(int maxStack, int maxLocals) {
+            // put try-finally around the whole method
+            final Label fy = mark();
+            // null exception type signifies finally block:
+            final Type exceptionType = null;
+            catchException(begin, fy, exceptionType);
+            onFinally();
+            throwException();
+            super.visitMaxs(maxStack, maxLocals);
+        }
+
+        @Override
+        protected void onMethodExit(int opcode) {
+            if (opcode != ATHROW) {
+                onFinally();
+            }
+        }
+
+        private void onFinally() {
+            // loop over fields and return any non-null element to being inaccessible:
+            push(0);
+            storeLocal(fieldCounter);
+
+            final Label test = mark();
+            final Label increment = new Label();
+            final Label endFinally = new Label();
+
+            loadLocal(fieldCounter);
+            push(fieldAccesses.size());
+            ifCmp(Type.INT_TYPE, GeneratorAdapter.GE, endFinally);
+
+            loadLocal(bitSet);
+            loadLocal(fieldCounter);
+            invokeVirtual(bitSetType, Method.getMethod("boolean get(int)"));
+
+            // if true, increment:
+            ifZCmp(NE, increment);
+
+            loadLocal(localFieldArray);
+            loadLocal(fieldCounter);
+            arrayLoad(fieldArrayType.getElementType());
+            push(false);
+            invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("void setAccessible(boolean)"));
+
+            mark(increment);
+            iinc(fieldCounter, 1);
+            goTo(test);
+            mark(endFinally);
+        }
+    }
+}

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,72 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.objectweb.asm.Type;
+
+/**
+ * Represents a Java field.
+ */
+public class Field {
+    public final int access;
+    public final String name;
+    public final Type type;
+
+    public Field(int access, String name, Type type) {
+        super();
+        this.access = access;
+        this.name = Validate.notNull(name);
+        this.type = Validate.notNull(type);
+    }
+
+    /**
+     * Considers name and type.
+     * 
+     * @param obj
+     * @return whether equal
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Field == false) {
+            return false;
+        }
+        final Field other = (Field) obj;
+        return StringUtils.equals(other.name, name) && ObjectUtils.equals(other.type, type);
+    }
+
+    /**
+     * Considers name and type.
+     * 
+     * @return hashCode
+     */
+    @Override
+    public int hashCode() {
+        int result = 57 << 2;
+        result |= name.hashCode();
+        result <<= 4;
+        result |= type.hashCode();
+        return result;
+    }
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,48 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import org.objectweb.asm.Type;
+
+public class FieldAccess extends Field {
+    public final Type owner;
+
+    public FieldAccess(int access, Type owner, String name, Type type) {
+        super(access, name, type);
+        this.owner = owner;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof FieldAccess == false) {
+            return false;
+        }
+        return super.equals(obj) && ((FieldAccess) obj).owner.equals(owner);
+    }
+
+    @Override
+    public int hashCode() {
+        final int result = super.hashCode() << 4;
+        return result | owner.hashCode();
+    }
+
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,80 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.util.Map;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.tree.ClassNode;
+
+/**
+ * For any privileged method called from another privileged method (actually the internal implementation method copied
+ * from the original method body) the call is replaced by a call to the target's internal implementation method, thus
+ * avoiding nested privileged invocations when possible. Persists everything to a tree model until the parent is
+ * complete; allowing us to use a tree model while yet building the high-level view as a stack of visitors.
+ */
+class InlineNestedPrivilegedCalls extends ClassNode {
+    private final Privilizer privilizer;
+
+    private final ClassVisitor next;
+
+    /**
+     * Map of original method to name of internal implementation method
+     */
+    private final Map<Method, String> privilegedMethods;
+
+    InlineNestedPrivilegedCalls(Privilizer privilizer, Map<Method, String> privilegedMethods, ClassVisitor next) {
+        super(Opcodes.ASM4);
+        this.privilizer = privilizer;
+        this.privilegedMethods = privilegedMethods;
+        this.next = next;
+    }
+
+    @Override
+    public void visitEnd() {
+        super.visitEnd();
+
+        accept(new ClassVisitor(Opcodes.ASM4, next) {
+            @Override
+            public MethodVisitor visitMethod(int access, final String name, String desc, String signature,
+                String[] exceptions) {
+                final Method outer = new Method(name, desc);
+                final MethodVisitor orig = super.visitMethod(access, name, desc, signature, exceptions);
+                if (privilegedMethods.containsValue(name)) {
+                    return new MethodVisitor(Opcodes.ASM4, orig) {
+                        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+                            if (owner.equals(InlineNestedPrivilegedCalls.this.name)) {
+                                final Method m = new Method(name, desc);
+                                if (privilegedMethods.containsKey(m)) {
+                                    name = privilegedMethods.get(m);
+                                    privilizer.debug("Inlining call from %s to %s as %s", outer, m, name);
+                                }
+                            }
+                            super.visitMethodInsn(opcode, owner, name, desc);
+                        }
+                    };
+                }
+                return orig;
+            }
+        });
+    }
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,249 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.weaver.model.WeaveEnvironment;
+import org.apache.commons.weaver.privilizer.AccessLevel;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.utils.URLArray;
+import org.apache.xbean.finder.archive.FileArchive;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.util.CheckClassAdapter;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+public class Privilizer {
+    abstract class PrivilizerClassVisitor extends ClassVisitor {
+        String className;
+        Type target;
+
+        protected PrivilizerClassVisitor() {
+            this(null);
+        }
+
+        protected PrivilizerClassVisitor(ClassVisitor cv) {
+            super(Opcodes.ASM4, cv);
+        }
+
+        protected Privilizer privilizer() {
+            return Privilizer.this;
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            super.visit(version, access, name, signature, superName, interfaces);
+            className = name;
+            target = Type.getObjectType(name);
+        }
+    }
+
+    class WriteClass extends PrivilizerClassVisitor {
+        WriteClass(ClassWriter cw) {
+            super(cw);
+        }
+
+        @Override
+        public void visitEnd() {
+            super.visitEnd();
+            final byte[] bytecode = ((ClassWriter) cv).toByteArray();
+
+            if (verify) {
+                verify(target, bytecode);
+            }
+
+            final File f = new File(fileArchive.getDir(), className.replace('.', File.separatorChar) + ".class");
+            try {
+                FileUtils.writeByteArrayToFile(f, bytecode);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static final String CONFIG_WEAVER = "privilizer.";
+
+    public static final String CONFIG_ACCESS_LEVEL = CONFIG_WEAVER + "accessLevel";
+
+    public static final String CONFIG_POLICY = CONFIG_WEAVER + "policy";
+
+    public static final String CONFIG_VERIFY = CONFIG_WEAVER + "verify";
+
+    private static final Logger log = Logger.getLogger(PrivilizerWeaver.class.getName());
+
+    private static final String GENERATE_NAME = "__privileged_%s";
+
+    static final Type[] EMPTY_TYPE_ARRAY = new Type[0];
+
+    public final AccessLevel accessLevel;
+    public final ClassLoader classLoader;
+    public final FileArchive fileArchive;
+    public final Policy policy;
+    public final boolean verify;
+
+    private final List<String> classpath;
+    final Set<Class<?>> woven;
+
+    public Privilizer(WeaveEnvironment weaveEnvironment) {
+        super();
+        this.policy = Policy.parse(weaveEnvironment.config.getProperty(CONFIG_POLICY));
+        this.accessLevel = AccessLevel.parse(weaveEnvironment.config.getProperty(CONFIG_ACCESS_LEVEL));
+        this.classpath = weaveEnvironment.classpath;
+        classLoader = new URLClassLoader(URLArray.fromPaths(weaveEnvironment.classpath));
+        fileArchive = new FileArchive(classLoader, weaveEnvironment.target);
+        verify = BooleanUtils.toBoolean(weaveEnvironment.config.getProperty(CONFIG_VERIFY));
+        woven = new HashSet<Class<?>>();
+    }
+
+    protected void debug(String message, Object... args) {
+        log.fine(String.format(message, args));
+    }
+
+    protected void verbose(String message, Object... args) {
+        log.fine(String.format(message, args));
+    }
+
+    protected void warn(String message, Object... args) {
+        log.warning(String.format(message, args));
+    }
+
+    protected void info(String message, Object... args) {
+        log.info(String.format(message, args));
+    }
+
+    protected void error(String message, Object... args) {
+        log.severe(String.format(message, args));
+    }
+
+    String generateName(String simple) {
+        return String.format(GENERATE_NAME, simple);
+    }
+
+    Type wrap(Type t) {
+        switch (t.getSort()) {
+            case Type.BOOLEAN:
+                return Type.getType(Boolean.class);
+            case Type.BYTE:
+                return Type.getType(Byte.class);
+            case Type.SHORT:
+                return Type.getType(Short.class);
+            case Type.INT:
+                return Type.getType(Integer.class);
+            case Type.CHAR:
+                return Type.getType(Character.class);
+            case Type.LONG:
+                return Type.getType(Long.class);
+            case Type.FLOAT:
+                return Type.getType(Float.class);
+            case Type.DOUBLE:
+                return Type.getType(Double.class);
+            case Type.VOID:
+                return Type.getType(Void.class);
+            default:
+                return t;
+        }
+    }
+
+    void blueprint(final Class<?> type, final Privilizing privilizing) {
+        debug("blueprinting class %s %s", type.getName(), privilizing);
+        try {
+            final ClassReader classReader = new ClassReader(fileArchive.getBytecode(type.getName()));
+
+            ClassVisitor cv;
+            cv = new WriteClass(new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
+            cv = new PrivilizingVisitor(this, cv);
+            cv = new BlueprintingVisitor(this, cv, privilizing);
+
+            classReader.accept(cv, ClassReader.EXPAND_FRAMES);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    void privilize(final Class<?> type) {
+        debug("privilizing class %s", type.getName());
+        try {
+            final ClassReader classReader = new ClassReader(fileArchive.getBytecode(type.getName()));
+            ClassVisitor cv;
+            cv = new WriteClass(new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
+            cv = new PrivilizingVisitor(this, cv);
+
+            classReader.accept(cv, ClassReader.EXPAND_FRAMES);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    void verify(final Type target, final byte[] bytecode) {
+        final ClassReader reader = new ClassReader(bytecode);
+
+        // use a new classloader that is always up to date:
+        final ClassLoader verifyClassLoader = new URLClassLoader(URLArray.fromPaths(classpath)) {
+            @Override
+            protected Class<?> findClass(String name) throws ClassNotFoundException {
+                if (target.getClassName().equals(name)) {
+                    final Class<?> result = defineClass(target.getClassName(), bytecode, 0, bytecode.length);
+                    resolveClass(result);
+                    return result;
+                }
+                return super.findClass(name);
+            }
+        };
+
+        final StringWriter w = new StringWriter();
+        CheckClassAdapter.verify(reader, verifyClassLoader, false, new PrintWriter(w));
+        final String error = w.toString();
+        if (!error.isEmpty()) {
+            error(error);
+            final StringWriter trace = new StringWriter();
+            reader.accept(new TraceClassVisitor(new PrintWriter(trace)), ClassReader.SKIP_DEBUG);
+            debug(trace.toString());
+            throw new IllegalStateException();
+        }
+        Validate.validState(StringUtils.isBlank(error), error);
+
+        final ClassVisitor checkInnerClasses = new ClassVisitor(Opcodes.ASM4, null) {
+            final Set<String> innerNames = new HashSet<String>();
+
+            @Override
+            public void visitInnerClass(String name, String outerName, String innerName, int access) {
+                super.visitInnerClass(name, outerName, innerName, access);
+                Validate.validState(innerNames.add(innerName), "%s already defined", innerName);
+            }
+        };
+        reader.accept(checkInnerClasses, ClassReader.SKIP_CODE);
+    }
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,84 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.lang.annotation.ElementType;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.weaver.model.ScanRequest;
+import org.apache.commons.weaver.model.Scanner;
+import org.apache.commons.weaver.model.WeavableClass;
+import org.apache.commons.weaver.model.WeaveEnvironment;
+import org.apache.commons.weaver.model.WeaveInterest;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilized;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.spi.Weaver;
+
+public class PrivilizerWeaver implements Weaver {
+    @Override
+    public boolean process(WeaveEnvironment weaveEnvironment, Scanner scanner) {
+        final Privilizer privilizer = new Privilizer(weaveEnvironment);
+
+        final Set<Class<?>> privilizedTypes = new LinkedHashSet<Class<?>>();
+
+        // handle blueprints:
+        for (WeavableClass<?> type : scanner.scan(
+            new ScanRequest().add(WeaveInterest.of(Privilizing.class, ElementType.TYPE))).getClasses()) {
+
+            final Class<?> t = type.getTarget();
+            if (privilizedTypes.add(t) && validateRequest(privilizer, type)) {
+                privilizer.blueprint(t, type.getAnnotation(Privilizing.class));
+            }
+        }
+
+        // handle remaining classes declaring @Privileged methods:
+
+        for (WeavableClass<?> type : scanner.scan(
+            new ScanRequest().add(WeaveInterest.of(Privileged.class, ElementType.METHOD))).getClasses()) {
+            final Class<?> t = type.getTarget();
+            if (privilizedTypes.add(t) && validateRequest(privilizer, type)) {
+                privilizer.privilize(t);
+            }
+        }
+        return !privilizedTypes.isEmpty();
+    }
+
+    /**
+     * Validate a weaving request for a given target type.
+     * 
+     * @param privilizer
+     * @param type
+     * 
+     * @return whether weaving should proceed
+     * @throws IllegalStateException if class has already been woven with some other policy
+     */
+    private boolean validateRequest(Privilizer privilizer, WeavableClass<?> type) {
+        Privilized marker = type.getAnnotation(Privilized.class);
+        if (marker == null) {
+            return privilizer.policy != Policy.NEVER;
+        }
+        Validate.validState(privilizer.policy == marker.value(), "%s already privilized with policy %s", type
+            .getTarget().getName(), marker.value());
+        return false;
+    }
+}

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,234 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javassist.Modifier;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.weaver.privilizer.AccessLevel;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilized;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.commons.StaticInitMerger;
+
+class PrivilizingVisitor extends Privilizer.PrivilizerClassVisitor {
+    final Map<Method, String> privilegedMethods = new LinkedHashMap<Method, String>();
+    boolean annotated;
+    final Policy policy;
+    final AccessLevel accessLevel;
+
+    PrivilizingVisitor(Privilizer privilizer, ClassVisitor cv) {
+        privilizer.super();
+        this.policy = privilizer.policy;
+        this.accessLevel = privilizer.accessLevel;
+        this.cv =
+            new InlineNestedPrivilegedCalls(privilizer, privilegedMethods, new StaticInitMerger(
+                privilizer.generateName("clinit"), cv));
+    }
+
+    private void annotate() {
+        if (!annotated) {
+            annotated = true;
+            final AnnotationVisitor privilizedVisitor =
+                super.visitAnnotation(Type.getType(Privilized.class).getDescriptor(), false);
+            privilizedVisitor.visitEnum("value", Type.getType(Policy.class).getDescriptor(), policy.name());
+            privilizedVisitor.visitEnd();
+        }
+    }
+
+    @Override
+    public void visitInnerClass(String name, String outerName, String innerName, int access) {
+        annotate();
+        super.visitInnerClass(name, outerName, innerName, access);
+    }
+
+    @Override
+    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+        annotate();
+        return super.visitField(access, name, desc, signature, value);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
+        final String[] exceptions) {
+        annotate();
+        final MethodVisitor originalMethod = super.visitMethod(access, name, desc, signature, exceptions);
+        final Method m = new Method(name, desc);
+
+        return new GeneratorAdapter(Opcodes.ASM4, originalMethod, access, name, desc) {
+
+            @Override
+            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                if (Type.getType(Privileged.class).getDescriptor().equals(desc)) {
+                    final AccessLevel localAccessLevel = AccessLevel.of(access);
+                    if (accessLevel.compareTo(localAccessLevel) > 0) {
+                        throw new RuntimeException(new IllegalAccessException("Method " + className + "#" + m
+                            + " must have maximum access level '" + accessLevel + "' but is defined wider ('"
+                            + localAccessLevel + "')"));
+                    }
+                    if (AccessLevel.PACKAGE.compareTo(accessLevel) > 0) {
+                        privilizer().warn("Possible security leak: granting privileges to %s method %s.%s",
+                            localAccessLevel, className, m);
+                    }
+                    privilegedMethods.put(m, privilizer().generateName(name));
+                }
+                return super.visitAnnotation(desc, visible);
+            }
+
+            @Override
+            public void visitCode() {
+                super.visitCode();
+                if (!privilegedMethods.containsKey(m)) {
+                    return;
+                }
+                final String impl = privilegedMethods.get(m);
+                final boolean instanceMethod = !Modifier.isStatic(access);
+
+                if (policy.isConditional()) {
+                    // test, loading boolean
+                    if (policy == Policy.ON_INIT) {
+                        getStatic(target, privilizer().generateName("hasSecurityManager"), Type.BOOLEAN_TYPE);
+                    } else if (policy == Policy.DYNAMIC) {
+                        checkSecurityManager(this);
+                    }
+                    final Label doPrivileged = new Label();
+                    
+                    // if true, goto doPrivileged:
+                    ifZCmp(NE, doPrivileged);
+
+                    final Method implMethod = new Method(impl, desc);
+                    if (instanceMethod) {
+                        loadThis();
+                        loadArgs();
+                        invokeVirtual(target, implMethod);
+                    } else {
+                        loadArgs();
+                        invokeStatic(target, implMethod);
+                    }
+                    returnValue();
+                    mark(doPrivileged);
+                }
+
+                // generate action:
+                final Type[] ctorArgs;
+                if (instanceMethod) {
+                    ctorArgs = ArrayUtils.add(m.getArgumentTypes(), 0, target);
+                } else {
+                    ctorArgs = m.getArgumentTypes();
+                }
+                final Type actionType = new ActionGenerator(access, m, exceptions, PrivilizingVisitor.this).build();
+                newInstance(actionType);
+                dup();
+                if (instanceMethod) {
+                    loadThis();
+                }
+                loadArgs();
+                invokeConstructor(actionType, new Method("<init>", Type.VOID_TYPE, ctorArgs));
+
+                final boolean exc = ArrayUtils.isNotEmpty(exceptions);
+                // mark try if needed
+                final Label privTry = exc ? mark() : null;
+
+                // execute action
+                final Type arg =
+                    exc ? Type.getType(PrivilegedExceptionAction.class) : Type.getType(PrivilegedAction.class);
+                final Method doPrivileged = new Method("doPrivileged", Type.getType(Object.class), new Type[] { arg });
+                invokeStatic(Type.getType(AccessController.class), doPrivileged);
+
+                unbox(m.getReturnType());
+                returnValue();
+
+                if (exc) {
+                    final Type caught = Type.getType(PrivilegedActionException.class);
+                    // end try
+                    final Label privCatch = mark();
+                    // catch
+                    catchException(privTry, privCatch, caught);
+                    // unwrap
+                    invokeVirtual(caught, new Method("getException", Type.getType(Exception.class),
+                        Privilizer.EMPTY_TYPE_ARRAY));
+                    // throw
+                    throwException();
+                }
+
+                // end original method
+                endMethod();
+
+                // substitute an impl visitor and continue
+                mv = cv.visitMethod(AccessLevel.PRIVATE.merge(access), impl, desc, signature, exceptions);
+                mv.visitCode();
+            }
+        };
+
+    }
+
+    public void visitEnd() {
+        annotate();
+        if (privilizer().policy == Policy.ON_INIT) {
+            final String fieldName = privilizer().generateName("hasSecurityManager");
+
+            visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, fieldName,
+                Type.BOOLEAN_TYPE.getDescriptor(), null, null).visitEnd();
+
+            final GeneratorAdapter mg =
+                new GeneratorAdapter(Opcodes.ACC_STATIC, new Method("<clinit>", "()V"), null,
+                    Privilizer.EMPTY_TYPE_ARRAY, this);
+            checkSecurityManager(mg);
+            mg.putStatic(target, fieldName, Type.BOOLEAN_TYPE);
+            mg.returnValue();
+            mg.endMethod();
+
+            super.visitEnd();
+        }
+    }
+
+    /**
+     * Generates the instructions to push onto the stack whether there is a security manager available
+     * 
+     * @param mg
+     */
+    private static void checkSecurityManager(GeneratorAdapter mg) {
+        final Label setFalse = new Label();
+        final Label done = new Label();
+        mg.invokeStatic(Type.getType(System.class),
+            new Method("getSecurityManager", Type.getType(SecurityManager.class), Privilizer.EMPTY_TYPE_ARRAY));
+        mg.ifNull(setFalse);
+        mg.push(true);
+        mg.goTo(done);
+        mg.mark(setFalse);
+        mg.push(false);
+        mg.mark(done);
+    }
+}
\ No newline at end of file

Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner Tue Jul 30 15:18:01 2013
@@ -15,5 +15,5 @@
 # specific language governing permissions and limitations
 # under the License.
 
-# this class gets picked up by the WeaveProcessor
+# this class gets picked up by the CleanProcessor
 org.apache.commons.weaver.privilizer.PrivilizerCleaner

Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver Tue Jul 30 15:18:01 2013
@@ -16,4 +16,4 @@
 # under the License.
 
 # this class gets picked up by the WeaveProcessor
-org.apache.commons.weaver.privilizer.PrivilizerWeaver
+org.apache.commons.weaver.privilizer.asm.PrivilizerWeaver