package org.tizzit.cocoon.generic.acting; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.avalon.framework.parameters.ParameterException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.thread.SingleThreaded; import org.apache.cocoon.acting.AbstractAction; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.environment.internal.EnvironmentHelper; import org.apache.commons.lang.StringUtils; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceNotFoundException; import org.apache.log4j.Logger; import org.tizzit.cocoon.generic.helper.MapHelper; /** * * <h5>Usage:</h5> * <p> * <pre> * <map:act type="multiParamResourceExistsAction"> * <map:parameter name="checkResource-theNameOfTheReturnParameter-1" value="layouts/html/fooBar.xml" /> * <map:parameter name="checkResource-theNameOfTheReturnParameter-2" value="layouts/html/common.xml" /> * <map:parameter name="checkResource-theNameOfTheReturnParameter-3" value="layouts/fooBar.xml" /> * * <-- OPTIONAL parameters --> * <map:parameter name="defaultValue-theNameOfTheReturnParameter1" value="myFileName" /> * * </map:act> * </pre> * </p> * <h5>Parameters</h5> * <ul> * <li><b>setRequestAttributes</b> - default: <i>false</i> - Text</li> * <li><b>defaultValue</b> - default: <i>common</i> - Text</li> * <li><b>replaceMode</b> - default: <i>fileName</i> - </li> * <li><b>checkResource-theNameOfTheReturnParameter</b> - Text</li> * <li><b>defaultValue-theNameOfTheReturnParameter</b> - Text</li> * <li><b>replaceMode-theNameOfTheReturnParameter</b> - Text</li> * </ul> * * This action can be configured to specify the value of the return parameters. * @author <a href="mailto:eduard.siebert@juwimm.com">Eduard Siebert</a> * @version $Id$ * @since tizzit-cocoon-components 02.11.2009 */ public class MultiParamResourceExistsAction extends AbstractAction implements SingleThreaded { private static Logger log = Logger.getLogger(MultiParamResourceExistsAction.class); private static final String DEFAULT_REPLACE_MODE = "full"; private static final String DEFAULT_RESOURCE_NAME = "common"; private static final String PREFIX_PARAM_NAME_CHECK_RESOURCES = "checkResource-"; private static final String PREFIX_PARAM_NAME_DEFAULT_VALUES = "defaultValue-"; private static final String PREFIX_PARAM_NAME_REPLACE_MODE_VALUES = "replaceMode-"; private static final String PARAM_NAME_SET_REQUEST_ATTR = "setRequestAttributes"; private static final String PARAM_NAME_DEFAULT_VALUE = "defaultValue"; private static final String PARAM_NAME_REPLACE_MODE = "replaceMode"; private static final Pattern pParamNameAndIndex = Pattern.compile("^" + PREFIX_PARAM_NAME_CHECK_RESOURCES + "(.*)\\-(\\d)$"); //Example: "checkResource-myParam-1" private Matcher m; private Parameters parameters = null; private Map< ? , ? > objectModel = null; private boolean hasMultiValueChecks = false; private Map<String, MultiParameterDataHolder> multiValueChecks; private List<String> keyPrefixList; private Map<String, String> sitemapParams; /** * @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) */ @SuppressWarnings("unchecked") public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception { if (log.isDebugEnabled()) log.debug("act() -> begin"); this.sitemapParams = new HashMap<String, String>(); this.parameters = parameters; this.objectModel = objectModel; final String[] paramNames = this.parameters.getNames(); for (int i = 0; i < paramNames.length; i++) { final String paramName = paramNames[i]; if (paramName.startsWith(PREFIX_PARAM_NAME_CHECK_RESOURCES)) { if (this.multiValueChecks == null) { this.multiValueChecks = new HashMap<String, MultiParameterDataHolder>(); } MultiParameterDataHolder dataHolder = new MultiParameterDataHolder(); dataHolder.originName = paramName; try { dataHolder.identifier = paramName.split("^" + PREFIX_PARAM_NAME_CHECK_RESOURCES)[1]; } catch (ArrayIndexOutOfBoundsException e) { log.error(PREFIX_PARAM_NAME_CHECK_RESOURCES + " has been without target! Please use \"" + PREFIX_PARAM_NAME_CHECK_RESOURCES + "yourParameterName\" as the name of a parameter!"); } this.m = pParamNameAndIndex.matcher(paramName); if (m.matches()) { this.hasMultiValueChecks = true; dataHolder.multiValue = true; dataHolder.returnName = m.group(1); //dataHolder.value = m.group(1); //this.processMultiValue(paramName, mp); if (this.keyPrefixList == null) { this.keyPrefixList = new ArrayList<String>(); } if (!this.keyPrefixList.contains(dataHolder.returnName)) { this.keyPrefixList.add(dataHolder.returnName); } } else { dataHolder.returnName = dataHolder.identifier; } dataHolder.value = this.parameters.getParameter(dataHolder.originName); if (m.matches()) { //add to map - this map will be checked later this.multiValueChecks.put(dataHolder.identifier, dataHolder); } else { boolean exists = this.resourceExists(resolver, dataHolder.value); if (exists) { this.sitemapParams.put(dataHolder.returnName, dataHolder.value); setRequestAttributes(dataHolder.returnName, dataHolder.value); } else { this.sitemapParams.put(dataHolder.returnName, this.getDefaultValue(dataHolder.returnName, dataHolder.value)); setRequestAttributes(dataHolder.returnName, this.getDefaultValue(dataHolder.returnName, dataHolder.value)); } } } } if (this.hasMultiValueChecks && this.keyPrefixList != null && this.keyPrefixList.size() > 0) { try { for (String keyPrefix : this.keyPrefixList) { int i = 0; boolean resourceExsists = false; String key = null; MultiParameterDataHolder dataHolder = null; do { if (this.multiValueChecks.containsKey(key)) { dataHolder = this.multiValueChecks.get(key); //this.context = EnvironmentHelper.getCurrentProcessor().getContext(); resourceExsists = this.resourceExists(resolver, dataHolder.value); if (resourceExsists) { this.sitemapParams.put(dataHolder.returnName, dataHolder.value); setRequestAttributes(dataHolder.returnName, dataHolder.value); } } i++; key = keyPrefix + "-" + i; } while (this.multiValueChecks.containsKey(key) && !resourceExsists); if (!resourceExsists && dataHolder != null) { this.sitemapParams.put(dataHolder.returnName, this.getDefaultValue(dataHolder.returnName, dataHolder.value)); setRequestAttributes(dataHolder.returnName, this.getDefaultValue(dataHolder.returnName, dataHolder.value)); } } } catch (Exception e) { log.error("Error: ", e); } } if (log.isDebugEnabled()) { log.debug(MapHelper.mapToString(this.sitemapParams)); } if (log.isDebugEnabled()) log.debug("act() -> end"); return this.sitemapParams; } private boolean resourceExists(SourceResolver resolver, String resourceURI) { boolean retVal = false; resourceURI = getValidResourceURI(resourceURI); Source resource = null; try { resource = resolver.resolveURI(resourceURI); if (resource.exists()) { retVal = true; } } catch (SourceNotFoundException e) { if (log.isDebugEnabled()) log.debug("havent found ressource " + resourceURI + " trying next!"); } catch (Exception e) { log.error("Error in act(): ", e); } finally { if (resource != null) { resolver.release(resource); } } return retVal; } private String getValidResourceURI(String resourceURI) { if (log.isDebugEnabled()) log.debug("getValidResourceURI() -> begin"); String retVal = resourceURI; String context = null; try { context = EnvironmentHelper.getCurrentProcessor().getContext(); } catch (Exception exe) { if (log.isDebugEnabled()) log.debug("Could not get context!"); } if (resourceURI.startsWith("/")) { if (StringUtils.isNotBlank(context)) { retVal = context + resourceURI; } else { retVal = resourceURI.replaceFirst("^/", ""); } } if (log.isDebugEnabled()) log.debug("getValidResourceURI() -> end"); return retVal; } private void setRequestAttributes(String attributeName, String resourceURI) { if (log.isDebugEnabled()) log.debug("setRequestAttributes() -> begin"); try { if (this.parameters.isParameter(PARAM_NAME_SET_REQUEST_ATTR)) { if (Boolean.parseBoolean(this.parameters.getParameter(PARAM_NAME_SET_REQUEST_ATTR))) { ObjectModelHelper.getRequest(this.objectModel).setAttribute(attributeName, resourceURI); if (log.isDebugEnabled()) log.debug("Setting request attribute \"" + attributeName + "\" to \"" + resourceURI + "\". Use \"{request-attr:" + attributeName + "}\" to get the value!"); } } } catch (Exception exe) { log.error("Error in setRequestAttributes(): ", exe); } if (log.isDebugEnabled()) log.debug("setRequestAttributes() -> end"); } private String fullReplace(String name, String path) { if (log.isDebugEnabled()) log.debug("fullReplace() -> begin"); String result = ""; try { result = this.parameters.getParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name); } catch (ParameterException e) { log.error("Error in fullReplace(): ", e); } if (log.isDebugEnabled()) { log.debug("Result: " + result); } if (log.isDebugEnabled()) log.debug("fullReplace() -> end"); return result; } private String replaceFileName(String name, String path) { if (log.isDebugEnabled()) log.debug("replaceFileName() -> begin"); String result = ""; String replaceRegExp = "^.*\\."; String replaceSuffix = "."; try { //String[] path = this.parameters.getParameter(PREFIX_PARAM_NAME_CHECK_RESOURCES + name).split("/"); String[] splittedPath = path.split("/"); for (int j = 0; j < splittedPath.length; j++) { if (j + 1 == splittedPath.length) { if (this.parameters.isParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name)) { result += splittedPath[j].replaceAll(replaceRegExp, this.parameters.getParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name) + replaceSuffix); } else if (this.parameters.isParameter(PARAM_NAME_DEFAULT_VALUE)) { result += splittedPath[j].replaceAll(replaceRegExp, this.parameters.getParameter(PARAM_NAME_DEFAULT_VALUE) + replaceSuffix); } else { result += splittedPath[j].replaceAll(replaceRegExp, DEFAULT_RESOURCE_NAME + replaceSuffix); } } else { result += splittedPath[j] + "/"; } } } catch (Exception e) { log.error("Error in replaceFileName(): ", e); } if (log.isDebugEnabled()) { log.debug("Result: " + result); } if (log.isDebugEnabled()) log.debug("replaceFileName() -> end"); return result; } private String getDefaultValue(String name, String path) { if (log.isDebugEnabled()) log.debug("getDefaultValue() -> begin"); String result = ""; try { if (this.parameters.isParameter(PREFIX_PARAM_NAME_REPLACE_MODE_VALUES + name) && this.parameters.isParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name)) { if (!this.parameters.getParameter(PREFIX_PARAM_NAME_REPLACE_MODE_VALUES + name).equalsIgnoreCase(DEFAULT_REPLACE_MODE)) { result = replaceFileName(name, path); } else { result = fullReplace(name, path); } } else if (this.parameters.isParameter(PARAM_NAME_REPLACE_MODE) && this.parameters.isParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name)) { if (!this.parameters.getParameter(PARAM_NAME_REPLACE_MODE).equalsIgnoreCase(DEFAULT_REPLACE_MODE)) { result = replaceFileName(name, path); } else { result = fullReplace(name, path); } } else if (this.parameters.isParameter(PREFIX_PARAM_NAME_DEFAULT_VALUES + name)) { result = fullReplace(name, path); } else { if (log.isDebugEnabled()) log.debug("Parameter \"defaultValue-" + name + "\" not found. Replacing the filename with \"" + DEFAULT_RESOURCE_NAME + "\"!"); result = replaceFileName(name, path); } } catch (Exception e) { log.error("Error in getDefaultValue(): ", e); } if (log.isDebugEnabled()) log.debug("getDefaultValue() -> end"); return result; } private class MultiParameterDataHolder { String identifier; String returnName; String originName; String value; boolean multiValue = false; } }