blob: c722308208aa2f2e24a80d3582e0225ef582ee04 [file] [log] [blame]
/*
* 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.site.usecases;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.lenya.ac.Identity;
import org.apache.lenya.ac.User;
import org.apache.lenya.cms.metadata.MetaData;
import org.apache.lenya.cms.metadata.MetaDataException;
import org.apache.lenya.cms.metadata.dublincore.DublinCore;
import org.apache.lenya.cms.publication.Document;
import org.apache.lenya.cms.publication.DocumentManager;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.publication.PublicationException;
import org.apache.lenya.cms.publication.PublicationUtil;
import org.apache.lenya.cms.publication.ResourceType;
import org.apache.lenya.cms.publication.URLInformation;
import org.apache.lenya.cms.repository.Node;
import org.apache.lenya.cms.site.SiteStructure;
import org.apache.lenya.cms.usecase.AbstractUsecase;
import org.apache.lenya.cms.usecase.UsecaseException;
/**
* <p>
* Abstract superclass for usecases to create a document.
* </p>
* <p>
* You can pass the following parameters into the usecase:
* </p>
* <ul>
* <li><strong>path</strong> - the path of the document to create (optional)</li>
* </ul>
*
* @version $Id$
*/
public abstract class Create extends AbstractUsecase {
protected static final String RESOURCE_TYPES = "resourceTypes";
protected static final String LANGUAGE = "language";
protected static final String LANGUAGES = "languages";
protected static final String PATH = "path";
protected static final String NODE_NAME = "nodeName";
protected static final String VISIBLEINNAV = "visibleInNav";
protected static final String SAMPLE = "sample";
protected static final String SAMPLES = "samples";
/**
* Ctor.
*/
public Create() {
super();
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#doCheckPreconditions()
*/
protected void doCheckPreconditions() throws Exception {
super.doCheckPreconditions();
if (!getArea().equals(Publication.AUTHORING_AREA)) {
addErrorMessage("This usecase can only be invoked in the authoring area!");
}
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#getNodesToLock()
*/
protected Node[] getNodesToLock() throws UsecaseException {
try {
SiteStructure structure = getPublication().getArea(getArea()).getSite();
Node[] nodes = { structure.getRepositoryNode() };
return nodes;
} catch (Exception e) {
throw new UsecaseException(e);
}
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#doCheckExecutionConditions()
*/
protected void doCheckExecutionConditions() throws Exception {
String navigationTitle = getDublinCoreParameter(DublinCore.ELEMENT_TITLE);
if (navigationTitle.trim().equals("")) {
addErrorMessage("missing-navigation-title");
}
if (getInitialDocument() == null) {
String[] samples = (String[]) getParameter(SAMPLES);
String sample = getParameterAsString(SAMPLE);
if (samples != null && samples.length > 1 && (sample == null || sample.equals(""))) {
addErrorMessage("missing-page-layout");
}
}
if (isPathValid()) {
String path = getNewDocumentPath();
SiteStructure site = getPublication().getArea(getArea()).getSite();
if (!createVersion() && site.contains(path)) {
String[] params = { path };
addErrorMessage("path-already-exists", params);
}
}
String doctypeName = getDocumentTypeName();
if (getParameterAsString(SAMPLE) == null && doctypeName != null) {
initSampleParameters();
}
}
/**
* This method is used by {@link #doCheckExecutionConditions()} to check if
* the path entered by the user is valid. If not, checking the existence of
* the new document in the site structure is omitted because this operation
* could cause errors.
* @return A boolean value.
*/
protected boolean isPathValid() {
return true;
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#doExecute()
*/
protected void doExecute() throws Exception {
super.doExecute();
// create new document
DocumentManager documentManager = null;
ServiceSelector selector = null;
ResourceType resourceType = null;
try {
documentManager = (DocumentManager) this.manager.lookup(DocumentManager.ROLE);
String language = getParameterAsString(LANGUAGE);
Document initialDocument = getInitialDocument();
Document document;
String title = getDublinCoreParameter(DublinCore.ELEMENT_TITLE).trim();
if (createVersion()) {
document = documentManager.addVersion(initialDocument, getArea(), language, true);
document.getLink().setLabel(title);
} else {
if (initialDocument == null) {
selector = (ServiceSelector) this.manager
.lookup(ResourceType.ROLE + "Selector");
resourceType = (ResourceType) selector.select(getDocumentTypeName());
String sampleName = getParameterAsString(SAMPLE, resourceType.getSampleNames()[0]);
ResourceType.Sample sample = resourceType.getSample(sampleName);
document = documentManager.add(getDocumentFactory(), resourceType, sample.getUri(),
getPublication(), getArea(), getNewDocumentPath(), language,
getSourceExtension(), title, getVisibleInNav());
document.setMimeType(sample.getMimeType());
} else {
document = documentManager.add(initialDocument, getArea(),
getNewDocumentPath(), language, getSourceExtension(), title,
getVisibleInNav());
}
}
setMetaData(document);
// the location to navigate to after completion of usecase
setDefaultTargetURL(document.getCanonicalWebappURL());
} finally {
if (documentManager != null) {
this.manager.release(documentManager);
}
if (selector != null) {
if (resourceType != null) {
selector.release(resourceType);
}
this.manager.release(selector);
}
}
}
protected String getDublinCoreParameter(String name) {
Object param = getParameter(DUBLIN_CORE_PREFIX + name);
if (param != null && getParameter(DUBLIN_CORE_PREFIX + name).getClass().isArray()) {
String[] values = (String[]) getParameter(DUBLIN_CORE_PREFIX + name);
StringBuffer paramValue = new StringBuffer();
for (int i = 0; i < values.length; i++) {
String value = values[i];
if (i > 0)
paramValue.append(',').append(value);
else
paramValue.append(value);
}
return paramValue.toString();
}
return getParameterAsString(DUBLIN_CORE_PREFIX + name, null);
}
protected void setDublinCoreParameter(String name, String value) {
setParameter(DUBLIN_CORE_PREFIX + name, value);
}
protected abstract boolean createVersion();
/**
* @return the extension to use for the document source.
*/
protected abstract String getSourceExtension();
/**
* @return the name of the document being created in the usecase
*/
protected abstract String getNewDocumentName();
/**
* @return the id of the new document being created in the usecase
*/
protected abstract String getNewDocumentPath();
/**
* If the document created in the usecase shall have initial contents copied
* from an existing document, construct that document in this method.
*
* @return A document.
*/
protected Document getInitialDocument() {
return null;
}
/**
* @return The type of the created document.
*/
protected abstract String getDocumentTypeName();
protected static final String DUBLIN_CORE_PREFIX = "dublincore.";
/**
* Sets the meta data of the created document.
*
* @param document The document.
* @throws MetaDataException if an error occurs.
*/
protected void setMetaData(Document document) throws MetaDataException {
if (document == null)
throw new IllegalArgumentException("parameter document may not be null");
MetaData dcMetaData = document.getMetaData(DublinCore.DC_NAMESPACE);
String[] dcKeys = dcMetaData.getAvailableKeys();
for (int i = 0; i < dcKeys.length; i++) {
String param = getDublinCoreParameter(dcKeys[i]);
if (param != null) {
dcMetaData.setValue(dcKeys[i], param);
}
}
}
/**
* @see org.apache.lenya.cms.usecase.AbstractUsecase#initParameters()
*/
protected void initParameters() {
super.initParameters();
Map objectModel = ContextHelper.getObjectModel(getContext());
Request request = ObjectModelHelper.getRequest(objectModel);
Session session = request.getSession(false);
Identity identity = (Identity) session.getAttribute(Identity.class.getName());
User user = identity.getUser();
if (user != null) {
setDublinCoreParameter(DublinCore.ELEMENT_CREATOR, user.getId());
} else {
setDublinCoreParameter(DublinCore.ELEMENT_CREATOR, "");
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
setDublinCoreParameter(DublinCore.ELEMENT_DATE, format.format(new GregorianCalendar()
.getTime()));
String doctypeName = getDocumentTypeName();
if (doctypeName != null) {
initSampleParameters();
setParameter(RESOURCE_TYPES, Collections.EMPTY_LIST);
} else {
String[] resourceTypes = getPublication().getResourceTypeNames();
setParameter(RESOURCE_TYPES, Arrays.asList(resourceTypes));
}
}
protected void initSampleParameters() {
ServiceSelector selector = null;
ResourceType resourceType = null;
try {
selector = (ServiceSelector) this.manager.lookup(ResourceType.ROLE + "Selector");
resourceType = (ResourceType) selector.select(getDocumentTypeName());
String[] samples = resourceType.getSampleNames();
if (samples.length == 0) {
addErrorMessage("The resource type [" + resourceType.getName()
+ "] doesn't provide any samples!");
} else {
setParameter(SAMPLES, samples);
String presetSample = getParameterAsString(SAMPLE);
if (presetSample == null) {
setParameter(SAMPLE, samples[0]);
} else {
List sampleList = Arrays.asList(samples);
if (!sampleList.contains(presetSample)) {
getLogger().warn(
"Sample [" + presetSample + "] not defined, using default sample.");
setParameter(SAMPLE, samples[0]);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (selector != null) {
if (resourceType != null) {
selector.release(resourceType);
}
this.manager.release(selector);
}
}
}
/**
* @return The source document or <code>null</code> if the usecase was not
* invoked on a document.
*/
protected Document getSourceDocument() {
Document document = null;
String url = getSourceURL();
try {
if (getDocumentFactory().isDocument(url)) {
document = getDocumentFactory().getFromURL(url);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return document;
}
/**
* @return The new document.
*/
protected Document getNewDocument() {
try {
String path = getNewDocumentPath();
String language = getParameterAsString(LANGUAGE);
return getPublication().getArea(getArea()).getSite().getNode(path).getLink(language)
.getDocument();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @return The area without the "info-" prefix.
*/
public String getArea() {
URLInformation info = new URLInformation(getSourceURL());
return info.getArea();
}
/**
* Access to the current publication. Use this when the publication is not
* yet known in the usecase: e.g. when creating a global asset. When adding
* a resource or a child to a document, access the publication via that
* document's interface instead.
*
* @return the publication in which the use-case is being executed
*/
protected Publication getPublication() {
try {
return PublicationUtil.getPublicationFromUrl(this.manager, getDocumentFactory(),
getSourceURL());
} catch (PublicationException e) {
throw new RuntimeException(e);
}
}
/**
* @return the visibleInNav Attribute of the document being created in the
* usecase
*/
protected boolean getVisibleInNav() {
if (getParameterAsString(VISIBLEINNAV).equals("false")) {
return false;
}
return true;
}
}