001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans;
043:
044: import junit.framework.AssertionFailedError;
045: import junit.textui.TestRunner;
046: import org.netbeans.junit.*;
047: import java.io.InputStream;
048: import java.lang.reflect.*;
049: import java.util.*;
050:
051: /** Test patching of openide.jar byte code for compatibility.
052: * @author Jaroslav Tulach
053: */
054: public class PatchByteCodeTest extends NbTestCase {
055:
056: public PatchByteCodeTest(String name) {
057: super (name);
058: }
059:
060: public static void main(String[] args) {
061: TestRunner.run(new NbTestSuite(PatchByteCodeTest.class));
062: }
063:
064: protected void setUp() throws Exception {
065: super .setUp();
066: }
067:
068: public void testBeanTreeViewLoad() throws Exception {
069: checkPatching("org.openide.explorer.view.BeanTreeView",
070: "data/BeanTreeView.clazz", null, null, null);
071: }
072:
073: /* XXX This module is obsolete. Does the test do anything else useful?
074: public void testCompilerGroupLoad () throws Exception {
075: checkPatching (
076: "org.openide.compiler.CompilerGroup",
077: "data/CompilerGroup.clazz",
078: null, null
079: );
080:
081: InputStream is = getClass ().getResourceAsStream ("data/CompilerGroup.clazz");
082: assertNotNull ("Class has not been found", is);
083:
084: byte[] arr = new byte[is.available ()];
085: int l = is.read (arr);
086: assertEquals ("Read exactly as much as expected", l, arr.length);
087:
088:
089: HashMap args = new HashMap ();
090: args.put ("netbeans.public", Arrays.asList(new String[] { "addCompilerListener", "removeCompilerListener" }) );
091: byte[] res = PatchByteCode.enhanceClass(arr, args);
092: PatchClassLoader loader = new PatchClassLoader ("org.openide.compiler.CompilerGroup", res, ClassLoader.getSystemClassLoader());
093:
094: Class c = loader.loadClass ("org.openide.compiler.CompilerGroup");
095:
096: Method m = c.getDeclaredMethod("addCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class });
097: assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ()));
098:
099: m = c.getDeclaredMethod("removeCompilerListener", new Class[] { org.openide.compiler.CompilerListener.class });
100: assertTrue ("Is not final", !Modifier.isFinal (m.getModifiers ()));
101: }
102: */
103:
104: public void testClassCanBeAlsoInstantiated() throws Exception {
105: Class c = checkPatching(Sample.class.getName(), "Sample.class",
106: "java.lang.Throwable", null, null);
107:
108: c.newInstance();
109: }
110:
111: public void testConstructorCanBeAlsoInstantiated() throws Exception {
112: Class c = checkPatching(Sample2.class.getName(),
113: "Sample2.class", "java.lang.Throwable", null,
114: new String[] { "<init>" });
115:
116: c.newInstance();
117: }
118:
119: public void testChangingSetOfSuperInterfaces() throws Exception {
120: Class c = checkPatching(Sample.class.getName(), "Sample.class",
121: "java.lang.Throwable", new String[] {
122: "org.openide.nodes.Node$Cookie",
123: "java.lang.Cloneable" }, null);
124:
125: assertEquals("Super class is throwable", Throwable.class, c
126: .getSuperclass());
127: Class[] ifaces = c.getInterfaces();
128: assertEquals("Two of them", 2, ifaces.length);
129:
130: Object obj = c.newInstance();
131: assertTrue("Is instance of Cookie",
132: obj instanceof org.openide.nodes.Node.Cookie);
133: assertTrue("Is instance of Cloneable", obj instanceof Cloneable);
134: }
135:
136: public void testPatchingOfFieldsAndMethodsToPublicAndNonFinal()
137: throws Exception {
138: InputStream is = getClass().getResourceAsStream("Sample.class");
139: assertNotNull("Class has not been found", is);
140:
141: byte[] arr = new byte[is.available()];
142: int l = is.read(arr);
143: assertEquals("Read exactly as much as expected", l, arr.length);
144:
145: HashMap args = new HashMap();
146: args.put("netbeans.public", Arrays.asList(new String[] {
147: "member", "field", "method", "staticmethod" }));
148: byte[] res = PatchByteCode.enhanceClass(arr, args);
149: PatchClassLoader loader = new PatchClassLoader(Sample.class
150: .getName(), res, ClassLoader.getSystemClassLoader());
151:
152: Class c = loader.loadClass(Sample.class.getName());
153:
154: assertTrue("Class should be public", Modifier.isPublic(c
155: .getModifiers()));
156:
157: Method m = c.getDeclaredMethod("method", new Class[0]);
158: assertNotNull("Mehtod method is there", m);
159: assertTrue("And is public", Modifier.isPublic(m.getModifiers()));
160: assertTrue("And is not final", !Modifier.isFinal(m
161: .getModifiers()));
162: assertTrue("And is not static", !Modifier.isStatic(m
163: .getModifiers()));
164: assertTrue("And is not synchronzied", !Modifier
165: .isSynchronized(m.getModifiers()));
166:
167: m = c.getDeclaredMethod("member", new Class[] { Object.class });
168: assertNotNull("Member method is there", m);
169: assertTrue("And is public", Modifier.isPublic(m.getModifiers()));
170: assertTrue("And is not final", !Modifier.isFinal(m
171: .getModifiers()));
172: assertTrue("And is not static", !Modifier.isStatic(m
173: .getModifiers()));
174: assertTrue("And is synchronzied", Modifier.isSynchronized(m
175: .getModifiers()));
176:
177: m = c.getDeclaredMethod("staticmethod", new Class[] {});
178: assertNotNull("Member method is there", m);
179: assertTrue("And is public", Modifier.isPublic(m.getModifiers()));
180: assertTrue("And is not final", !Modifier.isFinal(m
181: .getModifiers()));
182: assertTrue("And is not static", Modifier.isStatic(m
183: .getModifiers()));
184: assertTrue("And is not synchronzied", !Modifier
185: .isSynchronized(m.getModifiers()));
186:
187: java.lang.reflect.Field f;
188:
189: f = c.getDeclaredField("member");
190: assertNotNull("Really exists", f);
191: assertTrue("Is public", Modifier.isPublic(f.getModifiers()));
192: assertTrue("Is not final", !Modifier.isFinal(f.getModifiers()));
193: assertTrue("Is static", Modifier.isStatic(f.getModifiers()));
194:
195: f = c.getDeclaredField("field");
196: assertNotNull("Really exists", f);
197: assertTrue("Is public", Modifier.isPublic(f.getModifiers()));
198: assertTrue("Is not final", !Modifier.isFinal(f.getModifiers()));
199: assertTrue("Is static", !Modifier.isStatic(f.getModifiers()));
200:
201: }
202:
203: public void testRenameOfAMember() throws Exception {
204: InputStream is = getClass().getResourceAsStream("Sample.class");
205: assertNotNull("Class has not been found", is);
206:
207: byte[] arr = new byte[is.available()];
208: int l = is.read(arr);
209: assertEquals("Read exactly as much as expected", l, arr.length);
210:
211: HashMap args = new HashMap();
212: args.put("netbeans.rename", Arrays.asList(new String[] {
213: "staticmethod", "StaticMethod" }));
214: byte[] res = PatchByteCode.enhanceClass(arr, args);
215:
216: PatchClassLoader loader = new PatchClassLoader(Sample.class
217: .getName(), res, ClassLoader.getSystemClassLoader());
218:
219: Class c = loader.loadClass(Sample.class.getName());
220:
221: try {
222: c.getDeclaredMethod("staticmethod", new Class[] {});
223: fail("The old method is still present");
224: } catch (NoSuchMethodException ex) {
225: // ok, should not be there
226: }
227:
228: java.lang.reflect.Method m = c.getDeclaredMethod(
229: "StaticMethod", new Class[] {});
230: assertNotNull("Renamed method found", m);
231: }
232:
233: private Class checkPatching(String className, String resource,
234: String super class, String[] interfaces, String[] publc)
235: throws Exception {
236: if (super class == null) {
237: super class = PatchByteCodeTest.class.getName();
238: }
239:
240: InputStream is = getClass().getResourceAsStream(resource);
241: assertNotNull("Resource has been found " + resource, is);
242:
243: byte[] arr = new byte[is.available()];
244: int l = is.read(arr);
245: assertEquals("Read exactly as much as expected", l, arr.length);
246:
247: HashMap args = new HashMap();
248: args.put("netbeans.superclass", super class.replace('.', '/'));
249:
250: if (interfaces != null) {
251: StringBuffer sb = new StringBuffer();
252: String ap = "";
253: for (int i = 0; i < interfaces.length; i++) {
254: sb.append(ap);
255: sb.append(interfaces[i]);
256: ap = ",";
257: }
258: args.put("netbeans.interfaces", sb.toString().replace('.',
259: '/'));
260: }
261:
262: if (publc != null) {
263: args.put("netbeans.public", Arrays.asList(publc));
264: }
265:
266: byte[] res = PatchByteCode.enhanceClass(arr, args);
267: PatchClassLoader loader = new PatchClassLoader(className, res);
268:
269: Class c = loader.loadClass(className);
270:
271: assertEquals("Superclass changed appropriately", super class, c
272: .getSuperclass().getName());
273:
274: return c;
275: }
276:
277: private static final class PatchClassLoader extends ClassLoader {
278: private String res;
279: private byte[] arr;
280:
281: public PatchClassLoader(String res, byte[] arr) {
282: this (res, arr, PatchClassLoader.class.getClassLoader());
283: }
284:
285: public PatchClassLoader(String res, byte[] arr, ClassLoader c) {
286: super (c);
287:
288: this .res = res;
289: this .arr = arr;
290: }
291:
292: protected synchronized Class loadClass(String name,
293: boolean resolve) throws ClassNotFoundException {
294: if (res.equals(name)) {
295: byte[] patch = PatchByteCode.patch(arr, name);
296:
297: return defineClass(name, patch, 0, patch.length);
298: } else {
299: return super.loadClass(name, resolve);
300: }
301: }
302: }
303: }
|