blob: b9cecebdebeb745102fa6a10425e8028b4d1698d [file] [log] [blame]
/*
* 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.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.portal.LinkService;
import org.apache.cocoon.portal.PortalService;
import org.apache.cocoon.portal.coplet.CopletInstanceData;
import org.apache.cocoon.portal.event.impl.ChangeCopletInstanceAspectDataEvent;
import org.apache.cocoon.portal.event.impl.CopletJXPathEvent;
import org.apache.cocoon.portal.event.impl.JXPathEvent;
import org.apache.cocoon.xml.AttributesImpl;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.excalibur.xml.sax.XMLizable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* This transformer offers various functions for developing pipeline based coplets.
*
* Includes coplet instance data by using JXPath expressions.
* The transformer searches for tags <coplet:coplet xmlns:coplet="http://apache.org/cocoon/portal/coplet/1.0">.
* They must have an attribute "select" that contains a valid JXPath expression applying to the coplet instance data.<br><br>
*
* Example:<br><br>
*
* <pre>&lt;maxpageable xmlns:coplet="http://apache.org/cocoon/portal/coplet/1.0"&gt;
* &lt;coplet:coplet select="copletData.maxpageable"/&gt;
* &lt;/maxpageable&gt;<br></pre>
*
* The transformer will insert the boolean value specifying whether the coplet is
* maxpageable or not.<br>
* Please see also the documentation of superclass AbstractCopletTransformer for how
* the coplet instance data are acquired.
*
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
* @author <a href="mailto:bluetkemeier@s-und-n.de">Bj&ouml;rn L&uuml;tkemeier</a>
* @version CVS $Id: CopletTransformer.java,v 1.16 2004/03/05 13:02:16 bdelacretaz Exp $
*/
public class CopletTransformer
extends AbstractCopletTransformer {
/**
* The namespace URI to listen for.
*/
public static final String NAMESPACE_URI = "http://apache.org/cocoon/portal/coplet/1.0";
/**
* The XML element name to listen for.
*/
public static final String COPLET_ELEM = "coplet";
/**
* The attribute containing the JXPath expression.
*/
public static final String SELECT_ATTR = "select";
/**
* The XML element name to listen for.
*/
public static final String LINK_ELEM = "link";
/** Create a link containing several events */
public static final String LINKS_ELEM = "links";
/** The content for the links element */
public static final String CONTENT_ELEM = "content";
/** Are we inside a links element? */
protected boolean insideLinks;
/** The collected list of events */
protected List collectedEvents = new ArrayList();
/** The content of the links */
protected XMLizable content;
/**
* Creates new CopletTransformer.
*/
public CopletTransformer() {
this.defaultNamespaceURI = NAMESPACE_URI;
}
/* (non-Javadoc)
* @see org.apache.cocoon.transformation.AbstractSAXTransformer#setupTransforming()
*/
public void setupTransforming()
throws IOException, ProcessingException, SAXException {
super.setupTransforming();
this.insideLinks = false;
this.content = null;
this.collectedEvents.clear();
}
/**
* Overridden from superclass.
*/
public void startTransformingElement(String uri, String name, String raw, Attributes attr)
throws ProcessingException, IOException, SAXException {
if (name.equals(COPLET_ELEM)) {
String expression = attr.getValue(SELECT_ATTR);
if (expression == null) {
throw new ProcessingException("Attribute "+SELECT_ATTR+" must be spcified.");
}
CopletInstanceData cid = this.getCopletInstanceData();
JXPathContext jxpathContext = JXPathContext.newContext( cid );
Object object = jxpathContext.getValue(expression);
if (object == null) {
throw new ProcessingException("Could not find value for expression "+expression);
}
} else if (name.equals(LINK_ELEM)) {
PortalService portalService = null;
try {
portalService = (PortalService)this.manager.lookup(PortalService.ROLE);
final LinkService linkService = portalService.getComponentManager().getLinkService();
final String format = attr.getValue("format");
AttributesImpl newAttrs = new AttributesImpl();
newAttrs.setAttributes(attr);
newAttrs.removeAttribute("format");
if ( attr.getValue("href") != null ) {
final CopletInstanceData cid = this.getCopletInstanceData();
ChangeCopletInstanceAspectDataEvent event = new ChangeCopletInstanceAspectDataEvent(cid, null, null);
String value = linkService.getLinkURI(event);
if (value.indexOf('?') == -1) {
value = value + '?' + attr.getValue("href");
} else {
value = value + '&' + attr.getValue("href");
}
newAttrs.removeAttribute("href");
this.output(value, format, newAttrs );
} else {
final String path = attr.getValue("path");
final String value = attr.getValue("value");
newAttrs.removeAttribute("path");
newAttrs.removeAttribute("value");
JXPathEvent event = null;
if ( attr.getValue("layout") != null ) {
newAttrs.removeAttribute("layout");
final String layoutId = attr.getValue("layout");
Object layout = portalService.getComponentManager().getProfileManager().getPortalLayout(null, layoutId);
if ( layout != null ) {
event = new JXPathEvent(layout, path, value);
}
} else {
String copletId = attr.getValue("coplet");
newAttrs.removeAttribute("coplet");
final CopletInstanceData cid = this.getCopletInstanceData(copletId);
if ( cid != null ) {
event = new CopletJXPathEvent(cid, path, value);
}
}
if ( this.insideLinks ) {
if ( event != null ) {
this.collectedEvents.add(event);
}
} else {
final String href = linkService.getLinkURI(event);
this.output(href, format, newAttrs );
}
}
} catch (ServiceException e) {
throw new SAXException("Error getting portal service.", e);
} finally {
this.manager.release( portalService );
}
} else if (name.equals(LINKS_ELEM) ) {
this.insideLinks = true;
String format = attr.getValue("format");
if ( format == null ) {
format = "html-link";
}
this.stack.push(format);
} else if ( name.equals(CONTENT_ELEM) && this.insideLinks ) {
this.startSAXRecording();
} else {
super.startTransformingElement(uri, name, raw, attr);
}
}
/**
* Overridden from superclass.
*/
public void endTransformingElement(String uri, String name, String raw)
throws ProcessingException, IOException, SAXException {
if ( name.equals(LINK_ELEM) ) {
if ( !this.insideLinks ) {
String elem = (String)this.stack.pop();
if ( elem.length() > 0 ) {
this.sendEndElementEvent(elem);
}
}
} else if ( name.equals(LINKS_ELEM) ) {
this.insideLinks = false;
final String format = (String)this.stack.pop();
PortalService portalService = null;
try {
portalService = (PortalService)this.manager.lookup(PortalService.ROLE);
final LinkService linkService = portalService.getComponentManager().getLinkService();
final String href = linkService.getLinkURI(this.collectedEvents);
final AttributesImpl newAttrs = new AttributesImpl();
this.output(href, format, newAttrs );
} catch (ServiceException e) {
throw new SAXException("Error getting portal service.", e);
} finally {
this.manager.release( portalService );
}
this.collectedEvents.clear();
if ( this.content != null ) {
this.content.toSAX(this.contentHandler);
this.content = null;
}
String elem = (String)this.stack.pop();
if ( elem.length() > 0 ) {
this.sendEndElementEvent(elem);
}
} else if ( name.equals(CONTENT_ELEM) && this.insideLinks ) {
this.content = this.endSAXRecording();
} else if (!name.equals(COPLET_ELEM)) {
super.endTransformingElement(uri, name, raw);
}
}
/**
* Output the link
*/
protected void output(String uri, String format, AttributesImpl newAttrs)
throws SAXException {
if ( format == null ) {
// default
format = "html-link";
}
if ( "html-link".equals(format) ) {
newAttrs.addCDATAAttribute("href", uri);
this.sendStartElementEvent("a", newAttrs);
this.stack.push("a");
} else if ( "html-form".equals(format) ) {
newAttrs.addCDATAAttribute("action", uri);
this.sendStartElementEvent("form", newAttrs);
this.stack.push("form");
} else if ( "text".equals(format) ) {
this.sendTextEvent(uri);
this.stack.push("");
} else if ( "parameters".equals(format) ) {
final String value = uri.substring(uri.indexOf('?')+1);
this.sendTextEvent(value);
this.stack.push("");
} else {
// own format
newAttrs.addCDATAAttribute("href", uri);
this.sendStartElementEvent("link", newAttrs);
this.stack.push("link");
}
}
}