move implementation classes from core.api to core.impl
git-svn-id: https://svn.apache.org/repos/asf/lenya/trunk@1033147 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/AbstractPageEnvelopeModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/AbstractPageEnvelopeModule.java
new file mode 100644
index 0000000..9a6c6a0
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/AbstractPageEnvelopeModule.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ */
+
+/* $Id$ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.lenya.cms.publication.PageEnvelope;
+import org.apache.lenya.cms.publication.PageEnvelopeFactory;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.publication.Session;
+import org.apache.lenya.util.ServletHelper;
+import org.apache.lenya.utils.URLInformation;
+/**
+ * Abstract superclass for classes which need access to the page envelope.
+ *
+ * The web application URL can be provided in the attribute name, separated by a colon (":").
+ */
+public abstract class AbstractPageEnvelopeModule extends OperationModule {
+
+ /**
+ * Get the the page envelope for the given objectModel.
+ * @param objectModel the objectModel for which the page enevelope is requested.
+ * @param name The attribute name.
+ * @return a <code>PageEnvelope</code>
+ * @throws ConfigurationException if the page envelope could not be instantiated.
+ */
+ protected PageEnvelope getEnvelope(Map objectModel, String name) throws ConfigurationException {
+
+ String webappUrl = null;
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ URLInformation urlInfo = new URLInformation();
+
+ PageEnvelope envelope = (PageEnvelope) request.getAttribute(PageEnvelope.class.getName());
+ if (envelope == null) {
+
+ String[] snippets = name.split(":");
+ if (snippets.length > 1) {
+ webappUrl = snippets[1];
+ } else {
+ webappUrl = urlInfo.getWebappUrl();
+ }
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Resolving page envelope for URL [" + webappUrl + "]");
+ }
+
+ String contextPath = request.getContextPath();
+
+ try {
+ Session session = getSession();
+ Publication pub = null;
+ String pubId = urlInfo.getPublicationId();
+ if (pubId != null && session.existsPublication(pubId)) {
+ pub = session.getPublication(pubId);
+ }
+ envelope = PageEnvelopeFactory.getInstance().getPageEnvelope(
+ contextPath,
+ webappUrl,
+ pub);
+ } catch (Exception e) {
+ throw new ConfigurationException("Resolving page envelope failed: ", e);
+ }
+ request.setAttribute(PageEnvelope.class.getName(), envelope);
+ }
+ return envelope;
+ }
+
+ /**
+ * @param name The original attribute name.
+ * @return The attribute name without URL attachment.
+ */
+ protected String getAttributeName(String name) {
+ final String[] snippets = name.split(":");
+ return snippets[0];
+ }
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DateConverterModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DateConverterModule.java
new file mode 100644
index 0000000..583cf0c
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DateConverterModule.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+
+/**
+ * The DateConverterModule converts a date string from one format into
+ * another format.
+ * The conversion is defined by the nested elements <src-pattern/> and
+ * <pattern/> of the module declaration.
+ *
+ */
+public class DateConverterModule extends AbstractInputModule implements ThreadSafe {
+
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel) throws ConfigurationException {
+
+ String srcPattern = (String) this.settings.get("src-pattern");
+ String pattern = (String) this.settings.get("pattern");
+
+ if (modeConf != null) {
+ srcPattern = modeConf.getChild("src-pattern").getValue(srcPattern);
+ pattern = modeConf.getChild("pattern").getValue(pattern);
+ }
+
+ if (srcPattern==null) {
+ throw new ConfigurationException("Source date pattern not specified.");
+ }
+ if (pattern==null) {
+ throw new ConfigurationException("Date pattern not specified.");
+ }
+
+ try {
+ SimpleDateFormat srcFormat = new SimpleDateFormat(srcPattern);
+ SimpleDateFormat format = new SimpleDateFormat(pattern);
+ Date date = srcFormat.parse(name);
+ return format.format(date);
+ } catch (Exception e) {
+ throw new ConfigurationException("Could not convert date: "+name, e);
+ }
+ }
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentInfoModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentInfoModule.java
new file mode 100644
index 0000000..04c5444
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentInfoModule.java
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ *
+ */
+
+/* $Id:$ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.DocumentException;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.publication.Repository;
+import org.apache.lenya.cms.publication.Session;
+
+/**
+ * Input module to get document information.
+ * {doc-info:{publication-id}:{area}:{uuid}:{document-language}:{property}} where {property} may be:
+ * <ul>
+ * <li><strong><code>contentLength</code></strong> - the content length (number of bytes).</li>
+ * <li><strong><code>expires</code></strong> - the expiration date in ISO 8601 format.</li>
+ * <li><strong><code>lastModified</code></strong> - the last modification date in ISO 8601
+ * format.</li>
+ * <li><strong><code>mimeType</code></strong> - the MIME type</li>
+ * <li><strong><code>nodeName</code></strong> - the name of the node in the site structure</li>
+ * <li><strong><code>path</code></strong> - the path in the site structure (starting with a
+ * slash) or an empty string if the document is not referenced in the site structure.</li>
+ * <li><strong><code>resourceType</code></strong> - the name of the resource type</li>
+ * <li><strong><code>sourceExtension</code></strong> - the source extension</li>
+ * <li><strong><code>visibleInNav</code></strong> - <code>true</code> if the document's node
+ * is visible in the navigation, <code>false</code> otherwise.</li>
+ * <li><strong><code>webappUrl</code></strong> - the web application URL of the document or
+ * an empty string if the document is not referenced in the site structure.</li>
+ * </ul>
+ */
+public class DocumentInfoModule extends AbstractInputModule {
+
+ // Input module parameters:
+ protected final static String PARAM_PUBLICATION_ID = "publication-id";
+ protected final static String PARAM_AREA = "area";
+ protected final static String PARAM_UUID = "uuid";
+ protected final static String PARAM_DOCUMENT_LANGUAGE = "document-language";
+ protected final static String PARAM_PROPERTY = "property";
+ protected final static String PARAM_REVISION = "revision";
+ protected final static int MIN_MANDATORY_PARAMS = 5;
+
+ protected final static String UUID = "uuid";
+ protected final static String LANGUAGE = "language";
+ protected final static String PATH = "path";
+ protected final static String NODE_NAME = "nodeName";
+ protected final static String WEBAPP_URL = "webappUrl";
+ protected final static String DOCUMENT_URL = "documentUrl";
+ protected final static String RESOURCE_TYPE = "resourceType";
+ protected final static String LAST_MODIFIED = "lastModified";
+ protected final static String MIME_TYPE = "mimeType";
+ protected final static String CONTENT_LENGTH = "contentLength";
+ protected final static String SOURCE_EXTENSION = "sourceExtension";
+ protected final static String EXPIRES = "expires";
+ protected final static String VISIBLE_IN_NAVIGATION = "visibleInNav";
+
+ protected final static String[] PARAMS = { PARAM_PUBLICATION_ID, PARAM_AREA, PARAM_UUID,
+ PARAM_DOCUMENT_LANGUAGE, PARAM_PROPERTY, PARAM_REVISION };
+
+ protected final static String META_RESOURCE_TYPE = "resourceType";
+ protected final static String META_EXPIRES = "expires";
+
+ protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
+
+ private Repository repository;
+
+ /**
+ * Parse the parameters and return a document.
+ * @param publicationId The publication ID.
+ * @param area The area.
+ * @param uuid The document UUID.
+ * @param language The document language.
+ * @param revision The revision.
+ * @param objectModel The object model.
+ * @return The document object created.
+ * @throws ConfigurationException
+ */
+ protected Document getDocument(String publicationId, String area, String uuid, String language,
+ int revision, Map objectModel) throws ConfigurationException {
+ Document document = null;
+
+ Request request = ObjectModelHelper.getRequest(objectModel);
+
+ try {
+ Session session = this.repository.getSession(request);
+ Publication pub = session.getPublication(publicationId);
+ document = pub.getArea(area).getDocument(uuid, language, revision);
+ } catch (Exception e) {
+ throw new ConfigurationException("Error getting document [" + publicationId + ":"
+ + area + ":" + uuid + ":" + language + "]: " + e.getMessage(), e);
+ }
+ return document;
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttribute(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
+ */
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object value = null;
+
+ InputModuleParameters params = new InputModuleParameters(name, PARAMS, MIN_MANDATORY_PARAMS);
+
+ try {
+ int rev = -1;
+ if (params.isParameter(PARAM_REVISION)) {
+ String revision = params.getParameter(PARAM_REVISION);
+ if (!revision.equals("")) {
+ rev = Integer.valueOf(revision).intValue();
+ }
+ }
+
+ Document document = getDocument(params.getParameter(PARAM_PUBLICATION_ID), params
+ .getParameter(PARAM_AREA), params.getParameter(PARAM_UUID), params
+ .getParameter(PARAM_DOCUMENT_LANGUAGE), rev, objectModel);
+
+ String attribute = params.getParameter(PARAM_PROPERTY);
+
+ if (attribute.equals(RESOURCE_TYPE)) {
+ value = document.getResourceType().getName();
+ } else if (attribute.equals(LAST_MODIFIED)) {
+ value = this.dateFormat.format(new Date(document.getLastModified()));
+ } else if (attribute.equals(MIME_TYPE)) {
+ value = document.getMimeType();
+ } else if (attribute.equals(CONTENT_LENGTH)) {
+ value = Long.toString(document.getContentLength());
+ } else if (attribute.equals(SOURCE_EXTENSION)) {
+ value = document.getSourceExtension();
+ } else if (attribute.equals(LANGUAGE)) {
+ value = document.getLanguage();
+ } else if (attribute.equals(PATH)) {
+ value = document.getPath();
+ } else if (attribute.equals(NODE_NAME)) {
+ value = document.getName();
+ } else if (attribute.equals(UUID)) {
+ value = document.getUUID();
+ } else if (attribute.equals(WEBAPP_URL)) {
+ value = document.getCanonicalWebappURL();
+ } else if (attribute.equals(DOCUMENT_URL)) {
+ value = document.getCanonicalDocumentURL();
+ } else if (attribute.equals(EXPIRES)) {
+ try {
+ Date expires = document.getExpires();
+ value = this.dateFormat.format(expires);
+ } catch (DocumentException e) {
+ throw new ConfigurationException("Error getting expires date from document.", e);
+ }
+ } else if (attribute.equals(VISIBLE_IN_NAVIGATION)) {
+ value = Boolean.toString(isVisibleInNavigation(document));
+ } else {
+ throw new ConfigurationException("Attribute '" + attribute + "' not supported ["
+ + name + "]");
+ }
+ } catch (ConfigurationException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ConfigurationException("Error getting input module parameters.", e);
+ }
+
+ return value;
+ }
+
+ protected boolean isVisibleInNavigation(Document document) throws ConfigurationException {
+ try {
+ return document.getLink().getNode().isVisible();
+ } catch (DocumentException e) {
+ throw new ConfigurationException("Obtaining navigation visibility failed [" + document
+ + "]: " + e.getMessage(), e);
+ }
+
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public Repository getRepository() {
+ return repository;
+ }
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentURLModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentURLModule.java
new file mode 100644
index 0000000..610e170
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/DocumentURLModule.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.lenya.cms.publication.util.DocumentHelper;
+
+/**
+ * <p>
+ * This module constructs the document url taking into account difference in the language .version
+ * being created and used.
+ * </p>
+ * <p>
+ * Example:
+ * <code>{document-url:{page-envelope:area}:{page-envelope:document-uuid}:{page-envelope:document-language}}</code>
+ * </p>
+ * @version $Id$
+ */
+public class DocumentURLModule extends AbstractPageEnvelopeModule {
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttribute(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
+ */
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+
+ String url;
+
+ final String[] attributes = name.split(":");
+
+ if (attributes.length < 3) {
+ throw new ConfigurationException("Invalid number of parameters: " + attributes.length
+ + ". Expected 3 (area, document-uuid, language)");
+ }
+
+ final String area = attributes[0];
+ final String uuid = attributes[1];
+ final String language = attributes[2];
+
+ try {
+ DocumentHelper helper = new DocumentHelper(objectModel);
+ url = helper.getDocumentUrl(uuid, area, language);
+ } catch (Exception e) {
+ throw new ConfigurationException("Resolving attribute [" + name + "] failed: ", e);
+ }
+
+ return url;
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeNames(org.apache.avalon.framework.configuration.Configuration,
+ * java.util.Map)
+ */
+ public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ return Collections.EMPTY_SET.iterator();
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeValues(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
+ */
+ public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object[] objects = { getAttribute(name, modeConf, objectModel) };
+ return objects;
+ }
+
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/FallbackModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/FallbackModule.java
new file mode 100644
index 0000000..d09133f
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/FallbackModule.java
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.commons.lang.Validate;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.store.impl.MRUMemoryStore;
+import org.apache.lenya.cms.cocoon.source.FallbackSourceFactory;
+import org.apache.lenya.cms.publication.Repository;
+import org.apache.lenya.cms.publication.Session;
+import org.apache.lenya.cms.publication.URLInformation;
+import org.apache.lenya.util.ServletHelper;
+
+/**
+ * <p>
+ * This module returns the actual source URI of a fallback:// source. The protocol (fallback,
+ * template-fallback, ...) is configurable via the <em>protocol</em> parameter.
+ * </p>
+ */
+public class FallbackModule extends AbstractInputModule {
+
+ private String protocol;
+ protected MRUMemoryStore store;
+ private Repository repository;
+ private SourceResolver resolver;
+ private static Boolean useCache = null;
+
+ public void setRepository(Repository repo) {
+ this.repository = repo;
+ }
+
+ protected boolean useCache() {
+ return this.store != null;
+ }
+
+ public void setStore(MRUMemoryStore store) {
+ Validate.notNull(store);
+ this.store = store;
+ }
+
+ protected MRUMemoryStore getStore() {
+ return this.store;
+ }
+
+ protected String getPublicationId(Map objectModel) {
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ String webappUri = ServletHelper.getWebappURI(request);
+ URLInformation info = new URLInformation(webappUri);
+ String pubId = null;
+ try {
+ Session session = this.repository.getSession(request);
+ String pubIdCandidate = info.getPublicationId();
+ if (pubIdCandidate != null && session.existsPublication(pubIdCandidate)) {
+ pubId = pubIdCandidate;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return pubId;
+ }
+
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ String uri;
+ String fallbackUri = getFallbackUri(name);
+ if (useCache()) {
+ final String pubId = getPublicationId(objectModel);
+ String cacheKey = FallbackSourceFactory.getCacheKey(pubId, fallbackUri);
+ MRUMemoryStore store = getStore();
+ if (store.containsKey(cacheKey)) {
+ uri = (String) store.get(cacheKey);
+ } else {
+ uri = resolveSourceUri(name);
+ }
+ } else {
+ uri = resolveSourceUri(name);
+ }
+ return uri;
+ }
+
+ protected String resolveSourceUri(String name) throws ConfigurationException {
+ Source source = null;
+ try {
+ source = this.resolver.resolveURI(getFallbackUri(name));
+ return source.getURI();
+ } catch (Exception e) {
+ throw new ConfigurationException("Resolving fallback source [" + name + "] failed: ", e);
+ } finally {
+ if (source != null) {
+ this.resolver.release(source);
+ }
+ }
+ }
+
+ protected String getFallbackUri(String name) {
+ return this.protocol + "://" + name;
+ }
+
+ public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ return Collections.EMPTY_SET.iterator();
+ }
+
+ public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object[] objects = { getAttribute(name, modeConf, objectModel) };
+ return objects;
+ }
+
+ public void setProtocol(String protocol) {
+ Validate.notNull(protocol);
+ this.protocol = protocol;
+ }
+
+ public void setSourceResolver(SourceResolver resolver) {
+ this.resolver = resolver;
+ }
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/InputModuleParameters.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/InputModuleParameters.java
new file mode 100644
index 0000000..2ab073d
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/InputModuleParameters.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ */
+
+/* $Id:$ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.parameters.ParameterException;
+import org.apache.avalon.framework.parameters.Parameters;
+
+/**
+ * Input module parameter class.
+ * Parses input module parameters and offers accessors for the parameters.
+ * The parameters are expected to be separated by ":".
+ */
+public class InputModuleParameters {
+
+ protected final static char PARAM_SEPARATOR = ':';
+
+ protected Parameters params;
+ protected final String[] paramList;
+
+ /**
+ * Parse input module parameters.
+ * @param parameters Parameter to be parsed.
+ * @param paramList List of expected parameters.
+ * @param minParams Minimum number of parameters expected.
+ * @throws ConfigurationException if there is an error parsing the parameters.
+ */
+ public InputModuleParameters(String parameters, final String[] paramList, int minParams)
+ throws ConfigurationException
+ {
+ params = new Parameters();
+ this.paramList = (String[])paramList.clone();
+ parseParameters(parameters, minParams);
+ }
+
+ /**
+ * Parse parameters according to the parameter list passed.
+ * @param parameters
+ * @param minParams Minimum number of parameters.
+ * @return Parameters object initialized with parsed parameters.
+ * @throws ConfigurationException
+ */
+ protected Parameters parseParameters(String parameters, int minParams)
+ throws ConfigurationException
+ {
+ // Parse parameters
+ int start = 0;
+ int end = parameters.indexOf(PARAM_SEPARATOR);
+ for (int i=0; i<paramList.length; i++) {
+ if (end != -1) {
+ String paramToken = parameters.substring(start, end);
+ params.setParameter(paramList[i], paramToken);
+ start = end+1;
+ end = parameters.indexOf(PARAM_SEPARATOR, start+1);
+ } else {
+ if ((i+1) < minParams) {
+ // A mandatory parameter is missing.
+ throw new ConfigurationException("Error parsing parameters: mandatory parameter '"
+ + paramList[i] + "' not found [" + parameters + "]");
+ } else if (i == 0) {
+ // Zero or one parameter passed.
+ if (parameters.length() != 0) {
+ params.setParameter(paramList[i], parameters);
+ }
+ break;
+ } else {
+ // All parameters parsed except the last one.
+ String paramToken = parameters.substring(start);
+ if (paramToken.length() != 0) {
+ params.setParameter(paramList[i], paramToken);
+ }
+ break;
+ }
+ }
+ }
+ return params;
+ }
+
+ /**
+ * Get a parameter.
+ * @param param Name of requested parameter.
+ * @return Requested parameter.
+ * @throws ParameterException if the specified parameter cannot be found
+ */
+ public String getParameter(String param) throws ParameterException
+ {
+ return params.getParameter(param);
+ }
+
+ /**
+ * Does a parameter with given name exists?
+ * @param param Parameter name.
+ * @return True if parameters exists, otherwise false.
+ */
+ public boolean isParameter(String param) {
+ return params.isParameter(param);
+ }
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/OperationModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/OperationModule.java
new file mode 100644
index 0000000..b90d45a
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/OperationModule.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.cocoon.processing.ProcessInfoProvider;
+import org.apache.cocoon.spring.configurator.WebAppContextUtils;
+import org.apache.lenya.cms.publication.Repository;
+import org.apache.lenya.cms.publication.Session;
+
+/**
+ * Super class for operation-based input modules.
+ *
+ * @version $Id$
+ */
+public class OperationModule extends AbstractInputModule {
+
+ private Repository repository;
+ private org.apache.lenya.cms.publication.Session session;
+
+ protected Session getSession() {
+ if (this.session == null) {
+ ProcessInfoProvider processInfo = (ProcessInfoProvider) WebAppContextUtils
+ .getCurrentWebApplicationContext().getBean(ProcessInfoProvider.ROLE);
+ HttpServletRequest request = processInfo.getRequest();
+ this.session = this.getRepository().getSession(request);
+ }
+ return this.session;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+ public Repository getRepository() {
+ return repository;
+ }
+
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/PageEnvelopeModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/PageEnvelopeModule.java
new file mode 100644
index 0000000..407a1b6
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/PageEnvelopeModule.java
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ *
+ */
+
+/* $Id$ */
+
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.net.MalformedURLException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.DocumentLocator;
+import org.apache.lenya.cms.publication.PageEnvelope;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.publication.ResourceType;
+import org.apache.lenya.cms.site.SiteException;
+import org.apache.lenya.utils.URLInformation;
+
+/**
+ * Input module wrapping the page envelope. This module provides publication
+ * related information such as document-uuid, area, publication-id.
+ *
+ * @see org.apache.lenya.cms.publication.PageEnvelope
+ * @deprecated use DocumentInfoModule instead.
+ */
+public class PageEnvelopeModule extends AbstractPageEnvelopeModule {
+
+ protected static final String URI_PARAMETER_DOCTYPE = "doctype";
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttribute(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration,
+ * java.util.Map)
+ */
+ public Object getAttribute(final String attributeName, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+
+ final String name = getAttributeName(attributeName);
+
+ if (!Arrays.asList(PageEnvelope.PARAMETER_NAMES).contains(name)) {
+ throw new ConfigurationException("The attribute [" + name + "] is not supported!");
+ }
+
+ PageEnvelope envelope = getEnvelope(objectModel, attributeName);
+ Object value = null;
+
+ try {
+ if (name.equals(PageEnvelope.AREA)) {
+ value = envelope.getArea();
+ } else if (name.equals(PageEnvelope.CONTEXT)) {
+ value = envelope.getContext();
+ } else if (name.equals(PageEnvelope.IS_PUBLICATION)) {
+ value = Boolean.toString(envelope.getPublication() != null);
+ } else if (name.equals(PageEnvelope.PUBLICATION_ID)) {
+ Publication pub = envelope.getPublication();
+ value = pub != null ? pub.getId() : "";
+ } else if (name.equals(PageEnvelope.PUBLICATION)) {
+ value = envelope.getPublication();
+ } else if (name.equals(PageEnvelope.PUBLICATION_LANGUAGES_CSV)) {
+ value = StringUtils.join(envelope.getPublication().getLanguages(), ',');
+ } else if (name.equals(PageEnvelope.DEFAULT_LANGUAGE)) {
+ value = envelope.getPublication().getDefaultLanguage();
+ } else if (name.equals(PageEnvelope.LANGUAGE)) {
+ value = envelope.getLanguage();
+ } else if (name.equals(PageEnvelope.BREADCRUMB_PREFIX)) {
+ value = envelope.getPublication().getBreadcrumbPrefix();
+ } else if (name.equals(PageEnvelope.DOCUMENT_PATH)) {
+ value = getPath(envelope, objectModel);
+ } else {
+ Document document = envelope.getDocument();
+ if (document != null) {
+ if (name.equals(PageEnvelope.DOCUMENT)) {
+ value = document;
+ } else if (name.equals(PageEnvelope.DOCUMENT_ID)) {
+ getLogger().warn(
+ "This attribute [ " + name + " ] is deprecated."
+ + " Use document-path or document-uuid instead!");
+ value = document.getUUID();
+ } else if (name.equals(PageEnvelope.DOCUMENT_PARENT)) {
+ value = document.getLocator().getParent().getPath();
+ } else if (name.equals(PageEnvelope.DOCUMENT_NAME)) {
+ value = document.getName();
+ } else if (name.equals(PageEnvelope.DOCUMENT_LABEL)) {
+ value = document.getLink().getLabel();
+ } else if (name.equals(PageEnvelope.DOCUMENT_URL)) {
+ value = document.getCanonicalDocumentURL();
+ } else if (name.equals(PageEnvelope.DOCUMENT_URL_WITHOUT_LANGUAGE)) {
+ value = document.getCanonicalWebappURL();
+ } else if (name.equals(PageEnvelope.DOCUMENT_EXTENSION)) {
+ value = document.getExtension();
+ } else if (name.equals(PageEnvelope.DOCUMENT_SOURCE_EXTENSION)) {
+ value = document.getSourceExtension();
+ } else if (name.equals(PageEnvelope.DOCUMENT_UUID)) {
+ value = document.getUUID();
+ } else if (name.equals(PageEnvelope.DOCUMENT_LANGUAGE)) {
+ value = document.getLanguage();
+ } else if (name.equals(PageEnvelope.DOCUMENT_LANGUAGES)) {
+ value = document.getLanguages();
+ } else if (name.equals(PageEnvelope.DOCUMENT_LANGUAGES_CSV)) {
+ value = StringUtils.join(document.getLanguages(), ',');
+ } else if (name.equals(PageEnvelope.DOCUMENT_LASTMODIFIED)) {
+ Date date = new Date(document.getLastModified());
+ value = new SimpleDateFormat(DATE_FORMAT).format(date);
+ } else if (name.equals(PageEnvelope.DOCUMENT_MIME_TYPE)) {
+ value = document.getMimeType();
+ } else if (name.equals(PageEnvelope.DOCUMENT_TYPE)) {
+ ResourceType resourceType = document.getResourceType();
+ if (resourceType == null) {
+ value = null;
+ } else {
+ value = resourceType.getName();
+ }
+ }
+ }
+ }
+ } catch (final Exception e) {
+ throw new ConfigurationException("Getting attribute for name [" + name + "] failed: ",
+ e);
+ }
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Returning [" + name + "] = [" + value + "]");
+ }
+
+ return value;
+ }
+
+ protected String getPath(PageEnvelope envelope, Map objectModel) throws SiteException {
+ String path;
+ Document doc = envelope.getDocument();
+ if (doc == null) {
+ Publication pub = envelope.getPublication();
+ URLInformation info = new URLInformation();
+ String url = info.getWebappUrl();
+ DocumentLocator loc;
+ try {
+ loc = pub.getDocumentBuilder().getLocator(pub.getSession(), url);
+ } catch (MalformedURLException e) {
+ throw new SiteException(e);
+ }
+ path = loc.getPath();
+ } else {
+ path = doc.getLocator().getPath();
+ }
+ return path;
+ }
+
+ /**
+ * <code>DATE_FORMAT</code> The date format
+ */
+ public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeNames(org.apache.avalon.framework.configuration.Configuration,
+ * java.util.Map)
+ */
+ public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ return Arrays.asList(PageEnvelope.PARAMETER_NAMES).iterator();
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeValues(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration,
+ * java.util.Map)
+ */
+ public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object[] objects = { getAttribute(name, modeConf, objectModel) };
+
+ return objects;
+ }
+
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceExistsModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceExistsModule.java
new file mode 100644
index 0000000..c40ab46
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceExistsModule.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.excalibur.source.SourceResolver;
+
+/**
+ * Checks if a certain resource exists and returns either the string "true" or "false".
+ * @version $Id$
+ */
+public class ResourceExistsModule extends AbstractInputModule implements Serviceable, Disposable {
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttribute(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
+ */
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+
+ String resourceURI = name;
+
+ Source source = null;
+ boolean exists = false;
+ try {
+ source = this.resolver.resolveURI(resourceURI);
+ exists = source.exists();
+ } catch (SourceNotFoundException e) {
+ exists = false;
+ } catch (Exception e) {
+ getLogger().warn("Exception resolving resource [" + resourceURI + "]", e);
+ exists = false;
+ } finally {
+ if (source != null) {
+ this.resolver.release(source);
+ }
+ }
+
+ return Boolean.toString(exists);
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeNames(org.apache.avalon.framework.configuration.Configuration,
+ * java.util.Map)
+ */
+ public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ return Collections.EMPTY_SET.iterator();
+ }
+
+ private ServiceManager manager;
+ private SourceResolver resolver;
+
+ /**
+ * @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);
+ }
+
+ /**
+ * @see org.apache.avalon.framework.activity.Disposable#dispose()
+ */
+ public void dispose() {
+ super.dispose();
+ this.manager.release(this.resolver);
+ this.resolver = null;
+ this.manager = null;
+ }
+
+ /**
+ * @see org.apache.cocoon.components.modules.input.InputModule#getAttributeValues(java.lang.String,
+ * org.apache.avalon.framework.configuration.Configuration, java.util.Map)
+ */
+ public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object result = this.getAttribute(name, modeConf, objectModel);
+ return (result == null ? null : new Object[] { result });
+ }
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceTypeModule.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceTypeModule.java
new file mode 100644
index 0000000..c80abdf
--- /dev/null
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/cocoon/components/modules/input/ResourceTypeModule.java
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.cocoon.components.modules.input;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.commons.lang.StringUtils;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.Publication;
+import org.apache.lenya.cms.publication.Repository;
+import org.apache.lenya.cms.publication.ResourceType;
+import org.apache.lenya.cms.publication.ResourceTypeResolver;
+import org.apache.lenya.cms.publication.Session;
+import org.apache.lenya.util.ServletHelper;
+
+/**
+ * <p>
+ * Resource type module.
+ * </p>
+ * <p>
+ * The syntax is either <code>{resource-type:<attribute>}</code> (which uses the resource type
+ * of the currenlty requested document) or
+ * <code>{resource-type:<name>:<attribute>}</code> (which allows to access an arbitrary
+ * resource type).
+ * </p>
+ * <p>
+ * Attributes:
+ * </p>
+ * <ul>
+ * <li><strong><code>expires</code></strong> - the expiration date in RFC 822/1123 format, see
+ * {@link org.apache.lenya.cms.publication.ResourceType#getExpires()}</li>
+ * <li><strong><code>schemaUri</code></strong> - see {@link org.apache.lenya.xml.Schema#getURI()}</li>
+ * <li><strong><code>httpSchemaUri</code></strong> - the URI to request the schema over HTTP,
+ * without Proxy and context (use {proxy:} around it).</li>
+ * <li><strong><code>supportsFormat:{format}</code></strong> - true if the resource type supports
+ * this format, false otherwise</li>
+ * </ul>
+ */
+public class ResourceTypeModule extends AbstractInputModule {
+
+ protected static final String SCHEMA_URI = "schemaUri";
+ protected static final String HTTP_SCHEMA_URI = "httpSchemaUri";
+ protected static final String EXPIRES = "expires";
+ protected static final String SUPPORTS_FORMAT = "supportsFormat";
+
+ private Repository repository;
+ private ResourceTypeResolver resourceTypeResolver;
+
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+ Object value = null;
+
+ try {
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ Session session = this.repository.getSession(request);
+
+ ResourceType resourceType;
+ Publication pub = null;
+ String attribute;
+
+ String[] steps = name.split(":");
+ if (steps.length == 1) {
+ String webappUrl = ServletHelper.getWebappURI(request);
+ Document document = session.getUriHandler().getDocument(webappUrl);
+ pub = document.getPublication();
+
+ attribute = name;
+ resourceType = document.getResourceType();
+ } else {
+ attribute = steps[1];
+ String resourceTypeName = steps[0];
+ resourceType = getResourceTypeResolver().getResourceType(resourceTypeName);
+ }
+
+ if (attribute.startsWith("format-")) {
+ String[] formatSteps = name.split("-");
+ String format = formatSteps[1];
+ value = resourceType.getFormatURI(format);
+ } else if (attribute.equals(SCHEMA_URI)) {
+ value = resourceType.getSchema().getURI();
+ } else if (attribute.equals(HTTP_SCHEMA_URI)) {
+ String uri = resourceType.getSchema().getURI();
+ value = transformFallbackUriToHttp(pub.getId(), uri);
+ } else if (attribute.equals(EXPIRES)) {
+ Date expires = resourceType.getExpires();
+ SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss zzz");
+ value = sdf.format(expires);
+ } else if (attribute.equals(SUPPORTS_FORMAT)) {
+ String format = steps[steps.length - 1];
+ String[] formats = resourceType.getFormats();
+ return Boolean.toString(Arrays.asList(formats).contains(format));
+ } else {
+ throw new ConfigurationException("Attribute [" + name + "] not supported!");
+ }
+
+ } catch (Exception e) {
+ throw new ConfigurationException("Resolving attribute [" + name + "] failed: ", e);
+ }
+
+ return value;
+ }
+
+ /**
+ * Transforms a fallback URI for resources into a HTTP URL.
+ *
+ * Currently only supports module urls:
+ *
+ * fallback://lenya/modules/foo/resources/schemas/bar.rng ->
+ * prefix/pubid/modules/foo/schemas/bar.rng
+ *
+ * FIXME: allow other kind of fallback URIs
+ *
+ * @param pubid publication id of the current document
+ * @param prefix prefix which will be prepended to the resulting URL
+ * @param uri fallback uri, must start with fallback://
+ * @return A string.
+ * @throws ConfigurationException
+ */
+ protected String transformFallbackUriToHttp(String pubid, String uri)
+ throws ConfigurationException {
+ if (uri.startsWith("fallback://lenya/modules/")) {
+ String path = StringUtils.substringAfter(uri, "fallback://lenya/modules/");
+ String module = StringUtils.substringBefore(path, "/");
+ path = StringUtils.substringAfter(path, module + "/resources");
+ return "/" + pubid + "/modules/" + module + path;
+ } else {
+ throw new ConfigurationException("Don't know how to create HTTP URL from : " + uri);
+ }
+ }
+
+ public void setResourceTypeResolver(ResourceTypeResolver resourceTypeResolver) {
+ this.resourceTypeResolver = resourceTypeResolver;
+ }
+
+ public ResourceTypeResolver getResourceTypeResolver() {
+ return resourceTypeResolver;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
diff --git a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/publication/SessionImpl.java b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/publication/SessionImpl.java
index bae3284..f7deacd 100644
--- a/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/publication/SessionImpl.java
+++ b/org.apache.lenya.core.impl/src/main/java/org/apache/lenya/cms/publication/SessionImpl.java
@@ -26,6 +26,9 @@
import org.apache.lenya.cms.repository.SessionHolder;
import org.apache.lenya.transaction.UnitOfWork;
+/**
+ * @deprecated solve the concurrency beetween lenya-core-repository/o.a.l.cms.repository.SessionImpl and lenya-core-impl/o.a.l.cms.publication.SEssionImpl
+ */
public class SessionImpl implements Session, SessionHolder {
private static final Log logger = LogFactory.getLog(SessionImpl.class);
@@ -79,16 +82,14 @@
return ((IdentityWrapper) getRepositorySession().getIdentity()).getIdentity();
}
- private UnitOfWork unitOfWork;
-
/**
* @return The unit of work.
*/
protected UnitOfWork getUnitOfWork() {
- if (this.unitOfWork == null) {
- throw new RuntimeException("This session [" + getId() + "] is not modifiable!");
- }
- return this.unitOfWork;
+ if (repositorySession == null){
+ throw new RuntimeException("This session [" + getId() + "] is not modifiable!");
+ }
+ return repositorySession;
}
public String getId() {