1   /*
2    *
3    *  Copyright (c) 1998-2005, The University of Sheffield.
4    *
5    *  This file is part of GATE (see http://gate.ac.uk/), and is free
6    *  software, licenced under the GNU Library General Public License,
7    *  Version 2, June 1991 (in the distribution as file licence.html,
8    *  and also available at http://gate.ac.uk/gate/licence.html).
9    *
10   *  Valentin Tablan, 18/Feb/2002
11   *
12   *  $Id: Javac.java,v 1.24 2005/01/11 13:51:37 ian Exp $
13   */
14  package gate.util;
15  
16  import java.io.*;
17  import java.util.*;
18  
19  import gate.Gate;
20  import gate.GateConstants;
21  
22  /**
23   * This class compiles a set of java sources using the user's preferred Java
24   * compiler.  The default compiler used is the Eclipse JDT compiler, but this
25   * can be overridden by the user via an option in gate.xml.
26   */
27  public abstract class Javac implements GateConstants {
28  
29    /**
30     * Compiles a set of java sources and loads the compiled classes in the gate
31     * class loader.
32     * @param sources a map from fully qualified classname to java source
33     * @throws GateException in case of a compilation error or warning.
34     * In the case of warnings the compiled classes are loaded before the error is
35     * raised.
36     */
37    public static void loadClasses(Map sources) throws GateException {
38      if(compiler == null) {
39        setCompilerTypeFromUserConfig();
40      }
41  
42      compiler.compile(sources);
43    }
44  
45    /**
46     * Sets the type of compiler to be used, based on the user's configuration.
47     * The default is to use the Eclipse compiler unless the user requests
48     * otherwise.
49     */
50    private static void setCompilerTypeFromUserConfig() throws GateException {
51      if(classLoader == null) classLoader = Gate.getClassLoader();
52      // see if the user has expressed a preference
53      String compilerType = Gate.getUserConfig().getString(COMPILER_TYPE_KEY);
54      // if not, use the default
55      if(compilerType == null) {
56        compilerType = DEFAULT_COMPILER;
57      }
58  
59      // We try and load the compiler class first by treating the given name as a
60      // fully qualified class name.  If this fails, we prepend
61      // "gate.util.compilers." (so the user can say just "Sun" rather than
62      // "gate.util.compilers.Sun").  If that fails, we try the default value
63      // DEFAULT_COMPILER.  If that fails, we give up.
64      Class compilerClass = null;
65      try {
66        // first treat the compiler type as a fully qualified class name
67        compilerClass = classLoader.loadClass(compilerType, true);
68      }
69      catch(ClassNotFoundException cnfe) {
70        // not a problem
71      }
72  
73      if(compilerClass == null 
74          || !Javac.class.isAssignableFrom(compilerClass)) {
75        // failed to find the class as a FQN, so try relative to
76        // gate.util.compilers
77        compilerType = "gate.util.compilers." + compilerType;
78        try {
79          compilerClass = classLoader.loadClass(compilerType, true);
80        }
81        catch(ClassNotFoundException cnfe2) {
82          // still not a problem
83        }
84      }
85  
86      if(compilerClass == null
87          || !Javac.class.isAssignableFrom(compilerClass)) {
88        Err.prln("Unable to load compiler class " + compilerType 
89            + ", falling back to default of " + DEFAULT_COMPILER);
90        compilerType = DEFAULT_COMPILER;
91        try {
92          compilerClass = classLoader.loadClass(compilerType, true);
93        }
94        catch(ClassNotFoundException cnfe3) {
95          // a problem
96        }
97      }
98  
99      if(compilerClass == null
100         || !Javac.class.isAssignableFrom(compilerClass)) {
101       throw new GateException("Unable to load a Java compiler class");
102     }
103     
104     // At this point we have successfully loaded a compiler class.
105     // Now create an instance using a no-argument constructor.
106     try {
107       compiler = (Javac)compilerClass.newInstance();
108     }
109     catch(IllegalAccessException iae) {
110       Err.prln("Cannot access Java compiler class " + compilerType);
111       throw new GateException(iae);
112     }
113     catch(InstantiationException ie) {
114       Err.prln("Cannot instantiate Java compiler class " + compilerType);
115       throw new GateException(ie);
116     }
117   }
118 
119   /**
120    * Compile a set of Java sources, and load the resulting classes into the
121    * GATE class loader.
122    *
123    * @param sources a map from fully qualified classname to java source
124    * @throws GateException in case of a compilation error or warning.
125    * In the case of warnings, the compiled classes are loaded before the
126    * exception is thrown.
127    */
128   public abstract void compile(Map sources) throws GateException;
129 
130   /**
131    * The compiler to use.
132    */
133   private static Javac compiler = null;
134 
135   /**
136    * The GATE class loader.
137    */
138   private static GateClassLoader classLoader = null;
139   
140   /**
141    * The default compiler to use.
142    */
143   public static final String DEFAULT_COMPILER = "gate.util.compilers.Eclipse";
144 }
145