Added
Link Here
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. |
5 |
* |
6 |
* The contents of this file are subject to the terms of either the GNU |
7 |
* General Public License Version 2 only ("GPL") or the Common |
8 |
* Development and Distribution License("CDDL") (collectively, the |
9 |
* "License"). You may not use this file except in compliance with the |
10 |
* License. You can obtain a copy of the License at |
11 |
* http://www.netbeans.org/cddl-gplv2.html |
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
13 |
* specific language governing permissions and limitations under the |
14 |
* License. When distributing the software, include this License Header |
15 |
* Notice in each file and include the License file at |
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this |
17 |
* particular file as subject to the "Classpath" exception as provided |
18 |
* by Sun in the GPL Version 2 section of the License file that |
19 |
* accompanied this code. If applicable, add the following below the |
20 |
* License Header, with the fields enclosed by brackets [] replaced by |
21 |
* your own identifying information: |
22 |
* "Portions Copyrighted [year] [name of copyright owner]" |
23 |
* |
24 |
* Contributor(s): |
25 |
* |
26 |
* The Original Software is NetBeans. The Initial Developer of the Original |
27 |
* Software is Nokia. Portions Copyright 2005 Nokia. All Rights Reserved. |
28 |
* |
29 |
* If you wish your version of this file to be governed by only the CDDL |
30 |
* or only the GPL Version 2, indicate your decision by adding |
31 |
* "[Contributor] elects to include this software in this distribution |
32 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
33 |
* single choice of license, a recipient has the option to distribute |
34 |
* your version of this file under either the CDDL, the GPL Version 2 or |
35 |
* to extend the choice of license to its licensees as provided above. |
36 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
37 |
* Version 2 license, then the option applies only if the new code is |
38 |
* made subject to such option by the copyright holder. |
39 |
*/ |
40 |
|
41 |
package org.netbeans; |
42 |
|
43 |
import java.io.ByteArrayInputStream; |
44 |
import java.io.File; |
45 |
import java.io.FileOutputStream; |
46 |
import java.io.IOException; |
47 |
import java.io.InputStream; |
48 |
import java.net.MalformedURLException; |
49 |
import java.net.URL; |
50 |
import java.net.URLClassLoader; |
51 |
import java.util.Arrays; |
52 |
import java.util.Collections; |
53 |
import java.util.Enumeration; |
54 |
import java.util.HashSet; |
55 |
import java.util.List; |
56 |
import java.util.Set; |
57 |
import java.util.jar.JarEntry; |
58 |
import java.util.jar.JarFile; |
59 |
import java.util.jar.JarOutputStream; |
60 |
import java.util.jar.Manifest; |
61 |
import org.fakepkg.FakeIfceHidden; |
62 |
import org.openide.modules.SpecificationVersion; |
63 |
import org.openide.util.Enumerations; |
64 |
import org.openide.util.test.MockLookup; |
65 |
|
66 |
/** Verify contracts needed by Netigso. |
67 |
*/ |
68 |
public class ModuleFactoryAlienTest extends SetupHid { |
69 |
|
70 |
static { |
71 |
MockLookup.setInstances(new Factory()); |
72 |
} |
73 |
|
74 |
public ModuleFactoryAlienTest(String name) { |
75 |
super(name); |
76 |
} |
77 |
|
78 |
@Override |
79 |
protected void setUp() throws Exception { |
80 |
super.setUp(); |
81 |
} |
82 |
|
83 |
|
84 |
|
85 |
public void testFactoryCreatesAlienModules() throws Exception { |
86 |
MockModuleInstaller installer = new MockModuleInstaller(); |
87 |
MockEvents ev = new MockEvents(); |
88 |
ModuleManager mgr = new ModuleManager(installer, ev); |
89 |
mgr.mutexPrivileged().enterWriteAccess(); |
90 |
|
91 |
Module m2, m3; |
92 |
try { |
93 |
String mf = "AlienName: test-name.m2\n" + |
94 |
"AlienVersion: 1.1.0\n" + |
95 |
"AlienExport: org.fakepkg\n\n"; |
96 |
File j2 = changeManifest(new File(jars, "simple-module.jar"), mf); |
97 |
m2 = mgr.create(j2, null, false, false, false); |
98 |
mf = "AlienName: test-name\n" + |
99 |
"AlienVersion: 1.1.0\n" + |
100 |
"AlienExport: org.fakepkg\n\n"; |
101 |
File j3 = changeManifest(new File(jars, "depends-on-simple-module.jar"), mf); |
102 |
m3 = mgr.create(j3, null, false, false, false); |
103 |
mgr.enable(new HashSet<Module>(Arrays.asList(m2, m3))); |
104 |
} finally { |
105 |
mgr.mutexPrivileged().exitWriteAccess(); |
106 |
} |
107 |
ClassLoader l; |
108 |
URL u; |
109 |
Class<?> clazz; |
110 |
|
111 |
|
112 |
l = Thread.currentThread().getContextClassLoader(); |
113 |
u = l.getResource("org/fakepkg/Something.txt"); |
114 |
assertNotNull("Resource found", u); |
115 |
|
116 |
assertEquals("No dependencies", 0, m3.getDependencies().size()); |
117 |
|
118 |
clazz = l.loadClass("org.fakepkg.FakeIfce"); |
119 |
assertNotNull("Class loaded", clazz); |
120 |
assertEquals("it is our fake class", FakeIfceHidden.class, clazz); |
121 |
|
122 |
|
123 |
l = m3.getClassLoader(); |
124 |
|
125 |
assertNotNull("Classloader found", l); |
126 |
assertEquals("My classloader", Loader.class, l.getClass()); |
127 |
|
128 |
u = l.getResource("org/fakepkg/Something.txt"); |
129 |
assertNotNull("Resource found", u); |
130 |
|
131 |
clazz = l.loadClass("org.fakepkg.FakeIfce"); |
132 |
assertNotNull("Class loaded", clazz); |
133 |
assertEquals("it is our fake class", FakeIfceHidden.class, clazz); |
134 |
|
135 |
assertEquals("No dependencies", 0, m3.getDependencies().size()); |
136 |
} |
137 |
|
138 |
public void testAlienCanDependOnNetBeans() throws Exception { |
139 |
MockModuleInstaller installer = new MockModuleInstaller(); |
140 |
MockEvents ev = new MockEvents(); |
141 |
ModuleManager mgr = new ModuleManager(installer, ev); |
142 |
mgr.mutexPrivileged().enterWriteAccess(); |
143 |
HashSet<Module> both = null; |
144 |
try { |
145 |
String mfBar = "AlienName: org.bar\n" + |
146 |
"AlienExport: org.bar\n" + |
147 |
"AlienImport: org.foo\n" + |
148 |
"\n\n"; |
149 |
|
150 |
File j1 = new File(jars, "simple-module.jar"); |
151 |
File j2 = changeManifest(new File(jars, "depends-on-simple-module.jar"), mfBar); |
152 |
Module m1 = mgr.create(j1, null, false, false, false); |
153 |
Module m2 = mgr.create(j2, null, false, false, false); |
154 |
HashSet<Module> b = new HashSet<Module>(Arrays.asList(m1, m2)); |
155 |
mgr.enable(b); |
156 |
both = b; |
157 |
|
158 |
AlienModule am = (AlienModule)m2; |
159 |
am.loader.l = new URLClassLoader(new URL[] { am.jar.toURI().toURL() }, m1.getClassLoader()); |
160 |
|
161 |
|
162 |
Class<?> clazz = m2.getClassLoader().loadClass("org.bar.SomethingElse"); |
163 |
Class<?> sprclass = m2.getClassLoader().loadClass("org.foo.Something"); |
164 |
|
165 |
assertEquals("Correct parent is used", sprclass, clazz.getSuperclass()); |
166 |
} finally { |
167 |
if (both != null) { |
168 |
mgr.disable(both); |
169 |
} |
170 |
mgr.mutexPrivileged().exitWriteAccess(); |
171 |
} |
172 |
} |
173 |
|
174 |
public static class Factory extends ModuleFactory { |
175 |
private static Set<String> registered; |
176 |
|
177 |
static void clear() { |
178 |
} |
179 |
|
180 |
public Factory() { |
181 |
} |
182 |
|
183 |
static void registerBundle(Module m) throws IOException { |
184 |
|
185 |
} |
186 |
|
187 |
@Override |
188 |
public Module createFixed(Manifest mani, Object history, ClassLoader loader, boolean autoload, boolean eager, ModuleManager mgr, Events ev) throws InvalidException { |
189 |
Module m = super.createFixed(mani, history, loader, autoload, eager, mgr, ev); |
190 |
try { |
191 |
registerBundle(m); |
192 |
} catch (IOException ex) { |
193 |
throw (InvalidException)new InvalidException(m, ex.getMessage()).initCause(ex); |
194 |
} |
195 |
return m; |
196 |
} |
197 |
|
198 |
@Override |
199 |
public Module create( |
200 |
File jar, Object history, |
201 |
boolean reloadable, boolean autoload, boolean eager, |
202 |
ModuleManager mgr, Events ev |
203 |
) throws IOException { |
204 |
try { |
205 |
Module m = super.create(jar, history, reloadable, autoload, eager, mgr, ev); |
206 |
registerBundle(m); |
207 |
return m; |
208 |
} catch (InvalidException ex) { |
209 |
Manifest mani = ex.getManifest(); |
210 |
if (mani != null) { |
211 |
String name = mani.getMainAttributes().getValue("AlienName"); // NOI18N |
212 |
if (name == null) { |
213 |
throw ex; |
214 |
} |
215 |
return new AlienModule(mani, jar, mgr, ev, history, reloadable, autoload, eager); |
216 |
} |
217 |
throw ex; |
218 |
} |
219 |
} |
220 |
|
221 |
} |
222 |
|
223 |
static final class AlienModule extends Module { |
224 |
private Manifest manifest; |
225 |
private Loader loader; |
226 |
private String name; |
227 |
private File jar; |
228 |
|
229 |
public AlienModule(Manifest m, File jar, ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException { |
230 |
super(mgr, ev, history, reloadable, autoload, eager); |
231 |
|
232 |
this.manifest = m; |
233 |
this.name = manifest.getMainAttributes().getValue("AlienName"); |
234 |
this.jar = jar; |
235 |
} |
236 |
|
237 |
@Override |
238 |
public String[] getProvides() { |
239 |
return new String[0]; |
240 |
} |
241 |
|
242 |
@Override |
243 |
public String getCodeName() { |
244 |
return name; |
245 |
} |
246 |
|
247 |
@Override |
248 |
public String getCodeNameBase() { |
249 |
return getCodeName(); |
250 |
} |
251 |
|
252 |
@Override |
253 |
public int getCodeNameRelease() { |
254 |
return -1; |
255 |
} |
256 |
|
257 |
@Override |
258 |
public SpecificationVersion getSpecificationVersion() { |
259 |
return new SpecificationVersion("1.0"); |
260 |
} |
261 |
|
262 |
@Override |
263 |
public String getImplementationVersion() { |
264 |
return "testimpl"; // NOI18N |
265 |
} |
266 |
|
267 |
@Override |
268 |
protected void parseManifest() throws InvalidException { |
269 |
throw new UnsupportedOperationException("Not supported yet."); |
270 |
} |
271 |
|
272 |
@Override |
273 |
public List<File> getAllJars() { |
274 |
return Collections.emptyList(); |
275 |
} |
276 |
|
277 |
@Override |
278 |
public void setReloadable(boolean r) { |
279 |
throw new UnsupportedOperationException("Not supported yet."); |
280 |
} |
281 |
|
282 |
@Override |
283 |
public void reload() throws IOException { |
284 |
throw new UnsupportedOperationException("Not supported yet."); |
285 |
} |
286 |
|
287 |
@Override |
288 |
protected void classLoaderUp(Set<Module> parents) throws IOException { |
289 |
loader = new Loader(this); |
290 |
} |
291 |
|
292 |
@Override |
293 |
protected void classLoaderDown() { |
294 |
loader = null; |
295 |
} |
296 |
|
297 |
@Override |
298 |
public ClassLoader getClassLoader() throws IllegalArgumentException { |
299 |
if (loader == null) { |
300 |
throw new IllegalArgumentException("No classloader for " + getCodeNameBase()); // NOI18N |
301 |
} |
302 |
return loader; |
303 |
} |
304 |
|
305 |
@Override |
306 |
protected void cleanup() { |
307 |
} |
308 |
|
309 |
@Override |
310 |
protected void destroy() { |
311 |
} |
312 |
|
313 |
@Override |
314 |
public boolean isFixed() { |
315 |
return false; |
316 |
} |
317 |
|
318 |
@Override |
319 |
public Manifest getManifest() { |
320 |
return manifest; |
321 |
} |
322 |
|
323 |
@Override |
324 |
public Object getLocalizedAttribute(String attr) { |
325 |
// TBD; |
326 |
return null; |
327 |
} |
328 |
|
329 |
@Override |
330 |
public String toString() { |
331 |
return "Alien: " + getCodeName(); |
332 |
} |
333 |
} |
334 |
|
335 |
static final class Loader extends ProxyClassLoader { |
336 |
final AlienModule am; |
337 |
ClassLoader l; |
338 |
|
339 |
public Loader(AlienModule mf) throws MalformedURLException { |
340 |
super(new ClassLoader[0], true); |
341 |
Set<String> pkgs = new HashSet<String>(); |
342 |
pkgs.add(mf.getManifest().getMainAttributes().getValue("AlienExport")); |
343 |
addCoveredPackages(pkgs); |
344 |
this.am = mf; |
345 |
} |
346 |
|
347 |
@Override |
348 |
public URL findResource(String name) { |
349 |
if ("org/fakepkg/Something.txt".equals(name)) { |
350 |
URL u = ModuleFactoryAlienTest.class.getResource("/org/fakepkg/resource1.txt"); |
351 |
assertNotNull("text found", u); |
352 |
return u; |
353 |
} |
354 |
return null; |
355 |
} |
356 |
|
357 |
@Override |
358 |
@SuppressWarnings(value = "unchecked") |
359 |
public Enumeration<URL> findResources(String name) { |
360 |
return Enumerations.empty(); |
361 |
} |
362 |
|
363 |
@Override |
364 |
protected Class<?> doLoadClass(String pkg, String name) { |
365 |
if (name.equals("org.fakepkg.FakeIfce")) { |
366 |
return FakeIfceHidden.class; |
367 |
} |
368 |
try { |
369 |
return l == null ? null : l.loadClass(name); |
370 |
} catch (ClassNotFoundException ex) { |
371 |
ex.printStackTrace(); |
372 |
return null; |
373 |
} |
374 |
} |
375 |
|
376 |
@Override |
377 |
public String toString() { |
378 |
return "Alien[test]"; |
379 |
} |
380 |
} |
381 |
|
382 |
private File changeManifest(File orig, String manifest) throws IOException { |
383 |
File f = new File(getWorkDir(), orig.getName()); |
384 |
Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("utf-8"))); |
385 |
mf.getMainAttributes().putValue("Manifest-Version", "1.0"); |
386 |
JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf); |
387 |
JarFile jf = new JarFile(orig); |
388 |
Enumeration<JarEntry> en = jf.entries(); |
389 |
InputStream is; |
390 |
while (en.hasMoreElements()) { |
391 |
JarEntry e = en.nextElement(); |
392 |
if (e.getName().equals("META-INF/MANIFEST.MF")) { |
393 |
continue; |
394 |
} |
395 |
os.putNextEntry(e); |
396 |
is = jf.getInputStream(e); |
397 |
byte[] arr = new byte[4096]; |
398 |
for (;;) { |
399 |
int len = is.read(arr); |
400 |
if (len == -1) { |
401 |
break; |
402 |
} |
403 |
os.write(arr, 0, len); |
404 |
} |
405 |
is.close(); |
406 |
os.closeEntry(); |
407 |
} |
408 |
os.close(); |
409 |
|
410 |
return f; |
411 |
} |
412 |
|
413 |
} |