001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.webengine.jaxrs.scan;
013
014import java.io.IOException;
015import java.io.InputStream;
016import java.net.URL;
017import java.util.ArrayList;
018import java.util.Collection;
019import java.util.Enumeration;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.Map;
023import java.util.Set;
024
025import org.objectweb.asm.ClassReader;
026import org.osgi.framework.Bundle;
027
028/**
029 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
030 */
031public class Scanner {
032
033    public final static String PATH_ANNO = "Ljavax/ws/rs/Path;";
034
035    public final static String PROVIDER_ANNO = "Ljavax/ws/rs/ext/Provider;";
036
037    protected Bundle bundle;
038
039    protected String packageBase;
040
041    protected Map<String, Collection<Class<?>>> collectors;
042
043    public Scanner(Bundle bundle, String packageBase) {
044        this(bundle, packageBase, PATH_ANNO, PROVIDER_ANNO);
045    }
046
047    public Scanner(Bundle bundle, String packageBase, String... annotations) {
048        this.bundle = bundle;
049        this.packageBase = packageBase == null ? "/" : packageBase;
050        this.collectors = new HashMap<String, Collection<Class<?>>>();
051        for (String annotation : annotations) {
052            addCollector(annotation);
053        }
054    }
055
056    public void addCollector(String annotation) {
057        collectors.put(annotation, new ArrayList<Class<?>>());
058    }
059
060    public void addCollector(String annotation, Collection<Class<?>> collector) {
061        collectors.put(annotation, collector);
062    }
063
064    public Collection<Class<?>> getCollector(String annotation) {
065        return collectors.get(annotation);
066    }
067
068    public Map<String, Collection<Class<?>>> getCollectors() {
069        return collectors;
070    }
071
072    @SuppressWarnings("unchecked")
073    public void scan() throws ReflectiveOperationException, IOException {
074        Enumeration<URL> urls = bundle.findEntries(packageBase, "*.class", true);
075        if (urls == null) {
076            return;
077        }
078        Set<String> annotations = collectors.keySet();
079        while (urls.hasMoreElements()) {
080            URL url = urls.nextElement();
081            InputStream in = url.openStream();
082            try {
083                ClassReader cr = new ClassReader(in);
084                AnnotationReader reader = new AnnotationReader(annotations);
085                cr.accept(reader, null, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
086                if (reader.hasResults()) {
087                    String cname = reader.getClassName();
088                    for (String anno : reader.getResults()) {
089                        collectors.get(anno).add(bundle.loadClass(cname));
090                    }
091                }
092            } finally {
093                in.close();
094            }
095        }
096    }
097
098    public Set<Class<?>> getClasses() {
099        HashSet<Class<?>> result = new HashSet<Class<?>>();
100        for (Collection<Class<?>> c : collectors.values()) {
101            result.addAll(c);
102        }
103        return result;
104    }
105
106    public Set<Class<?>> getClasses(String anno) {
107        return new HashSet<Class<?>>(collectors.get(anno));
108    }
109}