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.webapps.session.context;
018:
019: import java.io.IOException;
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: import org.apache.cocoon.ProcessingException;
024: import org.apache.cocoon.components.source.SourceUtil;
025: import org.apache.cocoon.webapps.session.xml.XMLUtil;
026: import org.apache.cocoon.xml.IncludeXMLConsumer;
027: import org.apache.cocoon.xml.dom.DOMUtil;
028: import org.apache.excalibur.source.Source;
029: import org.apache.excalibur.source.SourceException;
030: import org.apache.excalibur.source.SourceParameters;
031: import org.apache.excalibur.source.SourceResolver;
032: import org.apache.excalibur.xml.xpath.NodeListImpl;
033: import org.apache.excalibur.xml.xpath.XPathProcessor;
034: import org.w3c.dom.Attr;
035: import org.w3c.dom.Document;
036: import org.w3c.dom.DocumentFragment;
037: import org.w3c.dom.Node;
038: import org.w3c.dom.NodeList;
039: import org.xml.sax.ContentHandler;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.ext.LexicalHandler;
042:
043: /**
044: * This is a simple implementation of the session context.
045: *
046: * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
047: * @deprecated This block is deprecated and will be removed in future versions.
048: * @version CVS $Id: SimpleSessionContext.java 485224 2006-12-10 17:24:05Z cziegeler $
049: */
050: public final class SimpleSessionContext implements SessionContext {
051:
052: /** Context name */
053: private String name;
054:
055: /** The content of the context */
056: private Document data;
057:
058: /** The attributes */
059: private Map attributes = new HashMap();
060:
061: /** load resource */
062: private String loadResource;
063:
064: /** save resource */
065: private String saveResource;
066:
067: /** The XPath Processor */
068: private XPathProcessor xpathProcessor;
069:
070: /** The source resolver */
071: private SourceResolver resolver;
072:
073: /**
074: * Constructor
075: */
076: public SimpleSessionContext(XPathProcessor xPathProcessor,
077: SourceResolver resolver) throws ProcessingException {
078: this .data = DOMUtil.createDocument();
079: this .data.appendChild(data.createElementNS(null, "context"));
080: this .xpathProcessor = xPathProcessor;
081: this .resolver = resolver;
082: }
083:
084: /**
085: * Get the name of the context
086: */
087: public String getName() {
088: return this .name;
089: }
090:
091: /* (non-Javadoc)
092: * @see org.apache.cocoon.webapps.session.context.SessionContext#setup(java.lang.String, java.lang.String, java.lang.String)
093: */
094: public void setup(String value, String loadResource,
095: String saveResource) {
096: this .name = value;
097: this .loadResource = loadResource;
098: this .saveResource = saveResource;
099: }
100:
101: public synchronized DocumentFragment getXML(String path)
102: throws ProcessingException {
103: DocumentFragment result = null;
104: NodeList list;
105: path = this .createPath(path);
106:
107: String[] pathComponents = DOMUtil.buildPathArray(path);
108: if (pathComponents == null) {
109: list = this .xpathProcessor.selectNodeList(this .data, path);
110: } else {
111: list = DOMUtil.getNodeListFromPath(data, pathComponents);
112: }
113:
114: if (list != null && list.getLength() > 0) {
115: Document doc = DOMUtil.createDocument();
116: result = doc.createDocumentFragment();
117:
118: for (int i = 0; i < list.getLength(); i++) {
119:
120: // the found node is either an attribute or an element
121: if (list.item(i).getNodeType() == Node.ATTRIBUTE_NODE) {
122: // if it is an attribute simple create a new text node with the value of the attribute
123: result.appendChild(doc.createTextNode(list.item(i)
124: .getNodeValue()));
125: } else {
126: // now we have an element
127: // copy all children of this element in the resulting tree
128: NodeList childs = list.item(i).getChildNodes();
129: if (childs != null) {
130: for (int m = 0; m < childs.getLength(); m++) {
131: result.appendChild(doc.importNode(childs
132: .item(m), true));
133: }
134: }
135: }
136: }
137: }
138:
139: return result;
140: }
141:
142: public synchronized void setXML(String path,
143: DocumentFragment fragment) throws ProcessingException {
144: path = this .createPath(path);
145: Node node = DOMUtil.selectSingleNode(data, path,
146: this .xpathProcessor);
147: if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
148: // now we have to serialize the fragment to a string and insert this
149: Attr attr = (Attr) node;
150: attr.setNodeValue(DOMUtil.getValueOfNode(fragment));
151:
152: } else {
153:
154: // remove old childs
155: while (node.hasChildNodes() == true) {
156: node.removeChild(node.getFirstChild());
157: }
158:
159: // Insert new childs
160: NodeList childs = fragment.getChildNodes();
161: if (childs != null && childs.getLength() > 0) {
162: for (int i = 0; i < childs.getLength(); i++) {
163: Node n = data.importNode(childs.item(i), true);
164: node.appendChild(n);
165: }
166: }
167: }
168: }
169:
170: /**
171: * Append a document fragment at the given path. The implementation of this
172: * method is context specific.
173: * Usually the children of the fragment are appended as new children of the
174: * node specified by the path.
175: * If the path is not existent it is created.
176: */
177: public synchronized void appendXML(String path,
178: DocumentFragment fragment) throws ProcessingException {
179: path = this .createPath(path);
180: Node node = DOMUtil.selectSingleNode(data, path,
181: this .xpathProcessor);
182: if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
183: Attr attr;
184:
185: if (node.getNodeValue() != null
186: || node.getNodeValue().trim().length() > 0) {
187: // this is an existing attr, create a new one
188: attr = node.getOwnerDocument().createAttributeNS(null,
189: node.getNodeName());
190: node.getParentNode().appendChild(attr);
191: } else {
192: attr = (Attr) node;
193: }
194:
195: // now we have to serialize the fragment to a string and insert this
196: attr.setNodeValue(DOMUtil.getValueOfNode(fragment));
197: } else {
198:
199: // Insert new childs
200: NodeList childs = fragment.getChildNodes();
201: if (childs != null && childs.getLength() > 0) {
202: for (int i = 0; i < childs.getLength(); i++) {
203: Node n = data.importNode(childs.item(i), true);
204: node.appendChild(n);
205: }
206: }
207: }
208: }
209:
210: /**
211: * Build path
212: */
213: private String createPath(String path) {
214: if (path == null)
215: path = "/";
216: if (!path.startsWith("/"))
217: path = "/" + path;
218: path = "context" + path;
219: if (path.endsWith("/"))
220: path = path.substring(0, path.length() - 1);
221: return path;
222: }
223:
224: /**
225: * Remove nodes
226: */
227: public synchronized void removeXML(String path)
228: throws ProcessingException {
229: NodeList list;
230: path = this .createPath(path);
231:
232: String[] pathComponents = DOMUtil.buildPathArray(path);
233: if (pathComponents == null) {
234: list = this .xpathProcessor.selectNodeList(this .data, path);
235: } else {
236: list = DOMUtil.getNodeListFromPath(data, pathComponents);
237: }
238: if (list != null && list.getLength() > 0) {
239: int len = list.getLength();
240: Node child;
241: for (int i = 0; i < len; i++) {
242: child = list.item(len - 1 - i);
243: child.getParentNode().removeChild(child);
244: }
245: }
246: }
247:
248: /**
249: * Get a copy the first node specified by the path.
250: */
251: public synchronized Node getSingleNode(String path)
252: throws ProcessingException {
253: Node result = null;
254:
255: path = this .createPath(path);
256:
257: try {
258: result = DOMUtil.getSingleNode(data, path,
259: this .xpathProcessor);
260: if (result != null)
261: result = result.cloneNode(true);
262: } catch (javax.xml.transform.TransformerException localException) {
263: throw new ProcessingException("TransformerException: "
264: + localException, localException);
265: }
266:
267: return result;
268: }
269:
270: /**
271: * Get a copy all the nodes specified by the path.
272: */
273: public synchronized NodeList getNodeList(String path)
274: throws ProcessingException {
275: NodeList result = null;
276:
277: path = this .createPath(path);
278:
279: String[] pathComponents = DOMUtil.buildPathArray(path);
280: if (pathComponents == null) {
281: result = this .xpathProcessor
282: .selectNodeList(this .data, path);
283: } else {
284: result = DOMUtil.getNodeListFromPath(data, pathComponents);
285: }
286: // clone list
287: if (result != null) {
288: result = new NodeListImpl(result);
289: }
290:
291: return result;
292: }
293:
294: /**
295: * Set the value of a node. The node is copied before insertion.
296: */
297: public synchronized void setNode(String path, Node node)
298: throws ProcessingException {
299: if (path == null || path.equals("/")) {
300: data = DOMUtil.createDocument();
301: data.appendChild(data.createElementNS(null, "context"));
302: data.getFirstChild().appendChild(
303: data.importNode(node, true));
304: } else {
305: path = this .createPath(path);
306: Node removeNode = DOMUtil.selectSingleNode(data, path,
307: this .xpathProcessor);
308: removeNode.getParentNode().replaceChild(
309: data.importNode(node, true), removeNode);
310: }
311: }
312:
313: /**
314: * Set a context attribute. If value is null the attribute is removed.
315: */
316: public synchronized void setAttribute(String key, Object value) {
317: if (value == null) {
318: attributes.remove(key);
319: } else {
320: attributes.put(key, value);
321: }
322: }
323:
324: /**
325: * Get a context attribute. If the attribute is not available return null
326: */
327: public synchronized Object getAttribute(String key) {
328: return attributes.get(key);
329: }
330:
331: /**
332: * Get a context attribute. If the attribute is not available the defaultObject is returned
333: */
334: public synchronized Object getAttribute(String key,
335: Object defaultObject) {
336: Object value = attributes.get(key);
337: if (value == null)
338: value = defaultObject;
339: return value;
340: }
341:
342: /**
343: * Get the value of this node. This is similiar to the xsl:value-of
344: * function. If the node does not exist, <code>null</code> is returned.
345: */
346: public synchronized String getValueOfNode(String path)
347: throws ProcessingException {
348: String value = null;
349:
350: path = this .createPath(path); // correct path
351: value = DOMUtil.getValueOf(data, path, this .xpathProcessor);
352:
353: return value;
354: }
355:
356: /**
357: * Set the value of a node.
358: */
359: public synchronized void setValueOfNode(String path, String value)
360: throws ProcessingException {
361: path = this .createPath(path); // correct path
362:
363: Node node = DOMUtil.selectSingleNode(data, path,
364: this .xpathProcessor);
365: if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
366: Attr attr = (Attr) node;
367: attr.setNodeValue(value);
368:
369: } else {
370:
371: // remove old childs
372: while (node.hasChildNodes() == true) {
373: node.removeChild(node.getFirstChild());
374: }
375:
376: node.appendChild(node.getOwnerDocument().createTextNode(
377: value));
378: }
379: }
380:
381: /**
382: * Stream the XML directly to the handler. This streams the contents of getXML()
383: * to the given handler without creating a DocumentFragment containing a copy
384: * of the data
385: */
386: public synchronized boolean streamXML(String path,
387: ContentHandler contentHandler, LexicalHandler lexicalHandler)
388: throws SAXException, ProcessingException {
389: NodeList list;
390: boolean streamed = false;
391: path = this .createPath(path);
392:
393: String[] pathComponents = DOMUtil.buildPathArray(path);
394: if (pathComponents == null) {
395: list = this .xpathProcessor.selectNodeList(this .data, path);
396: } else {
397: list = DOMUtil.getNodeListFromPath(data, pathComponents);
398: }
399: if (list != null && list.getLength() > 0) {
400: streamed = true;
401: for (int i = 0; i < list.getLength(); i++) {
402:
403: // the found node is either an attribute or an element
404: if (list.item(i).getNodeType() == Node.ATTRIBUTE_NODE) {
405: // if it is an attribute simple create a new text node with the value of the attribute
406: String value = list.item(i).getNodeValue();
407: contentHandler.characters(value.toCharArray(), 0,
408: value.length());
409: } else {
410: // now we have an element
411: // stream all children of this element to the resulting tree
412: NodeList childs = list.item(i).getChildNodes();
413: if (childs != null) {
414: for (int m = 0; m < childs.getLength(); m++) {
415: IncludeXMLConsumer.includeNode(childs
416: .item(m), contentHandler,
417: lexicalHandler);
418: }
419: }
420: }
421: }
422: }
423:
424: return streamed;
425: }
426:
427: /**
428: * Try to load XML into the context.
429: * If the context does not provide the ability of loading,
430: * an exception is thrown.
431: */
432: public void loadXML(String path, SourceParameters parameters)
433: throws SAXException, ProcessingException, IOException {
434: if (this .loadResource == null) {
435: throw new ProcessingException("The context " + this .name
436: + " does not support loading.");
437: }
438: Source source = null;
439: try {
440: source = SourceUtil.getSource(this .loadResource, null,
441: parameters, this .resolver);
442: Document doc = SourceUtil.toDOM(source);
443: DocumentFragment df = doc.createDocumentFragment();
444: df.appendChild(doc.getDocumentElement());
445: this .setXML(path, df);
446: } catch (SourceException se) {
447: throw SourceUtil.handle(se);
448: } finally {
449: resolver.release(source);
450: }
451: }
452:
453: /**
454: * Try to save XML from the context.
455: * If the context does not provide the ability of saving,
456: * an exception is thrown.
457: */
458: public void saveXML(String path, SourceParameters parameters)
459: throws SAXException, ProcessingException, IOException {
460: if (this .saveResource == null) {
461: throw new ProcessingException("The context " + this .name
462: + " does not support saving.");
463: }
464: DocumentFragment frag = this .getXML(path);
465: if (frag == null) {
466: // create empty fake document
467: frag = DOMUtil.createDocument().createDocumentFragment();
468: }
469:
470: XMLUtil.writeDOM(this .saveResource, null, parameters, frag,
471: this .resolver, "xml");
472: }
473:
474: }
|