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 org.apache.cocoon.portal.coplet.CopletInstanceData;
020: import org.apache.cocoon.portal.event.impl.CopletLinkEvent;
021: import org.apache.cocoon.xml.AttributesImpl;
022: import org.apache.cocoon.xml.XMLUtils;
023: import org.xml.sax.Attributes;
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.SAXException;
026:
027: /**
028: * This transformer is used to replace links (URIs) from elements
029: * like <a href="URI"> or <form action="URI"> with portal
030: * event uris. Therefore the transformer searches for <eventlink>
031: * elements replaces the URI form the attribute which is specified within
032: * an attribute called "attribute" and renames the element as specified
033: * within an attribute called "element".
034: *
035: * Example:<br><br>
036: *
037: * <pre>
038: * <root xmlns:ev="http://apache.org/cocoon/portal/eventlink/1.0">
039: * <ev:eventlink href="http://eventlinkexample" element="a" attribute="href">linktext</ev:eventlink>
040: * </root><br></pre>
041: *
042: * will be replaced with something like:<br><br>
043: *
044: * <pre>
045: * <root>
046: * <a href="portal?cocoon-portal-event=8">linktext</a>
047: * </root><br></pre>
048: *
049: * The transformer will create two CopletLinkEvents and insert corresponding links
050: * to them to the XML instead of "http://eventlinkexample". If such a link is pressed
051: * the corresponding CopletLinkEvent is sent to the Subscribers to be handled.<br>
052: * Please see also the documentation of superclass AbstractCopletTransformer for how
053: * the coplet instance data are acquired.
054: *
055: * @author <a href="mailto:gernot.koller@rizit.at">Gernot Koller</a>
056: *
057: * @version CVS $Id: NewEventLinkTransformer.java 572748 2007-09-04 17:35:19Z cziegeler $
058: */
059: public class NewEventLinkTransformer extends AbstractCopletTransformer {
060:
061: /**
062: * The namespace URI to listen for.
063: */
064: public static final String NAMESPACE_URI = "http://apache.org/cocoon/portal/eventlink/1.0";
065:
066: /**
067: * The XML element name to listen for.
068: */
069: public static final String EVENT_ELEM = "eventlink";
070:
071: /**
072: * An attribute's name of EVENT_ELEMENT.
073: */
074: public static final String ATTRIBUTE_ATTR = "attribute";
075:
076: /**
077: * An attribute's name of EVENT_ELEMENT.
078: */
079: public static final String ELEMENT_ATTR = "element";
080:
081: /**
082: * @see java.lang.Object#Object()
083: */
084: public NewEventLinkTransformer() {
085: this .defaultNamespaceURI = NAMESPACE_URI;
086: }
087:
088: /**
089: * @throws SAXException when the eventlink element does not contain the necessary attributes
090: * "element" and "attribute", retrieving the LinkURI from the LinkService fails,
091: * or an unknown element within the namespaces in encountered.
092: * @see org.apache.cocoon.transformation.AbstractSAXTransformer#startTransformingElement(String, String, String, Attributes)
093: */
094: public void startTransformingElement(String uri, String name,
095: String raw, Attributes attributes) throws SAXException {
096: if (!EVENT_ELEM.equals(name)) {
097: throw new SAXException("Unknown element encountered: "
098: + name);
099: }
100:
101: String attributeName = attributes.getValue(ATTRIBUTE_ATTR);
102: String elementName = attributes.getValue(ELEMENT_ATTR);
103:
104: if (attributeName == null) {
105: throw new SAXException("Element " + EVENT_ELEM
106: + " must have an attribute " + ATTRIBUTE_ATTR + ".");
107: }
108:
109: if (elementName == null) {
110: throw new SAXException("Element " + EVENT_ELEM
111: + " must have an attribute " + ELEMENT_ATTR + ".");
112: }
113:
114: // remove ATTRIBUTE_ATTR, "coplet" and ELEMENT_ATTR from attributes
115: AttributesImpl newAttributes = this
116: .getMutableAttributes(attributes);
117: newAttributes.removeAttribute(ELEMENT_ATTR);
118: newAttributes.removeAttribute(ATTRIBUTE_ATTR);
119: newAttributes.removeAttribute("coplet");
120:
121: int index = newAttributes.getIndex(attributeName);
122: String link = newAttributes.getValue(index);
123:
124: boolean formSpecialTreatment = false;
125: if ("form".equals(elementName)) {
126: //cut all query parameters from actions with method get, as these will be normaly ignored!
127: formSpecialTreatment = true;
128: if ("GET"
129: .equalsIgnoreCase(newAttributes.getValue("method"))
130: && link.indexOf('?') > 0) {
131: link = link.substring(0, link.indexOf('?'));
132: }
133: }
134:
135: String portalAction = null;
136: String portalEvent = null;
137:
138: // if attribute found that contains a link
139: if (link != null) {
140: CopletInstanceData cid = this
141: .getCopletInstanceData(attributes
142: .getValue("coplet"));
143: // create event link
144: CopletLinkEvent event = new CopletLinkEvent(cid, link);
145: String eventLink = this .portalService.getComponentManager()
146: .getLinkService().getLinkURI(event);
147:
148: //form elements need hidden inputs to change request parameters
149: if (formSpecialTreatment) {
150: int pos = eventLink.indexOf("cocoon-portal-action=");
151: if (pos != -1) {
152: int begin = pos + "cocoon-portal-action=".length();
153: int end = eventLink.indexOf('&', begin);
154: if (end == -1) {
155: end = eventLink.length();
156: }
157: portalAction = eventLink.substring(begin, end);
158: }
159: pos = eventLink.indexOf("cocoon-portal-event=");
160: if (pos != -1) {
161: int begin = pos + "cocoon-portal-event=".length();
162: int end = eventLink.indexOf('&', begin);
163: if (end == -1) {
164: end = eventLink.length();
165: }
166: portalEvent = eventLink.substring(begin, end);
167: }
168: pos = eventLink.indexOf('?');
169: if (pos != -1) {
170: eventLink = eventLink.substring(0, pos);
171: }
172: }
173:
174: // insert event link
175: newAttributes.setValue(index, eventLink);
176: }
177:
178: this .stack.push(elementName);
179:
180: this .contentHandler.startElement("", elementName, elementName,
181: newAttributes);
182:
183: //generate hidden inputs to add request parameters to the form action
184: if (formSpecialTreatment) {
185: this .sendHiddenFields(this .contentHandler, portalAction,
186: portalEvent);
187: }
188: }
189:
190: /**
191: * With forms the uri in the action attribute cannot be enhanced with request parameters.
192: * Instead hidden input fields must be inserted into the SAX stream to add request parameters.
193: * This method sends two hidden inputs adding the "cocoon-portal-action" parameter and
194: * the "cocoon-portal-event" parameter.
195: * @param contentHandler the content handler recieving the SAX events
196: * @param portalAction value of the "cocoon-portal-action" parameter
197: * @param portalEvent value of the "cocoon-portal-event" parameter
198: * @throws SAXException if sending the SAX events failed
199: */
200: private void sendHiddenFields(ContentHandler contentHandler,
201: String portalAction, String portalEvent)
202: throws SAXException {
203: if (portalAction != null) {
204: final AttributesImpl attributes = new AttributesImpl();
205: attributes.addCDATAAttribute("type", "hidden");
206: attributes
207: .addCDATAAttribute("name", "cocoon-portal-action");
208: attributes.addCDATAAttribute("value", portalAction);
209: XMLUtils.createElement(contentHandler, "input", attributes);
210: }
211:
212: if (portalEvent != null) {
213: final AttributesImpl attributes = new AttributesImpl();
214: attributes.addCDATAAttribute("type", "hidden");
215: attributes.addCDATAAttribute("name", "cocoon-portal-event");
216: attributes.addCDATAAttribute("value", portalEvent);
217: XMLUtils.createElement(contentHandler, "input", attributes);
218: }
219: }
220:
221: /**
222: * @see org.apache.cocoon.transformation.AbstractSAXTransformer#endTransformingElement(String, String, String)
223: */
224: public void endTransformingElement(String uri, String name,
225: String raw) throws SAXException {
226: String elementName = (String) this .stack.pop();
227: this .contentHandler.endElement("", elementName, elementName);
228: }
229: }
|