View Javadoc

1   /*******************************************************************************
2    *  Copyright (c) 2005, 2006, 2007 Imola Informatica.
3    *  All rights reserved. This program and the accompanying materials
4    *  are made available under the terms of the LGPL License v2.1
5    *  which accompanies this distribution, and is available at
6    *  http://www.gnu.org/licenses/lgpl.html
7    *******************************************************************************/
8   package it.imolinfo.jbi4ejb.webservice.generator;
9   
10  import it.imolinfo.jbi4ejb.Logger;
11  import it.imolinfo.jbi4ejb.LoggerFactory;
12  import it.imolinfo.jbi4ejb.exception.ClassGenerationException;
13  import it.imolinfo.jbi4ejb.exception.EJBDeployException;
14  import it.imolinfo.jbi4ejb.exception.EJBWSDLGenerationException;
15  import it.imolinfo.jbi4ejb.jbi.Messages;
16  import it.imolinfo.jbi4ejb.webservice.generator.bcm.AddExceptionSuperclass;
17  import it.imolinfo.jbi4ejb.webservice.generator.bcm.RemoveEJBInterfaceAdapter;
18  import it.imolinfo.jbi4ejb.webservice.generator.bcm.RemoteInterfaceExceptionAdapter;
19  
20  import java.io.ByteArrayOutputStream;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.io.PrintStream;
28  import java.io.PrintWriter;
29  import java.io.StringWriter;
30  import java.net.MalformedURLException;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.List;
34  
35  import org.objectweb.asm.ClassReader;
36  import org.objectweb.asm.ClassVisitor;
37  import org.objectweb.asm.ClassWriter;
38  import org.objectweb.asm.util.CheckClassAdapter;
39  import org.objectweb.asm.util.TraceClassVisitor;
40  
41  /**
42   * The Class EJBUtils.
43   * This class contains the helper method added for the jbi4Ejb project.
44   * The helper method in the <code>Utils</code> class are from the jbi4corba project
45   * 
46   * @author <a href="mailto:mpiraccini@imolinfo.it">Marco Piraccini</a>
47   */
48  public final class EJBUtils {
49          
50      /** Logger. */
51      static final Logger LOG = LoggerFactory.getLogger(EJBUtils.class);
52      private static final Messages MESSAGES
53      = Messages.getMessages(EJBUtils.class);
54      
55      /** The BUFFER_LENGTH (1024). */
56      private static final int BUFFER_LENGTH = 1024;
57      
58      /**
59       * Private constructor to avoid instantiation.
60       */
61      private EJBUtils() {}         
62      
63      /**
64       * Creates a temporary directory.
65       * 
66       * @return the created directory or <code>null</code> if the creation has
67       *         failed even though a file has been created.
68       * @throws IOException
69       *             if a file could not be created.
70       */
71      public static File createTempDir() throws IOException {
72          File f = File.createTempFile("EJBGENERATION_", null);
73  
74          /*
75           * java.io.File API can create only temporary files: delete the created
76           * file and make a directory with the same name
77           */
78          if (!f.delete()) {
79              return null;
80          }
81          if (!f.mkdir()) {
82              return null;
83          }
84          return f;
85      }
86  
87      /**
88       * Creates the stub.
89       * 
90       * @param classesDir
91       *            The directory containing the classes
92       * @param className
93       *            The class name to create the stub
94       * @param jarFilesName
95       *            The jar lists
96       * @throws EJBDeployException
97       *             If some problem occurs
98       */
99      public static void createStub(String classesDir, String className, List<String> jarFilesName)
100             throws EJBDeployException {
101              
102         StringBuffer classpathStr = new StringBuffer();
103         for (int i = 0; i < jarFilesName.size(); i++) {
104             classpathStr.append(jarFilesName.get(i)).append(File.pathSeparator);
105         }
106         classpathStr.append(classesDir);
107         String classpath = classpathStr.toString();        
108     
109         LOG.debug("Create stub classpath: " + classpath);
110     
111         List<String> params = new ArrayList<String>(Arrays.asList(new String[] {
112                 "-classpath", classpath, "-d", classesDir, "-iiop","-poa", "-verbose",
113                 className }));
114         ByteArrayOutputStream baos = new ByteArrayOutputStream();
115         PrintStream printstream = new PrintStream(baos);
116     
117         sun.rmi.rmic.Main main = new sun.rmi.rmic.Main(printstream, "rmic");
118     
119         boolean result = main.compile(params.toArray(new String[] {}));
120     
121         if (!result) {
122             LOG.debug(baos.toString());
123             throw new EJBDeployException("Errore nell'esecuzione di RMIC");
124         }
125     
126         LOG.debug("<<<<< compileRemoteClasses - end");
127     }
128     
129     /**
130      * Modify the interface generated from the WSDL, adding the correct application exceptions.
131      * 
132      * Retrieve the Applicative Exceptions, wrapped by a <code>org.codehaus.xfire.fault.FaultInfoException</code> in the
133      * WSDL-generated interface. Adds the correct exception to the throws clause of the interface, with the <code>java.rmi.RemoteException</code>
134      * The Exception classes are subclassed form <code>java.lang.Exception</code>  
135      * 
136      * @param portTypeClassName
137      *              The port type class name
138      * @param classesDirName
139      *              The classes directory
140      * tweakRemoteInterfaceGeneratedFromWSDL
141      * @throws ClassGenerationException
142      *              If some problem occurs
143      */
144     public static void tweakRemoteInterfaceGeneratedFromWSDL(String portTypeClassName, String classesDirName) throws ClassGenerationException  {
145 
146         LOG.debug("Adding the application exceptions to interface: " + portTypeClassName);
147         
148         ClassWriter cw = new ClassWriter(true);
149         ClassVisitor cc = new CheckClassAdapter(cw);
150         StringWriter sw = new StringWriter();
151         ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(sw));
152                 
153         // Get the classes classloader (to inspect hte declared exceptions)       
154         ClassLoader classLoader = null;
155         try {
156             classLoader = Util.getURLClassLoader(classesDirName);
157         } catch (MalformedURLException ex) {
158         	String msg=MESSAGES.getString("EJB001003_tweakRemoteInterfaceGeneratedFromWSDL", new Object[]{ex.getMessage()});
159             LOG.error(msg,ex);
160             throw new ClassGenerationException(msg,ex);
161         }
162         
163         RemoteInterfaceExceptionAdapter cv = new RemoteInterfaceExceptionAdapter(tv, classLoader);
164         
165         LOG.debug("new ClassReader - Begin");
166         ClassReader cr;
167         try {
168             cr = new ClassReader(new FileInputStream(getAsFileName(
169                     classesDirName, portTypeClassName, ".class")));
170         } catch (IOException e) {
171         	String msg=MESSAGES.getString("EJB001003_tweakRemoteInterfaceGeneratedFromWSDL", new Object[]{e.getMessage()});
172             LOG.error(msg,e);
173             throw new ClassGenerationException(msg,e);
174         }
175 
176         cr.accept(cv, true);
177 
178         LOG.debug("output of tracer during creation of class: " +
179                 portTypeClassName + "\n" + sw.toString());
180 
181         byte[] newBytecode = cw.toByteArray();
182 
183         // write class in the right place
184         String relativeFileName = portTypeClassName.replace('.',
185                 File.separatorChar);
186 
187         LOG.debug("FileName=" + relativeFileName);
188 
189         Util.saveAsJavaClass(classesDirName + File.separator +
190                 relativeFileName + ".class", newBytecode);
191         
192         // Add the Exception superclass to all the declared exceptions
193         List<String> exceptions = cv.getExceptionsAdded();    
194         addExceptionSuperclass(exceptions, classesDirName);
195     }
196     
197     /**
198      * Add <code>java.lang.Exception</code> as Superclass.
199      * The exception classes generated from the WSDL does extends
200      * <code>java.lang.Exception</code>.
201      * 
202      * 
203      * @param exceptions
204      *          The exceptions to transform
205      * @param classesDirName
206      *          Where the classes are
207      * 
208      * @throws ClassGenerationException
209      *          If some problem occurs
210      */
211     private static void addExceptionSuperclass(List<String> exceptions, String classesDirName) 
212             throws ClassGenerationException {
213         
214         for (int i = 0; i < exceptions.size(); i++) {
215             String exception = exceptions.get(i);
216             LOG.debug("Adding Exception superclass to exception: " + exception);
217             
218             ClassWriter  cw = new ClassWriter(true); // visitMaxs
219             ClassVisitor cc = new CheckClassAdapter(cw);
220             StringWriter sw = new StringWriter();
221             ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(sw));
222             
223             AddExceptionSuperclass cv = new AddExceptionSuperclass(tv);
224             
225             ClassReader cr;
226             try {
227                 cr = new ClassReader(new FileInputStream(getAsFileName(
228                         classesDirName, exception, ".class")));
229             } catch (IOException e) {
230             	String msg=MESSAGES.getString("EJB001004_addExceptionSuperclass", new Object[]{e.getMessage()});
231                 LOG.error(msg,e);
232                 throw new ClassGenerationException(msg,e);
233             }
234             cr.accept(cv, true);
235             byte[] newBytecode = cw.toByteArray();
236 
237             // Save the class bytecode
238             String relativeFileName = exception.replace('.', File.separatorChar);
239             Util.saveAsJavaClass(classesDirName + File.separator +
240                     relativeFileName + ".class", newBytecode);
241 
242         }
243     }
244     
245     /**
246      * Removes the implements <code>java.rmi.Remote</code> and throws <code>java.rmi.RemoteException</code> clauses, 
247      * using recursino (see EJB-53).
248      *   
249      * @param interfaceClassName
250      *              The port type class name
251      * @param classesDirName
252      *              The classes directory where to save the file
253      * tweakRemoteInterfaceGeneratedFromWSDL
254      * @throws ClassGenerationException
255      *              If some problem occurs
256      */
257     public static void removeEJBRemoteInterface(String interfaceClassName, String classesDirName) throws ClassGenerationException  {
258 
259         LOG.debug("Removing the remote interface from: " + interfaceClassName + " in directory: " + classesDirName);       
260         
261         ClassWriter cw = new ClassWriter(true);
262         ClassVisitor cc = new CheckClassAdapter(cw);
263         StringWriter sw = new StringWriter();
264         ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(sw));
265                        
266         RemoveEJBInterfaceAdapter cv = new RemoveEJBInterfaceAdapter(tv, classesDirName);
267                              
268         String classFileName = getAsFileName(classesDirName, interfaceClassName, ".class");
269         File classFile = new File(classFileName);
270         if (!classFile.exists()) {
271             // TODDO i18n
272             String msg  = "Class " + interfaceClassName + " not found in archive";
273             throw new ClassGenerationException(msg);
274         }
275         
276         ClassReader cr;
277         try {
278             cr = new ClassReader(new FileInputStream(classFile));
279         } catch (IOException e) {
280         	String msg=MESSAGES.getString("EJB001005_removeEJBRemoteInterface", new Object[]{e.getMessage()});
281             LOG.error(msg,e);
282             throw new ClassGenerationException(msg,e);
283         }
284 
285         cr.accept(cv, true);
286         byte[] newBytecode = cw.toByteArray();
287 
288         // write class in the right place
289         String relativeFileName = interfaceClassName.replace('.',
290                 File.separatorChar);
291 
292         Util.saveAsJavaClass(classesDirName + File.separator +
293                 relativeFileName + ".class", newBytecode);              
294     }    
295     
296     
297 
298     
299     /**
300      * Gets the as class as a file name.
301      * 
302      * @param basedir
303      *          The classes base directory
304      * @param javaName
305      *          The java name
306      * @param ext
307      *          The extension
308      *      
309      * @return the as file name
310      */
311     private static String getAsFileName(String basedir, String javaName,
312             String ext) {
313         char sep = File.separator.charAt(0);
314         String basedirRep = basedir.replace('\\', sep).replace('/', sep);
315 
316         return basedirRep + sep + javaName.replace('.', sep) + ext;
317     }
318     
319     /**
320      * Copy directory.
321      * 
322      * @param sourceLocation
323      *          The source directory
324      * @param targetLocation
325      *          The target directory
326      * 
327      * @throws IOException
328      *          If some problem occurs in copying directory
329      */
330     public static void copyDirectory(File sourceLocation , File targetLocation)
331     throws IOException {        
332         
333         if (sourceLocation.isDirectory()) {
334             if (!targetLocation.exists()) {
335                 targetLocation.mkdir();
336             }
337 
338             String[] children = sourceLocation.list();
339             for (int i=0; i<children.length; i++) {
340                 copyDirectory(new File(sourceLocation, children[i]),
341                         new File(targetLocation, children[i]));
342             }
343         } else {
344 
345             InputStream in = new FileInputStream(sourceLocation);
346             OutputStream out = new FileOutputStream(targetLocation);
347 
348             // Copy the bits from instream to outstream
349             byte[] buf = new byte[BUFFER_LENGTH];
350             int len;
351             while ((len = in.read(buf)) > 0) {
352                 out.write(buf, 0, len);
353             }
354             in.close();
355             out.close();
356         }
357     }
358     
359     
360 
361 }