blob: e6505088bdcaa9d43532ba146145595062f07dc4 [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.sling.servlets.post.impl.operations;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.servlets.post.Modification;
import org.apache.sling.servlets.post.PostResponse;
import org.apache.sling.servlets.post.SlingPostConstants;
import org.apache.sling.servlets.post.VersioningConfiguration;
/**
* The <code>AbstractCopyMoveOperation</code> is the abstract base close for
* the {@link CopyOperation} and {@link MoveOperation} classes implementing
* common behavior.
*/
abstract class AbstractCopyMoveOperation extends AbstractPostOperation {
@Override
protected final void doRun(final SlingHttpServletRequest request,
final PostResponse response,
final List<Modification> changes)
throws PersistenceException {
final VersioningConfiguration versioningConfiguration = getVersioningConfiguration(request);
final Resource resource = request.getResource();
final String source = resource.getPath();
// ensure dest is not empty/null and is absolute
String dest = request.getParameter(SlingPostConstants.RP_DEST);
if (dest == null || dest.length() == 0) {
throw new IllegalArgumentException("Unable to process "
+ getOperationName() + ". Missing destination");
}
// register whether the path ends with a trailing slash
final boolean trailingSlash = dest.endsWith("/");
// ensure destination is an absolute and normalized path
if (!dest.startsWith("/")) {
dest = ResourceUtil.getParent(source) + "/" + dest;
}
dest = ResourceUtil.normalize(dest);
// destination parent and name
final String dstParent = trailingSlash ? dest : ResourceUtil.getParent(dest);
// delete destination if already exists
if (!trailingSlash && request.getResourceResolver().getResource(dest) != null ) {
final String replaceString = request.getParameter(SlingPostConstants.RP_REPLACE);
final boolean isReplace = "true".equalsIgnoreCase(replaceString);
if (!isReplace) {
response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED,
"Cannot " + getOperationName() + " " + resource + " to "
+ dest + ": destination exists");
return;
} else {
this.jcrSsupport.checkoutIfNecessary(request.getResourceResolver().getResource(dstParent),
changes, versioningConfiguration);
}
} else {
// check if path to destination exists and create it, but only
// if it's a descendant of the current node
if (!dstParent.equals("")) {
final Resource parentResource = request.getResourceResolver().getResource(dstParent);
if (parentResource != null ) {
this.jcrSsupport.checkoutIfNecessary(parentResource, changes, versioningConfiguration);
} else {
response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED,
"Cannot " + getOperationName() + " " + resource + " to "
+ dest + ": parent of destination does not exist");
return;
}
}
// the destination is newly created, hence a create request
response.setCreateRequest(true);
}
final Iterator<Resource> resources = getApplyToResources(request);
final Resource destResource;
if (resources == null) {
final String dstName = trailingSlash ? null : ResourceUtil.getName(dest);
destResource = execute(changes, resource, dstParent, dstName, versioningConfiguration);
} else {
// multiple applyTo requires trailing slash on destination
if (!trailingSlash) {
throw new IllegalArgumentException(
"Applying "
+ getOperationName()
+ " to multiple resources requires a trailing slash on the destination");
}
// multiple copy will never return 201/CREATED
response.setCreateRequest(false);
while (resources.hasNext()) {
final Resource applyTo = resources.next();
execute(changes, applyTo, dstParent, null, versioningConfiguration);
}
destResource = request.getResourceResolver().getResource(dest);
}
if ( destResource == null ) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND,
"Missing source " + resource + " for " + getOperationName());
return;
}
// finally apply the ordering parameter
this.jcrSsupport.orderNode(request, destResource, changes);
}
/**
* Returns a short name to be used in log and status messages.
* @return the name of the operation
*/
protected abstract String getOperationName();
/**
* Actually executes the operation.
*
* @param changes the changes to execute
* @param source The source item to act upon.
* @param destParent The absolute path of the parent of the target item.
* @param destName The name of the target item inside the
* <code>destParent</code>. If <code>null</code> the name of
* the <code>source</code> is used as the target item name.
* @param versioningConfiguration the configuration for versioning
* @return the resource which results of this operation
* @throws PersistenceException May be thrown if an error occurs executing
* the operation.
*/
protected abstract Resource execute(List<Modification> changes,
Resource source,
String destParent,
String destName,
VersioningConfiguration versioningConfiguration)
throws PersistenceException;
}