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.configuration;
9   
10  import it.imolinfo.jbi4ejb.Logger;
11  import it.imolinfo.jbi4ejb.LoggerFactory;
12  import it.imolinfo.jbi4ejb.exception.EJBWSDLGenerationException;
13  import it.imolinfo.jbi4ejb.jbi.Messages;
14  import it.imolinfo.jbi4ejb.webservice.generator.JarUtil;
15  import it.imolinfo.jbi4ejb.webservice.generator.Util;
16  
17  import java.io.File;
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import javax.xml.parsers.DocumentBuilder;
23  import javax.xml.parsers.DocumentBuilderFactory;
24  import javax.xml.parsers.ParserConfigurationException;
25  
26  import org.w3c.dom.CharacterData;
27  import org.w3c.dom.Document;
28  import org.w3c.dom.Element;
29  import org.w3c.dom.Node;
30  import org.w3c.dom.NodeList;
31  import org.xml.sax.SAXException;
32  
33  /**
34   * The Class InterfaceExtractorUtil.
35   */
36  public final class InterfaceExtractorUtil {
37      
38      /** The Constant EAR_TEMP_DIR. */
39      private static final String EAR_TEMP_DIR = "EAR_";
40      
41      /** The Constant REMOTE. */
42      private static final String REMOTE = "remote";
43      
44      /** The Constant STATELESS. */
45      private static final String STATELESS = "Stateless";
46      
47      /** The Constant SESSION_TYPE. */
48      private static final String SESSION_TYPE = "session-type";
49      
50      /** The Constant SESSION. */
51      private static final String SESSION = "session";
52      
53      /** The Constant EJB. */
54      private static final String EJB = "ejb";
55      
56      /** The Constant APPLICATION_XML. */
57      private static final String APPLICATION_XML = "application.xml";
58      
59      /** Logger. */
60      private static final Logger LOG = LoggerFactory.getLogger(InterfaceExtractorUtil.class);
61      
62      private static final Messages MESSAGES=Messages.getMessages(InterfaceExtractorUtil.class);
63      
64      /**
65       * Instantiates a new interface extractor util.
66       */
67      private InterfaceExtractorUtil(){}
68      
69      /**
70       * Extract remote interfaces from ear.
71       * 
72       * Look for the <code>application.xml</code>. For each *.jar, extracts
73       * the jar names andfore each jar extracts the remote interfaces.
74       * 
75       * @param earPath
76       *            The ear path
77       * 
78       * @return the list< string> of the remote interfaces
79       * 
80       * @throws EJBWSDLGenerationException
81       *             If some problem occurs in extracting the interfaces
82       */
83      public static List<String> extractRemoteInterfacesFromEar(String earPath) throws EJBWSDLGenerationException {
84          
85          // Creates the temp dir
86          File tempDir;
87          try {
88              tempDir = File.createTempFile(EAR_TEMP_DIR, null);
89          } catch (IOException e) {
90          	String msg=MESSAGES.getString("EJB000001_Could_not_create_directory", new Object[]{EAR_TEMP_DIR});
91              LOG.error(msg,e);
92              throw new EJBWSDLGenerationException(msg,e);
93          } 
94          tempDir.delete();
95          tempDir.mkdir();
96          
97          try {
98              JarUtil.unjar(new File(earPath), tempDir);
99          } catch (IOException e) {
100         	String msg=MESSAGES.getString("EJB000002_Failure_in_opening_Jarfile", new Object[] {earPath});
101             LOG.error(msg,e);
102             throw new EJBWSDLGenerationException(msg,e);
103         }
104         File applicationXml = findSingleFile(tempDir.getAbsolutePath(), APPLICATION_XML);
105         
106         if (applicationXml == null) {
107             String msg=MESSAGES.getString("EJB000003_No_application.xml_found_in_earPath", new Object[] {earPath});
108             LOG.error(msg);
109             throw new EJBWSDLGenerationException(msg);     
110         }
111         
112         // Gets the jar list
113         List<String> jarList = getEjbJarFromApplicationXML(applicationXml);
114 
115         List<String> remoteInterfaces = new ArrayList<String>();
116         
117         // For each jar, retrieves the remote interface
118         for (String jarName:jarList) {            
119             File jarFile = findSingleFile(tempDir.getAbsolutePath(), jarName);
120             remoteInterfaces.addAll(extractRemoteInterfaceFromJar(jarFile.getAbsolutePath()));
121         }        
122         
123         // Removes the temp dir
124         tempDir.delete();
125         
126         return remoteInterfaces;
127     }
128     
129     /**
130      * Extract remote interfaces from the jar. Look for the ejb-jar.xml (ejb
131      * <2.1) and the ejb3.0 annotations
132      * 
133      * @param jarPath
134      *            The ear path
135      * 
136      * @return the list< string> of the remote interfaces
137      * 
138      * @throws EJBWSDLGenerationException
139      *             If some problem occurs in extracting the interfaces
140      */    
141     public static List<String> extractRemoteInterfaceFromJar(String jarPath) throws EJBWSDLGenerationException {
142         
143         List<String> remoteInterfaces = new ArrayList<String>();
144         
145         // Creates the temp dir
146         File tempDir;
147         try {
148             tempDir = File.createTempFile("JAR_", null);
149         } catch (IOException e) {
150         	String msg=MESSAGES.getString("EJB000001_Could_not_create_directory", new Object[]{"JAR_"});
151             LOG.error(msg,e);
152             throw new EJBWSDLGenerationException(msg,e);
153         	
154         } 
155         tempDir.delete();
156         tempDir.mkdir();
157         
158         try {
159             JarUtil.unjar(new File(jarPath), tempDir);
160         } catch (IOException e) {
161         	String msg=MESSAGES.getString("EJB000002_Failure_in_opening_Jarfile", new Object[] {jarPath});
162             LOG.error(msg,e);
163             throw new EJBWSDLGenerationException(msg,e);      	
164         }
165         
166         File ejbJarXml = findSingleFile(tempDir.getAbsolutePath(), "ejb-jar.xml");
167         List<String> interfacesListFromEjbJar = new ArrayList<String>();
168         if (ejbJarXml != null) {
169         // Gets the jar list from the ejb-jar        
170             interfacesListFromEjbJar = getInterfacesFromEjbJarXml(ejbJarXml);
171         }
172         remoteInterfaces.addAll(interfacesListFromEjbJar);
173         
174         // Gets the jar list from the annotations (planned for release 1.0)
175         // List<String> interfacesListFromAnnotations = getInterfacesFromAnnotations(tempDir.getAbsolutePath());               
176         // remoteInterfaces.addAll(interfacesListFromAnnotations);
177 
178         
179         // TODO remove temporary directory        
180         tempDir.delete();
181         
182         return remoteInterfaces;
183     }
184 
185     
186     /**
187      * Finds a file in a directory. Teh file MUST be found and MUST be one.
188      * 
189      * @param sourceDir
190      *            The dir
191      * @param fileName
192      *            The file name
193      * 
194      * @return
195      *      The file found
196      * 
197      * @throws EJBWSDLGenerationException
198      *             If >1 files are found.
199      * 
200      * The file
201      * 
202      * The file found, null if no file found.
203      */
204     private static File findSingleFile(String sourceDir, String fileName) throws EJBWSDLGenerationException {
205         
206         File applicationXml = null;
207         List<File> files = Util.findFilesFromSourceDirectoryFromExactFileName(sourceDir, fileName);
208         if (files.size() > 1) {
209         	String msg=MESSAGES.getString("EJB000004_Found_file_size_exceeded", new Object[] {files.size()}, new Object[] {fileName});
210             LOG.error(msg);
211             throw new EJBWSDLGenerationException(msg); 
212         } else if (files.size() != 0) {
213             applicationXml = files.get(0);    
214         }        
215         return applicationXml;
216     }
217     
218     /**
219      * Gets the ejb remote interfaces from ejb jar xml.
220      * 
221      * @param ejbJarXml
222      *            The ejb-jar xml path
223      * 
224      * @return the interfaces from ejb jar xml
225      * 
226      * @throws EJBWSDLGenerationException
227      *             If some xml parsing problem occurs in parsing ejb-jar.xml
228      */
229     private static List<String>getInterfacesFromEjbJarXml(File ejbJarXml) throws EJBWSDLGenerationException {
230         List<String> interfacesList = new ArrayList<String>();
231 
232         Document doc = getDocument(ejbJarXml);
233 
234         // For each "session"
235         NodeList nodes = doc.getElementsByTagName(SESSION);
236 
237         for (int i = 0; i < nodes.getLength(); i++) {
238             Element element = (Element) nodes.item(i);
239 
240             NodeList sessionType = element.getElementsByTagName(SESSION_TYPE);                
241             Element type = (Element) sessionType.item(0);
242             // If it's a stateless, adds the remote interface to the list
243             if (getCharacterDataFromElement(type).equalsIgnoreCase(STATELESS)) {
244                 LOG.debug("Found a stateless EJB");
245                 NodeList remoteElement = element.getElementsByTagName(REMOTE);
246                 Element remote = (Element) remoteElement.item(0);
247                 String remoteInterfaceName = getCharacterDataFromElement(remote);
248                 LOG.debug("Found a stateless EJB with interface: " + remoteInterfaceName);
249                 interfacesList.add(remoteInterfaceName);
250             }                
251         }
252         
253         return interfacesList;
254     }
255     
256 //    /**
257 //     * Gets the interfaces from annotations.
258 //     *
259 //     * This method finds the @Stateless classes, then:
260 //     *  - If the EJB as also the @Remote annotation, ok. else
261 //     *  - if one of the interfaces implemented is @Remote, ok.
262 //     *  
263 //     *  TODO implements! Palnned for 1.0
264 //     * @param classesDir
265 //     *          The classes directory
266 //     * @return the interfaces from annotations
267 //     * 
268 //     * @throws EJBWSDLGenerationException
269 //     *         If some xml parsing problem occurs in
270 //     */
271 //    private static List<String>getInterfacesFromAnnotations(String classesDir) throws EJBWSDLGenerationException {
272 //        List<String> interfacesList = new ArrayList<String>();
273 //        ClassLoader classLoader = null;
274 //        try {
275 //            classLoader = Util.getURLClassLoader(classesDir);            
276 //        } catch (MalformedURLException e) {
277 //            // TODO i18n
278 //            String msg = e.getMessage();
279 //            LOG.error(msg);
280 //            throw new EJBWSDLGenerationException(e);
281 //        }
282 //        // Find all the classes
283 //        List<File> classes = Util.findFilesFromSourceDirectory(classesDir, ".class");
284 //        for (File classFilePath: classes) {
285 //           // TODO implements... for each class, inspect it
286 //            
287 //        }
288 //        return interfacesList;
289 //    }    
290 //    
291       
292     /**
293  * Gets the ejb-jar list from the application.xml file.
294  * 
295  * @param applicationXml
296  *            The application.xml ear file
297  * 
298  * @return
299  *  The ejb-jar list
300  * 
301  * @throws EJBWSDLGenerationException
302  *             If some xml parsing problem occurs in parsing application.xml
303  * 
304  * The ejb interfaces for the ear.
305  */
306     private static List<String> getEjbJarFromApplicationXML(File applicationXml) throws EJBWSDLGenerationException {
307 
308         List<String> jarList = new ArrayList<String>();                      
309 
310         Document doc = getDocument(applicationXml);
311 
312         NodeList nodes = doc.getElementsByTagName(EJB);
313 
314         for (int i = 0; i < nodes.getLength(); i++) {
315             Element element = (Element) nodes.item(i);
316             String ejbJarName = getCharacterDataFromElement(element);
317             jarList.add(ejbJarName);
318         }
319 
320         return jarList;
321     }
322     
323     /**
324      * Gets the element text. <el>text</el> -> returns 'text'
325      * 
326      * @param e
327      *            The element
328      * 
329      * @return
330      * 
331      * The element text
332      */
333     private static String getCharacterDataFromElement(Element e) {
334         Node child = e.getFirstChild();
335         if (child instanceof CharacterData) {
336           CharacterData cd = (CharacterData) child;
337             return cd.getData();
338           }
339         return "";
340      }
341 
342     /**
343      * Gets the <code>Document</code> form a file. Disable the dtd-validation.
344      * 
345      * @param file
346      *            The file to be aprsed
347      * 
348      * @return the document
349      * 
350      * @throws EJBWSDLGenerationException
351      *             If some parsing problem occurs.
352      */
353     private static Document getDocument(File file) throws EJBWSDLGenerationException {
354         Document doc = null;
355         try {
356             
357             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
358             factory.setValidating(false);
359             factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", Boolean.FALSE);                
360             DocumentBuilder builder = factory.newDocumentBuilder();
361             doc = builder.parse(file);
362             
363         }catch (ParserConfigurationException e) {
364         	String msg=MESSAGES.getString("EJB000005_Error_in_getting_document", new Object[]{file});
365             LOG.error(msg,e);
366             throw new EJBWSDLGenerationException(msg,e);
367         }   catch (IOException e) {
368         	String msg=MESSAGES.getString("EJB000005_Error_in_getting_document", new Object[]{file});
369             LOG.error(msg,e);
370             throw new EJBWSDLGenerationException(msg,e);
371         } catch (SAXException e) {
372             String msg=MESSAGES.getString("EJB000005_Error_in_getting_document", new Object[]{file});
373             LOG.error(msg,e);
374             throw new EJBWSDLGenerationException(msg,e);
375         }    
376         return doc;
377     }
378     
379     /**
380      * Extract all the ear classes in a temporary directory, to generate the
381      * WSDL.
382      * 
383      * @param earPath
384      *            The ear file path
385      * 
386      * @return the temporary directory path
387      * 
388      * @throws EJBWSDLGenerationException
389      *             If some problem occurs in WSDL generation
390      */
391     public static String extractEarClassesInTempDirectory(String earPath)  throws EJBWSDLGenerationException {
392                     
393             // Creates the temp dir
394             File tempDir;
395             try {
396                 tempDir = File.createTempFile(EAR_TEMP_DIR, null);
397             } catch (IOException e) {
398             	String msg=MESSAGES.getString("EJB000001_Could_not_create_directory", new Object[]{EAR_TEMP_DIR});
399                 LOG.error(msg,e);
400                 throw new EJBWSDLGenerationException(msg,e);
401             } 
402             tempDir.delete();
403             tempDir.mkdir();
404             
405             try {
406                 JarUtil.unjar(new File(earPath), tempDir);
407             } catch (IOException e) {
408             	String msg=MESSAGES.getString("EJB000001_Could_not_create_directory", new Object[]{EAR_TEMP_DIR});
409                 LOG.error(msg,e);
410                 throw new EJBWSDLGenerationException(msg,e);
411             }
412             File applicationXml = findSingleFile(tempDir.getAbsolutePath(), APPLICATION_XML);
413             
414             if (applicationXml == null) {
415             	String msg=MESSAGES.getString("EJB000003_No_application.xml_found_in_earPath", new Object[] {earPath});
416                 LOG.error(msg);
417                 throw new EJBWSDLGenerationException(msg);
418             }
419             
420             // Gets the jar list
421             List<String> jarList = getEjbJarFromApplicationXML(applicationXml);
422                         
423             // For each jar, retrieves the remote interface
424             for (String jarName:jarList) {
425                 LOG.info("EJB000006_Found_ejb-jar", new Object[]{jarName});
426                 File jarFile = findSingleFile(tempDir.getAbsolutePath(), jarName);
427             try {
428                 JarUtil.unjar(jarFile, tempDir);
429                 } catch (IOException e) {
430                 	String msg=MESSAGES.getString("EJB000002_Failure_in_opening_Jarfile", new Object[] {jarFile});
431                     LOG.error(msg,e);
432                     throw new EJBWSDLGenerationException(msg,e);
433                 }
434             }                    
435             
436             return tempDir.getAbsolutePath();
437         }
438     
439 
440 }