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.generation;
018:
019: import org.apache.bsf.BSFException;
020: import org.apache.bsf.BSFManager;
021: import org.apache.bsf.util.IOUtils;
022:
023: import org.apache.avalon.framework.configuration.Configurable;
024: import org.apache.avalon.framework.configuration.Configuration;
025: import org.apache.avalon.framework.configuration.ConfigurationException;
026: import org.apache.cocoon.ProcessingException;
027: import org.apache.cocoon.ResourceNotFoundException;
028: import org.apache.cocoon.components.source.SourceUtil;
029: import org.apache.excalibur.source.Source;
030: import org.apache.excalibur.source.SourceException;
031: import org.apache.excalibur.xml.sax.SAXParser;
032: import org.xml.sax.InputSource;
033:
034: import java.io.FileNotFoundException;
035: import java.io.InputStreamReader;
036: import java.io.Reader;
037: import java.io.StringReader;
038:
039: /**
040: * The Scriptgenerator executes arbitraty scripts using the BSF framework
041: * and additional interpreter (Rhino, Groovy, Jython, etc.) as a
042: * Cocoon Generator.
043: *
044: * Additional language support can be added during configuration, eg
045: * using:
046: *
047: * <pre>
048: * <add-languages>
049: * <language name="potatoscript" src="edu.purdue.cs.bsf.engines.Potatoscript">
050: * <extension>pos</extension>
051: * <extension>psc</extension>
052: * <language>
053: * <language name="kawa-scheme" src="org.gnu.kawa.bsf.engines.KawaEngine">
054: * <extension>scm</extension>
055: * <language>
056: * </add-languages>
057: * </pre>
058: *
059: * @author <a href="mailto:jafoster@engmail.uwaterloo.ca">Jason Foster</a>
060: * @version CVS $Id: ScriptGenerator.java 433543 2006-08-22 06:22:54Z crossley $
061: */
062: public class ScriptGenerator extends ServiceableGenerator implements
063: Configurable {
064:
065: protected static class BSFLanguage {
066: public String name;
067: public String engineSrc;
068: public String[] extensions;
069: }
070:
071: protected BSFLanguage[] additionalLanguages;
072:
073: /** The source */
074: private Source inputSource;
075:
076: public void configure(Configuration conf)
077: throws ConfigurationException {
078: if (conf != null) {
079: //add optional support for additional languages
080: Configuration languagesToAdd = conf
081: .getChild("add-languages");
082:
083: Configuration[] languages = languagesToAdd
084: .getChildren("language");
085: this .additionalLanguages = new BSFLanguage[languages.length];
086:
087: for (int i = 0; i < languages.length; i++) {
088: Configuration language = languages[i];
089: BSFLanguage bsfLanguage = new BSFLanguage();
090:
091: bsfLanguage.name = language.getAttribute("name");
092: bsfLanguage.engineSrc = language.getAttribute("src");
093:
094: getLogger().debug(
095: "Configuring ScriptGenerator with additional BSF language "
096: + bsfLanguage.name);
097: getLogger().debug(
098: "Configuring ScriptGenerator with BSF engine "
099: + bsfLanguage.engineSrc);
100:
101: Configuration[] extensions = language
102: .getChildren("extension");
103: bsfLanguage.extensions = new String[extensions.length];
104:
105: for (int j = 0; j < extensions.length; j++) {
106: bsfLanguage.extensions[j] = extensions[j]
107: .getValue();
108: getLogger().debug(
109: "Configuring ScriptGenerator with lang extension "
110: + bsfLanguage.extensions[j]);
111: }
112: this .additionalLanguages[i] = bsfLanguage;
113: }
114: }
115: }
116:
117: public void recycle() {
118: if (this .inputSource != null) {
119: this .resolver.release(this .inputSource);
120: this .inputSource = null;
121: }
122: super .recycle();
123: }
124:
125: public void generate() throws ProcessingException {
126: SAXParser parser = null;
127: try {
128: // Figure out what file to open and do so
129: getLogger().debug("processing file [" + super .source + "]");
130: this .inputSource = this .resolver.resolveURI(super .source);
131:
132: getLogger().debug(
133: "file resolved to [" + this .inputSource.getURI()
134: + "]");
135:
136: Reader in = new InputStreamReader(this .inputSource
137: .getInputStream());
138:
139: // Set up the BSF manager and register relevant helper "beans"
140: BSFManager mgr = new BSFManager();
141:
142: // add BSF support for additional languages
143: if (this .additionalLanguages != null) {
144: for (int i = 0; i < this .additionalLanguages.length; ++i) {
145: getLogger()
146: .debug(
147: "adding BSF language "
148: + this .additionalLanguages[i].name
149: + " with engine "
150: + this .additionalLanguages[i].engineSrc);
151:
152: BSFManager.registerScriptingEngine(
153: this .additionalLanguages[i].name,
154: this .additionalLanguages[i].engineSrc,
155: this .additionalLanguages[i].extensions);
156: }
157: }
158: StringBuffer output = new StringBuffer();
159:
160: // make useful objects available to scripts
161: mgr.registerBean("resolver", this .resolver);
162: mgr.registerBean("source", super .source);
163: mgr.registerBean("objectModel", this .objectModel);
164: mgr.registerBean("parameters", this .parameters);
165: mgr.registerBean("logger", getLogger());
166:
167: // provide both a StringBuffer and ContentHandler to script,
168: // so that it can provide XML either as a String or as SAX events
169: mgr.registerBean("output", output);
170: mgr.registerBean("contentHandler", contentHandler);
171:
172: // Execute the script
173: if (getLogger().isDebugEnabled()) {
174: getLogger().debug(
175: "BSFManager execution begining ("
176: + inputSource.getURI() + ")");
177: }
178: mgr.exec(BSFManager.getLangFromFilename(this .inputSource
179: .getURI()), this .inputSource.getURI(), 0, 0,
180: IOUtils.getStringFromReader(in));
181: if (getLogger().isDebugEnabled()) {
182: getLogger().debug("BSFManager execution complete");
183: }
184:
185: // If script wrote something to output buffer, use it
186: if (output.length() > 0) {
187: if (getLogger().isDebugEnabled()) {
188: getLogger().debug(
189: "Using String output provided by script ("
190: + output.toString() + ")");
191: }
192: InputSource xmlInput = new InputSource(
193: new StringReader(output.toString()));
194: parser = (SAXParser) (this .manager
195: .lookup(SAXParser.ROLE));
196: parser.parse(xmlInput, this .xmlConsumer);
197: } else {
198: if (getLogger().isDebugEnabled()) {
199: getLogger()
200: .debug(
201: "Script provided no String output, content should have been written to contentHandler");
202: }
203: }
204:
205: } catch (SourceException se) {
206: throw SourceUtil.handle(se);
207: } catch (FileNotFoundException e) {
208: throw new ResourceNotFoundException(
209: "Could not load script "
210: + this .inputSource.getURI(), e);
211: } catch (BSFException e) {
212: throw new ProcessingException(
213: "BSFException in ScriptGenerator.generate()", e);
214: } catch (Exception e) {
215: throw new ProcessingException(
216: "Exception in ScriptGenerator.generate()", e);
217: } finally {
218: if (parser != null) {
219: this.manager.release(parser);
220: }
221: }
222: }
223: }
|