
org.modeshape.web.jcr.rest.handler.RestBinaryHandler Maven / Gradle / Ivy
/*
* ModeShape (http://www.modeshape.org)
*
* Licensed 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.modeshape.web.jcr.rest.handler;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.modeshape.common.util.CheckArg;
import org.modeshape.common.util.StringUtil;
import org.modeshape.jcr.api.JcrConstants;
import org.modeshape.web.jcr.rest.model.RestItem;
import org.modeshape.web.jcr.rest.model.RestProperty;
/**
* Class which handles incoming requests related to {@link Binary binary values}
*
* @author Horia Chiorean
*/
public final class RestBinaryHandler extends AbstractHandler {
/**
* The default content disposition prefix, used when serving binary content.
*/
public static final String DEFAULT_CONTENT_DISPOSITION_PREFIX = "attachment;filename=";
private static final String DEFAULT_MIME_TYPE = MediaType.APPLICATION_OCTET_STREAM;
/**
* Returns a binary {@link Property} for the given repository, workspace and path.
*
* @param request a non-null {@link HttpServletRequest} request
* @param repositoryName a non-null {@link String} representing the name of a repository.
* @param workspaceName a non-null {@link String} representing the name of a workspace.
* @param binaryAbsPath a non-null {@link String} representing the absolute path to a binary property.
* @return the {@link Property} instance which is located at the given path. If such a property is not located, an exception
* is thrown.
* @throws RepositoryException if any JCR related operation fails, including the case when the path to the property isn't valid.
*/
public Property getBinaryProperty( HttpServletRequest request,
String repositoryName,
String workspaceName,
String binaryAbsPath ) throws RepositoryException {
Session session = getSession(request, repositoryName, workspaceName);
return session.getProperty(binaryAbsPath);
}
/**
* Returns a default Content-Disposition {@link String} for a given binary property.
*
* @param binaryProperty a non-null {@link Property}
* @return a non-null String which represents a valid Content-Disposition.
* @throws RepositoryException if any JCR related operation involving the binary property fail.
*/
public String getDefaultContentDisposition( Property binaryProperty ) throws RepositoryException {
Node parentNode = getParentNode(binaryProperty);
String parentName = parentNode.getName();
if (StringUtil.isBlank(parentName)) {
parentName = "binary";
}
return DEFAULT_CONTENT_DISPOSITION_PREFIX + parentName;
}
/**
* Returns the default mime-type of a given binary property.
*
* @param binaryProperty a non-null {@link Property}
* @return a non-null String which represents the mime-type of the binary property.
* @throws RepositoryException if any JCR related operation involving the binary property fail.
*/
public String getDefaultMimeType( Property binaryProperty ) throws RepositoryException {
try {
Binary binary = binaryProperty.getBinary();
return binary instanceof org.modeshape.jcr.api.Binary ? ((org.modeshape.jcr.api.Binary)binary)
.getMimeType() : DEFAULT_MIME_TYPE;
} catch (IOException e) {
logger.warn("Cannot determine default mime-type", e);
return DEFAULT_MIME_TYPE;
}
}
/**
* Updates the {@link Property property} at the given path with the content from the given {@link InputStream}.
*
* @param request a non-null {@link HttpServletRequest} request
* @param repositoryName a non-null {@link String} representing the name of a repository.
* @param workspaceName a non-null {@link String} representing the name of a workspace.
* @param binaryPropertyAbsPath a non-null {@link String} representing the absolute path to a binary property.
* @param binaryStream an {@link InputStream} which represents the new content of the binary property.
* @param allowCreation a boolean flag which indicates what the behavior should be in case such a property does
* not exist on its parent node: if the flag is {@code true}, the property will be created, otherwise a response code indicating
* the absence is returned.
* @return a {@link Response} object, which is either OK and contains the rest representation of the binary property, or is
* NOT_FOUND.
* @throws RepositoryException if any JCR related operations fail
* @throws IllegalArgumentException if the given input stream is {@code null}
*/
public Response updateBinary( HttpServletRequest request,
String repositoryName,
String workspaceName,
String binaryPropertyAbsPath,
InputStream binaryStream,
boolean allowCreation ) throws RepositoryException {
CheckArg.isNotNull(binaryStream, "request body");
String parentPath = parentPath(binaryPropertyAbsPath);
Session session = getSession(request, repositoryName, workspaceName);
Node parent = (Node)itemAtPath(parentPath, session);
int lastSlashInd = binaryPropertyAbsPath.lastIndexOf('/');
String propertyName = lastSlashInd == -1 ? binaryPropertyAbsPath : binaryPropertyAbsPath.substring(lastSlashInd + 1);
boolean createdNewValue = false;
try {
Property binaryProperty = null;
try {
binaryProperty = parent.getProperty(propertyName);
//edit an existing property
Binary binary = session.getValueFactory().createBinary(binaryStream);
binaryProperty.setValue(binary);
} catch (PathNotFoundException e) {
if (!allowCreation) {
return Response.status(Response.Status.NOT_FOUND).build();
}
// create a new binary property
Binary binary = session.getValueFactory().createBinary(binaryStream);
binaryProperty = parent.setProperty(propertyName, binary);
createdNewValue = true;
}
session.save();
RestProperty restItem = (RestProperty)createRestItem(request, 0, session, binaryProperty);
return createdNewValue ? Response.status(Response.Status.CREATED).entity(restItem).build() :
Response.ok().entity(restItem).build();
} finally {
try {
binaryStream.close();
} catch (IOException e) {
logger.error("Cannot close binary stream", e);
}
}
}
/**
* Uploads a binary value at the given path, creating each missing path segment as an [nt:folder]. The binary is uploaded
* as an [nt:resource] node of a [nt:file] node, both of which are created.
* @param request a {@link HttpServletRequest}, never {@code null}
* @param repositoryName a {@link String}, the repository name; never {@code null}
* @param workspaceName a {@link String}, the workspace name; never {@code null}
* @param filePath a {@link String}, file absolute path to the [nt:file] node; never {@code null}
* @param binaryStream an {@link java.io.InputStream} from which the binary content will be read.
* @return a {@link javax.ws.rs.core.Response} object, never {@code null}
* @throws RepositoryException if anything unexpected fails.
*/
public Response uploadBinary( HttpServletRequest request,
String repositoryName,
String workspaceName,
String filePath,
InputStream binaryStream) throws RepositoryException {
CheckArg.isNotNull(binaryStream, "request body");
String[] segments = filePath.split("\\/");
List parsedSegments = new ArrayList<>();
for (String segment : segments) {
if (!StringUtil.isBlank(segment)) {
parsedSegments.add(segment);
}
}
if (parsedSegments.isEmpty()) {
return exceptionResponse("The path '" + filePath + "' should contain at least one segment");
}
Session session = getSession(request, repositoryName, workspaceName);
Node fileNode;
try {
fileNode = session.getNode(filePath);
} catch (PathNotFoundException e) {
fileNode = null;
}
try {
Node content;
Response.Status responseStatus;
if (fileNode == null) {
String filename = parsedSegments.get(parsedSegments.size() - 1);
String parentPath = "/";
Node parent = session.getNode(parentPath);
for (int i = 0; i < parsedSegments.size() - 1; i++) {
String childName = parsedSegments.get(i);
try {
parent = parent.getNode(childName);
} catch (PathNotFoundException e) {
parent = parent.addNode(childName, JcrConstants.NT_FOLDER);
}
}
fileNode = parent.addNode(filename, JcrConstants.NT_FILE);
content = fileNode.addNode(JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE);
responseStatus = Response.Status.CREATED;
} else {
if (!JcrConstants.NT_FILE.equalsIgnoreCase(fileNode.getPrimaryNodeType().getName())) {
return exceptionResponse("The node at '" + filePath + "' does not have the [nt:file] primary type");
}
content = fileNode.getNode(JcrConstants.JCR_CONTENT);
responseStatus = Response.Status.OK;
}
Binary binary = session.getValueFactory().createBinary(binaryStream);
Property binaryProperty = content.setProperty(JcrConstants.JCR_DATA, binary);
session.save();
RestItem restItem = createRestItem(request, 0, session, binaryProperty);
return Response.status(responseStatus).entity(restItem).build();
} finally {
try {
binaryStream.close();
} catch (IOException ioe) {
logger.error("Cannot close binary stream", ioe);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy