KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > nbbuild > NbPatchClass


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.nbbuild;
21
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.net.URLClassLoader JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.jar.JarFile JavaDoc;
31 import org.apache.tools.ant.AntClassLoader;
32 import org.apache.tools.ant.Project;
33 import org.apache.tools.ant.types.Path;
34 import org.apache.tools.ant.types.FileSet;
35 import org.apache.tools.ant.BuildException;
36 import org.apache.tools.ant.taskdefs.MatchingTask;
37 import org.apache.tools.ant.DirectoryScanner;
38 import java.util.Vector JavaDoc;
39
40 /**
41  * @author Jaroslav Tulach
42  */

43 public class NbPatchClass extends MatchingTask {
44
45     /* Path to library containing the patch method */
46     private Path patchPath;
47     public Path createClasspath() {
48         if (patchPath == null) {
49             patchPath = new Path(getProject());
50         }
51         return patchPath.createPath();
52     }
53     
54     
55     /* Name of class with patch method */
56     private String JavaDoc patchClass = "org.netbeans.PatchByteCode"; //NOI18N
57
public void setPatchClass (String JavaDoc f) {
58         patchClass = f;
59     }
60     
61     /** Name of the method to call. Must have byte[] array argument and return the same
62      */

63     private String JavaDoc patchMethod = "patch"; //NOI18N
64
public void setPatchMethod (String JavaDoc f) {
65         patchMethod = f;
66     }
67     
68     /** Source JAR to extract.
69      */

70     public void setSource (File JavaDoc f) {
71         if (f.exists()) {
72             log ("Adding source file " + f.getAbsolutePath(), Project.MSG_VERBOSE);
73             FileSet xfs = new FileSet();
74             xfs.setDir(f.getParentFile());
75             log("Setting FileSet's dir to \"" + f.getParentFile().getAbsolutePath() + "\"", Project.MSG_DEBUG );
76             xfs.setIncludes(f.getName());
77             log("Setting FileSet's include to \"" + f.getName() + "\"",Project.MSG_DEBUG );
78             DirectoryScanner ds = xfs.getDirectoryScanner(getProject());
79             String JavaDoc[] files = ds.getIncludedFiles();
80             if (files.length < 1) {
81                 log ("FileSet is empty, source doesn't doesn't exist (" + f.getParentFile().getAbsolutePath() + ")", Project.MSG_VERBOSE);
82             } else {
83                 log ("Adding FileSet with " + files.length + " file(s)", Project.MSG_VERBOSE);
84                 addFileset(xfs);
85             }
86         }
87     }
88     
89     /* Base dir to find classes relative to */
90     private File JavaDoc targetdir;
91     public void setTargetdir (File JavaDoc f) {
92         targetdir = f;
93     }
94     
95     /**
96      * Adds a set of files (nested fileset attribute).
97      */

98     private Vector JavaDoc<FileSet> filesets = new Vector JavaDoc<FileSet>();
99     public void addFileset(FileSet set) {
100         log ("Adding new FileSet", Project.MSG_DEBUG);
101         filesets.addElement(set);
102     }
103  
104     public void execute() throws BuildException {
105         if (targetdir == null) {
106             throw new BuildException ("Attribute targetdir must be specified");
107         }
108
109         boolean fs_empty = true;
110         for (int i=0; i<filesets.size() && fs_empty; i++) {
111             FileSet n = filesets.elementAt(i);
112             if ( n != null ) {
113                 DirectoryScanner ds = n.getDirectoryScanner(getProject());
114                 String JavaDoc[] files = ds.getIncludedFiles();
115                 File JavaDoc bdir = ds.getBasedir();
116                 if (files.length < 1) log ("FileSet is empty, doesn't have included files", Project.MSG_VERBOSE);
117                 for (int k=0; k < files.length && fs_empty; k++) {
118                     File JavaDoc n_file = new File JavaDoc(bdir, files[k]);
119                     if (n_file.exists()) fs_empty = false;
120                 }
121             }
122         }
123                     
124         if (fs_empty) {
125             throw new BuildException ("Attribute \"source\" or fileset includes must be specified");
126         }
127         
128         //
129
// Initialize the method
130
//
131

132         log ("Initializing patching " + patchClass + '.' + patchMethod);
133         
134         ClassLoader JavaDoc cl = new AntClassLoader(getProject(), patchPath);
135         
136         java.lang.reflect.Method JavaDoc m;
137         try {
138             Class JavaDoc<?> c = cl.loadClass(patchClass);
139             m = c.getMethod(patchMethod, byte[].class, String JavaDoc.class);
140             if (m.getReturnType() != byte[].class) {
141                 throw new BuildException ("Method does not return byte[]: " + m);
142             }
143         } catch (Exception JavaDoc ex) {
144             throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex);
145         }
146         
147         /*
148         try {
149             log ("Testing method " + m);
150             byte[] res = (byte[])m.invoke (null, new Object[] { new byte[0], "someString" });
151         } catch (Exception ex) {
152             throw new BuildException ("Exception during test invocation of the method", ex);
153         }
154         */

155                         
156         //
157
// Ok we have the method and we can do the patching
158
// go over fileset includes
159

160         for (FileSet n : filesets) {
161             if ( n != null ) {
162                 DirectoryScanner ds = n.getDirectoryScanner(getProject());
163                 String JavaDoc[] files = ds.getIncludedFiles();
164                 File JavaDoc bdir = ds.getBasedir();
165                 for (int k=0; k <files.length; k++) {
166                     File JavaDoc n_file = new File JavaDoc(bdir, files[k]);
167                     JarFile JavaDoc jar;
168                     log("Checking classes in jarfile " + n_file, Project.MSG_VERBOSE);
169
170                     try {
171                         jar = new JarFile JavaDoc (n_file);
172                     } catch (IOException JavaDoc ex) {
173                         throw new BuildException ("Problem initializing file " + n_file, ex);
174                     }
175                     
176                     // do the patching
177
java.util.Enumeration JavaDoc it = jar.entries();
178                     while (it.hasMoreElements()) {
179                         java.util.jar.JarEntry JavaDoc e = (java.util.jar.JarEntry JavaDoc)it.nextElement ();
180                         String JavaDoc entryname = e.getName();
181                         if (!entryname.endsWith(".class")) { //NOI18N
182
// resource, skip
183
log("Skipping record (probably directory or resource) " + entryname, Project.MSG_DEBUG);
184                             continue;
185                         }
186                         String JavaDoc name = entryname.substring(0, entryname.length() - 6).replace('/', '.');
187             
188                         int size = (int)e.getSize();
189                         if (size <= 4) {
190                             // not interesting entry
191
log("Class " + name + " is not an interesting entry (<5 bytes)", Project.MSG_DEBUG);
192                             continue;
193                         }
194
195                         log("Checking class " + name, Project.MSG_DEBUG);
196                         
197                         byte[] arr = new byte[size];
198                         
199                         try {
200                             java.io.InputStream JavaDoc is = jar.getInputStream(e);
201                             
202                             int indx = 0;
203                             while (indx < arr.length) {
204                                 int read = is.read (arr, indx, arr.length - indx);
205                                 if (read == -1) {
206                                     throw new BuildException("Entry: " + name + " size should be: " + size + " but was read just: " + indx);
207                                 }
208                                 indx += read;
209                             }
210                         } catch (IOException JavaDoc ex) {
211                             throw new BuildException (ex);
212                         }
213                         
214                         byte[] original = arr.clone();
215                         byte[] out;
216                         try {
217                             out = (byte[])m.invoke (null, new Object JavaDoc[] { arr, name });
218                         } catch (java.lang.reflect.InvocationTargetException JavaDoc ex) {
219                             throw new BuildException (ex.getTargetException());
220                         } catch (Exception JavaDoc ex) {
221                             throw new BuildException (ex);
222                         }
223                         
224                         if (java.util.Arrays.equals (original, out)) {
225                             // no patching, go on
226
log("Not patching class " + name, Project.MSG_DEBUG);
227                             continue;
228                         }
229             
230                         File JavaDoc f = new File JavaDoc (targetdir, e.getName ().replace ('/', File.separatorChar));
231                         if (f.exists () && f.lastModified() > n_file.lastModified ()) {
232                             // if the file is newer
233
log("Patched class " + name + " in " + targetdir.getAbsolutePath() + " is newer than jarfile of origin, not saving patched bytestream to file " + f.getAbsolutePath() , Project.MSG_VERBOSE);
234                             continue;
235                         }
236                         
237                         f.getParentFile().mkdirs();
238                         
239                         log ("Writing patched file " + f, Project.MSG_INFO);
240                         //log ("Writing patched file " + f + " (jarfile of origin " + n_file.getName() + ")", Project.MSG_VERBOSE);
241

242                         try {
243                             FileOutputStream JavaDoc os = new FileOutputStream JavaDoc (f);
244                             os.write (out);
245                             os.close ();
246                         } catch (IOException JavaDoc ex) {
247                             throw new BuildException ("Cannot write file " + f, ex);
248                         }
249                     }
250             }
251         }
252         }
253     }
254     
255 }
256
Popular Tags