1 19 20 package org.netbeans.nbbuild; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.net.URL ; 27 import java.net.URLClassLoader ; 28 import java.util.ArrayList ; 29 import java.util.Iterator ; 30 import java.util.jar.JarFile ; 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 ; 39 40 43 public class NbPatchClass extends MatchingTask { 44 45 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 56 private String patchClass = "org.netbeans.PatchByteCode"; public void setPatchClass (String f) { 58 patchClass = f; 59 } 60 61 63 private String patchMethod = "patch"; public void setPatchMethod (String f) { 65 patchMethod = f; 66 } 67 68 70 public void setSource (File 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 [] 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 90 private File targetdir; 91 public void setTargetdir (File f) { 92 targetdir = f; 93 } 94 95 98 private Vector <FileSet> filesets = new Vector <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 [] files = ds.getIncludedFiles(); 115 File 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 n_file = new File (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 132 log ("Initializing patching " + patchClass + '.' + patchMethod); 133 134 ClassLoader cl = new AntClassLoader(getProject(), patchPath); 135 136 java.lang.reflect.Method m; 137 try { 138 Class <?> c = cl.loadClass(patchClass); 139 m = c.getMethod(patchMethod, byte[].class, String .class); 140 if (m.getReturnType() != byte[].class) { 141 throw new BuildException ("Method does not return byte[]: " + m); 142 } 143 } catch (Exception ex) { 144 throw new BuildException ("Cannot initialize class " + patchClass + " and method " + patchMethod, ex); 145 } 146 147 155 156 160 for (FileSet n : filesets) { 161 if ( n != null ) { 162 DirectoryScanner ds = n.getDirectoryScanner(getProject()); 163 String [] files = ds.getIncludedFiles(); 164 File bdir = ds.getBasedir(); 165 for (int k=0; k <files.length; k++) { 166 File n_file = new File (bdir, files[k]); 167 JarFile jar; 168 log("Checking classes in jarfile " + n_file, Project.MSG_VERBOSE); 169 170 try { 171 jar = new JarFile (n_file); 172 } catch (IOException ex) { 173 throw new BuildException ("Problem initializing file " + n_file, ex); 174 } 175 176 java.util.Enumeration it = jar.entries(); 178 while (it.hasMoreElements()) { 179 java.util.jar.JarEntry e = (java.util.jar.JarEntry )it.nextElement (); 180 String entryname = e.getName(); 181 if (!entryname.endsWith(".class")) { log("Skipping record (probably directory or resource) " + entryname, Project.MSG_DEBUG); 184 continue; 185 } 186 String name = entryname.substring(0, entryname.length() - 6).replace('/', '.'); 187 188 int size = (int)e.getSize(); 189 if (size <= 4) { 190 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 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 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 [] { arr, name }); 218 } catch (java.lang.reflect.InvocationTargetException ex) { 219 throw new BuildException (ex.getTargetException()); 220 } catch (Exception ex) { 221 throw new BuildException (ex); 222 } 223 224 if (java.util.Arrays.equals (original, out)) { 225 log("Not patching class " + name, Project.MSG_DEBUG); 227 continue; 228 } 229 230 File f = new File (targetdir, e.getName ().replace ('/', File.separatorChar)); 231 if (f.exists () && f.lastModified() > n_file.lastModified ()) { 232 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 242 try { 243 FileOutputStream os = new FileOutputStream (f); 244 os.write (out); 245 os.close (); 246 } catch (IOException ex) { 247 throw new BuildException ("Cannot write file " + f, ex); 248 } 249 } 250 } 251 } 252 } 253 } 254 255 } 256 | Popular Tags |