001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package nl.hippo.cms.javascript;
017:
018: import java.io.IOException;
019: import java.io.Serializable;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.parameters.ParameterException;
027: import org.apache.avalon.framework.parameters.Parameters;
028: import org.apache.cocoon.ProcessingException;
029: import org.apache.cocoon.caching.CacheableProcessingComponent;
030: import org.apache.cocoon.environment.ObjectModelHelper;
031: import org.apache.cocoon.environment.Request;
032: import org.apache.cocoon.environment.Session;
033: import org.apache.cocoon.environment.SourceResolver;
034: import org.apache.cocoon.transformation.AbstractSAXTransformer;
035: import org.apache.cocoon.xml.AttributesImpl;
036: import org.apache.cocoon.xml.XMLUtils;
037: import org.apache.excalibur.source.SourceValidity;
038: import org.apache.excalibur.source.impl.validity.NOPValidity;
039: import org.xml.sax.Attributes;
040: import org.xml.sax.SAXException;
041:
042: /**
043: * @author <a href="mailto:abogaart@hippo.nl">Arthur Bogaart</a>
044: *
045: */
046: public class JavascriptPackageTransformer extends
047: AbstractSAXTransformer implements CacheableProcessingComponent {
048:
049: /**
050: * <p>
051: * The namespace URI of the elements recognized by this transformer.
052: * </p>
053: */
054: private static final String NS_URI = "http://hippo.nl/cms/javascript"; //TODO: implement namespace
055: private static final String EMPTY_NS_URI = "";
056:
057: private static final String PACKAGE_ELEMENT = "scriptpackage";
058: private static final String SCRIPT_ELEMENT = "script";
059: private static final String SCRIPT_ATTR_TYPE = "text/javascript";
060:
061: private static final String JSPACKAGE_KEY = "jspackage-key";
062: private static final String SRC_ATTRIBUTE = "src";
063: private static final String ID_ATTRIBUTE = "id";
064: private static final String INLINE_ATTRIBUTE = "inline";
065:
066: private Request request;
067: private Session session;
068:
069: private boolean lenient = false;//TODO: implement config
070: private String packagerUrl;
071: private State state = new State();
072: private JavascriptPackageHandler jph;
073:
074: public void setup(SourceResolver resolver, Map objectModel,
075: String src, Parameters parameters)
076: throws ProcessingException, SAXException, IOException {
077:
078: super .setup(resolver, objectModel, src, parameters);
079: this .resolver = resolver;
080: request = ObjectModelHelper.getRequest(objectModel);
081: session = request.getSession();
082: jph = new JavascriptPackageHandler(lenient, getLogger()
083: .getChildLogger("JavascriptPackageHandler"));
084: try {
085: this .packagerUrl = parameters.getParameter("packagerUrl");
086: } catch (ParameterException e) {
087: throw new ProcessingException(
088: "Parameter packagerUrl is undefined");
089: }
090: }
091:
092: public void recycle() {
093: super .recycle();
094: state.clear(false);
095: }
096:
097: public void startDocument() throws SAXException {
098:
099: if (super .contentHandler != null) {
100: super .contentHandler.startDocument();
101: }
102: }
103:
104: /**
105: * Receive notification of the end of a document.
106: */
107: public void endDocument() throws SAXException {
108:
109: if (super .contentHandler != null) {
110: super .contentHandler.endDocument();
111: }
112: }
113:
114: public void startTransformingElement(String uri, String name,
115: String raw, Attributes attr) throws SAXException,
116: IOException, ProcessingException {
117:
118: if (getLogger().isDebugEnabled()) {
119: getLogger().debug(
120: "Start transforming element. uri=" + uri
121: + ", name=" + name + ", raw=" + raw
122: + ", attr=" + attr.getValue("id"));
123: }
124:
125: if (name.equals(PACKAGE_ELEMENT)) {
126: if (state.inScriptWrapper) {
127: throw new ProcessingException(
128: "Package elements cannot be nested.");
129: }
130: state.setInScriptWrapper();
131: if (attr.getValue(INLINE_ATTRIBUTE) != null
132: && attr.getValue(INLINE_ATTRIBUTE).equals("true")) {
133: state.setInline();
134: }
135: state.setId(attr.getValue(ID_ATTRIBUTE));
136: } else if (state.inScriptWrapper && name.equals(SCRIPT_ELEMENT)) {
137: state.addSource(attr.getValue(SRC_ATTRIBUTE));
138: } else {
139: super .contentHandler.startElement(uri, name, raw, attr);
140: }
141:
142: }
143:
144: public void endTransformingElement(String uri, String name,
145: String raw) throws SAXException, IOException,
146: ProcessingException {
147:
148: if (getLogger().isDebugEnabled()) {
149: getLogger().debug(
150: "Start transforming element. uri=" + uri
151: + ", name=" + name + ", raw=" + raw);
152: }
153: if (name.equals(PACKAGE_ELEMENT)) {
154: if (state.inline) {
155: super .contentHandler.startElement(EMPTY_NS_URI,
156: SCRIPT_ELEMENT, SCRIPT_ELEMENT,
157: XMLUtils.EMPTY_ATTRIBUTES);
158: jph.sourcesToCharacters(state.sources, resolver,
159: contentHandler);
160: super .contentHandler.endElement(EMPTY_NS_URI,
161: SCRIPT_ELEMENT, SCRIPT_ELEMENT);
162: } else {
163: AttributesImpl attr = new AttributesImpl();
164: attr.addCDATAAttribute("src", packagerUrl
165: + state.getId() + ".js");
166: attr.addCDATAAttribute("type", SCRIPT_ATTR_TYPE);
167: super .contentHandler.startElement(EMPTY_NS_URI,
168: SCRIPT_ELEMENT, SCRIPT_ELEMENT, attr);
169:
170: Map packages = (session.getAttribute(JSPACKAGE_KEY) != null) ? (Map) session
171: .getAttribute(JSPACKAGE_KEY)
172: : new HashMap();
173: packages.put(state.getId(), state.sources);
174: session.setAttribute(JSPACKAGE_KEY, packages);
175:
176: super .contentHandler.endElement(EMPTY_NS_URI,
177: SCRIPT_ELEMENT, SCRIPT_ELEMENT);
178: }
179: state.clear(true);
180: } else if (state.inScriptWrapper) {
181: //ignore end element of all scriptwrapper content
182: } else {
183: super .contentHandler.endElement(uri, name, raw);
184: }
185: }
186:
187: public Serializable getKey() {
188: return "1";
189: }
190:
191: public SourceValidity getValidity() {
192: return NOPValidity.SHARED_INSTANCE;
193: }
194:
195: class State {
196: private String id = "";
197: private boolean inScriptWrapper = false;
198: private boolean inline = false;
199: private List sources = new ArrayList();
200:
201: public void setInline() {
202: inline = true;
203: }
204:
205: public void setInScriptWrapper() {
206: inScriptWrapper = true;
207: }
208:
209: public String getId() {
210: return id;
211: }
212:
213: public void setId(String id) {
214: this .id = id;
215: }
216:
217: public void addSource(String source) {
218: sources.add(source);
219: }
220:
221: public Iterator getSourcesIterator() {
222: return sources.iterator();
223: }
224:
225: public void clear(boolean restart) {
226: inScriptWrapper = false;
227: inline = false;
228: id = "";
229: if (restart)
230: sources = new ArrayList();
231: else
232: sources.clear();
233: }
234: }
235: }
|