View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.weaver.privilizer;
20  
21  import java.io.InputStream;
22  import java.lang.annotation.ElementType;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.weaver.model.ScanRequest;
27  import org.apache.commons.weaver.model.Scanner;
28  import org.apache.commons.weaver.model.WeavableClass;
29  import org.apache.commons.weaver.model.WeaveEnvironment;
30  import org.apache.commons.weaver.model.WeaveInterest;
31  import org.apache.commons.weaver.spi.Cleaner;
32  import org.objectweb.asm.ClassReader;
33  import org.objectweb.asm.ClassVisitor;
34  
35  /**
36   * Removes classes privilized with a different policy.
37   */
38  public class PrivilizerCleaner implements Cleaner {
39  
40      @Override
41      public boolean clean(final WeaveEnvironment environment, final Scanner scanner) {
42          final Privilizer privilizer = new Privilizer(environment);
43  
44          final List<String> toDelete = new ArrayList<>();
45  
46          final ScanRequest scanRequest = new ScanRequest().add(WeaveInterest.of(Privilized.class, ElementType.TYPE));
47  
48          environment.debug("Cleaning classes privilized with policy other than %s", privilizer.policy);
49          for (final WeavableClass<?> weavableClass : scanner.scan(scanRequest).getClasses().with(Privilized.class)) {
50              final Policy privilizedPolicy = Policy.valueOf(weavableClass.getAnnotation(Privilized.class).value());
51              if (privilizedPolicy == privilizer.policy) {
52                  continue;
53              }
54              final String className = weavableClass.getTarget().getName();
55              environment.debug("Class %s privilized with %s; deleting.", className, privilizedPolicy);
56  
57              try (InputStream bytecode = privilizer.env.getClassfile(className).getInputStream()) {
58                  final ClassReader classReader = new ClassReader(bytecode);
59                  classReader.accept(new ClassVisitor(Privilizer.ASM_VERSION) {
60                      @Override
61                      @SuppressWarnings("PMD.UseVarargs") // overridden method
62                      public void visit(final int version, final int access, final String name, final String signature,
63                          final String superName, final String[] interfaces) {
64                          toDelete.add(name);
65                      }
66  
67                      @Override
68                      public void visitInnerClass(final String name, final String outerName, final String innerName,
69                          final int access) {
70                          if (toDelete.contains(outerName)) {
71                              toDelete.add(name);
72                          }
73                      }
74                  }, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES);
75              } catch (final Exception e) {
76                  throw new IllegalStateException(e);
77              }
78          }
79          boolean result = false;
80          for (final String className : toDelete) {
81              final String resourcePath = toResourcePath(className);
82              final boolean success = environment.deleteResource(resourcePath);
83              environment.debug("Deletion of resource %s was %ssuccessful.", resourcePath, success ? "" : "un");
84              result |= success;
85          }
86          return result;
87      }
88  
89      private static String toResourcePath(final String className) {
90          return className.replace('.', '/') + ".class";
91      }
92  
93  }