| /* |
| * Copyright 1999-2002,2004 The Apache Software Foundation. |
| * |
| * Licensed 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 java.util.Stack; |
| |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.cocoon.portal.LinkService; |
| import org.apache.cocoon.portal.coplet.CopletInstanceData; |
| import org.apache.cocoon.portal.event.impl.CopletLinkEvent; |
| import org.w3c.dom.DocumentFragment; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| /** |
| * This transformer searches for event descriptions in the XML. |
| * For each one an event is created and the event link is inserted into the XML |
| * instead of the description.<br><br> |
| * |
| * Example:<br><br> |
| * |
| * <pre><root xmlns:event="http://apache.org/cocoon/portal/eventlink/1.0"> |
| * <event:event attribute="href"> |
| * <a href="http://eventlinkexample"/> |
| * </event:event> |
| * <event:event element="uri"> |
| * <link><uri>http://eventlinkexample</uri></link> |
| * </event:event> |
| * </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:bluetkemeier@s-und-n.de">Björn Lütkemeier</a> |
| * |
| * @version CVS $Id: EventLinkTransformer.java,v 1.7 2004/03/05 13:02:16 bdelacretaz Exp $ |
| */ |
| public class EventLinkTransformer |
| 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 = "event"; |
| |
| /** |
| * 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"; |
| |
| /** |
| * Used to signal whether the transformer is inside an EVENT_ELEM tag. |
| */ |
| private boolean insideEvent = false; |
| |
| /** |
| * The attribute defining the link inside an EVENT_ELEM tag. |
| */ |
| private String attributeName = null; |
| |
| /** |
| * The element defining the link inside an EVENT_ELEM tag. |
| */ |
| private String elementName = null; |
| |
| /** |
| * Used to store elements' attributes between startTransformingElement and endTransformingElement. |
| */ |
| private Stack attrStack = new Stack(); |
| |
| /** |
| * Overridden from superclass. |
| */ |
| public void recycle() { |
| super.recycle(); |
| this.insideEvent = false; |
| this.attributeName = null; |
| this.elementName = null; |
| this.attrStack.clear(); |
| } |
| |
| /** |
| * Overridden from superclass. |
| */ |
| public void startElement(String uri, String name, String raw, Attributes attr) |
| throws SAXException { |
| |
| if (uri.equals(NAMESPACE_URI) && name.equals(EVENT_ELEM)) { |
| if (this.insideEvent) { |
| throw new SAXException("Elements "+EVENT_ELEM+" must not be nested."); |
| } |
| this.insideEvent = true; |
| |
| // get element or attribute name that contains links |
| this.attributeName = attr.getValue(ATTRIBUTE_ATTR); |
| this.elementName = attr.getValue(ELEMENT_ATTR); |
| |
| // at least one of them must be set |
| if (this.attributeName == null && this.elementName == null) { |
| throw new SAXException("Element "+EVENT_ELEM+" must have one of attributes "+ATTRIBUTE_ATTR+" and "+ELEMENT_ATTR+"."); |
| } |
| } else { |
| if (this.insideEvent) { |
| // store attributes for endTransformingElement |
| this.attrStack.push(new AttributesImpl(attr)); |
| |
| /* Record element content. In case of an element we asume, that no |
| * children exist but only text content, since the text content shall |
| * be the link. Therefore we do startTextRecording. Otherwise we |
| * record the whole subtree. |
| */ |
| if (this.elementName != null && name.equals(this.elementName)) { |
| this.startTextRecording(); |
| } else { |
| this.startRecording(); |
| } |
| } else { |
| super.startElement(uri, name, raw, attr); |
| } |
| } |
| } |
| |
| /** |
| * Overridden from superclass. |
| */ |
| public void endElement(String uri, String name, String raw) |
| throws SAXException { |
| |
| if (uri.equals(NAMESPACE_URI) && name.equals(EVENT_ELEM)) { |
| this.attributeName = null; |
| this.elementName = null; |
| this.insideEvent = false; |
| } else { |
| if (this.insideEvent) { |
| AttributesImpl attr = (AttributesImpl)this.attrStack.pop(); |
| |
| // process attribute that contains link |
| if (this.attributeName != null) { |
| int index = attr.getIndex(this.attributeName); |
| String link = attr.getValue(index); |
| |
| // if attribute found that contains a link |
| if (link != null) { |
| CopletInstanceData cid = this.getCopletInstanceData(); |
| LinkService linkService = null; |
| try { |
| linkService = (LinkService)this.manager.lookup(LinkService.ROLE); |
| |
| // create event link |
| CopletLinkEvent event = new CopletLinkEvent(cid, link); |
| String eventLink = linkService.getLinkURI(event); |
| |
| // insert event link |
| attr.setValue(index, eventLink); |
| } catch (ServiceException e) { |
| throw new SAXException(e); |
| } finally { |
| this.manager.release(linkService); |
| } |
| } |
| } |
| |
| String eventLink = null; |
| DocumentFragment fragment = null; |
| |
| // process element that contains link |
| if (this.elementName != null && name.equals(this.elementName)) { |
| String link = this.endTextRecording(); |
| |
| CopletInstanceData cid = this.getCopletInstanceData(); |
| LinkService linkService = null; |
| try { |
| linkService = (LinkService)this.manager.lookup(LinkService.ROLE); |
| |
| // create event link |
| CopletLinkEvent event = new CopletLinkEvent(cid, link); |
| eventLink = linkService.getLinkURI(event); |
| } catch (ServiceException e) { |
| throw new SAXException(e); |
| } finally { |
| this.manager.release(linkService); |
| } |
| } else { |
| fragment = this.endRecording(); |
| } |
| |
| // stream element |
| super.startElement(uri, name, raw, attr); |
| if (eventLink != null) { |
| // insert event link |
| super.characters(eventLink.toCharArray(), 0, eventLink.length()); |
| } else if (fragment != null) { |
| super.sendEvents(fragment); |
| } |
| super.endElement(uri, name, raw); |
| } else { |
| super.endElement(uri, name, raw); |
| } |
| } |
| } |
| |
| } |