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.portal.context;
018:
019: import org.apache.cocoon.ProcessingException;
020: import org.apache.cocoon.environment.ObjectModelHelper;
021: import org.apache.cocoon.environment.Request;
022: import org.apache.cocoon.webapps.portal.PortalConstants;
023: import org.apache.cocoon.webapps.portal.components.PortalManager;
024: import org.apache.cocoon.webapps.portal.components.PortalManagerImpl;
025: import org.apache.cocoon.webapps.session.context.SessionContext;
026: import org.apache.cocoon.xml.IncludeXMLConsumer;
027: import org.apache.cocoon.xml.dom.DOMBuilder;
028: import org.apache.cocoon.xml.dom.DOMUtil;
029: import org.apache.excalibur.source.SourceParameters;
030: import org.apache.excalibur.xml.xpath.XPathProcessor;
031: import org.xml.sax.ContentHandler;
032: import org.xml.sax.SAXException;
033: import org.xml.sax.ext.LexicalHandler;
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Element;
036: import org.w3c.dom.Node;
037: import org.w3c.dom.NodeList;
038: import org.w3c.dom.DocumentFragment;
039: import org.w3c.dom.Attr;
040:
041: import java.io.IOException;
042: import java.util.HashMap;
043: import java.util.Map;
044:
045: /**
046: * The portal context
047: *
048: * This context allows access to various parts of a portal profile.
049: * The context provides reading of the following xml, if the current
050: * resource is running inside a portal module:
051: * <layout>
052: * <portal>
053: * ...
054: * </portal>
055: * <coplets>
056: * ...
057: * </coplets>
058: * </layout>
059: * <configuration>
060: * ...
061: * </configuration>
062: *
063: * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
064: * @version CVS $Id: SessionContextImpl.java 433543 2006-08-22 06:22:54Z crossley $
065: */
066: public final class SessionContextImpl implements SessionContext {
067:
068: /* This contains all information about the currently processed coplet */
069: public static ThreadLocal copletInfo = new ThreadLocal();
070:
071: /** The context name */
072: private String name;
073:
074: /** The attributes */
075: private Map attributes = new HashMap();
076:
077: /** The cached layoutDOM */
078: private Document layoutDOM;
079:
080: /** The cached configurationDOM */
081: private Document configurationDOM;
082:
083: /** The current profile */
084: private Map profile;
085:
086: /** All coplet parameters */
087:
088: private SourceParameters copletPars;
089:
090: /** The status profile */
091: private Element statusProfile;
092:
093: /** the coplet id */
094: private String copletID;
095:
096: /** The number of the coplet */
097: private String copletNumber;
098:
099: /** The profile ID */
100: private String profileID;
101:
102: /** The portal URI */
103: private String portalURI;
104:
105: /** The media type */
106: private String mediaType;
107:
108: /** The current request */
109: private Request request;
110:
111: /** The XPath Processor */
112: private XPathProcessor xpathProcessor;
113:
114: public SessionContextImpl(String name, Map objectModel,
115: PortalManager portal, XPathProcessor xpathProcessor)
116: throws IOException, SAXException, ProcessingException {
117: this .xpathProcessor = xpathProcessor;
118: this .setup(name, null, null);
119:
120: // try to get the resource connector info
121: Map info = (Map) SessionContextImpl.copletInfo.get();
122: if (info != null) {
123: SessionContextImpl.copletInfo.set(null);
124: this .copletPars = (SourceParameters) info
125: .get(PortalConstants.COPLETINFO_PARAMETERS);
126: this .portalURI = (String) info
127: .get(PortalConstants.COPLETINFO_PORTALURI);
128: if (this .copletPars != null) {
129: this .copletID = this .copletPars
130: .getParameter(PortalConstants.PARAMETER_ID);
131: this .copletNumber = this .copletPars
132: .getParameter(PortalConstants.PARAMETER_NUMBER);
133: if (this .copletID != null && this .copletNumber != null) {
134: this .portalURI = this .portalURI
135: + (this .portalURI.indexOf('?') == -1 ? '?'
136: : '&') + "portalcmd=update_"
137: + this .copletID + "_" + this .copletNumber;
138: }
139: }
140: this .statusProfile = (Element) info
141: .get(PortalConstants.COPLETINFO_STATUSPROFILE);
142: }
143: this .mediaType = (this .copletPars != null ? (String) copletPars
144: .getParameter(PortalConstants.PARAMETER_MEDIA) : portal
145: .getMediaType());
146: // get the profile
147:
148: SessionContext context = portal.getContext(false);
149: if (context != null) {
150: if (context
151: .getAttribute(PortalManager.ATTRIBUTE_PORTAL_ROLE) != null) {
152: this .profileID = portal
153: .getProfileID(
154: PortalManager.BUILDTYPE_VALUE_ID,
155: (String) context
156: .getAttribute(PortalManager.ATTRIBUTE_PORTAL_ROLE),
157: (String) context
158: .getAttribute(PortalManager.ATTRIBUTE_PORTAL_ID),
159: false);
160: this .profile = portal.retrieveProfile(this .profileID);
161: }
162: }
163: this .getConfigurationDOM(portal);
164: this .request = ObjectModelHelper.getRequest(objectModel);
165: }
166:
167: /**
168: * Get the name of the context
169: */
170: public String getName() {
171: return this .name;
172: }
173:
174: public Request getRequest() {
175: return this .request;
176: }
177:
178: /**
179: * Get the layout DOM
180: */
181: private void getLayoutDOM() throws ProcessingException {
182: if (this .layoutDOM == null && this .profile != null) {
183: try {
184: Map portalLayouts = (Map) this .profile
185: .get(PortalConstants.PROFILE_PORTAL_LAYOUTS);
186: Map copletLayouts = (Map) this .profile
187: .get(PortalConstants.PROFILE_COPLET_LAYOUTS);
188: DOMBuilder builder = new DOMBuilder();
189: builder.startDocument();
190: PortalManagerImpl.streamLayoutProfile(builder,
191: portalLayouts, copletLayouts, this .mediaType);
192: builder.endDocument();
193: this .layoutDOM = builder.getDocument();
194: } catch (SAXException local) {
195: throw new ProcessingException("Unable to get portal."
196: + local, local);
197: }
198: }
199: }
200:
201: /**
202: * Get the configuration DOM
203: */
204: private void getConfigurationDOM(PortalManager portal)
205: throws ProcessingException, IOException {
206: if (this .configurationDOM == null && portal != null) {
207: try {
208: String contextID = null;
209: if (this .copletID != null && this .copletNumber != null) {
210: contextID = "coplet_" + copletID + "_"
211: + copletNumber;
212: }
213: DOMBuilder builder = new DOMBuilder();
214: builder.startDocument();
215: portal.streamConfiguration(builder, this .portalURI,
216: this .profileID, this .mediaType, contextID);
217: builder.endDocument();
218: this .configurationDOM = builder.getDocument();
219: } catch (SAXException local) {
220: throw new ProcessingException("Unable to get portal."
221: + local, local);
222: }
223: }
224: }
225:
226: /* Set the context name */
227: public void setup(String value, String load, String save) {
228: name = value;
229: }
230:
231: /**
232: * Get the xml fragment
233: */
234: public synchronized DocumentFragment getXML(String path)
235: throws ProcessingException {
236: DocumentFragment result = null;
237:
238: if (path.startsWith("/"))
239: path = path.substring(1);
240: NodeList list = null;
241:
242: if (path == null || path.length() == 0) {
243: Document doc = DOMUtil.createDocument();
244: result = doc.createDocumentFragment();
245: this .getLayoutDOM();
246: if (this .layoutDOM != null) {
247: result.appendChild(doc.importNode(this .layoutDOM
248: .getDocumentElement(), true));
249: }
250: if (this .configurationDOM != null) {
251: result.appendChild(doc.importNode(this .configurationDOM
252: .getDocumentElement(), true));
253: }
254:
255: if (this .statusProfile != null) {
256: if (this .copletID != null && this .copletNumber != null) {
257: String statusPath = "customization/coplet[@id='"
258: + copletID + "' and @number='"
259: + copletNumber + "']";
260: try {
261: Node node = DOMUtil.getSingleNode(
262: this .statusProfile, statusPath,
263: this .xpathProcessor);
264: if (node != null) {
265: Element copletData = doc.createElementNS(
266: null, "coplet-data");
267: NodeList childs = node.getChildNodes();
268: if (childs != null) {
269: for (int l = 0; l < childs.getLength(); l++) {
270: copletData.appendChild(doc
271: .importNode(childs.item(l),
272: true));
273: }
274: }
275: result.appendChild(copletData);
276: }
277: } catch (javax.xml.transform.TransformerException localException) {
278: throw new ProcessingException(
279: "TransformerException: "
280: + localException,
281: localException);
282: }
283: }
284: }
285: }
286:
287: if (path.equals("layout") || path.startsWith("layout/")) {
288: try {
289: this .getLayoutDOM();
290: if (this .layoutDOM != null)
291: list = DOMUtil.selectNodeList(this .layoutDOM, path,
292: this .xpathProcessor);
293: } catch (javax.xml.transform.TransformerException localException) {
294: throw new ProcessingException("TransformerException: "
295: + localException, localException);
296: }
297: }
298:
299: if (path.equals("configuration")
300: || path.startsWith("configuration/")) {
301: try {
302: if (this .configurationDOM != null)
303: list = DOMUtil.selectNodeList(
304: this .configurationDOM, path,
305: this .xpathProcessor);
306: } catch (javax.xml.transform.TransformerException localException) {
307: throw new ProcessingException("TransformerException: "
308: + localException, localException);
309: }
310: }
311:
312: if (path.startsWith("coplet-data/")
313: || path.equals("coplet-data")) {
314:
315: if (this .statusProfile != null) {
316: if (this .copletID != null && this .copletNumber != null) {
317: String statusPath = "customization/coplet[@id='"
318: + copletID + "' and @number='"
319: + copletNumber + "']";
320: if (path.startsWith("coplet-data/")) {
321: statusPath = statusPath + path.substring(11);
322: }
323: try {
324: list = DOMUtil.selectNodeList(
325: this .statusProfile, statusPath,
326: this .xpathProcessor);
327: } catch (javax.xml.transform.TransformerException localException) {
328: throw new ProcessingException(
329: "TransformerException: "
330: + localException,
331: localException);
332: }
333: }
334: }
335: }
336:
337: if (list != null && list.getLength() > 0) {
338: Document doc = DOMUtil.createDocument();
339: result = doc.createDocumentFragment();
340:
341: for (int i = 0; i < list.getLength(); i++) {
342:
343: // the found node is either an attribute or an element
344: if (list.item(i).getNodeType() == Node.ATTRIBUTE_NODE) {
345: // if it is an attribute simple create a new text node with the value of the attribute
346: result.appendChild(doc.createTextNode(list.item(i)
347: .getNodeValue()));
348: } else {
349: // now we have an element
350: // copy all children of this element in the resulting tree
351: NodeList childs = list.item(i).getChildNodes();
352: if (childs != null) {
353: for (int m = 0; m < childs.getLength(); m++) {
354: result.appendChild(doc.importNode(childs
355: .item(m), true));
356: }
357: }
358: }
359: }
360: }
361:
362: return result;
363: }
364:
365: /**
366: * Set the xml
367: */
368: public synchronized void setXML(String path,
369: DocumentFragment fragment) throws ProcessingException {
370: if (path != null) {
371: if (path.startsWith("/"))
372: path = path.substring(1);
373: if (path.startsWith("coplet-data/")
374: || path.equals("coplet-data")) {
375:
376: if (this .statusProfile != null) {
377: if (this .copletID != null
378: && this .copletNumber != null) {
379: String statusPath = "customization/coplet[@id='"
380: + copletID
381: + "' and @number='"
382: + copletNumber + "']";
383: if (path.startsWith("coplet-data/")) {
384: statusPath = statusPath
385: + path.substring(11);
386: }
387:
388: Node node = DOMUtil.selectSingleNode(
389: this .statusProfile, statusPath,
390: this .xpathProcessor);
391: if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
392: // now we have to serialize the fragment to a string and insert this
393: Attr attr = (Attr) node;
394: attr.setNodeValue(DOMUtil
395: .getValueOfNode(fragment));
396: } else {
397:
398: // remove old childs
399: while (node.hasChildNodes()) {
400: node.removeChild(node.getFirstChild());
401: }
402:
403: // Insert new childs
404: NodeList childs = fragment.getChildNodes();
405: if (childs != null
406: && childs.getLength() > 0) {
407: for (int i = 0; i < childs.getLength(); i++) {
408: Node n = this .statusProfile
409: .getOwnerDocument()
410: .importNode(childs.item(i),
411: true);
412: node.appendChild(n);
413: }
414: }
415: }
416:
417: if (this .copletPars.getParameter(
418: PortalConstants.PARAMETER_PERSISTENT,
419: "false").equals("true")) {
420: this .profile
421: .put(
422: PortalConstants.PROFILE_SAVE_STATUS_FLAG,
423: "true");
424: }
425: }
426: }
427: }
428: }
429:
430: }
431:
432: /**
433: * Append a document fragment at the given path. The implementation of this
434: * method is context specific.
435: * Usually the children of the fragment are appended as new children of the
436: * node specified by the path.
437: * If the path is not existent it is created.
438: */
439: public synchronized void appendXML(String path,
440: DocumentFragment fragment) throws ProcessingException {
441: throw new ProcessingException("appendXML() not implemented.");
442: }
443:
444: /**
445: * Remove nodes
446: */
447: public synchronized void removeXML(String path)
448: throws ProcessingException {
449: throw new ProcessingException("removeXML() not implemented.");
450: }
451:
452: /**
453: * Get a copy the first node specified by the path.
454: */
455: public synchronized Node getSingleNode(String path)
456: throws ProcessingException {
457: // Node result = null;
458: throw new ProcessingException(
459: "getSingleNode() not implemented.");
460: // return result;
461: }
462:
463: /**
464: * Get a copy all the nodes specified by the path.
465: */
466: public synchronized NodeList getNodeList(String path)
467: throws ProcessingException {
468: // NodeList result = null;
469: throw new ProcessingException("getNodeList() not implemented.");
470: // return result;
471: }
472:
473: /**
474: * Set the value of a node. The node is copied before insertion.
475: */
476: public synchronized void setNode(String path, Node node)
477: throws ProcessingException {
478: throw new ProcessingException("setNode() not implemented.");
479: }
480:
481: /**
482: * Set a context attribute. If value is null the attribute is removed.
483: */
484: public synchronized void setAttribute(String key, Object value) {
485: if (value == null) {
486: attributes.remove(key);
487: } else {
488: attributes.put(key, value);
489: }
490: }
491:
492: /**
493: * Get a context attribute. If the attribute is not available return null
494: */
495: public synchronized Object getAttribute(String key) {
496: return attributes.get(key);
497: }
498:
499: /**
500: * Get a context attribute. If the attribute is not available the defaultObject is returned
501: */
502: public synchronized Object getAttribute(String key,
503: Object defaultObject) {
504: Object value = attributes.get(key);
505: if (value == null)
506: value = defaultObject;
507: return value;
508: }
509:
510: /**
511: * Get the value of this node. This is similiar to the xsl:value-of
512: * function. If the node does not exist, <code>null</code> is returned.
513: */
514: public synchronized String getValueOfNode(String path)
515: throws ProcessingException {
516: // String value = null;
517: throw new ProcessingException(
518: "getValueOfNode() not implemented.");
519: // return value;
520: }
521:
522: /**
523: * Set the value of a node.
524: */
525: public synchronized void setValueOfNode(String path, String value)
526: throws ProcessingException {
527: throw new ProcessingException(
528: "setValueOfNode() not implemented.");
529: }
530:
531: /**
532: * Stream the XML directly to the handler. This streams the contents of getXML()
533: * to the given handler without creating a DocumentFragment containing a copy
534: * of the data
535: */
536: public synchronized boolean streamXML(String path,
537: ContentHandler contentHandler, LexicalHandler lexicalHandler)
538: throws SAXException, ProcessingException {
539: boolean streamed = false;
540: DocumentFragment fragment = this .getXML(path);
541: if (fragment != null) {
542: streamed = true;
543: IncludeXMLConsumer.includeNode(fragment, contentHandler,
544: lexicalHandler);
545: }
546: return streamed;
547: }
548:
549: /**
550: * Try to load XML into the context.
551: * If the context does not provide the ability of loading,
552: * an exception is thrown.
553: */
554: public void loadXML(String path, SourceParameters parameters)
555: throws SAXException, ProcessingException, IOException {
556: throw new ProcessingException("The context " + this .name
557: + " does not support loading.");
558: }
559:
560: /**
561: * Try to save XML from the context.
562: * If the context does not provide the ability of saving,
563: * an exception is thrown.
564: */
565: public void saveXML(String path, SourceParameters parameters)
566: throws SAXException, ProcessingException, IOException {
567: throw new ProcessingException("The context " + this .name
568: + " does not support saving.");
569: }
570: }
|