1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.osgi.annotations;
20
21 import java.io.File;
22 import java.io.InputStream;
23 import java.net.URI;
24 import java.net.URL;
25 import java.util.Comparator;
26 import java.util.Enumeration;
27 import java.util.Set;
28 import java.util.StringTokenizer;
29 import java.util.TreeSet;
30 import java.util.concurrent.ConcurrentHashMap;
31
32 import org.eclipse.jetty.annotations.ClassNameResolver;
33 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
34 import org.eclipse.jetty.util.ConcurrentHashSet;
35 import org.eclipse.jetty.util.resource.Resource;
36 import org.osgi.framework.Bundle;
37 import org.osgi.framework.Constants;
38
39
40
41
42 public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationParser
43 {
44 private Set<URI> _alreadyParsed = new ConcurrentHashSet<URI>();
45
46 private ConcurrentHashMap<URI,Bundle> _uriToBundle = new ConcurrentHashMap<URI, Bundle>();
47 private ConcurrentHashMap<Bundle,Resource> _bundleToResource = new ConcurrentHashMap<Bundle,Resource>();
48 private ConcurrentHashMap<Resource, Bundle> _resourceToBundle = new ConcurrentHashMap<Resource, Bundle>();
49 private ConcurrentHashMap<Bundle,URI> _bundleToUri = new ConcurrentHashMap<Bundle, URI>();
50
51
52
53
54
55
56
57
58
59 protected Resource indexBundle(Bundle bundle) throws Exception
60 {
61 File bundleFile = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
62 Resource resource = Resource.newResource(bundleFile.toURI());
63 URI uri = resource.getURI();
64 _uriToBundle.putIfAbsent(uri,bundle);
65 _bundleToUri.putIfAbsent(bundle,uri);
66 _bundleToResource.putIfAbsent(bundle,resource);
67 _resourceToBundle.putIfAbsent(resource,bundle);
68 return resource;
69 }
70 protected URI getURI(Bundle bundle)
71 {
72 return _bundleToUri.get(bundle);
73 }
74 protected Resource getResource(Bundle bundle)
75 {
76 return _bundleToResource.get(bundle);
77 }
78 protected Bundle getBundle (Resource resource)
79 {
80 return _resourceToBundle.get(resource);
81 }
82
83
84
85
86
87 @Override
88 public void parse (Set<? extends Handler> handlers, URI[] uris, ClassNameResolver resolver)
89 throws Exception
90 {
91 for (URI uri : uris)
92 {
93 Bundle associatedBundle = _uriToBundle.get(uri);
94 if (associatedBundle == null)
95 {
96 if (!_alreadyParsed.add(uri))
97 {
98 continue;
99 }
100
101
102 super.parse(handlers, new URI[] {uri},resolver);
103 }
104 else
105 {
106 parse(handlers, associatedBundle,resolver);
107 }
108 }
109 }
110
111 protected void parse(Set<? extends Handler> handlers, Bundle bundle, ClassNameResolver resolver)
112 throws Exception
113 {
114 URI uri = _bundleToUri.get(bundle);
115 if (!_alreadyParsed.add(uri))
116 {
117 return;
118 }
119
120 String bundleClasspath = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH);
121 if (bundleClasspath == null)
122 {
123 bundleClasspath = ".";
124 }
125
126 TreeSet<String> paths = new TreeSet<String>(
127 new Comparator<String>()
128 {
129 public int compare(String o1, String o2)
130 {
131 int paths1 = new StringTokenizer(o1,"/",false).countTokens();
132 int paths2 = new StringTokenizer(o2,"/",false).countTokens();
133 if (paths1 == paths2)
134 {
135 return o1.compareTo(o2);
136 }
137 return paths2 - paths1;
138 }
139 });
140 boolean hasDotPath = false;
141 StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, ",;", false);
142 while (tokenizer.hasMoreTokens())
143 {
144 String token = tokenizer.nextToken().trim();
145 if (!token.startsWith("/"))
146 {
147 token = "/" + token;
148 }
149 if (token.equals("/."))
150 {
151 hasDotPath = true;
152 }
153 else if (!token.endsWith(".jar") && !token.endsWith("/"))
154 {
155 paths.add(token+"/");
156 }
157 else
158 {
159 paths.add(token);
160 }
161 }
162
163
164
165 if (bundle.getEntry("/.classpath") != null)
166 {
167 if (bundle.getEntry("/bin/") != null)
168 {
169 paths.add("/bin/");
170 }
171 else if (bundle.getEntry("/target/classes/") != null)
172 {
173 paths.add("/target/classes/");
174 }
175 }
176 Enumeration classes = bundle.findEntries("/","*.class",true);
177 if (classes == null)
178 {
179 return;
180 }
181 while (classes.hasMoreElements())
182 {
183 URL classUrl = (URL) classes.nextElement();
184 String path = classUrl.getPath();
185
186 String name = null;
187 for (String prefixPath : paths)
188 {
189 if (path.startsWith(prefixPath))
190 {
191 name = path.substring(prefixPath.length());
192 break;
193 }
194 }
195 if (name == null && hasDotPath)
196 {
197
198 name = path.substring(1);
199 }
200 if (name == null)
201 {
202
203
204 continue;
205 }
206
207 String shortName = name.replace('/', '.').substring(0,name.length()-6);
208 if ((resolver == null) || (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
209 {
210 try (InputStream classInputStream = classUrl.openStream())
211 {
212 scanClass(handlers, getResource(bundle), classInputStream);
213 }
214 }
215 }
216 }
217 }