001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020package org.apache.commons.weaver.model;
021
022import java.lang.annotation.Annotation;
023import java.lang.reflect.AnnotatedElement;
024import java.lang.reflect.Constructor;
025import java.lang.reflect.Field;
026import java.lang.reflect.Method;
027import java.util.Iterator;
028import java.util.NoSuchElementException;
029import java.util.concurrent.ConcurrentNavigableMap;
030import java.util.concurrent.ConcurrentSkipListMap;
031
032import org.apache.commons.lang3.Validate;
033import org.apache.commons.weaver.WeaveProcessor;
034import org.apache.commons.weaver.spi.Weaver;
035
036/**
037 * <p>Encapsulates the result of scanning based on a {@link ScanRequest}. The
038 * scan results are available in a structure corresponding to the Java class
039 * hierarchy; i.e.:
040 * <pre>
041 *   package
042 *   |_class
043 *     |_field
044 *     |_method
045 *     | |_method parameter
046 *     |_constructor
047 *       |_constructor parameter
048 * </pre>
049 * </p><p>
050 * The tree of results can be iterated in this manner using
051 * {@link #getPackages()}. However, if a given {@link Weaver} is known not to
052 * handle packages but some other element, convenience methods are provided
053 * here giving direct access to the various elements that may have been
054 * discovered.
055 * </p>
056 */
057public class ScanResult {
058    private abstract static class Projection<PARENT, CHILD extends AnnotatedElement> implements
059        AnnotatedElements<CHILD> {
060        private final Iterable<PARENT> parents;
061
062        Projection(final Iterable<PARENT> parents) {
063            super();
064            this.parents = parents;
065        }
066
067        protected abstract Iterable<CHILD> childrenOf(PARENT parent);
068
069        @Override
070        public Iterator<CHILD> iterator() {
071            final Iterator<PARENT> parentIterator = parents.iterator();
072            return new Iterator<CHILD>() {
073                private Iterator<CHILD> children = nextChildren();
074
075                @Override
076                public synchronized boolean hasNext() {
077                    return children != null;
078                }
079
080                @Override
081                public synchronized CHILD next() {
082                    if (children == null) {
083                        throw new NoSuchElementException();
084                    }
085                    try {
086                        return children.next();
087                    } finally {
088                        if (!children.hasNext()) {
089                            children = nextChildren();
090                        }
091                    }
092                }
093
094                @Override
095                public void remove() {
096                    throw new UnsupportedOperationException();
097                }
098
099                private Iterator<CHILD> nextChildren() {
100                    while (parentIterator.hasNext()) {
101                        final Iterator<CHILD> prospect = childrenOf(parentIterator.next()).iterator();
102                        if (prospect.hasNext()) {
103                            return prospect;
104                        }
105                    }
106                    return null;
107                }
108            };
109        }
110
111        @Override
112        public AnnotatedElements<CHILD> with(final Class<? extends Annotation> annotationType) {
113            return new AnnotatedWith<CHILD>(this, annotationType);
114        }
115    }
116
117    private static class AnnotatedWith<W extends AnnotatedElement> implements AnnotatedElements<W> {
118        final Iterable<W> wrapped;
119        final Class<? extends Annotation> annotationType;
120
121        AnnotatedWith(final Iterable<W> wrapped, final Class<? extends Annotation> annotationType) {
122            super();
123            this.wrapped = wrapped;
124            this.annotationType = annotationType;
125        }
126
127        @Override
128        public Iterator<W> iterator() {
129            final Iterator<W> iter = wrapped.iterator();
130            return new Iterator<W>() {
131                W next = read();
132
133                private W read() {
134                    while (iter.hasNext()) {
135                        final W element = iter.next();
136                        if (element.isAnnotationPresent(annotationType)) {
137                            return element;
138                        }
139                    }
140                    return null;
141                }
142
143                @Override
144                public boolean hasNext() {
145                    return next != null;
146                }
147
148                @Override
149                public W next() {
150                    if (next == null) {
151                        throw new NoSuchElementException();
152                    }
153                    try {
154                        return next;
155                    } finally {
156                        next = read();
157                    }
158                }
159
160                @Override
161                public void remove() {
162                    throw new UnsupportedOperationException();
163                }
164            };
165        }
166
167        @Override
168        public AnnotatedElements<W> with(final Class<? extends Annotation> annotationType) {
169            return new AnnotatedWith<W>(this, annotationType);
170        }
171
172    }
173
174    private final ConcurrentNavigableMap<String, WeavablePackage> packages =
175        new ConcurrentSkipListMap<String, WeavablePackage>();
176
177    /**
178     * Public for use by {@link WeaveProcessor}.
179     * @param pkg to wrap
180     * @return {@link WeavablePackage}
181     */
182    public WeavablePackage getWeavable(final Package pkg) {
183        final String key = pkg.getName();
184        if (packages.containsKey(key)) {
185            return packages.get(key);
186        }
187        final WeavablePackage result = new WeavablePackage(pkg);
188        final WeavablePackage faster = packages.putIfAbsent(key, result);
189        return faster == null ? result : faster;
190    }
191
192    /**
193     * Public for use by {@link WeaveProcessor}.
194     * @param cls to wrap
195     * @param <T> type
196     * @return {@link WeavableClass}
197     */
198    public <T> WeavableClass<T> getWeavable(final Class<T> cls) {
199        return getWeavable(cls.getPackage()).getWeavable(cls);
200    }
201
202    /**
203     * Public for use by {@link WeaveProcessor}.
204     * @param fld to wrap
205     * @return {@link WeavableField}
206     */
207    public WeavableField<?> getWeavable(final Field fld) {
208        return getWeavable(fld.getDeclaringClass()).getWeavable(fld);
209    }
210
211    /**
212     * Public for use by {@link WeaveProcessor}.
213     * @param methd to wrap
214     * @return {@link WeavableMethod}
215     */
216    public WeavableMethod<?> getWeavable(final Method methd) {
217        return getWeavable(methd.getDeclaringClass()).getWeavable(methd);
218    }
219
220    /**
221     * Public for use by {@link WeaveProcessor}.
222     * @param ctor to wrap
223     * @param <T> type
224     * @return {@link WeavableConstructor}
225     */
226    public <T> WeavableConstructor<T> getWeavable(final Constructor<T> ctor) {
227        return getWeavable(ctor.getDeclaringClass()).getWeavable(ctor);
228    }
229
230    /**
231     * Iterate or filter {@link WeavablePackage}s.
232     * @return {@link AnnotatedElements}
233     */
234    public AnnotatedElements<WeavablePackage> getPackages() {
235        return new AnnotatedElements<WeavablePackage>() {
236
237            @Override
238            public Iterator<WeavablePackage> iterator() {
239                return packages.values().iterator();
240            }
241
242            @Override
243            public AnnotatedElements<WeavablePackage> with(final Class<? extends Annotation> annotationType) {
244                return new AnnotatedWith<WeavablePackage>(packages.values(), annotationType);
245            }
246        };
247    }
248
249    /**
250     * Iterate or filter {@link WeavableClass}es.
251     * @return {@link AnnotatedElements}
252     */
253    public AnnotatedElements<WeavableClass<?>> getClasses() {
254        return new Projection<WeavablePackage, WeavableClass<?>>(getPackages()) {
255
256            @Override
257            protected Iterable<WeavableClass<?>> childrenOf(final WeavablePackage parent) {
258                return parent.getClasses();
259            }
260        };
261    }
262
263    /**
264     * Iterate or filter {@link WeavableClass}es assignable to {@code supertype}.
265     * @param supertype {@link Class} whose subtypes are sought
266     * @return {@link AnnotatedElements}
267     */
268    public AnnotatedElements<WeavableClass<?>> getClassesAssignableTo(final Class<?> supertype) {
269        Validate.notNull(supertype, "supertype");
270
271        return new Projection<WeavablePackage, WeavableClass<?>>(getPackages()) {
272
273            @Override
274            protected Iterable<WeavableClass<?>> childrenOf(final WeavablePackage parent) {
275                return parent.getClasses();
276            }
277
278            @Override
279            public Iterator<WeavableClass<?>> iterator() {
280                final Iterator<WeavableClass<?>> toWrap = super.iterator();
281                return new Iterator<WeavableClass<?>>() {
282                    {
283                        read();
284                    }
285
286                    private WeavableClass<?> next;
287
288                    private void read() {
289                        while (toWrap.hasNext()) {
290                            final WeavableClass<?> test = toWrap.next();
291                            if (supertype.isAssignableFrom(test.getTarget())) {
292                                next = test;
293                                return;
294                            }
295                        }
296                        next = null;
297                    }
298
299                    @Override
300                    public boolean hasNext() {
301                        return next != null;
302                    }
303
304                    @Override
305                    public WeavableClass<?> next() {
306                        try {
307                            return next;
308                        } finally {
309                            read();
310                        }
311                    }
312
313                    @Override
314                    public void remove() {
315                        toWrap.remove();
316                    }
317                };
318            }
319        };
320    }
321
322    /**
323     * Iterate or filter {@link WeavableField}s.
324     * @return {@link AnnotatedElements}
325     */
326    public AnnotatedElements<WeavableField<?>> getFields() {
327        return new Projection<WeavableClass<?>, WeavableField<?>>(getClasses()) {
328
329            @Override
330            protected Iterable<WeavableField<?>> childrenOf(final WeavableClass<?> parent) {
331                @SuppressWarnings({ "unchecked", "rawtypes" })
332                final Iterable<WeavableField<?>> result = ((WeavableClass) parent).getFields();
333                return result;
334            }
335        };
336    }
337
338    /**
339     * Iterate or filter {@link WeavableConstructor}s.
340     * @return {@link AnnotatedElements}
341     */
342    public AnnotatedElements<WeavableConstructor<?>> getConstructors() {
343        return new Projection<WeavableClass<?>, WeavableConstructor<?>>(getClasses()) {
344
345            @Override
346            protected Iterable<WeavableConstructor<?>> childrenOf(final WeavableClass<?> parent) {
347                @SuppressWarnings({ "unchecked", "rawtypes" })
348                final Iterable<WeavableConstructor<?>> result = ((WeavableClass) parent).getConstructors();
349                return result;
350            }
351        };
352    }
353
354    /**
355     * Iterate or filter {@link WeavableMethod}s.
356     * @return {@link AnnotatedElements}
357     */
358    public AnnotatedElements<WeavableMethod<?>> getMethods() {
359        return new Projection<WeavableClass<?>, WeavableMethod<?>>(getClasses()) {
360
361            @Override
362            protected Iterable<WeavableMethod<?>> childrenOf(final WeavableClass<?> parent) {
363                @SuppressWarnings({ "unchecked", "rawtypes" })
364                final Iterable<WeavableMethod<?>> result = ((WeavableClass) parent).getMethods();
365                return result;
366            }
367        };
368    }
369
370    /**
371     * Iterate or filter {@link WeavableMethodParameter}s.
372     * @return {@link AnnotatedElements}
373     */
374    public AnnotatedElements<WeavableMethodParameter<?>> getMethodParameters() {
375        return new Projection<WeavableMethod<?>, WeavableMethodParameter<?>>(getMethods()) {
376
377            @Override
378            protected Iterable<WeavableMethodParameter<?>> childrenOf(final WeavableMethod<?> parent) {
379                @SuppressWarnings({ "unchecked", "rawtypes" })
380                final Iterable<WeavableMethodParameter<?>> result = ((WeavableMethod) parent).getParameters();
381                return result;
382            }
383        };
384    }
385
386    /**
387     * Iterate or filter {@link WeavableConstructorParameter}s.
388     * @return {@link AnnotatedElements}
389     */
390    public AnnotatedElements<WeavableConstructorParameter<?>> getConstructorParameters() {
391
392        return new Projection<WeavableConstructor<?>, WeavableConstructorParameter<?>>(getConstructors()) {
393
394            @Override
395            protected Iterable<WeavableConstructorParameter<?>> childrenOf(final WeavableConstructor<?> parent) {
396                @SuppressWarnings({ "unchecked", "rawtypes" })
397                final Iterable<WeavableConstructorParameter<?>> result = ((WeavableConstructor) parent).getParameters();
398                return result;
399            }
400        };
401    }
402
403}