/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.portal.transformation; import org.apache.cocoon.portal.coplet.CopletInstanceData; import org.apache.cocoon.portal.event.impl.CopletLinkEvent; import org.apache.cocoon.xml.AttributesImpl; import org.apache.cocoon.xml.XMLUtils; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; /** * This transformer is used to replace links (URIs) from elements * like <a href="URI"> or <form action="URI"> with portal * event uris. Therefore the transformer searches for <eventlink> * elements replaces the URI form the attribute which is specified within * an attribute called "attribute" and renames the element as specified * within an attribute called "element". * * Example:<br><br> * * <pre> * <root xmlns:ev="http://apache.org/cocoon/portal/eventlink/1.0"> * <ev:eventlink href="http://eventlinkexample" element="a" attribute="href">linktext</ev:eventlink> * </root><br></pre> * * will be replaced with something like:<br><br> * * <pre> * <root> * <a href="portal?cocoon-portal-event=8">linktext</a> * </root><br></pre> * * The transformer will create two CopletLinkEvents and insert corresponding links * to them to the XML instead of "http://eventlinkexample". If such a link is pressed * the corresponding CopletLinkEvent is sent to the Subscribers to be handled.<br> * Please see also the documentation of superclass AbstractCopletTransformer for how * the coplet instance data are acquired. * * @author <a href="mailto:gernot.koller@rizit.at">Gernot Koller</a> * * @version CVS $Id$ */ public class NewEventLinkTransformer extends AbstractCopletTransformer { /** * The namespace URI to listen for. */ public static final String NAMESPACE_URI = "http://apache.org/cocoon/portal/eventlink/1.0"; /** * The XML element name to listen for. */ public static final String EVENT_ELEM = "eventlink"; /** * An attribute's name of EVENT_ELEMENT. */ public static final String ATTRIBUTE_ATTR = "attribute"; /** * An attribute's name of EVENT_ELEMENT. */ public static final String ELEMENT_ATTR = "element"; /** * @see java.lang.Object#Object() */ public NewEventLinkTransformer() { this.defaultNamespaceURI = NAMESPACE_URI; } /** * @throws SAXException when the eventlink element does not contain the necessary attributes * "element" and "attribute", retrieving the LinkURI from the LinkService fails, * or an unknown element within the namespaces in encountered. * @see org.apache.cocoon.transformation.AbstractSAXTransformer#startTransformingElement(String, String, String, Attributes) */ public void startTransformingElement(String uri, String name, String raw, Attributes attributes) throws SAXException { if (!EVENT_ELEM.equals(name)) { throw new SAXException("Unknown element encountered: " + name); } String attributeName = attributes.getValue(ATTRIBUTE_ATTR); String elementName = attributes.getValue(ELEMENT_ATTR); if (attributeName == null) { throw new SAXException( "Element " + EVENT_ELEM + " must have an attribute " + ATTRIBUTE_ATTR + "."); } if (elementName == null) { throw new SAXException( "Element " + EVENT_ELEM + " must have an attribute " + ELEMENT_ATTR + "."); } // remove ATTRIBUTE_ATTR, "coplet" and ELEMENT_ATTR from attributes AttributesImpl newAttributes = this.getMutableAttributes(attributes); newAttributes.removeAttribute(ELEMENT_ATTR); newAttributes.removeAttribute(ATTRIBUTE_ATTR); newAttributes.removeAttribute("coplet"); int index = newAttributes.getIndex(attributeName); String link = newAttributes.getValue(index); boolean formSpecialTreatment = false; if ("form".equals(elementName)) { //cut all query parameters from actions with method get, as these will be normaly ignored! formSpecialTreatment = true; if ("GET".equalsIgnoreCase(newAttributes.getValue("method")) && link.indexOf('?') > 0) { link = link.substring(0, link.indexOf('?')); } } String portalAction = null; String portalEvent = null; // if attribute found that contains a link if (link != null) { CopletInstanceData cid = this.getCopletInstanceData(attributes.getValue("coplet")); // create event link CopletLinkEvent event = new CopletLinkEvent(cid, link); String eventLink = this.portalService.getComponentManager().getLinkService().getLinkURI(event); //form elements need hidden inputs to change request parameters if (formSpecialTreatment) { int pos = eventLink.indexOf("cocoon-portal-action="); if ( pos != -1 ) { int begin = pos + "cocoon-portal-action=".length(); int end = eventLink.indexOf('&', begin); if (end == -1) { end = eventLink.length(); } portalAction = eventLink.substring(begin, end); } pos = eventLink.indexOf("cocoon-portal-event="); if ( pos != -1 ) { int begin = pos + "cocoon-portal-event=".length(); int end = eventLink.indexOf('&', begin); if (end == -1) { end = eventLink.length(); } portalEvent = eventLink.substring(begin, end); } pos = eventLink.indexOf('?'); if ( pos != -1 ) { eventLink = eventLink.substring(0, pos); } } // insert event link newAttributes.setValue(index, eventLink); } this.stack.push(elementName); this.contentHandler.startElement( "", elementName, elementName, newAttributes); //generate hidden inputs to add request parameters to the form action if (formSpecialTreatment) { this.sendHiddenFields(this.contentHandler, portalAction, portalEvent); } } /** * With forms the uri in the action attribute cannot be enhanced with request parameters. * Instead hidden input fields must be inserted into the SAX stream to add request parameters. * This method sends two hidden inputs adding the "cocoon-portal-action" parameter and * the "cocoon-portal-event" parameter. * @param contentHandler the content handler recieving the SAX events * @param portalAction value of the "cocoon-portal-action" parameter * @param portalEvent value of the "cocoon-portal-event" parameter * @throws SAXException if sending the SAX events failed */ private void sendHiddenFields(ContentHandler contentHandler, String portalAction, String portalEvent) throws SAXException { if ( portalAction != null ) { final AttributesImpl attributes = new AttributesImpl(); attributes.addCDATAAttribute("type", "hidden"); attributes.addCDATAAttribute("name", "cocoon-portal-action"); attributes.addCDATAAttribute("value", portalAction); XMLUtils.createElement(contentHandler, "input", attributes); } if ( portalEvent != null ) { final AttributesImpl attributes = new AttributesImpl(); attributes.addCDATAAttribute("type", "hidden"); attributes.addCDATAAttribute("name", "cocoon-portal-event"); attributes.addCDATAAttribute("value", portalEvent); XMLUtils.createElement(contentHandler, "input", attributes); } } /** * @see org.apache.cocoon.transformation.AbstractSAXTransformer#endTransformingElement(String, String, String) */ public void endTransformingElement(String uri, String name, String raw) throws SAXException { String elementName = (String) this.stack.pop(); this.contentHandler.endElement("", elementName, elementName); } }