001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.citation;
031
032import java.lang.reflect.Method;
033import java.util.Collection;
034import java.util.LinkedHashSet;
035import java.util.Set;
036
037import org.openimaj.citation.annotation.Reference;
038import org.openimaj.citation.annotation.References;
039
040/**
041 * Listener that registers instances of {@link Reference} annotations.
042 * 
043 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
044 */
045public class ReferenceListener {
046        private static Set<Reference> references = new LinkedHashSet<Reference>();
047
048        static {
049                addOpenIMAJReference();
050        }
051
052        private static synchronized void addOpenIMAJReference() {
053                try {
054                        final Class<?> clz = ReferenceListener.class.getClassLoader().loadClass("org.openimaj.OpenIMAJ");
055                        addReference(clz);
056                } catch (final ClassNotFoundException e) {
057                        // assume that core-citation is being used outside OpenIMAJ
058                        // and that thus you don't want/need an OI reference.
059                }
060        }
061
062        /**
063         * Register the given {@link Reference}
064         * 
065         * @param r
066         *            the {@link Reference}
067         */
068        public static synchronized void addReference(Reference r) {
069                references.add(r);
070        }
071
072        /**
073         * Register the any {@link Reference} or {@link References} from the given
074         * class.
075         * 
076         * @param clz
077         *            the class
078         */
079        public static void addReference(Class<?> clz) {
080                final Reference ann = clz.getAnnotation(Reference.class);
081
082                if (ann != null)
083                        addReference(ann);
084
085                final References ann2 = clz.getAnnotation(References.class);
086                if (ann2 != null)
087                        for (final Reference r : ann2.references())
088                                addReference(r);
089
090                processPackage(clz);
091        }
092
093        private static void processPackage(Class<?> clz) {
094                Package base = clz.getPackage();
095
096                while (base != null) {
097                        if (base.isAnnotationPresent(Reference.class))
098                                addReference(base.getAnnotation(Reference.class));
099
100                        if (base.isAnnotationPresent(References.class))
101                                for (final Reference r : base.getAnnotation(References.class).references())
102                                        addReference(r);
103
104                        final String name = base.getName();
105                        final int dot = name.lastIndexOf(".");
106
107                        if (dot < 0)
108                                break;
109
110                        base = Package.getPackage(name.substring(0, dot));
111                }
112        }
113
114        /**
115         * Register the any {@link Reference} or {@link References} from the given
116         * method.
117         * 
118         * @param clz
119         *            the class
120         * @param methodName
121         * @param signature
122         */
123        public static void addReference(Class<?> clz, String methodName, String signature) {
124                for (final Method m : clz.getDeclaredMethods()) {
125                        if (m.getName().equals(methodName) && m.toString().endsWith(signature)) {
126                                final Reference ann = m.getAnnotation(Reference.class);
127
128                                if (ann != null)
129                                        addReference(ann);
130
131                                final References ann2 = m.getAnnotation(References.class);
132                                if (ann2 != null)
133                                        for (final Reference r : ann2.references())
134                                                addReference(r);
135                        }
136                }
137
138                processPackage(clz);
139        }
140
141        /**
142         * Reset the references held by the listener, returning the current set of
143         * references.
144         * 
145         * @return the current set of references.
146         */
147        public static synchronized Set<Reference> reset() {
148                final Set<Reference> oldRefs = references;
149                references = new LinkedHashSet<Reference>();
150                addOpenIMAJReference();
151                return oldRefs;
152        }
153
154        /**
155         * Get a copy of the references collected by the listener
156         * 
157         * @return the references.
158         */
159        public static synchronized Set<Reference> getReferences() {
160                return new LinkedHashSet<Reference>(references);
161        }
162
163        /**
164         * Register the given {@link Reference}s
165         * 
166         * @param refs
167         *            the {@link Reference}s
168         */
169        public static void addReferences(Collection<Reference> refs) {
170                references.addAll(refs);
171        }
172}