/*
* (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* dmetzler
*/
package org.nuxeo.ecm.restapi.server.jaxrs.blob;
import static org.nuxeo.ecm.core.io.download.DownloadService.BLOBHOLDER_PREFIX;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import org.apache.commons.lang.StringUtils;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.PropertyException;
import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
import org.nuxeo.ecm.core.versioning.VersioningService;
import org.nuxeo.ecm.platform.web.common.ServletHelper;
import org.nuxeo.ecm.webengine.WebException;
import org.nuxeo.ecm.webengine.forms.FormData;
import org.nuxeo.ecm.webengine.model.WebObject;
import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
import org.nuxeo.ecm.webengine.model.impl.DefaultObject;
/**
* @since 5.8
*/
@WebObject(type = "blob")
public class BlobObject extends DefaultObject {
private String fieldPath;
private DocumentModel doc;
private BlobHolder bh;
@Override
protected void initialize(Object... args) {
super.initialize(args);
if (args.length == 2) {
fieldPath = (String) args[0];
doc = (DocumentModel) args[1];
if (fieldPath == null) {
if (bh == null && doc.hasSchema("file")) {
fieldPath = "file:content";
} else {
throw new IllegalArgumentException("No xpath specified and document does not have 'file' schema");
}
} else {
if (fieldPath.startsWith(BLOBHOLDER_PREFIX)) {
bh = doc.getAdapter(BlobHolder.class);
if (bh != null) {
fieldPath = fieldPath.replace(BLOBHOLDER_PREFIX, "");
} else {
throw new WebResourceNotFoundException("No BlobHolder found");
}
}
}
}
}
@Override
public <A> A getAdapter(Class<A> adapter) {
if (adapter.isAssignableFrom(Blob.class)) {
return adapter.cast(getBlob());
}
return super.getAdapter(adapter);
}
protected Blob getBlob() {
if (bh != null) {
if (StringUtils.isBlank(fieldPath) || fieldPath.equals("0")) {
return bh.getBlob();
} else {
int index = Integer.parseInt(fieldPath);
return bh.getBlobs().get(index);
}
}
return (Blob) doc.getPropertyValue(fieldPath);
}
public BlobHolder getBlobHolder() {
return bh;
}
/**
* @since 8.2
*/
public DocumentModel getDocument() {
return doc;
}
/**
* @since 8.2
*/
public String getXpath() {
return fieldPath;
}
@GET
public Object doGet(@Context Request request) {
Blob blob = getBlob();
if (blob == null) {
throw new WebResourceNotFoundException("No attached file at " + fieldPath);
}
return blob;
}
/**
* @deprecated since 7.3. Now returns directly the Blob and use default {@code BlobWriter}.
*/
@Deprecated
public static Response buildResponseFromBlob(Request request, HttpServletRequest httpServletRequest, Blob blob,
String filename) {
if (filename == null) {
filename = blob.getFilename();
}
String digest = blob.getDigest();
EntityTag etag = digest == null ? null : new EntityTag(digest);
if (etag != null) {
Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
if (builder != null) {
return builder.build();
}
}
String contentDisposition = ServletHelper.getRFC2231ContentDisposition(httpServletRequest, filename);
// cached resource did change or no ETag -> serve updated content
Response.ResponseBuilder builder = Response.ok(blob).header("Content-Disposition", contentDisposition).type(
blob.getMimeType());
if (etag != null) {
builder.tag(etag);
}
return builder.build();
}
@DELETE
public Response doDelete() {
if (bh != null) {
throw new IllegalArgumentException("Cannot modify a Blob using a BlobHolder");
}
try {
doc.getProperty(fieldPath).remove();
} catch (PropertyException e) {
throw WebException.wrap("Failed to delete attached file into property: " + fieldPath, e);
}
CoreSession session = ctx.getCoreSession();
session.saveDocument(doc);
session.save();
return Response.noContent().build();
}
@PUT
public Response doPut() {
FormData form = ctx.getForm();
Blob blob = form.getFirstBlob();
if (blob == null) {
throw new IllegalArgumentException("Could not find any uploaded file");
}
if (bh != null) {
throw new IllegalArgumentException("Cannot modify a Blob using a BlobHolder");
}
try {
doc.setPropertyValue(fieldPath, (Serializable) blob);
} catch (PropertyException e) {
throw WebException.wrap("Failed to attach file", e);
}
// make snapshot
doc.putContextData(VersioningService.VERSIONING_OPTION, form.getVersioningOption());
CoreSession session = ctx.getCoreSession();
session.saveDocument(doc);
session.save();
return Response.ok("blob updated").build();
}
}