You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by cr...@apache.org on 2012/11/26 23:15:11 UTC
svn commit: r1413895 - in /cocoon/branches/BRANCH_2_1_X/src:
java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java
test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest
Author: crossley
Date: Mon Nov 26 22:15:10 2012
New Revision: 1413895
URL: http://svn.apache.org/viewvc?rev=1413895&view=rev
Log:
Fix line endings and set svn:eol-style property.
Modified:
cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java (contents, props changed)
cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest (contents, props changed)
Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java?rev=1413895&r1=1413894&r2=1413895&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java Mon Nov 26 22:15:10 2012
@@ -1,515 +1,515 @@
-package org.apache.cocoon.components.modules.input;
-
-import org.apache.avalon.framework.service.ServiceException;
-import org.apache.avalon.framework.service.ServiceManager;
-import org.apache.avalon.framework.service.Serviceable;
-import org.apache.avalon.framework.thread.ThreadSafe;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.excalibur.source.SourceResolver;
-import org.apache.excalibur.source.SourceValidity;
-import org.apache.excalibur.source.Source;
-import org.apache.excalibur.store.Store;
-import org.apache.cocoon.components.source.SourceUtil;
-import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
-import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
-
-import org.apache.cocoon.sitemap.PatternException;
-import org.apache.cocoon.ProcessingException;
-import org.apache.commons.collections.map.ReferenceMap;
-import org.apache.commons.collections.map.AbstractReferenceMap;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import java.util.Map;
-import java.net.MalformedURLException;
-import java.io.IOException;
-
-/**
- * <grammar>
- * <define name="input.module.config.contents" combine="choice">
- * <optional><element name="cacheable"><data type="boolean"/></element></optional>
- * <optional><element name="reloadable"><data type="boolean"/></element></optional>
- * <optional>
- * <ref name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
- * </optional>
- * <optional><element name="cache-role"><data type="String"/></element></optional>
- * </define>
- * <p/>
- * <define name="input.module.runtime.contents" combine="choice">
- * <optional>
- * <ref name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
- * </optional>
- * </define>
- * <p/>
- * <define name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
- * <element name="file">
- * <attribute name="src"><data type="anyURI"/></attribute>
- * <optional><attribute name="cacheable"><data type="boolean"/></attribute></optional>
- * <optional><attribute name="reloadable"><data type="boolean"/></attribute></optional>
- * </element>
- * </define>
- * </grammar>
- * <p/>
- * This module provides an Input Module interface to any XML document, by using
- * XPath expressions as attribute keys.
- * The XML can be obtained from any Cocoon <code>Source</code> (e.g.,
- * <code>cocoon:/...</code>, <code>context://..</code>, and regular URLs).
- * Sources can be cached in memory for better performance and reloaded if
- * changed. The source can also contain references to other input modules to allow the source
- * file name to be determined dynamically.
- * <p/>
- * Caching and reloading can be turned on / off (default: caching on,
- * reloading off) through <code><reloadable>false</reloadable></code>
- * and <code><cacheable>false</cacheable></code>. The file
- * (source) to use is specified through <code><file
- * src="protocol:path/to/file.xml" reloadable="true" cacheable="true"/></code>
- * optionally overriding the defaults for caching and/or reloading. When specfied as attributes
- * to the file element the values for cacheable and reloadable may be input module references which
- * will be resolved on every call. These must resolve to 'true' or 'false'.
- * </>
- * The XML documents will be cached using the Store configured via the cache-role configuration
- * element. If not specified the default Store as specified in this classes ROLE attribute will
- * be used.
- * <p/>
- * In addition, xpath expressions can be cached for higher performance.
- * Thus, if an expression has been evaluated for a file, the result
- * is cached and will be reused, the expression is not evaluated
- * a second time. This can be turned off using the <code>cache-expressions</code>
- * configuration option.
- *
- * @version $Id: $
- */
-public class XPathXMLFileModule extends AbstractInputModule
- implements Serviceable, ThreadSafe
-{
- public static final String ROLE = Store.ROLE + "/XPathXMLFileTransientStore";
- /**
- * Contains all globally registered extension classes and
- * packages. Thus the lookup and loading of globally registered
- * extensions is done only once.
- */
- protected JXPathHelperConfiguration configuration;
-
- /**
- * Static (cocoon.xconf) configuration location, for error reporting
- */
- String staticConfLocation;
-
- /**
- * Cached documents
- */
- private Store cache;
-
- /**
- * Determines whether the configured source document should be cached.
- */
- private String cacheParm;
- private Boolean cacheSource;
-
- /**
- * Determines whether the configured source document should be reloaded.
- */
- private String reloadParm;
- private Boolean reloadSource;
-
- /**
- * Default value for reloadability of sources. Defaults to false.
- */
- boolean reloadAll;
- /**
- * Default value for cacheability of xpath expressions. Defaults to true.
- */
- private boolean cacheExpressions;
-
- /**
- * Whether the source needs to be resolved.
- */
- private boolean needsResolve;
-
- /**
- * Overrides attribute name
- */
- protected String parameter;
-
- /**
- * Default src
- */
- private String src;
-
- protected SourceResolver resolver;
- protected ServiceManager manager;
-
-
- /* (non-Javadoc)
- * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
- */
- public void service(ServiceManager manager) throws ServiceException {
- this.manager = manager;
- this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
- }
-
- /**
- * Static (cocoon.xconf) configuration.
- * Configuration is expected to be of the form:
- * <...>
- * <reloadable><b>true</b>|false</reloadable>
- * <cacheable><b>true</b>|false</cacheable>
- * <cache-role>org.apache.excalibur.store.Store/TransientStore</cache-role>
- * <file src="<i>src</i>"/>
- * ...
- * </...>
- * <p/>
- * The <file/> element specifies a file pattern. Only one
- * <file> can be specified, however it can contain references to input modules which will be resolved
- * each time the module is used. The configured <i>src</i> is used if not
- * overridden via a file parameter in the sitemap.
- *
- * @param config a <code>Configuration</code> value, as described above.
- * @throws org.apache.avalon.framework.configuration.ConfigurationException
- * if an error occurs
- */
- public void configure(Configuration config) throws ConfigurationException {
- this.configuration = JXPathHelper.setup(config);
- this.staticConfLocation = config.getLocation();
- Configuration roleConfig = config.getChild("cache-role", true);
- boolean cacheAll = config.getChild("cacheable").getValueAsBoolean(true);
- this.reloadAll = config.getChild("reloadable").getValueAsBoolean(true);
- String cacheRole = roleConfig.getValue(ROLE);
-
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("Using cache " + cacheRole);
- }
-
- try {
- this.cache = (Store) this.manager.lookup(cacheRole);
- } catch (ServiceException ce) {
- throw new ConfigurationException("Unable to lookup cache: " + cacheRole, ce);
- }
-
- Configuration fileConfig = config.getChild("file");
-
- this.src = fileConfig.getAttribute("src");
- this.cacheParm = fileConfig.getAttribute("cacheable", null);
- this.reloadParm = fileConfig.getAttribute("reloadable", null);
- if (this.cacheParm == null) {
- this.cacheSource = Boolean.valueOf(cacheAll);
- } else if (VariableResolverFactory.needsResolve(this.cacheParm)) {
- this.cacheSource = null;
- } else {
- this.cacheSource = Boolean.valueOf(this.cacheParm);
- }
- if (this.reloadParm == null) {
- this.reloadSource = Boolean.valueOf(this.reloadAll);
- } else if (VariableResolverFactory.needsResolve(this.reloadParm)) {
- this.reloadSource = null;
- } else {
- this.reloadSource = Boolean.valueOf(this.reloadParm);
- }
-
- // init caches
- this.cacheExpressions = config.getChild("cache-expressions").getValueAsBoolean(true);
- this.needsResolve = VariableResolverFactory.needsResolve(this.src);
- }
-
- /**
- * Dispose this component
- */
- public void dispose() {
- super.dispose();
- if (this.manager != null) {
- this.manager.release(this.resolver);
- this.manager.release(this.cache);
- this.resolver = null;
- this.cache = null;
- this.manager = null;
- }
- }
-
- public Object getAttribute(String name, Configuration modeConf, Map objectModel)
- throws ConfigurationException {
- return getAttribute(name, modeConf, objectModel, false);
- }
-
- public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
- throws ConfigurationException {
- Object result = getAttribute(name, modeConf, objectModel, true);
- return (result != null ? (Object[]) result : null);
- }
- /**
- * Get the DocumentInfo for the DOM object that JXPath will operate on when evaluating
- * attributes. This DOM is loaded from a Source, specified in the
- * modeConf, or (if modeConf is null) from the
- * {@link #configure(org.apache.avalon.framework.configuration.Configuration)}.
- *
- * @param name The JXPath to retrieve
- * @param modeConf The dynamic configuration for the current operation. May
- * be <code>null</code>, in which case static (cocoon.xconf) configuration
- * is used. Configuration is expected to have a <file> child node, and
- * be of the form:
- * <...>
- * <file src="..." reloadable="true|false"/>
- * </...>
- * @param objectModel Object Model for the current module operation.
- * @param getValues true if multiple values should be retrieve, false otherwise
- * @return the result of the XPath query into the XML document
- * @throws ConfigurationException if an error occurs.
- */
- private Object getAttribute(String name, Configuration modeConf, Map objectModel, boolean getValues)
- throws ConfigurationException {
-
- if (modeConf != null) {
- name = modeConf.getChild("parameter").getValue(this.parameter != null ? this.parameter : name);
- }
-
- boolean hasDynamicConf = false; // whether we have a <file src="..."> dynamic configuration
- Configuration fileConf = null; // the nested <file>, if any
-
- if (modeConf != null && modeConf.getChildren().length > 0) {
- fileConf = modeConf.getChild("file", false);
- if (fileConf == null) {
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("Missing 'file' child element at " + modeConf.getLocation());
- }
- } else {
- hasDynamicConf = true;
- }
- }
-
- String src = this.src;
- Boolean cacheSource = this.cacheSource;
- Boolean reloadSource = this.cacheSource;
- boolean needsResolve = this.needsResolve;
- String cacheParm = this.cacheParm;
- String reloadParm = this.reloadParm;
-
- if (hasDynamicConf) {
- src = fileConf.getAttribute("src");
- cacheParm = fileConf.getAttribute("cacheable", this.cacheParm);
- reloadParm = fileConf.getAttribute("reloadable", this.reloadParm);
- if (cacheParm == null) {
- cacheSource = this.cacheSource;
- } else if (VariableResolverFactory.needsResolve(cacheParm)) {
- cacheSource = null;
- if (cacheSource == null) {
- try {
- VariableResolver varResolver = VariableResolverFactory.getResolver(cacheParm, this.manager);
- cacheSource = Boolean.valueOf(varResolver.resolve(objectModel));
- } catch (PatternException pe) {
- throw new ConfigurationException("Error resolving " + cacheParm, pe);
- }
- }
- } else {
- cacheSource = Boolean.valueOf(cacheParm);
- }
- if (reloadParm == null) {
- reloadSource = this.reloadSource;
- } else if (VariableResolverFactory.needsResolve(reloadParm)) {
- reloadSource = null;
- } else {
- reloadSource = Boolean.valueOf(reloadParm);
- }
- needsResolve = true;
- }
- if (cacheSource == null) {
- try {
- VariableResolver varResolver = VariableResolverFactory.getResolver(cacheParm, this.manager);
- cacheSource = Boolean.valueOf(varResolver.resolve(objectModel));
- } catch (PatternException pe) {
- throw new ConfigurationException("Error resolving " + cacheParm, pe);
- }
- }
- if (reloadSource == null) {
- try {
- VariableResolver varResolver =
- VariableResolverFactory.getResolver(reloadParm, this.manager);
- reloadSource = Boolean.valueOf(varResolver.resolve(objectModel));
- } catch (PatternException pe) {
- throw new ConfigurationException("Error resolving " + reloadParm, pe);
- }
- }
-
- if (src == null) {
- throw new ConfigurationException(
- "No source specified"
- + (modeConf != null ? ", either dynamically in " + modeConf.getLocation() + ", or " : "")
- + " statically in "
- + staticConfLocation);
- }
-
- if (needsResolve) {
- try {
- VariableResolver varResolver = VariableResolverFactory.getResolver(src, this.manager);
- src = varResolver.resolve(objectModel);
- } catch (PatternException pe) {
- throw new ConfigurationException("Error resolving variables for " + src, pe);
- }
- }
-
- Object result;
-
- if (cacheSource.booleanValue()) {
- DocumentInfo info = (DocumentInfo) this.cache.get(src);
- if (info == null || (reloadSource.booleanValue() && !info.isValid())) {
- Source docSource = null;
- try {
- docSource = resolver.resolveURI(src);
- DocumentInfo newInfo = new DocumentInfo(src, SourceUtil.toDOM(docSource),
- docSource.getValidity(), this.cacheExpressions, this.resolver);
- synchronized(this.cache) {
- DocumentInfo cachedInfo = (DocumentInfo)this.cache.get(src);
- if (cachedInfo == null || cachedInfo == info) {
- this.cache.store(src, newInfo);
- info = newInfo;
- } else {
- info = cachedInfo;
- }
- }
- } catch (MalformedURLException mue) {
- throw new ConfigurationException("Unable to resolve " + src, mue);
- } catch (IOException ioe) {
- throw new ConfigurationException("Unable to access" + src, ioe);
- } catch (ProcessingException pe) {
- throw new ConfigurationException("Unable to process " + src, pe);
- } catch (SAXException se) {
- throw new ConfigurationException("Error processing XML document " + src, se);
- } finally {
- if (docSource != null) {
- resolver.release(docSource);
- }
- }
- }
- if (info.cacheExpressions) {
- Map cache = getValues ? info.expressionValuesCache : info.expressionCache;
- synchronized (cache) {
- if (cache.containsKey(name)) {
- result = cache.get(name);
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("for " + name + " using cached result " + result);
- }
- } else {
- result = getResult(name, info.document, modeConf, getValues);
- if (result != null) {
- cache.put(name, result);
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("for " + name + " newly caching result " + result);
- }
- } else {
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("for " + name + " result is null");
- }
- }
- }
- }
- } else {
- result = getResult(name, info.document, modeConf, getValues);
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("for " + name + " result is " + result);
- }
- }
- } else {
- Source docSource = null;
- try {
- docSource = resolver.resolveURI(src);
- result = getResult(name, SourceUtil.toDOM(docSource), modeConf, getValues);
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("for " + name + " result is " + result);
- }
- } catch (MalformedURLException mue) {
- throw new ConfigurationException("Unable to resolve " + src, mue);
- } catch (IOException ioe) {
- throw new ConfigurationException("Unable to access" + src, ioe);
- } catch (ProcessingException pe) {
- throw new ConfigurationException("Unable to process " + src, pe);
- } catch (SAXException se) {
- throw new ConfigurationException("Error processing XML document " + src, se);
- } finally {
- if (docSource != null) {
- resolver.release(docSource);
- }
- }
- }
-
- return result;
- }
-
- private Object getResult(String name, Document document, Configuration modeConf, boolean getValues)
- throws ConfigurationException {
- Object result;
-
- if (getValues) {
- result = JXPathHelper.getAttributeValues(name, modeConf, this.configuration, document);
- } else {
- result = JXPathHelper.getAttributeValue(name, modeConf, this.configuration, document);
- }
- return result;
- }
-
- /**
- * Used to keep track of the Document, its validity and any cached expressions.
- */
- private static class DocumentInfo
- {
- public DocumentInfo(String uri, Document doc, SourceValidity validity, boolean cacheExpressions,
- SourceResolver resolver) {
- this.cacheExpressions = cacheExpressions;
- if (cacheExpressions) {
- expressionCache = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT);
- expressionValuesCache = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT);
- }
- this.resolver = resolver;
- this.uri = uri;
- this.document = doc;
- this.validity = validity;
- }
-
- private boolean cacheExpressions;
-
- private final String uri;
-
- private final SourceValidity validity;
-
- private final SourceResolver resolver;
-
- /**
- * Source content cached as DOM Document
- */
- private final Document document;
-
- private Map expressionCache;
- private Map expressionValuesCache;
-
- /**
- * Returns true if the document is valid, false otherwise.
- * <p/>
- *
- * @return returns true if the document is valid, false otherwise.
- */
- private boolean isValid() {
- Source src = null;
- boolean result = true;
-
- try {
- int valid = validity == null ? SourceValidity.INVALID : validity.isValid();
- if (valid == SourceValidity.UNKNOWN) {
- // Get new source and validity
- src = resolver.resolveURI(this.uri);
- SourceValidity newValidity = src.getValidity();
- valid = validity.isValid(newValidity);
- }
- if (valid != SourceValidity.VALID) {
- result = false;
- }
- }
- catch (Exception ex) {
- result = false;
- }
- finally {
- if (src != null) {
- resolver.release(src);
- }
- }
- return result;
- }
- }
+package org.apache.cocoon.components.modules.input;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.store.Store;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory;
+import org.apache.cocoon.components.treeprocessor.variables.VariableResolver;
+
+import org.apache.cocoon.sitemap.PatternException;
+import org.apache.cocoon.ProcessingException;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.commons.collections.map.AbstractReferenceMap;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.util.Map;
+import java.net.MalformedURLException;
+import java.io.IOException;
+
+/**
+ * <grammar>
+ * <define name="input.module.config.contents" combine="choice">
+ * <optional><element name="cacheable"><data type="boolean"/></element></optional>
+ * <optional><element name="reloadable"><data type="boolean"/></element></optional>
+ * <optional>
+ * <ref name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
+ * </optional>
+ * <optional><element name="cache-role"><data type="String"/></element></optional>
+ * </define>
+ * <p/>
+ * <define name="input.module.runtime.contents" combine="choice">
+ * <optional>
+ * <ref name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
+ * </optional>
+ * </define>
+ * <p/>
+ * <define name="org.apache.cocoon.components.modules.input.XPathXMLFileModule:file">
+ * <element name="file">
+ * <attribute name="src"><data type="anyURI"/></attribute>
+ * <optional><attribute name="cacheable"><data type="boolean"/></attribute></optional>
+ * <optional><attribute name="reloadable"><data type="boolean"/></attribute></optional>
+ * </element>
+ * </define>
+ * </grammar>
+ * <p/>
+ * This module provides an Input Module interface to any XML document, by using
+ * XPath expressions as attribute keys.
+ * The XML can be obtained from any Cocoon <code>Source</code> (e.g.,
+ * <code>cocoon:/...</code>, <code>context://..</code>, and regular URLs).
+ * Sources can be cached in memory for better performance and reloaded if
+ * changed. The source can also contain references to other input modules to allow the source
+ * file name to be determined dynamically.
+ * <p/>
+ * Caching and reloading can be turned on / off (default: caching on,
+ * reloading off) through <code><reloadable>false</reloadable></code>
+ * and <code><cacheable>false</cacheable></code>. The file
+ * (source) to use is specified through <code><file
+ * src="protocol:path/to/file.xml" reloadable="true" cacheable="true"/></code>
+ * optionally overriding the defaults for caching and/or reloading. When specfied as attributes
+ * to the file element the values for cacheable and reloadable may be input module references which
+ * will be resolved on every call. These must resolve to 'true' or 'false'.
+ * </>
+ * The XML documents will be cached using the Store configured via the cache-role configuration
+ * element. If not specified the default Store as specified in this classes ROLE attribute will
+ * be used.
+ * <p/>
+ * In addition, xpath expressions can be cached for higher performance.
+ * Thus, if an expression has been evaluated for a file, the result
+ * is cached and will be reused, the expression is not evaluated
+ * a second time. This can be turned off using the <code>cache-expressions</code>
+ * configuration option.
+ *
+ * @version $Id: $
+ */
+public class XPathXMLFileModule extends AbstractInputModule
+ implements Serviceable, ThreadSafe
+{
+ public static final String ROLE = Store.ROLE + "/XPathXMLFileTransientStore";
+ /**
+ * Contains all globally registered extension classes and
+ * packages. Thus the lookup and loading of globally registered
+ * extensions is done only once.
+ */
+ protected JXPathHelperConfiguration configuration;
+
+ /**
+ * Static (cocoon.xconf) configuration location, for error reporting
+ */
+ String staticConfLocation;
+
+ /**
+ * Cached documents
+ */
+ private Store cache;
+
+ /**
+ * Determines whether the configured source document should be cached.
+ */
+ private String cacheParm;
+ private Boolean cacheSource;
+
+ /**
+ * Determines whether the configured source document should be reloaded.
+ */
+ private String reloadParm;
+ private Boolean reloadSource;
+
+ /**
+ * Default value for reloadability of sources. Defaults to false.
+ */
+ boolean reloadAll;
+ /**
+ * Default value for cacheability of xpath expressions. Defaults to true.
+ */
+ private boolean cacheExpressions;
+
+ /**
+ * Whether the source needs to be resolved.
+ */
+ private boolean needsResolve;
+
+ /**
+ * Overrides attribute name
+ */
+ protected String parameter;
+
+ /**
+ * Default src
+ */
+ private String src;
+
+ protected SourceResolver resolver;
+ protected ServiceManager manager;
+
+
+ /* (non-Javadoc)
+ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+ */
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+ }
+
+ /**
+ * Static (cocoon.xconf) configuration.
+ * Configuration is expected to be of the form:
+ * <...>
+ * <reloadable><b>true</b>|false</reloadable>
+ * <cacheable><b>true</b>|false</cacheable>
+ * <cache-role>org.apache.excalibur.store.Store/TransientStore</cache-role>
+ * <file src="<i>src</i>"/>
+ * ...
+ * </...>
+ * <p/>
+ * The <file/> element specifies a file pattern. Only one
+ * <file> can be specified, however it can contain references to input modules which will be resolved
+ * each time the module is used. The configured <i>src</i> is used if not
+ * overridden via a file parameter in the sitemap.
+ *
+ * @param config a <code>Configuration</code> value, as described above.
+ * @throws org.apache.avalon.framework.configuration.ConfigurationException
+ * if an error occurs
+ */
+ public void configure(Configuration config) throws ConfigurationException {
+ this.configuration = JXPathHelper.setup(config);
+ this.staticConfLocation = config.getLocation();
+ Configuration roleConfig = config.getChild("cache-role", true);
+ boolean cacheAll = config.getChild("cacheable").getValueAsBoolean(true);
+ this.reloadAll = config.getChild("reloadable").getValueAsBoolean(true);
+ String cacheRole = roleConfig.getValue(ROLE);
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Using cache " + cacheRole);
+ }
+
+ try {
+ this.cache = (Store) this.manager.lookup(cacheRole);
+ } catch (ServiceException ce) {
+ throw new ConfigurationException("Unable to lookup cache: " + cacheRole, ce);
+ }
+
+ Configuration fileConfig = config.getChild("file");
+
+ this.src = fileConfig.getAttribute("src");
+ this.cacheParm = fileConfig.getAttribute("cacheable", null);
+ this.reloadParm = fileConfig.getAttribute("reloadable", null);
+ if (this.cacheParm == null) {
+ this.cacheSource = Boolean.valueOf(cacheAll);
+ } else if (VariableResolverFactory.needsResolve(this.cacheParm)) {
+ this.cacheSource = null;
+ } else {
+ this.cacheSource = Boolean.valueOf(this.cacheParm);
+ }
+ if (this.reloadParm == null) {
+ this.reloadSource = Boolean.valueOf(this.reloadAll);
+ } else if (VariableResolverFactory.needsResolve(this.reloadParm)) {
+ this.reloadSource = null;
+ } else {
+ this.reloadSource = Boolean.valueOf(this.reloadParm);
+ }
+
+ // init caches
+ this.cacheExpressions = config.getChild("cache-expressions").getValueAsBoolean(true);
+ this.needsResolve = VariableResolverFactory.needsResolve(this.src);
+ }
+
+ /**
+ * Dispose this component
+ */
+ public void dispose() {
+ super.dispose();
+ if (this.manager != null) {
+ this.manager.release(this.resolver);
+ this.manager.release(this.cache);
+ this.resolver = null;
+ this.cache = null;
+ this.manager = null;
+ }
+ }
+
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ return getAttribute(name, modeConf, objectModel, false);
+ }
+
+ public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object result = getAttribute(name, modeConf, objectModel, true);
+ return (result != null ? (Object[]) result : null);
+ }
+ /**
+ * Get the DocumentInfo for the DOM object that JXPath will operate on when evaluating
+ * attributes. This DOM is loaded from a Source, specified in the
+ * modeConf, or (if modeConf is null) from the
+ * {@link #configure(org.apache.avalon.framework.configuration.Configuration)}.
+ *
+ * @param name The JXPath to retrieve
+ * @param modeConf The dynamic configuration for the current operation. May
+ * be <code>null</code>, in which case static (cocoon.xconf) configuration
+ * is used. Configuration is expected to have a <file> child node, and
+ * be of the form:
+ * <...>
+ * <file src="..." reloadable="true|false"/>
+ * </...>
+ * @param objectModel Object Model for the current module operation.
+ * @param getValues true if multiple values should be retrieve, false otherwise
+ * @return the result of the XPath query into the XML document
+ * @throws ConfigurationException if an error occurs.
+ */
+ private Object getAttribute(String name, Configuration modeConf, Map objectModel, boolean getValues)
+ throws ConfigurationException {
+
+ if (modeConf != null) {
+ name = modeConf.getChild("parameter").getValue(this.parameter != null ? this.parameter : name);
+ }
+
+ boolean hasDynamicConf = false; // whether we have a <file src="..."> dynamic configuration
+ Configuration fileConf = null; // the nested <file>, if any
+
+ if (modeConf != null && modeConf.getChildren().length > 0) {
+ fileConf = modeConf.getChild("file", false);
+ if (fileConf == null) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Missing 'file' child element at " + modeConf.getLocation());
+ }
+ } else {
+ hasDynamicConf = true;
+ }
+ }
+
+ String src = this.src;
+ Boolean cacheSource = this.cacheSource;
+ Boolean reloadSource = this.cacheSource;
+ boolean needsResolve = this.needsResolve;
+ String cacheParm = this.cacheParm;
+ String reloadParm = this.reloadParm;
+
+ if (hasDynamicConf) {
+ src = fileConf.getAttribute("src");
+ cacheParm = fileConf.getAttribute("cacheable", this.cacheParm);
+ reloadParm = fileConf.getAttribute("reloadable", this.reloadParm);
+ if (cacheParm == null) {
+ cacheSource = this.cacheSource;
+ } else if (VariableResolverFactory.needsResolve(cacheParm)) {
+ cacheSource = null;
+ if (cacheSource == null) {
+ try {
+ VariableResolver varResolver = VariableResolverFactory.getResolver(cacheParm, this.manager);
+ cacheSource = Boolean.valueOf(varResolver.resolve(objectModel));
+ } catch (PatternException pe) {
+ throw new ConfigurationException("Error resolving " + cacheParm, pe);
+ }
+ }
+ } else {
+ cacheSource = Boolean.valueOf(cacheParm);
+ }
+ if (reloadParm == null) {
+ reloadSource = this.reloadSource;
+ } else if (VariableResolverFactory.needsResolve(reloadParm)) {
+ reloadSource = null;
+ } else {
+ reloadSource = Boolean.valueOf(reloadParm);
+ }
+ needsResolve = true;
+ }
+ if (cacheSource == null) {
+ try {
+ VariableResolver varResolver = VariableResolverFactory.getResolver(cacheParm, this.manager);
+ cacheSource = Boolean.valueOf(varResolver.resolve(objectModel));
+ } catch (PatternException pe) {
+ throw new ConfigurationException("Error resolving " + cacheParm, pe);
+ }
+ }
+ if (reloadSource == null) {
+ try {
+ VariableResolver varResolver =
+ VariableResolverFactory.getResolver(reloadParm, this.manager);
+ reloadSource = Boolean.valueOf(varResolver.resolve(objectModel));
+ } catch (PatternException pe) {
+ throw new ConfigurationException("Error resolving " + reloadParm, pe);
+ }
+ }
+
+ if (src == null) {
+ throw new ConfigurationException(
+ "No source specified"
+ + (modeConf != null ? ", either dynamically in " + modeConf.getLocation() + ", or " : "")
+ + " statically in "
+ + staticConfLocation);
+ }
+
+ if (needsResolve) {
+ try {
+ VariableResolver varResolver = VariableResolverFactory.getResolver(src, this.manager);
+ src = varResolver.resolve(objectModel);
+ } catch (PatternException pe) {
+ throw new ConfigurationException("Error resolving variables for " + src, pe);
+ }
+ }
+
+ Object result;
+
+ if (cacheSource.booleanValue()) {
+ DocumentInfo info = (DocumentInfo) this.cache.get(src);
+ if (info == null || (reloadSource.booleanValue() && !info.isValid())) {
+ Source docSource = null;
+ try {
+ docSource = resolver.resolveURI(src);
+ DocumentInfo newInfo = new DocumentInfo(src, SourceUtil.toDOM(docSource),
+ docSource.getValidity(), this.cacheExpressions, this.resolver);
+ synchronized(this.cache) {
+ DocumentInfo cachedInfo = (DocumentInfo)this.cache.get(src);
+ if (cachedInfo == null || cachedInfo == info) {
+ this.cache.store(src, newInfo);
+ info = newInfo;
+ } else {
+ info = cachedInfo;
+ }
+ }
+ } catch (MalformedURLException mue) {
+ throw new ConfigurationException("Unable to resolve " + src, mue);
+ } catch (IOException ioe) {
+ throw new ConfigurationException("Unable to access" + src, ioe);
+ } catch (ProcessingException pe) {
+ throw new ConfigurationException("Unable to process " + src, pe);
+ } catch (SAXException se) {
+ throw new ConfigurationException("Error processing XML document " + src, se);
+ } finally {
+ if (docSource != null) {
+ resolver.release(docSource);
+ }
+ }
+ }
+ if (info.cacheExpressions) {
+ Map cache = getValues ? info.expressionValuesCache : info.expressionCache;
+ synchronized (cache) {
+ if (cache.containsKey(name)) {
+ result = cache.get(name);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("for " + name + " using cached result " + result);
+ }
+ } else {
+ result = getResult(name, info.document, modeConf, getValues);
+ if (result != null) {
+ cache.put(name, result);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("for " + name + " newly caching result " + result);
+ }
+ } else {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("for " + name + " result is null");
+ }
+ }
+ }
+ }
+ } else {
+ result = getResult(name, info.document, modeConf, getValues);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("for " + name + " result is " + result);
+ }
+ }
+ } else {
+ Source docSource = null;
+ try {
+ docSource = resolver.resolveURI(src);
+ result = getResult(name, SourceUtil.toDOM(docSource), modeConf, getValues);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("for " + name + " result is " + result);
+ }
+ } catch (MalformedURLException mue) {
+ throw new ConfigurationException("Unable to resolve " + src, mue);
+ } catch (IOException ioe) {
+ throw new ConfigurationException("Unable to access" + src, ioe);
+ } catch (ProcessingException pe) {
+ throw new ConfigurationException("Unable to process " + src, pe);
+ } catch (SAXException se) {
+ throw new ConfigurationException("Error processing XML document " + src, se);
+ } finally {
+ if (docSource != null) {
+ resolver.release(docSource);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private Object getResult(String name, Document document, Configuration modeConf, boolean getValues)
+ throws ConfigurationException {
+ Object result;
+
+ if (getValues) {
+ result = JXPathHelper.getAttributeValues(name, modeConf, this.configuration, document);
+ } else {
+ result = JXPathHelper.getAttributeValue(name, modeConf, this.configuration, document);
+ }
+ return result;
+ }
+
+ /**
+ * Used to keep track of the Document, its validity and any cached expressions.
+ */
+ private static class DocumentInfo
+ {
+ public DocumentInfo(String uri, Document doc, SourceValidity validity, boolean cacheExpressions,
+ SourceResolver resolver) {
+ this.cacheExpressions = cacheExpressions;
+ if (cacheExpressions) {
+ expressionCache = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT);
+ expressionValuesCache = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT);
+ }
+ this.resolver = resolver;
+ this.uri = uri;
+ this.document = doc;
+ this.validity = validity;
+ }
+
+ private boolean cacheExpressions;
+
+ private final String uri;
+
+ private final SourceValidity validity;
+
+ private final SourceResolver resolver;
+
+ /**
+ * Source content cached as DOM Document
+ */
+ private final Document document;
+
+ private Map expressionCache;
+ private Map expressionValuesCache;
+
+ /**
+ * Returns true if the document is valid, false otherwise.
+ * <p/>
+ *
+ * @return returns true if the document is valid, false otherwise.
+ */
+ private boolean isValid() {
+ Source src = null;
+ boolean result = true;
+
+ try {
+ int valid = validity == null ? SourceValidity.INVALID : validity.isValid();
+ if (valid == SourceValidity.UNKNOWN) {
+ // Get new source and validity
+ src = resolver.resolveURI(this.uri);
+ SourceValidity newValidity = src.getValidity();
+ valid = validity.isValid(newValidity);
+ }
+ if (valid != SourceValidity.VALID) {
+ result = false;
+ }
+ }
+ catch (Exception ex) {
+ result = false;
+ }
+ finally {
+ if (src != null) {
+ resolver.release(src);
+ }
+ }
+ return result;
+ }
+ }
}
\ No newline at end of file
Propchange: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/modules/input/XPathXMLFileModule.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest
URL: http://svn.apache.org/viewvc/cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest?rev=1413895&r1=1413894&r2=1413895&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest (original)
+++ cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest Mon Nov 26 22:15:10 2012
@@ -1,39 +1,39 @@
-<?xml version="1.0" ?>
-<!--
- 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.
--->
-<testcase>
- <roles>
- <role name="org.apache.excalibur.source.SourceFactorySelector"
- shorthand="source-factories"
- default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"/>
-
- <role name="org.apache.excalibur.source.SourceResolver"
- shorthand="source-resolver"
- default-class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
- </roles>
-
- <components>
- <source-factories>
- <component-instance class="org.apache.excalibur.source.impl.ResourceSourceFactory" name="resource"/>
- <component-instance class="org.apache.cocoon.components.source.impl.ZipSourceFactory" name="zip"/>
- <component-instance class="org.apache.excalibur.source.impl.URLSourceFactory" name="*"/>
- </source-factories>
-
- <source-resolver class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
- </components>
-
-</testcase>
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+<testcase>
+ <roles>
+ <role name="org.apache.excalibur.source.SourceFactorySelector"
+ shorthand="source-factories"
+ default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"/>
+
+ <role name="org.apache.excalibur.source.SourceResolver"
+ shorthand="source-resolver"
+ default-class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
+ </roles>
+
+ <components>
+ <source-factories>
+ <component-instance class="org.apache.excalibur.source.impl.ResourceSourceFactory" name="resource"/>
+ <component-instance class="org.apache.cocoon.components.source.impl.ZipSourceFactory" name="zip"/>
+ <component-instance class="org.apache.excalibur.source.impl.URLSourceFactory" name="*"/>
+ </source-factories>
+
+ <source-resolver class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
+ </components>
+
+</testcase>
Propchange: cocoon/branches/BRANCH_2_1_X/src/test/org/apache/cocoon/components/source/impl/ZipSourceTestCase.xtest
------------------------------------------------------------------------------
svn:eol-style = native