001 /*
002 *
003 * Copyright (c) 1995-2010, The University of Sheffield. See the file
004 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
005 *
006 * This file is part of GATE (see http://gate.ac.uk/), and is free
007 * software, licenced under the GNU Library General Public License,
008 * Version 2, June 1991 (in the distribution as file licence.html,
009 * and also available at http://gate.ac.uk/gate/licence.html).
010 *
011 * Valentin Tablan, 18/Feb/2002
012 *
013 * $Id: Javac.java 12006 2009-12-01 17:24:28Z thomas_heitz $
014 */
015 package gate.util;
016
017 import java.io.*;
018 import java.lang.reflect.Constructor;
019 import java.lang.reflect.InvocationTargetException;
020 import java.util.*;
021
022 import gate.Gate;
023 import gate.GateConstants;
024
025 /**
026 * This class compiles a set of java sources using the user's preferred
027 * Java compiler. The default compiler used is the Eclipse JDT compiler,
028 * but this can be overridden by the user via an option in gate.xml.
029 */
030 public abstract class Javac implements GateConstants {
031
032 /**
033 * Compiles a set of java sources and loads the compiled classes in
034 * the gate class loader.
035 *
036 * @param sources a map from fully qualified classname to java source
037 * @throws GateException in case of a compilation error or warning. In
038 * the case of warnings the compiled classes are loaded
039 * before the error is raised.
040 */
041 public static void loadClasses(Map sources) throws GateException {
042 if(compiler == null) {
043 setCompilerTypeFromUserConfig();
044 }
045
046 compiler.compile(sources);
047 }
048
049 /**
050 * Sets the type of compiler to be used, based on the user's
051 * configuration. The default is to use the Eclipse compiler unless
052 * the user requests otherwise.
053 */
054 private static void setCompilerTypeFromUserConfig() throws GateException {
055 if(classLoader == null) classLoader = Gate.getClassLoader();
056 // see if the user has expressed a preference
057 String compilerType = Gate.getUserConfig().getString(COMPILER_TYPE_KEY);
058 // if not, use the default
059 if(compilerType == null) {
060 compilerType = DEFAULT_COMPILER;
061 }
062
063 // We try and load the compiler class first by treating the given
064 // name as a fully qualified class name. If this fails, we prepend
065 // "gate.util.compilers." (so the user can say just "Sun" rather
066 // than "gate.util.compilers.Sun"). If that fails, we try the
067 // default value DEFAULT_COMPILER. If that fails, we give up.
068 try {
069 // first treat the compiler type as a fully qualified class name
070 compiler = createCompilerInstance(compilerType);
071 }
072 catch(GateException ge) {
073 // if it's the default compiler we've just failed to load, give up
074 // now
075 if(DEFAULT_COMPILER.equals(compilerType)) {
076 throw ge;
077 }
078
079 // we failed to find the class as a FQN, so try relative to
080 // gate.util.compilers
081 compilerType = "gate.util.compilers." + compilerType;
082 try {
083 compiler = createCompilerInstance(compilerType);
084 }
085 catch(GateException ge2) {
086 // if it's the default compiler we've just failed to load, give
087 // up now
088 if(DEFAULT_COMPILER.equals(compilerType)) {
089 throw ge2;
090 }
091
092 Err.prln("Unable to load compiler class " + compilerType
093 + ", falling back to default of " + DEFAULT_COMPILER);
094 compilerType = DEFAULT_COMPILER;
095 // last try - fall back on the default value. If this fails we
096 // just allow the failure exception to propagate up the stack
097 // from here.
098 compiler = createCompilerInstance(compilerType);
099 }
100 }
101 }
102
103 private static Javac createCompilerInstance(String compilerType)
104 throws GateException {
105 Class compilerClass = null;
106 try {
107 // first treat the compiler type as a fully qualified class name
108 compilerClass = classLoader.loadClass(compilerType, true);
109 }
110 catch(ClassNotFoundException cnfe) {
111 // ignore exception but leave compilerClass == null
112 }
113
114 if(compilerClass == null || !Javac.class.isAssignableFrom(compilerClass)) {
115 throw new GateException("Unable to load Java compiler class "
116 + compilerType);
117 }
118
119 // At this point we have successfully loaded a compiler class.
120 // Now try and create an instance using a no-argument constructor.
121 try {
122 Constructor<?> noArgConstructor = compilerClass.getConstructor();
123 return (Javac)noArgConstructor.newInstance();
124 }
125 catch(IllegalAccessException iae) {
126 throw new GateException("Cannot access Java compiler class "
127 + compilerType, iae);
128 }
129 catch(InstantiationException ie) {
130 throw new GateException("Cannot instantiate Java compiler class "
131 + compilerType, ie);
132 }
133 catch(NoSuchMethodException nsme) {
134 throw new GateException("Java compiler class " + compilerType
135 + " does not have a no-argument constructor", nsme);
136 }
137 catch(InvocationTargetException ite) {
138 throw new GateException("Exception when constructing Java compiler " +
139 "of type " + compilerType, ite.getCause());
140 }
141 catch(ExceptionInInitializerError eiie) {
142 throw new GateException("Exception when initializing Java compiler "
143 + "class " + compilerType, eiie.getCause());
144 }
145 }
146
147 /**
148 * Compile a set of Java sources, and load the resulting classes into
149 * the GATE class loader.
150 *
151 * @param sources a map from fully qualified classname to java source
152 * @throws GateException in case of a compilation error or warning. In
153 * the case of warnings, the compiled classes are loaded
154 * before the exception is thrown.
155 */
156 public abstract void compile(Map sources) throws GateException;
157
158 /**
159 * The compiler to use.
160 */
161 private static Javac compiler = null;
162
163 /**
164 * The GATE class loader.
165 */
166 private static GateClassLoader classLoader = null;
167
168 /**
169 * The default compiler to use.
170 */
171 public static final String DEFAULT_COMPILER = "gate.util.compilers.Eclipse";
172 }
|