/** * Copyright (c) 2009 Juwi MacMillan Group GmbH * * 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 de.juwimm.cms.cocoon.acting; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.avalon.excalibur.pool.Poolable; import org.apache.avalon.framework.parameters.ParameterException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ResourceNotFoundException; import org.apache.cocoon.acting.AbstractAction; import org.apache.cocoon.caching.CacheableProcessingComponent; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.SourceResolver; import org.apache.excalibur.source.SourceValidity; import org.apache.excalibur.source.impl.validity.TimeStampValidity; import org.apache.log4j.Logger; import org.tizzit.util.XercesHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import de.juwimm.cms.beans.WebServiceSpring; import de.juwimm.cms.cocoon.helper.CocoonSpringHelper; /** * This action can extract a value from the content of a cms-page.<br/> * Therefore it needs the viewComponentId of a page and a key or XPath-Query.<br/> * If both parameters are given and set, the XPathQuery is evaluated.<br/> * The result is send back to the sitemap.<br/> * One usage could be the selection of an email-address for sendung a mail without<br/> * transfering the address with a form from the client via http. Now you can give<br/> * an id and a key or query and this action passes the requested value to the sitemap.<br/> * * <p><h5>Configuration:</h5> * <pre> * <map:action name="cms.actions.xpathvalue" src="de.juwimm.cms.cocoon.acting.XPathValueAction"/> * </pre> * <p><h5>Usage:</h5><br/>Normally you will use this action inside the CmsTemplateAction. * <pre> * <map:match pattern="* /** /kvp-*.*"> * <map:act type="cms.actions.template"> * <map:parameter name="siteId" value="{global:clientId}"/> * <map:parameter name="parameters" value="true"/> * <map:parameter name="language" value="{1}"/> * <map:parameter name="path" value="{2}"/> * <map:parameter name="viewType" value="browser"/> * <map:act type="cms.actions.xpathvalue"> * <map:parameter name="viewComponentId" value="{viewComponentId}"/> * <!-- either --> * <map:parameter name="XPathQuery" value="//node()[∂id='1']/*[position() = 2]"/> * <!-- or --> * <map:parameter name="key" value="{../3}"/> * <!-- if both parameters are given and set, the XPathQuery is evaluated --> * <map:parameter name="liveserver" value="{conquest-properties:liveserver}"/> * <map:generate src="xml/nix.xml"/> * <map:transform src="templates/keyvaluepair.xsl"> * <map:parameter name="xPathValue" value="{XPathValue}"/> * <map:parameter name="viewComponentId" value="{../viewComponentId}"/> * <map:parameter name="key" value="{../../3}"/> * </map:transform> * </map:act> * <map:match pattern="* /** /kvp-*.xml"> * <map:serialize type="xml"/> * </map:match> * </map:act> * </map:match> * </pre> * If you want to search for a "key"-parameter the xml-content must contain this structure: * <pre> * <keyvalue dcfname="keyvalue" label="Key-Value-Pair"> * <item description="key1" id="1" timestamp="1097487299283"> * <key dcfname="key" description="key1"><![CDATA[key1]]></key> * <value dcfname="value" description="value1"><![CDATA[value1]]></value> * </item> * <item description="key2" id="2" timestamp="1097487322357"> * <key dcfname="key" description="key2"><![CDATA[key2]]></key> * <value dcfname="value" description="value2"><![CDATA[value2]]></value> * </item> * </keyvalue> * </pre> * </p> * <p><h5>Result:</h5> * This action returns the value "XPathValue" to the pipeline. * </p> * @see de.juwimm.cms.cocoon.acting.CmsTemplateAction * * @author <a href="mailto:carsten.schalm@juwimm.com">Carsten Schalm</a> * Juwi|MacMillan Group Gmbh, Walsrode, Germany * @version $Id$ * @since ConQuest 2.0 */ public class XPathValueAction extends AbstractAction implements CacheableProcessingComponent, Poolable { private final Logger log = Logger.getLogger(XPathValueAction.class); private boolean iAmTheLiveserver = false; private WebServiceSpring webSpringBean = null; private Serializable uniqueKey; private Integer viewComponentId = null; private long chgDate = 0; private static final String PARENT_OF_KEY = "keyvalue"; private static final String RESULT_PARAMETER_NAME = "XPathValue"; /* (non-Javadoc) * @see org.apache.cocoon.acting.Action#act(org.apache.cocoon.environment.Redirector, * org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters) */ public Map<String, String> act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception { if (log.isDebugEnabled()) log.debug("start acting"); try { webSpringBean = (WebServiceSpring) CocoonSpringHelper.getBean(objectModel, CocoonSpringHelper.WEB_SERVICE_SPRING); } catch (Exception exf) { log.error("Could not load webservicespringbean!", exf); } Map<String, String> sitemapParams = new HashMap<String, String>(); Document contentDoc = null; this.viewComponentId = new Integer(parameters.getParameter("viewComponentId")); String xPathQuery = ""; String key = ""; Request request = ObjectModelHelper.getRequest(objectModel); uniqueKey = request.getRequestURI(); try { xPathQuery = parameters.getParameter("XPathQuery"); } catch (ParameterException pe) { if (log.isDebugEnabled()) log.debug("Parameter \"XPathQuery\" is missing " + pe.getMessage()); } try { key = parameters.getParameter("key"); } catch (ParameterException pe) { if (log.isDebugEnabled()) log.debug("Parameter \"key\" is missing " + pe.getMessage()); } try { iAmTheLiveserver = new Boolean(parameters.getParameter("liveserver")).booleanValue(); } catch (Exception exe) { } if (log.isDebugEnabled()) log.debug("begin generate"); if (log.isDebugEnabled()) log.debug("GETTING XML FROM BEAN"); try { String content = webSpringBean.getContent(viewComponentId, iAmTheLiveserver); if (log.isDebugEnabled()) log.debug("GOT XML FROM BEAN"); contentDoc = XercesHelper.string2Dom(content); if (log.isDebugEnabled()) log.debug("end generate"); if (!("".equals(xPathQuery))) { Element value = (Element) XercesHelper.findNode(contentDoc, xPathQuery); if (value != null) { String strValue = value.getFirstChild().getNodeValue(); if (strValue != null) { sitemapParams.put(XPathValueAction.RESULT_PARAMETER_NAME, strValue); } else { sitemapParams.put(XPathValueAction.RESULT_PARAMETER_NAME, ""); } } else { sitemapParams.put(XPathValueAction.RESULT_PARAMETER_NAME, ""); } } else if (!("".equals(key))) { // search for key in content Iterator it = XercesHelper.findNodes(contentDoc, "//" + XPathValueAction.PARENT_OF_KEY); while (it.hasNext()) { Element currentIteration = (Element) it.next(); Iterator itemIt = XercesHelper.findNodes(currentIteration, "./item"); while (itemIt.hasNext()) { Element currItem = (Element) itemIt.next(); Node currentKey = XercesHelper.findNode(currItem, "./key"); String currKey = currentKey.getFirstChild().getNodeValue(); if (currKey.equalsIgnoreCase(key)) { Node valueNode = XercesHelper.findNode(currItem, "./value"); String value = valueNode.getFirstChild().getNodeValue(); sitemapParams.put(XPathValueAction.RESULT_PARAMETER_NAME, value); break; } } } } else { // no key or XPathQuery given if (log.isDebugEnabled()) log.debug("can't fetch value, neither key nor xpathquery given!"); sitemapParams.put(XPathValueAction.RESULT_PARAMETER_NAME, ""); } } catch (Exception exe) { if (log.isDebugEnabled()) log.debug("An unknown error occured " + exe.getMessage()); } if (contentDoc == null) { throw new ResourceNotFoundException("Could not find resource with viewComponentId " + viewComponentId); } if (log.isDebugEnabled()) log.debug("finished acting"); return sitemapParams; } /* (non-Javadoc) * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey() */ public Serializable getKey() { return this.uniqueKey; } /* (non-Javadoc) * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity() */ public SourceValidity getValidity() { chgDate = 0; try { chgDate = getModifiedDate().getTime(); } catch (Exception exe) { log.error("An error occured", exe); } if (chgDate != 0) { SourceValidity sv = new TimeStampValidity(chgDate); return sv; } return null; } /** * Returns the last modified Date of this ViewComponent. <br> * It will also check, if there are some contained DatabaseComponents or other dynamic content, which have to be * checked. */ private Date getModifiedDate() { if (log.isDebugEnabled()) log.debug("start getModifiedDate"); Date retDte = new Date(System.currentTimeMillis()); try { retDte = webSpringBean.getModifiedDate4Cache(viewComponentId); } catch (Exception exe) { log.error("an unknown error occured", exe); } if (log.isDebugEnabled()) log.debug("end getModifiedDate with " + retDte); return retDte; } public void recycle() { if (log.isDebugEnabled()) log.debug("begin recycle"); uniqueKey = null; viewComponentId = null; chgDate = 0; webSpringBean = null; if (log.isDebugEnabled()) log.debug("end recycle"); } }