Java tutorial
/* * Copyright 2003-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.attributes; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Field; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.StringTokenizer; /** * An index providing a list of elements with given attributes. This * requires that the attribute is {@link Indexed} and that the * attribute indexer tool has been run on the jar file containing the * classes. * * @since 2.1 */ public class AttributeIndex { /** * Reference to a method parameter. A method parameter * is defined by the Method object it is defined in, and the index * of the parameter in the method's parameter list. * * @since 2.1 */ public static class MethodParameter { private final Method method; private final int index; /** * Constructs a new MethodParameter. * * @since 2.1 */ public MethodParameter(Method method, int index) { this.method = method; this.index = index; } /** * Get the method this parameter is defined in. * * @since 2.1 */ public Method getMethod() { return method; } /** * Get the index of this parameter in the parameter list of the method. * * @since 2.1 */ public int getIndex() { return index; } /** * Compares two <code>MethodParameter</code>s for equality. * They must point to the same method and have the same index. * * @since 2.1 */ public boolean equals(Object o) { return o != null && o instanceof MethodParameter && method.equals(((MethodParameter) o).method) && index == ((MethodParameter) o).index; } /** * Computes the hashCode. * * @since 2.1 */ public int hashCode() { return method.hashCode() + index; } /** * Converts this method parameter into a human-readable string. * * @since 2.1 */ public String toString() { return method.toString() + ":" + index; } } /** * A constructor parameter. A method parameter * is defined by the Method object it is defined in, and the index * of the parameter in the method's parameter list. * * @since 2.1 */ public static class ConstructorParameter { private final Constructor ctor; private final int index; /** * Constructs a new ConstructorParameter. * * @since 2.1 */ public ConstructorParameter(Constructor ctor, int index) { this.ctor = ctor; this.index = index; } /** * Get the constructor this parameter is defined in. * * @since 2.1 */ public Constructor getConstructor() { return ctor; } /** * Get the index of this parameter in the parameter list of the constructor. * * @since 2.1 */ public int getIndex() { return index; } /** * Compares two <code>ConstructorParameter</code>s for equality. * They must point to the same constructor and have the same index. * * @since 2.1 */ public boolean equals(Object o) { return o != null && o instanceof ConstructorParameter && ctor.equals(((ConstructorParameter) o).ctor) && index == ((ConstructorParameter) o).index; } /** * Computes the hashCode. * * @since 2.1 */ public int hashCode() { return ctor.hashCode() + index; } /** * Converts this constructor parameter into a human-readable string. * * @since 2.1 */ public String toString() { return ctor.toString() + ":" + index; } } private static class IndexNode { public Collection classes = new HashSet(); public Collection fields = new HashSet(); public Collection methods = new HashSet(); public Collection constructors = new HashSet(); public Collection returnValues = new HashSet(); public Collection constructorParameters = new HashSet(); public Collection methodParameters = new HashSet(); public void seal() { classes = seal(classes); fields = seal(fields); methods = seal(methods); constructors = seal(constructors); returnValues = seal(returnValues); constructorParameters = seal(constructorParameters); methodParameters = seal(methodParameters); } private Collection seal(Collection coll) { return Collections.unmodifiableCollection(coll); } } private final HashMap index = new HashMap(); private final ClassLoader classLoader; /** * Creates a new AttributeIndex for the given ClassLoader. * * @since 2.1 */ public AttributeIndex(ClassLoader cl) throws Exception { this.classLoader = cl; Enumeration e = cl.getResources("META-INF/attrs.index"); while (e.hasMoreElements()) { URL url = (URL) e.nextElement(); loadFromURL(url); } Iterator iter = index.values().iterator(); while (iter.hasNext()) { ((IndexNode) iter.next()).seal(); } } private IndexNode getNode(Class attributeClass) { IndexNode node = (IndexNode) index.get(attributeClass.getName()); if (node == null) { node = new IndexNode(); index.put(attributeClass.getName(), node); } return node; } private void addIndex(Collection attributes, Class clazz) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).classes.add(clazz); } } private void addIndex(Collection attributes, Field field) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).fields.add(field); } } private void addIndex(Collection attributes, Method method) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).methods.add(method); } } private void addIndex(Collection attributes, Constructor constructor) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).constructors.add(constructor); } } private void addReturnIndex(Collection attributes, Method method) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).returnValues.add(method); } } private void addIndex(Collection attributes, Method method, int parameter) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).methodParameters.add(new MethodParameter(method, parameter)); } } private void addIndex(Collection attributes, Constructor ctor, int parameter) { Iterator iter = attributes.iterator(); while (iter.hasNext()) { getNode(iter.next().getClass()).constructorParameters.add(new ConstructorParameter(ctor, parameter)); } } /** * Add a class to the index. */ private void addClass(String clazzName) throws Exception { Class clazz = classLoader.loadClass(clazzName); // Get the attributes attached to the class itself... Collection coll = Attributes.getAttributes(clazz); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, clazz); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { coll = Attributes.getAttributes(fields[i]); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, fields[i]); } Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { coll = Attributes.getAttributes(methods[i]); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, methods[i]); // Return values coll = Attributes.getReturnAttributes(methods[i]); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addReturnIndex(coll, methods[i]); // Parameters int numParameters = methods[i].getParameterTypes().length; for (int j = 0; j < numParameters; j++) { coll = Attributes.getParameterAttributes(methods[i], j); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, methods[i], j); } } Constructor[] ctors = clazz.getDeclaredConstructors(); for (int i = 0; i < ctors.length; i++) { coll = Attributes.getAttributes(ctors[i]); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, ctors[i]); // Parameters int numParameters = ctors[i].getParameterTypes().length; for (int j = 0; j < numParameters; j++) { coll = Attributes.getParameterAttributes(ctors[i], j); coll = AttributeUtil.getObjectsWithAttributeType(coll, Indexed.class); addIndex(coll, ctors[i], j); } } } /** * Load the attrs.index from a given URL. * * @since 2.1 */ private void loadFromURL(URL url) throws Exception { URLConnection connection = url.openConnection(); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); try { String currentAttributeClass = null; String line = null; while ((line = br.readLine()) != null) { if (line.startsWith("Class: ")) { String className = line.substring("Class: ".length()).trim(); addClass(className); } } } finally { br.close(); } } /** * Gets a Collection of the classes that have an attribute of the specified class. * The Collection contains the class names (String). * * @deprecated Use the getClasses(Class) method instead. * * @since 2.1 */ public Collection getClassesWithAttribute(String attributeClass) { if (index.containsKey(attributeClass)) { Collection classes = ((IndexNode) index.get(attributeClass)).classes; Iterator iter = classes.iterator(); Collection converted = new ArrayList(classes.size()); while (iter.hasNext()) { converted.add(((Class) iter.next()).getName().replace('$', '.')); } return converted; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the classes that have an attribute of the specified class. * The Collection contains the class names (String). * * @deprecated Use the getClasses(Class) method instead. */ public Collection getClassesWithAttribute(Class attributeClass) { return getClassesWithAttribute(attributeClass.getName()); } /** * Gets a Collection of the <code>Class</code>es that have an attribute of the specified class. * The Collection contains the classes (Class). * * @since 2.1 */ public Collection getClasses(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).classes; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>Method</code>s that have an attribute of the specified class. * The Collection contains the methods (java.lang.reflect.Method). * * @since 2.1 */ public Collection getMethods(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).methods; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>Method</code>s whose return value has an attribute of the specified class. * The Collection contains the methods (java.lang.reflect.Method). * * @since 2.1 */ public Collection getMethodsReturning(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).returnValues; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>Field</code>s that have an attribute of the specified class. * The Collection contains the methods (java.lang.reflect.Field). * * @since 2.1 */ public Collection getFields(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).fields; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>Constructor</code>s that have an attribute of the specified class. * The Collection contains the methods (java.lang.reflect.Constructor). * * @since 2.1 */ public Collection getConstructors(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).constructors; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>ConstructorParameter</code>s that have an attribute of the specified class. * The Collection contains the methods ({@link AttributeIndex.ConstructorParameter}). * * @since 2.1 */ public Collection getConstructorParameters(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).constructorParameters; } else { return Collections.EMPTY_SET; } } /** * Gets a Collection of the <code>MethodParameter</code>s that have an attribute of the specified class. * The Collection contains the methods ({@link AttributeIndex.MethodParameter}). * * @since 2.1 */ public Collection getMethodParameters(Class attributeClass) { if (index.containsKey(attributeClass.getName())) { return ((IndexNode) index.get(attributeClass.getName())).methodParameters; } else { return Collections.EMPTY_SET; } } }