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.portal.transformation;
018:
019: import java.util.Stack;
020:
021: import org.apache.cocoon.portal.LinkService;
022: import org.apache.cocoon.portal.coplet.CopletInstanceData;
023: import org.apache.cocoon.portal.event.impl.CopletLinkEvent;
024: import org.w3c.dom.DocumentFragment;
025: import org.xml.sax.Attributes;
026: import org.xml.sax.SAXException;
027: import org.xml.sax.helpers.AttributesImpl;
028:
029: /**
030: * This transformer searches for event descriptions in the XML.
031: * For each one an event is created and the event link is inserted into the XML
032: * instead of the description.<br><br>
033: *
034: * Example:<br><br>
035: *
036: * <pre><root xmlns:event="http://apache.org/cocoon/portal/eventlink/1.0">
037: * <event:event attribute="href">
038: * <a href="http://eventlinkexample"/>
039: * </event:event>
040: * <event:event element="uri">
041: * <link><uri>http://eventlinkexample</uri></link>
042: * </event:event>
043: * </root><br></pre>
044: *
045: * The transformer will create two CopletLinkEvents and insert corresponding links
046: * to them to the XML instead of "http://eventlinkexample". If such a link is pressed
047: * the corresponding CopletLinkEvent is sent to the Subscribers to be handled.<br>
048: * Please see also the documentation of superclass AbstractCopletTransformer for how
049: * the coplet instance data are acquired.
050: *
051: * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a>
052: * @version $Id: EventLinkTransformer.java 433543 2006-08-22 06:22:54Z crossley $
053: */
054: public class EventLinkTransformer extends AbstractCopletTransformer {
055:
056: /**
057: * The namespace URI to listen for.
058: */
059: public static final String NAMESPACE_URI = "http://apache.org/cocoon/portal/eventlink/1.0";
060:
061: /**
062: * The XML element name to listen for.
063: */
064: public static final String EVENT_ELEM = "event";
065:
066: /**
067: * An attribute's name of EVENT_ELEMENT.
068: */
069: public static final String ATTRIBUTE_ATTR = "attribute";
070:
071: /**
072: * An attribute's name of EVENT_ELEMENT.
073: */
074: public static final String ELEMENT_ATTR = "element";
075:
076: /**
077: * Used to signal whether the transformer is inside an EVENT_ELEM tag.
078: */
079: private boolean insideEvent = false;
080:
081: /**
082: * The attribute defining the link inside an EVENT_ELEM tag.
083: */
084: private String attributeName;
085:
086: /**
087: * The element defining the link inside an EVENT_ELEM tag.
088: */
089: private String elementName;
090:
091: /**
092: * Used to store elements' attributes between startTransformingElement and endTransformingElement.
093: */
094: private Stack attrStack = new Stack();
095:
096: /**
097: * Overridden from superclass.
098: */
099: public void recycle() {
100: this .insideEvent = false;
101: this .attributeName = null;
102: this .elementName = null;
103: this .attrStack.clear();
104:
105: super .recycle();
106: }
107:
108: /**
109: * Overridden from superclass.
110: */
111: public void startElement(String uri, String name, String raw,
112: Attributes attr) throws SAXException {
113:
114: if (uri.equals(NAMESPACE_URI) && name.equals(EVENT_ELEM)) {
115: if (this .insideEvent) {
116: throw new SAXException("Elements " + EVENT_ELEM
117: + " must not be nested.");
118: }
119: this .insideEvent = true;
120:
121: // get element or attribute name that contains links
122: this .attributeName = attr.getValue(ATTRIBUTE_ATTR);
123: this .elementName = attr.getValue(ELEMENT_ATTR);
124:
125: // at least one of them must be set
126: if (this .attributeName == null && this .elementName == null) {
127: throw new SAXException("Element " + EVENT_ELEM
128: + " must have one of attributes "
129: + ATTRIBUTE_ATTR + " and " + ELEMENT_ATTR + ".");
130: }
131: } else {
132: if (this .insideEvent) {
133: // store attributes for endTransformingElement
134: this .attrStack.push(new AttributesImpl(attr));
135:
136: /* Record element content. In case of an element we asume, that no
137: * children exist but only text content, since the text content shall
138: * be the link. Therefore we do startTextRecording. Otherwise we
139: * record the whole subtree.
140: */
141: if (this .elementName != null
142: && name.equals(this .elementName)) {
143: this .startTextRecording();
144: } else {
145: this .startRecording();
146: }
147: } else {
148: super .startElement(uri, name, raw, attr);
149: }
150: }
151: }
152:
153: /**
154: * Overridden from superclass.
155: */
156: public void endElement(String uri, String name, String raw)
157: throws SAXException {
158:
159: if (uri.equals(NAMESPACE_URI) && name.equals(EVENT_ELEM)) {
160: this .attributeName = null;
161: this .elementName = null;
162: this .insideEvent = false;
163: } else {
164: if (this .insideEvent) {
165: AttributesImpl attr = (AttributesImpl) this .attrStack
166: .pop();
167:
168: // process attribute that contains link
169: if (this .attributeName != null) {
170: int index = attr.getIndex(this .attributeName);
171: String link = attr.getValue(index);
172:
173: // if attribute found that contains a link
174: if (link != null) {
175: CopletInstanceData cid = this
176: .getCopletInstanceData(attr
177: .getValue("coplet"));
178: LinkService linkService = this .portalService
179: .getComponentManager().getLinkService();
180:
181: // create event link
182: CopletLinkEvent event = new CopletLinkEvent(
183: cid, link);
184: String eventLink = linkService
185: .getLinkURI(event);
186:
187: // insert event link
188: attr.setValue(index, eventLink);
189: }
190: }
191:
192: String eventLink = null;
193: DocumentFragment fragment = null;
194:
195: // process element that contains link
196: if (this .elementName != null
197: && name.equals(this .elementName)) {
198: String link = this .endTextRecording();
199:
200: CopletInstanceData cid = this
201: .getCopletInstanceData();
202: LinkService linkService = this .portalService
203: .getComponentManager().getLinkService();
204:
205: // create event link
206: CopletLinkEvent event = new CopletLinkEvent(cid,
207: link);
208: eventLink = linkService.getLinkURI(event);
209: } else {
210: fragment = this .endRecording();
211: }
212:
213: // stream element
214: super .startElement(uri, name, raw, attr);
215: if (eventLink != null) {
216: // insert event link
217: super .characters(eventLink.toCharArray(), 0,
218: eventLink.length());
219: } else if (fragment != null) {
220: super.sendEvents(fragment);
221: }
222: super.endElement(uri, name, raw);
223: } else {
224: super.endElement(uri, name, raw);
225: }
226: }
227: }
228: }
|