View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.javaflow.utils;
18  
19  import org.apache.commons.javaflow.bytecode.transformation.ResourceTransformer;
20  import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.FileNotFoundException;
28  import java.io.FileOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.util.jar.JarEntry;
33  import java.util.jar.JarInputStream;
34  import java.util.jar.JarOutputStream;
35  
36  public final class RewritingUtils {
37  
38      private final static Log log = LogFactory.getLog(RewritingUtils.class);
39  
40      public interface Matcher {
41          boolean isMatching( final String name );
42      }
43      
44      private final static Matcher MATCH_ALL = new Matcher() {
45          public boolean isMatching(final String pName) {
46              return true;
47          }
48      };
49      
50      /*
51       * @todo multiple transformers
52       */
53      public static void rewriteClassFile(
54              final File pInput,
55              final ResourceTransformer transformer,
56              final File pOutput
57              ) throws IOException {
58  
59          final byte[] original = toByteArray(pInput);
60          byte[] transformed = transformer.transform(original);
61          final FileOutputStream os = new FileOutputStream(pOutput);
62          os.write(transformed);
63          os.close();
64      }
65  
66      public static boolean rewriteJar(
67              final JarInputStream pInput,
68              final ResourceTransformer transformer,
69              final JarOutputStream pOutput
70              ) throws IOException {
71          return rewriteJar(pInput, transformer, pOutput, MATCH_ALL);
72      }
73  
74      public static boolean rewriteJar(
75              final JarInputStream pInput,
76              final ResourceTransformer transformer,
77              final JarOutputStream pOutput,
78              final Matcher pMatcher
79              ) throws IOException {
80  
81          boolean changed = false;
82  
83          while(true) {
84              final JarEntry entry = pInput.getNextJarEntry();
85  
86              if (entry == null) {
87                  break;
88              }
89  
90              if (entry.isDirectory()) {
91                  pOutput.putNextEntry(new JarEntry(entry));
92                  continue;
93              }
94  
95              final String name = entry.getName();
96  
97              pOutput.putNextEntry(new JarEntry(name));
98  
99              if (name.endsWith(".class")) {
100                 if (pMatcher.isMatching(name)) {
101 
102                     if (log.isDebugEnabled()) {
103                         log.debug("transforming " + name);
104                     }
105 
106                     final byte[] original = toByteArray(pInput);
107 
108                     byte[] transformed = transformer.transform(original);
109 
110                     pOutput.write(transformed);
111 
112                     changed |= transformed.length != original.length;
113 
114                     continue;
115                 }
116             } else if (name.endsWith(".jar")
117                 || name.endsWith(".ear")
118                 || name.endsWith(".zip")
119                 || name.endsWith(".war")) {
120 
121                 changed |= rewriteJar(
122                         new JarInputStream(pInput),
123                         transformer,
124                         new JarOutputStream(pOutput),
125                         pMatcher
126                         );
127 
128                 continue;
129             }
130 
131             int length = copy(pInput,pOutput);
132 
133             log.debug("copied " + name + "(" + length + ")");
134         }
135 
136         pInput.close();
137         pOutput.close();
138 
139         return changed;
140     }
141 
142     public static byte[] toByteArray(File f) throws IOException {
143         InputStream in = new FileInputStream(f);
144         try {
145             return toByteArray(in);
146         } finally {
147             in.close();
148         }
149     }
150 
151     public static byte[] toByteArray(InputStream in) throws IOException {
152         ByteArrayOutputStream baos = new ByteArrayOutputStream();
153         copy(in,baos);
154         return baos.toByteArray();
155     }
156 
157     /**
158      * Copies the entire {@link InputStream} to the given {@link OutputStream}.
159      *
160      * @return
161      *      the number of bytes copied.
162      */
163     public static int copy(InputStream in, OutputStream out) throws IOException {
164         byte[] buf = new byte[8192];
165         int n;
166         int total = 0;
167         while ((n = in.read(buf)) >= 0) {
168             out.write(buf, 0, n);
169             total += n;
170         }
171         return total;
172     }
173 
174 
175     public static void main(final String[] args) throws FileNotFoundException, IOException {
176         ResourceTransformer transformer = new BcelClassTransformer();
177 
178         for (int i=0; i<args.length; i+=2) {
179             System.out.println("rewriting " + args[i]);
180 
181             RewritingUtils.rewriteJar(
182                     new JarInputStream(new FileInputStream(args[i])),
183                     transformer,
184                     new JarOutputStream(new FileOutputStream(args[i+1]))
185                     );
186         }
187 
188         System.out.println("done");
189         
190     }
191 }