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