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