diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 0696fa5b9da..9aa08b03e78 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -137,6 +137,9 @@ Build * LUCENE-4636: Upgrade ivy to 2.3.0 (Shawn Heisey via Robert Muir) +* LUCENE-4570: Use the Policeman Formbidden API checker, released separately + from Lucene and downloaded via Ivy. (Uwe Schindler, Robert Muir) + ======================= Lucene 4.1.0 ======================= Changes in backwards compatibility policy diff --git a/lucene/build.xml b/lucene/build.xml index 6751ce0f43e..7961b92ac9a 100644 --- a/lucene/build.xml +++ b/lucene/build.xml @@ -157,28 +157,34 @@ - + + + + + + + + + - - - - - - + + + + - + - + diff --git a/lucene/common-build.xml b/lucene/common-build.xml index 45267c7ac41..8056e5b02f3 100644 --- a/lucene/common-build.xml +++ b/lucene/common-build.xml @@ -1902,6 +1902,14 @@ ${tests-output}/junit4-*.suites - per-JVM executed suites + + + + + + + diff --git a/lucene/licenses/asm-debug-all-4.1.jar.sha1 b/lucene/licenses/asm-debug-all-4.1.jar.sha1 deleted file mode 100644 index 09de7a9691d..00000000000 --- a/lucene/licenses/asm-debug-all-4.1.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -dd6ba5c392d4102458494e29f54f70ac534ec2a2 diff --git a/lucene/licenses/asm-debug-all-LICENSE-BSD_LIKE.txt b/lucene/licenses/asm-debug-all-LICENSE-BSD_LIKE.txt deleted file mode 100644 index c5aba7be471..00000000000 --- a/lucene/licenses/asm-debug-all-LICENSE-BSD_LIKE.txt +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2000-2011 INRIA, France Telecom -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holders nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lucene/licenses/asm-debug-all-NOTICE.txt b/lucene/licenses/asm-debug-all-NOTICE.txt deleted file mode 100644 index f6df5a6fe78..00000000000 --- a/lucene/licenses/asm-debug-all-NOTICE.txt +++ /dev/null @@ -1,2 +0,0 @@ -ASM - Lightweight Java Bytecode Manipulation Framework -Copyright © 1999-2012, OW2 Consortium diff --git a/lucene/tools/build.xml b/lucene/tools/build.xml index 55f5b4a2cd7..35310bc1f2b 100644 --- a/lucene/tools/build.xml +++ b/lucene/tools/build.xml @@ -25,7 +25,6 @@ - - - - - - diff --git a/lucene/tools/src/java/lucene-solr.antlib.xml b/lucene/tools/src/java/lucene-solr.antlib.xml index f18d8a3287b..6ab57c6695a 100644 --- a/lucene/tools/src/java/lucene-solr.antlib.xml +++ b/lucene/tools/src/java/lucene-solr.antlib.xml @@ -18,7 +18,4 @@ - diff --git a/lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java b/lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java deleted file mode 100644 index 545e2496195..00000000000 --- a/lucene/tools/src/java/org/apache/lucene/validation/ForbiddenApisCheckTask.java +++ /dev/null @@ -1,498 +0,0 @@ -package org.apache.lucene.validation; - -/* - * 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. - */ - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Label; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.Method; - -import org.apache.tools.ant.AntClassLoader; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.FileSet; -import org.apache.tools.ant.types.Reference; -import org.apache.tools.ant.types.Resource; -import org.apache.tools.ant.types.ResourceCollection; -import org.apache.tools.ant.types.resources.FileResource; -import org.apache.tools.ant.types.resources.Resources; -import org.apache.tools.ant.types.resources.FileResource; -import org.apache.tools.ant.types.resources.StringResource; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.BufferedReader; -import java.io.Reader; -import java.io.File; -import java.io.StringReader; -import java.util.Arrays; -import java.util.Collections; -import java.util.Formatter; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.HashSet; -import java.util.Set; - -/** - * Task to check if a set of class files contains calls to forbidden APIs - * from a given classpath and list of API signatures (either inline or as pointer to files). - * In contrast to other ANT tasks, this tool does only visit the given classpath - * and the system classloader. It uses the local classpath in preference to the system classpath - * (which violates the spec). - */ -public class ForbiddenApisCheckTask extends Task { - - private final Resources classFiles = new Resources(); - private final Resources apiSignatures = new Resources(); - private Path classpath = null; - - private boolean failOnUnsupportedJava = false; - - ClassLoader loader = null; - - final Map classesToCheck = new HashMap(); - final Map classpathClassCache = new HashMap(); - - final Map forbiddenFields = new HashMap(); - final Map forbiddenMethods = new HashMap(); - final Map forbiddenClasses = new HashMap(); - - /** Reads a class (binary name) from the given {@link ClassLoader}. */ - ClassSignatureLookup getClassFromClassLoader(final String clazz) throws BuildException { - ClassSignatureLookup c = classpathClassCache.get(clazz); - if (c == null) { - try { - final InputStream in = loader.getResourceAsStream(clazz.replace('.', '/') + ".class"); - if (in == null) { - throw new BuildException("Loading of class " + clazz + " failed: Not found"); - } - try { - classpathClassCache.put(clazz, c = new ClassSignatureLookup(new ClassReader(in))); - } finally { - in.close(); - } - } catch (IOException ioe) { - throw new BuildException("Loading of class " + clazz + " failed.", ioe); - } - } - return c; - } - - /** Adds the method signature to the list of disallowed methods. The Signature is checked against the given ClassLoader. */ - private void addSignature(final String signature) throws BuildException { - final String clazz, field; - final Method method; - int p = signature.indexOf('#'); - if (p >= 0) { - clazz = signature.substring(0, p); - final String s = signature.substring(p + 1); - p = s.indexOf('('); - if (p >= 0) { - if (p == 0) { - throw new BuildException("Invalid method signature (method name missing): " + signature); - } - // we ignore the return type, its just to match easier (so return type is void): - try { - method = Method.getMethod("void " + s, true); - } catch (IllegalArgumentException iae) { - throw new BuildException("Invalid method signature: " + signature); - } - field = null; - } else { - field = s; - method = null; - } - } else { - clazz = signature; - method = null; - field = null; - } - // check class & method/field signature, if it is really existent (in classpath), but we don't really load the class into JVM: - final ClassSignatureLookup c = getClassFromClassLoader(clazz); - if (method != null) { - assert field == null; - // list all methods with this signature: - boolean found = false; - for (final Method m : c.methods) { - if (m.getName().equals(method.getName()) && Arrays.equals(m.getArgumentTypes(), method.getArgumentTypes())) { - found = true; - forbiddenMethods.put(c.reader.getClassName() + '\000' + m, signature); - // don't break when found, as there may be more covariant overrides! - } - } - if (!found) { - throw new BuildException("No method found with following signature: " + signature); - } - } else if (field != null) { - assert method == null; - if (!c.fields.contains(field)) { - throw new BuildException("No field found with following name: " + signature); - } - forbiddenFields.put(c.reader.getClassName() + '\000' + field, signature); - } else { - assert field == null && method == null; - // only add the signature as class name - forbiddenClasses.put(c.reader.getClassName(), signature); - } - } - - /** Reads a list of API signatures. Closes the Reader when done (on Exception, too)! */ - private void parseApiFile(Reader reader) throws IOException { - final BufferedReader r = new BufferedReader(reader); - try { - String line; - while ((line = r.readLine()) != null) { - line = line.trim(); - if (line.length() == 0 || line.startsWith("#")) - continue; - addSignature(line); - } - } finally { - r.close(); - } - } - - /** Parses a class given as (FileSet) Resource */ - private ClassReader loadClassFromResource(final Resource res) throws BuildException { - try { - final InputStream stream = res.getInputStream(); - try { - return new ClassReader(stream); - } finally { - stream.close(); - } - } catch (IOException ioe) { - throw new BuildException("IO problem while reading class file " + res, ioe); - } - } - - /** Parses a class given as Resource and checks for valid method invocations */ - private int checkClass(final ClassReader reader) { - final int[] violations = new int[1]; - reader.accept(new ClassVisitor(Opcodes.ASM4) { - final String className = Type.getObjectType(reader.getClassName()).getClassName(); - String source = null; - - @Override - public void visitSource(String source, String debug) { - this.source = source; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM4) { - private int lineNo = -1; - - private ClassSignatureLookup lookupRelatedClass(String internalName) { - ClassSignatureLookup c = classesToCheck.get(internalName); - if (c == null) try { - c = getClassFromClassLoader(internalName); - } catch (BuildException be) { - // we ignore lookup errors and simply ignore this related class - c = null; - } - return c; - } - - private boolean checkClassUse(String owner) { - final String printout = forbiddenClasses.get(owner); - if (printout != null) { - log("Forbidden class use: " + printout, Project.MSG_ERR); - return true; - } - return false; - } - - private boolean checkMethodAccess(String owner, Method method) { - if (checkClassUse(owner)) { - return true; - } - final String printout = forbiddenMethods.get(owner + '\000' + method); - if (printout != null) { - log("Forbidden method invocation: " + printout, Project.MSG_ERR); - return true; - } - final ClassSignatureLookup c = lookupRelatedClass(owner); - if (c != null && !c.methods.contains(method)) { - final String superName = c.reader.getSuperName(); - if (superName != null && checkMethodAccess(superName, method)) { - return true; - } - final String[] interfaces = c.reader.getInterfaces(); - if (interfaces != null) { - for (String intf : interfaces) { - if (intf != null && checkMethodAccess(intf, method)) { - return true; - } - } - } - } - return false; - } - - private boolean checkFieldAccess(String owner, String field) { - if (checkClassUse(owner)) { - return true; - } - final String printout = forbiddenFields.get(owner + '\000' + field); - if (printout != null) { - log("Forbidden field access: " + printout, Project.MSG_ERR); - return true; - } - final ClassSignatureLookup c = lookupRelatedClass(owner); - if (c != null && !c.fields.contains(field)) { - final String superName = c.reader.getSuperName(); - if (superName != null && checkFieldAccess(superName, field)) { - return true; - } - final String[] interfaces = c.reader.getInterfaces(); - if (interfaces != null) { - for (String intf : interfaces) { - if (intf != null && checkFieldAccess(intf, field)) { - return true; - } - } - } - } - return false; - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - if (checkMethodAccess(owner, new Method(name, desc))) { - violations[0]++; - reportSourceAndLine(); - } - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (checkFieldAccess(owner, name)) { - violations[0]++; - reportSourceAndLine(); - } - } - - private void reportSourceAndLine() { - final StringBuilder sb = new StringBuilder(" in ").append(className); - if (source != null && lineNo >= 0) { - new Formatter(sb, Locale.ROOT).format(" (%s:%d)", source, lineNo).flush(); - } - log(sb.toString(), Project.MSG_ERR); - } - - @Override - public void visitLineNumber(int lineNo, Label start) { - this.lineNo = lineNo; - } - }; - } - }, ClassReader.SKIP_FRAMES); - return violations[0]; - } - - @Override - public void execute() throws BuildException { - AntClassLoader antLoader = null; - try { - if (classpath != null) { - classpath.setProject(getProject()); - this.loader = antLoader = getProject().createClassLoader(ClassLoader.getSystemClassLoader(), classpath); - // force that loading from this class loader is done first, then parent is asked. - // This violates spec, but prevents classes in any system classpath to be used if a local one is available: - antLoader.setParentFirst(false); - } else { - this.loader = ClassLoader.getSystemClassLoader(); - } - classFiles.setProject(getProject()); - apiSignatures.setProject(getProject()); - - final long start = System.currentTimeMillis(); - - // check if we can load runtime classes (e.g. java.lang.String). - // If this fails, we have a newer Java version than ASM supports: - try { - getClassFromClassLoader(String.class.getName()); - } catch (IllegalArgumentException iae) { - final String msg = String.format(Locale.ROOT, - "Your Java version (%s) is not supported by <%s/>. Please run the checks with a supported JDK!", - System.getProperty("java.version"), getTaskName()); - if (failOnUnsupportedJava) { - throw new BuildException(msg); - } else { - log("WARNING: " + msg, Project.MSG_WARN); - return; - } - } - - try { - @SuppressWarnings("unchecked") - Iterator iter = (Iterator) apiSignatures.iterator(); - if (!iter.hasNext()) { - throw new BuildException("You need to supply at least one API signature definition through apiFile=, , or inner text."); - } - while (iter.hasNext()) { - final Resource r = iter.next(); - if (!r.isExists()) { - throw new BuildException("Resource does not exist: " + r); - } - if (r instanceof StringResource) { - final String s = ((StringResource) r).getValue(); - if (s != null && s.trim().length() > 0) { - log("Reading inline API signatures...", Project.MSG_INFO); - parseApiFile(new StringReader(s)); - } - } else { - log("Reading API signatures: " + r, Project.MSG_INFO); - parseApiFile(new InputStreamReader(r.getInputStream(), "UTF-8")); - } - } - } catch (IOException ioe) { - throw new BuildException("IO problem while reading files with API signatures.", ioe); - } - if (forbiddenMethods.isEmpty() && forbiddenClasses.isEmpty()) { - throw new BuildException("No API signatures found; use apiFile=, , or inner text to define those!"); - } - - log("Loading classes to check...", Project.MSG_INFO); - - @SuppressWarnings("unchecked") - Iterator iter = (Iterator) classFiles.iterator(); - if (!iter.hasNext()) { - throw new BuildException("There is no given or the fileset does not contain any class files to check."); - } - while (iter.hasNext()) { - final Resource r = iter.next(); - if (!r.isExists()) { - throw new BuildException("Class file does not exist: " + r); - } - - ClassReader reader = loadClassFromResource(r); - classesToCheck.put(reader.getClassName(), new ClassSignatureLookup(reader)); - } - - log("Scanning for API signatures and dependencies...", Project.MSG_INFO); - - int errors = 0; - for (final ClassSignatureLookup c : classesToCheck.values()) { - errors += checkClass(c.reader); - } - - log(String.format(Locale.ROOT, - "Scanned %d (and %d related) class file(s) for forbidden API invocations (in %.2fs), %d error(s).", - classesToCheck.size(), classpathClassCache.size(), (System.currentTimeMillis() - start) / 1000.0, errors), - errors > 0 ? Project.MSG_ERR : Project.MSG_INFO); - - if (errors > 0) { - throw new BuildException("Check for forbidden API calls failed, see log."); - } - } finally { - this.loader = null; - if (antLoader != null) antLoader.cleanup(); - antLoader = null; - classesToCheck.clear(); - classpathClassCache.clear(); - forbiddenFields.clear(); - forbiddenMethods.clear(); - forbiddenClasses.clear(); - } - } - - /** Set of class files to check */ - public void add(ResourceCollection rc) { - classFiles.add(rc); - } - - /** A file with API signatures apiFile= attribute */ - public void setApiFile(File file) { - apiSignatures.add(new FileResource(getProject(), file)); - } - - /** Set of files with API signatures as nested element */ - public FileSet createApiFileSet() { - final FileSet fs = new FileSet(); - fs.setProject(getProject()); - apiSignatures.add(fs); - return fs; - } - - /** Support for API signatures list as nested text */ - public void addText(String text) { - apiSignatures.add(new StringResource(getProject(), text)); - } - - /** Classpath as classpath= attribute */ - public void setClasspath(Path classpath) { - createClasspath().append(classpath); - } - - /** Classpath as classpathRef= attribute */ - public void setClasspathRef(Reference r) { - createClasspath().setRefid(r); - } - - /** Classpath as nested element */ - public Path createClasspath() { - if (this.classpath == null) { - this.classpath = new Path(getProject()); - } - return this.classpath.createPath(); - } - - public void setFailOnUnsupportedJava(boolean failOnUnsupportedJava) { - this.failOnUnsupportedJava = failOnUnsupportedJava; - } - - static final class ClassSignatureLookup { - public final ClassReader reader; - public final Set methods; - public final Set fields; - - public ClassSignatureLookup(final ClassReader reader) { - this.reader = reader; - final Set methods = new HashSet(); - final Set fields = new HashSet(); - reader.accept(new ClassVisitor(Opcodes.ASM4) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - final Method m = new Method(name, desc); - methods.add(m); - return null; - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - fields.add(name); - return null; - } - }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - this.methods = Collections.unmodifiableSet(methods); - this.fields = Collections.unmodifiableSet(fields); - } - } - -} diff --git a/solr/build.xml b/solr/build.xml index 9c0cfdf6fb1..963a6c9c667 100644 --- a/solr/build.xml +++ b/solr/build.xml @@ -236,19 +236,29 @@ - + + + + + + + + + + + - - - - - - + + + + + - + @@ -258,8 +268,7 @@ - - + diff --git a/solr/common-build.xml b/solr/common-build.xml index f56e96bb1b7..3a90428a730 100644 --- a/solr/common-build.xml +++ b/solr/common-build.xml @@ -68,6 +68,10 @@ where X.Y.M is the last version released (on this branch). --> + + +