View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.rolemapper;
30  
31  import java.io.DataInputStream;
32  import java.io.File;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.net.URL;
36  import java.net.URLDecoder;
37  import java.util.ArrayList;
38  import java.util.Enumeration;
39  import java.util.List;
40  import java.util.zip.ZipEntry;
41  import java.util.zip.ZipFile;
42  
43  import javassist.bytecode.AnnotationsAttribute;
44  import javassist.bytecode.ClassFile;
45  import javassist.bytecode.annotation.Annotation;
46  
47  import org.openrdf.elmo.annotations.rdf;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  /**
52   * Scans directories and jars for classes that have one or more Elmo annotation.
53   * 
54   * @author James Leigh
55   * 
56   */
57  class Scanner {
58  	private final Logger logger = LoggerFactory.getLogger(HierarchicalRoleMapper.class);
59  
60  	private ClassLoader cl;
61  
62  	private String pkgName;
63  
64  	private String resource;
65  
66  	public Scanner(ClassLoader cl, String resource) {
67  		this.cl = cl;
68  		this.resource = resource;
69  		pkgName = rdf.class.getPackage().getName();
70  	}
71  
72  	public List<String> scan(URL url) throws IOException {
73  		String urlPath = URLDecoder.decode(url.getFile(), "UTF-8");
74  		assert urlPath.endsWith(resource);
75  		urlPath = urlPath.substring(0, urlPath.length() - resource.length());
76  		if (urlPath.startsWith("file:")) {
77  			urlPath = urlPath.substring(5);
78  		}
79  		if (urlPath.lastIndexOf('!') > 0) {
80  			urlPath = urlPath.substring(0, urlPath.lastIndexOf('!'));
81  		}
82  		List<String> roles = new ArrayList<String>();
83  		File file = new File(urlPath);
84  		logger.info("Scanning {}", file);
85  		if (file.isDirectory()) {
86  			roles.addAll(scanDirectory(file, null));
87  		} else {
88  			ZipFile zip = new ZipFile(file);
89  			Enumeration<? extends ZipEntry> entries = zip.entries();
90  			while (entries.hasMoreElements()) {
91  				ZipEntry entry = entries.nextElement();
92  				String name = getClassName(entry.getName());
93  				if (name != null) {
94  					roles.add(name);
95  				}
96  			}
97  		}
98  		return roles;
99  	}
100 
101 	private List<String> scanDirectory(File file, String path)
102 			throws IOException {
103 		List<String> roles = new ArrayList<String>();
104 		for (File child : file.listFiles()) {
105 			String newPath = path == null ? child.getName() : path + '/'
106 					+ child.getName();
107 			if (child.isDirectory()) {
108 				roles.addAll(scanDirectory(child, newPath));
109 			} else {
110 				String name = getClassName(newPath);
111 				if (name != null) {
112 					roles.add(name);
113 				}
114 			}
115 		}
116 		return roles;
117 	}
118 
119 	private String getClassName(String name) throws IOException {
120 		// NOTE package-info.class should be excluded
121 		if (!name.endsWith(".class") || name.contains("-"))
122 			return null;
123 		InputStream stream = cl.getResourceAsStream(name);
124 		assert stream != null : name;
125 		DataInputStream dstream = new DataInputStream(stream);
126 		try {
127 			ClassFile cf = new ClassFile(dstream);
128 			AnnotationsAttribute attr = (AnnotationsAttribute) cf
129 					.getAttribute(AnnotationsAttribute.visibleTag);
130 			if (attr == null)
131 				return null;
132 			Annotation[] annotations = attr.getAnnotations();
133 			if (annotations == null)
134 				return null;
135 			for (Annotation ann : annotations) {
136 				if (ann.getTypeName().startsWith(pkgName))
137 					return cf.getName();
138 			}
139 			return null;
140 		} finally {
141 			dstream.close();
142 			stream.close();
143 		}
144 	}
145 }