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() {