View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import java.util.Properties;
7   
8   public class LanguageFactory {
9   
10  	// TODO derive and provide this at runtime instead, used by outside IDEs
11     public static String[] supportedLanguages = new String[]{"java", "jsp", "cpp", "c", "php", "ruby","fortran", "ecmascript","cs" };
12     
13     private static final String SUFFIX = "Language";
14     public static final String EXTENSION = "extension";
15     public static final String BY_EXTENSION = "by_extension";
16     private static final String PACKAGE = "net.sourceforge.pmd.cpd.";
17  
18      public Language createLanguage(String language) {
19          return createLanguage(language, new Properties());
20      }
21  
22     public Language createLanguage(String language, Properties properties)
23     {
24       language = this.languageAliases(language);
25       // First, we look for a parser following this syntax 'RubyLanguage'
26       Language implementation;
27       try {
28         implementation = this.dynamicLanguageImplementationLoad(this.languageConventionSyntax(language));
29         if ( implementation == null )
30         {
31           // if it failed, we look for a parser following this syntax 'CPPLanguage'
32           implementation = this.dynamicLanguageImplementationLoad(language.toUpperCase());
33           //TODO: Should we try to break the coupling with PACKAGE by try to load the class
34           // based on her sole name ?
35           if ( implementation == null )
36           {
37             // No proper implementation
38             // FIXME: We should log a warning, shouldn't we ?
39             return new AnyLanguage(language);
40           }
41         }
42         return implementation;
43       } catch (InstantiationException e) {
44         e.printStackTrace();
45       } catch (IllegalAccessException e) {
46         e.printStackTrace();
47       }
48       return null;
49     }
50  
51       private String languageAliases(String language)
52       {
53         // CPD and C language share the same parser
54         if ( "c".equals(language) ) {
55           return "cpp";
56         }
57         return language;
58       }
59  
60      private Language dynamicLanguageImplementationLoad(String language) throws InstantiationException, IllegalAccessException
61      {
62          try {
63              return (Language) this.getClass().getClassLoader().loadClass(
64                  PACKAGE + language + SUFFIX).newInstance();
65          } catch (ClassNotFoundException e) {
66              // No class found, returning default implementation
67              // FIXME: There should be somekind of log of this
68              return null;
69          } catch (NoClassDefFoundError e) {
70              // Windows is case insensitive, so it may find the file, even though
71              // the name has a different case. Since Java is case sensitive, it
72              // will not accept the classname inside the file that was found and
73              // will throw a NoClassDefFoundError
74              return null;
75          }
76      }
77  
78     /*
79      * This method does simply this:
80      * ruby -> Ruby
81      * fortran -> Fortran
82      * ...
83      */
84     private String languageConventionSyntax(String language) {
85         return Character.toUpperCase(language.charAt(0)) + language.substring(1, language.length()).toLowerCase();
86      }
87  }