001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.language.programming;
018:
019: import org.apache.avalon.framework.context.Context;
020: import org.apache.avalon.framework.context.ContextException;
021: import org.apache.avalon.framework.context.Contextualizable;
022: import org.apache.avalon.framework.parameters.Parameters;
023: import org.apache.avalon.framework.parameters.ParameterException;
024:
025: import org.apache.cocoon.Constants;
026: import org.apache.cocoon.components.language.LanguageException;
027: import org.apache.cocoon.components.language.programming.java.JavaProgram;
028: import org.apache.cocoon.util.ClassUtils;
029: import org.apache.cocoon.util.IOUtils;
030:
031: import java.io.File;
032:
033: /**
034: * A compiled programming language. This class extends <code>AbstractProgrammingLanguage</code> adding support for compilation
035: * and object program files
036: * @author <a href="mailto:ricardo@apache.org">Ricardo Rocha</a>
037: * @version CVS $Id: CompiledProgrammingLanguage.java 433543 2006-08-22 06:22:54Z crossley $
038: */
039: public abstract class CompiledProgrammingLanguage extends
040: AbstractProgrammingLanguage implements Contextualizable {
041:
042: /** The compiler */
043: protected Class compilerClass;
044:
045: /** The local classpath */
046: protected String classpath;
047:
048: /** The source deletion option */
049: protected boolean deleteSources = false;
050:
051: /**
052: * Set the configuration parameters. This method instantiates the sitemap-specified language compiler
053: * @param params The configuration parameters
054: * @exception ParameterException If the language compiler cannot be loaded
055: */
056: public void parameterize(Parameters params)
057: throws ParameterException {
058: super .parameterize(params);
059:
060: String compilerClass = params.getParameter("compiler");
061: try {
062: this .compilerClass = ClassUtils.loadClass(compilerClass);
063: } catch (ClassNotFoundException e) {
064: throw new ParameterException("Unable to load compiler: "
065: + compilerClass, e);
066: }
067: this .deleteSources = params.getParameterAsBoolean(
068: "delete-sources", false);
069: }
070:
071: /**
072: * Set the context
073: * @param context The context
074: */
075: public void contextualize(Context context) throws ContextException {
076: this .classpath = (String) context
077: .get(Constants.CONTEXT_CLASSPATH);
078: }
079:
080: /**
081: * Return the language's canonical object file extension.
082: * @return The object file extension
083: */
084: public abstract String getObjectExtension();
085:
086: /**
087: * Unload a previously loaded program
088: * @param program A previously loaded object program
089: * @exception LanguageException If an error occurs during unloading
090: */
091: public abstract void doUnload(Object program)
092: throws LanguageException;
093:
094: /**
095: * Unload a previously loaded program given its original filesystem location
096: * @param program The previously loaded object program
097: * @param filename The base filename of the object program
098: * @param baseDirectory The directory contaning the object program file
099: * @exception LanguageException If an error occurs
100: */
101: protected final void doUnload(Object program, String filename,
102: File baseDirectory) throws LanguageException {
103: int index = filename.lastIndexOf(File.separator);
104: String dir = filename.substring(0, index);
105: String file = filename.substring(index + 1);
106:
107: File baseDir = new File(baseDirectory, dir);
108: File[] files = baseDir.listFiles();
109:
110: for (int i = 0; (files != null) && (i < files.length); i++) {
111: if (files[i].getName().startsWith(file)) {
112: files[i].delete();
113: }
114: }
115: this .doUnload(program);
116: }
117:
118: /**
119: * Actually load an object program from a file.
120: * @param filename The object program base file name
121: * @param baseDirectory The directory containing the object program file
122: * @return The loaded object program
123: * @exception LanguageException If an error occurs during loading
124: */
125: protected abstract Class loadProgram(String filename,
126: File baseDirectory) throws LanguageException;
127:
128: /**
129: * Compile a source file yielding a loadable object file.
130: * @param filename The object program base file name
131: * @param baseDirectory The directory containing the object program file
132: * @param encoding The encoding expected in the source file or <code>null</code> if it is the platform's default encoding
133: * @exception LanguageException If an error occurs during compilation
134: */
135: protected abstract void compile(String filename,
136: File baseDirectory, String encoding)
137: throws LanguageException;
138:
139: /**
140: * Preload an object program from a file.
141: * This method does not compiles the corresponding source file.
142: *
143: * @param filename The object program base file name
144: * @param baseDirectory The directory containing the object program file
145: * @param encoding The encoding expected in the source file or <code>null</code> if it is the platform's default encoding
146: * @return The loaded object program
147: * @exception LanguageException If an error occurs during compilation
148: */
149: public Program preload(String filename, File baseDirectory,
150: String encoding) throws LanguageException {
151: // Don't need to test for existence of the object code as it might be bundled into the WAR.
152: try {
153: Class program = this .loadProgram(filename, baseDirectory);
154: // Create and discard test instance.
155: program.newInstance();
156: return new JavaProgram(program);
157: } catch (Throwable t) {
158: throw new LanguageException("Unable to preload program "
159: + filename, t);
160: }
161: }
162:
163: /**
164: * Load an object program from a file.
165: * This method compiles the corresponding source file if necessary.
166: *
167: * @param filename The object program base file name
168: * @param baseDirectory The directory containing the object program file
169: * @param encoding The encoding expected in the source file or <code>null</code> if it is the platform's default encoding
170: * @return The loaded object program
171: * @exception LanguageException If an error occurs during compilation
172: */
173: public Program load(String filename, File baseDirectory,
174: String encoding) throws LanguageException {
175:
176: // Does source file exist?
177: File sourceFile = new File(baseDirectory, filename + "."
178: + this .getSourceExtension());
179: if (!sourceFile.exists()) {
180: throw new LanguageException(
181: "Can't load program - File doesn't exist: "
182: + IOUtils.getFullFilename(sourceFile));
183: }
184: if (!sourceFile.isFile()) {
185: throw new LanguageException(
186: "Can't load program - File is not a normal file: "
187: + IOUtils.getFullFilename(sourceFile));
188: }
189: if (!sourceFile.canRead()) {
190: throw new LanguageException(
191: "Can't load program - File cannot be read: "
192: + IOUtils.getFullFilename(sourceFile));
193: }
194: this .compile(filename, baseDirectory, encoding);
195: if (this .deleteSources) {
196: sourceFile.delete();
197: }
198: Class program = this .loadProgram(filename, baseDirectory);
199:
200: // Try to instantiate once to ensure there are no exceptions thrown in the constructor
201: try {
202: // Create and discard test instance
203: program.newInstance();
204: } catch (IllegalAccessException iae) {
205: getLogger().debug(
206: "No public constructor for class "
207: + program.getName());
208: } catch (Exception e) {
209: // Unload class and delete the object file, or it won't be recompiled
210: // (leave the source file to allow examination).
211: this .doUnload(program);
212: new File(baseDirectory, filename + "."
213: + this .getObjectExtension()).delete();
214:
215: String message = "Error while instantiating " + filename;
216: getLogger().debug(message, e);
217: throw new LanguageException(message, e);
218: }
219:
220: if (program == null) {
221: throw new LanguageException("Can't load program : "
222: + baseDirectory.toString() + File.separator
223: + filename);
224: }
225:
226: return new JavaProgram(program);
227: }
228: }
|