mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Added stream content 'kind of' web script, modified ContentGet webscript to use common code, create GET thumbnail method based on stream content kind of web script
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9395 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
<webscript>
|
<webscript>
|
||||||
<shortname>Thumbnails</shortname>
|
<shortname>Thumbnails</shortname>
|
||||||
<description>Delete a thumbnail for a content resource</description>
|
<description>Delete a thumbnail for a content resource</description>
|
||||||
<url>/api/node/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/node/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<url>/api/path/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/path/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<format default="json"/>
|
<format default="json"/>
|
||||||
<authentication>guest</authentication>
|
<authentication>guest</authentication>
|
||||||
<transaction>required</transaction>
|
<transaction>required</transaction>
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<webscript>
|
<webscript kind="org.alfresco.repository.content.stream">
|
||||||
<shortname>Thumbnails</shortname>
|
<shortname>Thumbnails</shortname>
|
||||||
<description>Create a new thumbnail for a content resource</description>
|
<description>Get a named thumbnail for a content resource</description>
|
||||||
<url>/api/node/{store_type}/{store_id}/{id}/content{property?}/thumbnails</url>
|
<url>/api/node/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<url>/api/path/{store_type}/{store_id}/{id}/content{property?}/thumbnails</url>
|
<url>/api/path/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<format default="json"/>
|
<format default="">argument</format>
|
||||||
<authentication>guest</authentication>
|
<authentication>guest</authentication>
|
||||||
<transaction>required</transaction>
|
<transaction>required</transaction>
|
||||||
</webscript>
|
</webscript>
|
@@ -13,17 +13,25 @@ function main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the thumbnail name from the JSON content
|
// Get the thumbnail name from the JSON content
|
||||||
var thumbnailName = pathSegments[8];
|
var thumbnailName = url.templateArgs.thumbnailname; //pathSegments[pathSegments.length - 1];
|
||||||
|
|
||||||
// 404 if no thumbnail name found
|
// 404 if no thumbnail name found
|
||||||
if (thumbnailName == null)
|
if (thumbnailName == null)
|
||||||
{
|
{
|
||||||
status.setCode(status.STATUS_NOT_FOUND, "Thumbnail name was not provided");
|
status.setCode(status.STATUS_NOT_FOUND, "Thumbnail name was not provided");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the thumbnail ...
|
// Get the thumbnail
|
||||||
|
var thumbnail = node.getThumbnail(thumbnailName);
|
||||||
|
if (thumbnail == null)
|
||||||
|
{
|
||||||
|
// 404 since no thumbnail was found
|
||||||
|
status.setCode(status.STATUS_NOT_FOUND, "Thumbnail was not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place the details of the thumbnail into the model, this will be used to stream the content to the client
|
||||||
|
model.contentNode = thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
@@ -1,8 +1,8 @@
|
|||||||
<webscript>
|
<webscript>
|
||||||
<shortname>Thumbnails</shortname>
|
<shortname>Thumbnails</shortname>
|
||||||
<description>Update a thumbnail for a content resource</description>
|
<description>Update a thumbnail for a content resource</description>
|
||||||
<url>/api/node/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/node/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<url>/api/path/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/path/{store_type}/{store_id}/{id}/content{property}/thumbnails/{thumbnailname}</url>
|
||||||
<format default="json"/>
|
<format default="json"/>
|
||||||
<authentication>guest</authentication>
|
<authentication>guest</authentication>
|
||||||
<transaction>required</transaction>
|
<transaction>required</transaction>
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<webscript>
|
<webscript>
|
||||||
<shortname>Thumbnails</shortname>
|
<shortname>Thumbnails</shortname>
|
||||||
<description>Get a named thumbnail for a content resource</description>
|
<description>Get the thumbnails for a content resource</description>
|
||||||
<url>/api/node/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/node/{store_type}/{store_id}/{id}/content{property}/thumbnails</url>
|
||||||
<url>/api/path/{store_type}/{store_id}/{id}/content{property?}/thumbnails/{thumbnailname}</url>
|
<url>/api/path/{store_type}/{store_id}/{id}/content{property}/thumbnails</url>
|
||||||
<format default=""/>
|
<format default="json"/>
|
||||||
<authentication>guest</authentication>
|
<authentication>guest</authentication>
|
||||||
<transaction>required</transaction>
|
<transaction>required</transaction>
|
||||||
</webscript>
|
</webscript>
|
@@ -33,8 +33,7 @@ function main()
|
|||||||
// Prep the model
|
// Prep the model
|
||||||
model.node = node;
|
model.node = node;
|
||||||
model.thumbnailName = thumbnailName;
|
model.thumbnailName = thumbnailName;
|
||||||
model.thumbnail = thumbnail;
|
model.thumbnail = thumbnail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
@@ -187,7 +187,7 @@
|
|||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- Content Retrieval -->
|
<!-- Content Retrieval -->
|
||||||
<bean id="webscript.org.alfresco.repository.store.content.get" class="org.alfresco.repo.web.scripts.bean.ContentGet" parent="webscript">
|
<bean id="webscript.org.alfresco.repository.store.content.get" class="org.alfresco.repo.web.scripts.content.ContentGet" parent="webscript">
|
||||||
<property name="repository" ref="repositoryHelper" />
|
<property name="repository" ref="repositoryHelper" />
|
||||||
<property name="namespaceService" ref="NamespaceService" />
|
<property name="namespaceService" ref="NamespaceService" />
|
||||||
<property name="permissionService" ref="PermissionService" />
|
<property name="permissionService" ref="PermissionService" />
|
||||||
@@ -196,6 +196,13 @@
|
|||||||
<property name="mimetypeService" ref="MimetypeService" />
|
<property name="mimetypeService" ref="MimetypeService" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="webscript.org.alfresco.repository.content.stream" class="org.alfresco.repo.web.scripts.content.StreamContent" parent="webscript">
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="contentService" ref="ContentService" />
|
||||||
|
<property name="mimetypeService" ref="MimetypeService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- Remote Store service - AVM -->
|
<!-- Remote Store service - AVM -->
|
||||||
<bean id="webscript.org.alfresco.repository.store.remoteavm.get" class="org.alfresco.repo.web.scripts.bean.AVMRemoteStore" parent="webscript">
|
<bean id="webscript.org.alfresco.repository.store.remoteavm.get" class="org.alfresco.repo.web.scripts.bean.AVMRemoteStore" parent="webscript">
|
||||||
<property name="mimetypeService" ref="MimetypeService" />
|
<property name="mimetypeService" ref="MimetypeService" />
|
||||||
|
@@ -131,11 +131,12 @@ public abstract class BaseWebScriptTest extends TestCase
|
|||||||
MockHttpServletResponse response = BaseWebScriptTest.getServer().submitRequest(method, url, new HashMap<String, String>(), body, contentType);
|
MockHttpServletResponse response = BaseWebScriptTest.getServer().submitRequest(method, url, new HashMap<String, String>(), body, contentType);
|
||||||
if (expectedStatus > 0 && expectedStatus != response.getStatus())
|
if (expectedStatus > 0 && expectedStatus != response.getStatus())
|
||||||
{
|
{
|
||||||
if (response.getStatus() == 500)
|
//if (response.getStatus() == 500)
|
||||||
{
|
//{
|
||||||
System.out.println(response.getContentAsString());
|
System.out.println(response.getContentAsString());
|
||||||
}
|
//}
|
||||||
fail("Expected status code " + expectedStatus + " , " + response.getStatus() + " was returned.");
|
|
||||||
|
fail("Expected status code " + expectedStatus + " , " + response.getStatus() + " was returned");
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@@ -1,283 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
* As a special exception to the terms and conditions of version 2.0 of
|
|
||||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
|
||||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
|
||||||
* FLOSS exception. You should have recieved a copy of the text describing
|
|
||||||
* the FLOSS exception, and it is also available here:
|
|
||||||
* http://www.alfresco.com/legal/licensing"
|
|
||||||
*/
|
|
||||||
package org.alfresco.repo.web.scripts.bean;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
|
||||||
import org.alfresco.repo.model.Repository;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentService;
|
|
||||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.cmr.security.AccessStatus;
|
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
|
||||||
import org.alfresco.service.namespace.QName;
|
|
||||||
import org.alfresco.util.URLEncoder;
|
|
||||||
import org.alfresco.web.scripts.AbstractWebScript;
|
|
||||||
import org.alfresco.web.scripts.Cache;
|
|
||||||
import org.alfresco.web.scripts.WebScriptException;
|
|
||||||
import org.alfresco.web.scripts.WebScriptRequest;
|
|
||||||
import org.alfresco.web.scripts.WebScriptResponse;
|
|
||||||
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
|
|
||||||
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content Retrieval Service
|
|
||||||
*
|
|
||||||
* Stream content from the Repository.
|
|
||||||
*
|
|
||||||
* @author davidc
|
|
||||||
*/
|
|
||||||
public class ContentGet extends AbstractWebScript
|
|
||||||
{
|
|
||||||
// Logger
|
|
||||||
private static final Log logger = LogFactory.getLog(ContentGet.class);
|
|
||||||
|
|
||||||
private static final String NODE_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
|
||||||
|
|
||||||
// Component dependencies
|
|
||||||
private Repository repository;
|
|
||||||
private NamespaceService namespaceService;
|
|
||||||
private PermissionService permissionService;
|
|
||||||
private NodeService nodeService;
|
|
||||||
private ContentService contentService;
|
|
||||||
private MimetypeService mimetypeService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param repository
|
|
||||||
*/
|
|
||||||
public void setRepository(Repository repository)
|
|
||||||
{
|
|
||||||
this.repository = repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param namespaceService
|
|
||||||
*/
|
|
||||||
public void setNamespaceService(NamespaceService namespaceService)
|
|
||||||
{
|
|
||||||
this.namespaceService = namespaceService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param permissionService
|
|
||||||
*/
|
|
||||||
public void setPermissionService(PermissionService permissionService)
|
|
||||||
{
|
|
||||||
this.permissionService = permissionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param nodeService
|
|
||||||
*/
|
|
||||||
public void setNodeService(NodeService nodeService)
|
|
||||||
{
|
|
||||||
this.nodeService = nodeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param contentService
|
|
||||||
*/
|
|
||||||
public void setContentService(ContentService contentService)
|
|
||||||
{
|
|
||||||
this.contentService = contentService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mimetypeService
|
|
||||||
*/
|
|
||||||
public void setMimetypeService(MimetypeService mimetypeService)
|
|
||||||
{
|
|
||||||
this.mimetypeService = mimetypeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
|
||||||
*/
|
|
||||||
public void execute(WebScriptRequest req, WebScriptResponse res)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
// NOTE: This web script must be executed in a HTTP Servlet environment
|
|
||||||
if (!(req instanceof WebScriptServletRequest))
|
|
||||||
{
|
|
||||||
throw new WebScriptException("Content retrieval must be executed in HTTP Servlet environment");
|
|
||||||
}
|
|
||||||
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
|
|
||||||
HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse();
|
|
||||||
|
|
||||||
// convert web script URL to node reference in Repository
|
|
||||||
String match = req.getServiceMatch().getPath();
|
|
||||||
String[] matchParts = match.split("/");
|
|
||||||
String extensionPath = req.getExtensionPath();
|
|
||||||
String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/");
|
|
||||||
String[] path = new String[extParts.length -1];
|
|
||||||
System.arraycopy(extParts, 1, path, 0, extParts.length -1);
|
|
||||||
NodeRef nodeRef = repository.findNodeRef(matchParts[2], path);
|
|
||||||
if (nodeRef == null)
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine content property
|
|
||||||
QName propertyQName = ContentModel.PROP_CONTENT;
|
|
||||||
String contentPart = extParts[0];
|
|
||||||
if (contentPart.length() > 0 && contentPart.charAt(0) == ';')
|
|
||||||
{
|
|
||||||
if (contentPart.length() < 2)
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed");
|
|
||||||
}
|
|
||||||
String propertyName = contentPart.substring(1);
|
|
||||||
if (propertyName.length() > 0)
|
|
||||||
{
|
|
||||||
propertyQName = QName.createQName(propertyName, namespaceService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine attachment
|
|
||||||
boolean attach = Boolean.valueOf(req.getParameter("a"));
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")");
|
|
||||||
|
|
||||||
// check that the user has at least READ_CONTENT access - else redirect to the login page
|
|
||||||
if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED)
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Permission denied");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check If-Modified-Since header and set Last-Modified header as appropriate
|
|
||||||
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
|
|
||||||
long modifiedSince = httpReq.getDateHeader("If-Modified-Since");
|
|
||||||
if (modifiedSince > 0L)
|
|
||||||
{
|
|
||||||
// round the date to the ignore millisecond value which is not supplied by header
|
|
||||||
long modDate = (modified.getTime() / 1000L) * 1000L;
|
|
||||||
if (modDate <= modifiedSince)
|
|
||||||
{
|
|
||||||
httpRes.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle attachment
|
|
||||||
if (attach == true)
|
|
||||||
{
|
|
||||||
// set header based on filename - will force a Save As from the browse if it doesn't recognize it
|
|
||||||
// this is better than the default response of the browser trying to display the contents
|
|
||||||
httpRes.setHeader("Content-Disposition", "attachment");
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the content reader
|
|
||||||
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
|
|
||||||
if (reader == null || !reader.exists())
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to locate content for node ref " + nodeRef + " (property: " + propertyQName.toString() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
// establish mimetype
|
|
||||||
String mimetype = reader.getMimetype();
|
|
||||||
if (mimetype == null || mimetype.length() == 0)
|
|
||||||
{
|
|
||||||
mimetype = MimetypeMap.MIMETYPE_BINARY;
|
|
||||||
int extIndex = extensionPath.lastIndexOf('.');
|
|
||||||
if (extIndex != -1)
|
|
||||||
{
|
|
||||||
String ext = extensionPath.substring(extIndex + 1);
|
|
||||||
String mt = mimetypeService.getMimetypesByExtension().get(ext);
|
|
||||||
if (mt != null)
|
|
||||||
{
|
|
||||||
mimetype = mt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mimetype for the content and the character encoding + length for the stream
|
|
||||||
httpRes.setContentType(mimetype);
|
|
||||||
httpRes.setCharacterEncoding(reader.getEncoding());
|
|
||||||
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
|
|
||||||
|
|
||||||
// set caching
|
|
||||||
Cache cache = new Cache();
|
|
||||||
cache.setNeverCache(false);
|
|
||||||
cache.setMustRevalidate(true);
|
|
||||||
cache.setLastModified(modified);
|
|
||||||
res.setCache(cache);
|
|
||||||
|
|
||||||
// get the content and stream directly to the response output stream
|
|
||||||
// assuming the repository is capable of streaming in chunks, this should allow large files
|
|
||||||
// to be streamed directly to the browser response stream.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
reader.getContent(res.getOutputStream());
|
|
||||||
}
|
|
||||||
catch (SocketException e1)
|
|
||||||
{
|
|
||||||
// the client cut the connection - our mission was accomplished apart from a little error message
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
|
|
||||||
}
|
|
||||||
catch (ContentIOException e2)
|
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to generate a URL to a content node for downloading content from the server.
|
|
||||||
* The content is supplied directly in the reponse. This generally means a browser will
|
|
||||||
* attempt to open the content directly if possible, else it will prompt to save the file.
|
|
||||||
*
|
|
||||||
* @param ref NodeRef of the content node to generate URL for (cannot be null)
|
|
||||||
* @param name File name end element to return on the url (used by the browser on Save)
|
|
||||||
*
|
|
||||||
* @return URL to download the content from the specified node
|
|
||||||
*/
|
|
||||||
public final static String generateNodeURL(NodeRef ref, String name)
|
|
||||||
{
|
|
||||||
return MessageFormat.format(NODE_URL, new Object[] {
|
|
||||||
ref.getStoreRef().getProtocol(),
|
|
||||||
ref.getStoreRef().getIdentifier(),
|
|
||||||
ref.getId(),
|
|
||||||
URLEncoder.encode(name) } );
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
* As a special exception to the terms and conditions of version 2.0 of
|
||||||
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
|
* FLOSS exception. You should have recieved a copy of the text describing
|
||||||
|
* the FLOSS exception, and it is also available here:
|
||||||
|
* http://www.alfresco.com/legal/licensing"
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.content;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.model.Repository;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.util.URLEncoder;
|
||||||
|
import org.alfresco.web.scripts.WebScriptException;
|
||||||
|
import org.alfresco.web.scripts.WebScriptRequest;
|
||||||
|
import org.alfresco.web.scripts.WebScriptResponse;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content Retrieval Service
|
||||||
|
*
|
||||||
|
* Stream content from the Repository.
|
||||||
|
*
|
||||||
|
* @author davidc
|
||||||
|
*/
|
||||||
|
public class ContentGet extends StreamContent
|
||||||
|
{
|
||||||
|
// Logger
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final Log logger = LogFactory.getLog(ContentGet.class);
|
||||||
|
|
||||||
|
private static final String NODE_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||||
|
|
||||||
|
// Component dependencies
|
||||||
|
private Repository repository;
|
||||||
|
private NamespaceService namespaceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param repository
|
||||||
|
*/
|
||||||
|
public void setRepository(Repository repository)
|
||||||
|
{
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param namespaceService
|
||||||
|
*/
|
||||||
|
public void setNamespaceService(NamespaceService namespaceService)
|
||||||
|
{
|
||||||
|
this.namespaceService = namespaceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||||
|
*/
|
||||||
|
public void execute(WebScriptRequest req, WebScriptResponse res)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// convert web script URL to node reference in Repository
|
||||||
|
String match = req.getServiceMatch().getPath();
|
||||||
|
String[] matchParts = match.split("/");
|
||||||
|
String extensionPath = req.getExtensionPath();
|
||||||
|
String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/");
|
||||||
|
String[] path = new String[extParts.length -1];
|
||||||
|
System.arraycopy(extParts, 1, path, 0, extParts.length -1);
|
||||||
|
NodeRef nodeRef = repository.findNodeRef(matchParts[2], path);
|
||||||
|
if (nodeRef == null)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine content property
|
||||||
|
QName propertyQName = ContentModel.PROP_CONTENT;
|
||||||
|
String contentPart = extParts[0];
|
||||||
|
if (contentPart.length() > 0 && contentPart.charAt(0) == ';')
|
||||||
|
{
|
||||||
|
if (contentPart.length() < 2)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed");
|
||||||
|
}
|
||||||
|
String propertyName = contentPart.substring(1);
|
||||||
|
if (propertyName.length() > 0)
|
||||||
|
{
|
||||||
|
propertyQName = QName.createQName(propertyName, namespaceService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine attachment
|
||||||
|
boolean attach = Boolean.valueOf(req.getParameter("a"));
|
||||||
|
|
||||||
|
// Stream the content
|
||||||
|
streamContent(req, res, nodeRef, propertyQName, attach);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to generate a URL to a content node for downloading content from the server.
|
||||||
|
* The content is supplied directly in the reponse. This generally means a browser will
|
||||||
|
* attempt to open the content directly if possible, else it will prompt to save the file.
|
||||||
|
*
|
||||||
|
* @param ref NodeRef of the content node to generate URL for (cannot be null)
|
||||||
|
* @param name File name end element to return on the url (used by the browser on Save)
|
||||||
|
*
|
||||||
|
* @return URL to download the content from the specified node
|
||||||
|
*/
|
||||||
|
public final static String generateNodeURL(NodeRef ref, String name)
|
||||||
|
{
|
||||||
|
return MessageFormat.format(NODE_URL, new Object[] {
|
||||||
|
ref.getStoreRef().getProtocol(),
|
||||||
|
ref.getStoreRef().getIdentifier(),
|
||||||
|
ref.getId(),
|
||||||
|
URLEncoder.encode(name) } );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
* As a special exception to the terms and conditions of version 2.0 of
|
||||||
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
|
* FLOSS exception. You should have recieved a copy of the text describing
|
||||||
|
* the FLOSS exception, and it is also available here:
|
||||||
|
* http://www.alfresco.com/legal/licensing"
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.content;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.content.MimetypeMap;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.alfresco.web.scripts.AbstractWebScript;
|
||||||
|
import org.alfresco.web.scripts.Cache;
|
||||||
|
import org.alfresco.web.scripts.Container;
|
||||||
|
import org.alfresco.web.scripts.Description;
|
||||||
|
import org.alfresco.web.scripts.ScriptContent;
|
||||||
|
import org.alfresco.web.scripts.Status;
|
||||||
|
import org.alfresco.web.scripts.WebScriptException;
|
||||||
|
import org.alfresco.web.scripts.WebScriptRequest;
|
||||||
|
import org.alfresco.web.scripts.WebScriptResponse;
|
||||||
|
import org.alfresco.web.scripts.WebScriptStatus;
|
||||||
|
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
|
||||||
|
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web script 'type' that can be used when the binary data of a content property needs to be streamed back to the client
|
||||||
|
* as the result of executing the web script.
|
||||||
|
*
|
||||||
|
* @author Roy Wetherall
|
||||||
|
*/
|
||||||
|
public class StreamContent extends AbstractWebScript
|
||||||
|
{
|
||||||
|
// Logger
|
||||||
|
private static final Log logger = LogFactory.getLog(StreamContent.class);
|
||||||
|
|
||||||
|
protected PermissionService permissionService;
|
||||||
|
protected NodeService nodeService;
|
||||||
|
protected ContentService contentService;
|
||||||
|
protected MimetypeService mimetypeService;
|
||||||
|
|
||||||
|
// Script Context
|
||||||
|
private String basePath;
|
||||||
|
private ScriptContent executeScript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mimetypeService
|
||||||
|
*/
|
||||||
|
public void setMimetypeService(MimetypeService mimetypeService)
|
||||||
|
{
|
||||||
|
this.mimetypeService = mimetypeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param permissionService
|
||||||
|
*/
|
||||||
|
public void setPermissionService(PermissionService permissionService)
|
||||||
|
{
|
||||||
|
this.permissionService = permissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nodeService
|
||||||
|
*/
|
||||||
|
public void setNodeService(NodeService nodeService)
|
||||||
|
{
|
||||||
|
this.nodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param contentService
|
||||||
|
*/
|
||||||
|
public void setContentService(ContentService contentService)
|
||||||
|
{
|
||||||
|
this.contentService = contentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.alfresco.web.scripts.AbstractWebScript#init(org.alfresco.web.scripts.WebScriptRegistry)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void init(Container container, Description description)
|
||||||
|
{
|
||||||
|
super.init(container, description);
|
||||||
|
|
||||||
|
// Test for "execute" script
|
||||||
|
basePath = getDescription().getId();
|
||||||
|
String scriptPath = basePath + ".js";
|
||||||
|
executeScript = container.getScriptProcessor().findScript(scriptPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||||
|
*/
|
||||||
|
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
|
||||||
|
{
|
||||||
|
// retrieve requested format
|
||||||
|
String format = req.getFormat();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// construct model for script / template
|
||||||
|
Status status = new Status();
|
||||||
|
Cache cache = new Cache(getDescription().getRequiredCache());
|
||||||
|
Map<String, Object> model = executeImpl(req, status, cache);
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
model = new HashMap<String, Object>(8, 1.0f);
|
||||||
|
}
|
||||||
|
model.put("status", status);
|
||||||
|
model.put("cache", cache);
|
||||||
|
|
||||||
|
// execute script if it exists
|
||||||
|
if (executeScript != null)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Executing script " + executeScript.getPathDescription());
|
||||||
|
|
||||||
|
Map<String, Object> scriptModel = createScriptParameters(req, res, model);
|
||||||
|
// add return model allowing script to add items to template model
|
||||||
|
Map<String, Object> returnModel = new HashMap<String, Object>(8, 1.0f);
|
||||||
|
scriptModel.put("model", returnModel);
|
||||||
|
executeScript(executeScript, scriptModel);
|
||||||
|
mergeScriptModelIntoTemplateModel(returnModel, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the content parameters from the model
|
||||||
|
NodeRef nodeRef = (NodeRef)model.get("contentNode");
|
||||||
|
if (nodeRef == null)
|
||||||
|
{
|
||||||
|
throw new WebScriptException("The content node was not specified so the content cannot be streamed to the client");
|
||||||
|
}
|
||||||
|
QName propertyQName = null;
|
||||||
|
String contentProperty = (String)model.get("contentProperty");
|
||||||
|
if (contentProperty == null)
|
||||||
|
{
|
||||||
|
// default to the standard content property
|
||||||
|
propertyQName = ContentModel.PROP_CONTENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
propertyQName = QName.createQName(contentProperty);
|
||||||
|
}
|
||||||
|
Boolean attachBoolean = (Boolean)model.get("attach");
|
||||||
|
boolean attach = false;
|
||||||
|
if (attachBoolean != null)
|
||||||
|
{
|
||||||
|
attach = attachBoolean.booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// is a redirect to a status specific template required?
|
||||||
|
if (status.getRedirect())
|
||||||
|
{
|
||||||
|
// create model for template rendering
|
||||||
|
Map<String, Object> templateModel = createTemplateParameters(req, res, model);
|
||||||
|
sendStatus(req, res, status, cache, format, templateModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Stream the content
|
||||||
|
streamContent(req, res, nodeRef, propertyQName, attach);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Throwable e)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
logger.info("Caught exception & redirecting to status template: " + e.getMessage());
|
||||||
|
|
||||||
|
// extract status code, if specified
|
||||||
|
int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
|
if (e instanceof WebScriptException)
|
||||||
|
{
|
||||||
|
statusCode = ((WebScriptException)e).getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send status
|
||||||
|
Status status = new Status();
|
||||||
|
status.setCode(statusCode);
|
||||||
|
status.setMessage(e.getMessage());
|
||||||
|
status.setException(e);
|
||||||
|
Cache cache = new Cache();
|
||||||
|
cache.setNeverCache(true);
|
||||||
|
Map<String, Object> customModel = new HashMap<String, Object>(8, 1.0f);
|
||||||
|
customModel.put("status", status);
|
||||||
|
Map<String, Object> templateModel = createTemplateParameters(req, res, customModel);
|
||||||
|
sendStatus(req, res, status, cache, format, templateModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge script generated model into template-ready model
|
||||||
|
*
|
||||||
|
* @param scriptModel script model
|
||||||
|
* @param templateModel template model
|
||||||
|
*/
|
||||||
|
final private void mergeScriptModelIntoTemplateModel(Map<String, Object> scriptModel, Map<String, Object> templateModel)
|
||||||
|
{
|
||||||
|
for (Map.Entry<String, Object> entry : scriptModel.entrySet())
|
||||||
|
{
|
||||||
|
// retrieve script model value
|
||||||
|
Object value = entry.getValue();
|
||||||
|
Object templateValue = getContainer().getScriptProcessor().unwrapValue(value);
|
||||||
|
templateModel.put(entry.getKey(), templateValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute custom Java logic
|
||||||
|
*
|
||||||
|
* @param req Web Script request
|
||||||
|
* @param status Web Script status
|
||||||
|
* @return custom service model
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
protected Map<String, Object> executeImpl(WebScriptRequest req, WebScriptStatus status)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute custom Java logic
|
||||||
|
*
|
||||||
|
* @param req Web Script request
|
||||||
|
* @param status Web Script status
|
||||||
|
* @return custom service model
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||||
|
{
|
||||||
|
return executeImpl(req, new WebScriptStatus(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute custom Java logic
|
||||||
|
*
|
||||||
|
* @param req Web Script request
|
||||||
|
* @param status Web Script status
|
||||||
|
* @param cache Web Script cache
|
||||||
|
* @return custom service model
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// NOTE: Redirect to those web scripts implemented before cache support and v2.9
|
||||||
|
return executeImpl(req, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a template (of given format) to the Web Script Response
|
||||||
|
*
|
||||||
|
* @param format template format (null, default format)
|
||||||
|
* @param model data model to render
|
||||||
|
* @param writer where to output
|
||||||
|
*/
|
||||||
|
final protected void renderFormatTemplate(String format, Map<String, Object> model, Writer writer)
|
||||||
|
{
|
||||||
|
format = (format == null) ? "" : format;
|
||||||
|
String templatePath = basePath + "." + format + ".ftl";
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Rendering template '" + templatePath + "'");
|
||||||
|
|
||||||
|
renderTemplate(templatePath, model, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streams the content on a given node's content property to the response of the web script.
|
||||||
|
*
|
||||||
|
* @param req request
|
||||||
|
* @param res response
|
||||||
|
* @param nodeRef the node reference
|
||||||
|
* @param propertyQName the content property name
|
||||||
|
* @param attach indicates whether the content should be streamed as an attachment or not
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void streamContent(WebScriptRequest req, WebScriptResponse res, NodeRef nodeRef, QName propertyQName, boolean attach)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// NOTE: This web script must be executed in a HTTP Servlet environment
|
||||||
|
if (!(req instanceof WebScriptServletRequest))
|
||||||
|
{
|
||||||
|
throw new WebScriptException("Content retrieval must be executed in HTTP Servlet environment");
|
||||||
|
}
|
||||||
|
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
|
||||||
|
HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")");
|
||||||
|
|
||||||
|
// check that the user has at least READ_CONTENT access - else redirect to the login page
|
||||||
|
if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check If-Modified-Since header and set Last-Modified header as appropriate
|
||||||
|
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
|
||||||
|
long modifiedSince = httpReq.getDateHeader("If-Modified-Since");
|
||||||
|
if (modifiedSince > 0L)
|
||||||
|
{
|
||||||
|
// round the date to the ignore millisecond value which is not supplied by header
|
||||||
|
long modDate = (modified.getTime() / 1000L) * 1000L;
|
||||||
|
if (modDate <= modifiedSince)
|
||||||
|
{
|
||||||
|
httpRes.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle attachment
|
||||||
|
if (attach == true)
|
||||||
|
{
|
||||||
|
// set header based on filename - will force a Save As from the browse if it doesn't recognize it
|
||||||
|
// this is better than the default response of the browser trying to display the contents
|
||||||
|
httpRes.setHeader("Content-Disposition", "attachment");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the content reader
|
||||||
|
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
|
||||||
|
if (reader == null || !reader.exists())
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to locate content for node ref " + nodeRef + " (property: " + propertyQName.toString() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish mimetype
|
||||||
|
String mimetype = reader.getMimetype();
|
||||||
|
String extensionPath = req.getExtensionPath();
|
||||||
|
if (mimetype == null || mimetype.length() == 0)
|
||||||
|
{
|
||||||
|
mimetype = MimetypeMap.MIMETYPE_BINARY;
|
||||||
|
int extIndex = extensionPath.lastIndexOf('.');
|
||||||
|
if (extIndex != -1)
|
||||||
|
{
|
||||||
|
String ext = extensionPath.substring(extIndex + 1);
|
||||||
|
String mt = mimetypeService.getMimetypesByExtension().get(ext);
|
||||||
|
if (mt != null)
|
||||||
|
{
|
||||||
|
mimetype = mt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set mimetype for the content and the character encoding + length for the stream
|
||||||
|
httpRes.setContentType(mimetype);
|
||||||
|
httpRes.setCharacterEncoding(reader.getEncoding());
|
||||||
|
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
|
||||||
|
|
||||||
|
// set caching
|
||||||
|
Cache cache = new Cache();
|
||||||
|
cache.setNeverCache(false);
|
||||||
|
cache.setMustRevalidate(true);
|
||||||
|
cache.setLastModified(modified);
|
||||||
|
res.setCache(cache);
|
||||||
|
|
||||||
|
// get the content and stream directly to the response output stream
|
||||||
|
// assuming the repository is capable of streaming in chunks, this should allow large files
|
||||||
|
// to be streamed directly to the browser response stream.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
reader.getContent(res.getOutputStream());
|
||||||
|
}
|
||||||
|
catch (SocketException e1)
|
||||||
|
{
|
||||||
|
// the client cut the connection - our mission was accomplished apart from a little error message
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
|
||||||
|
}
|
||||||
|
catch (ContentIOException e2)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -105,17 +105,27 @@ public class ThumbnailServiceTest extends BaseWebScriptTest
|
|||||||
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_FLASH) != null)
|
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_PDF, MimetypeMap.MIMETYPE_FLASH) != null)
|
||||||
{
|
{
|
||||||
String url = "/api/node/" + pdfNode.getStoreRef().getProtocol() + "/" + pdfNode.getStoreRef().getIdentifier() + "/" + pdfNode.getId() + "/content/thumbnails";
|
String url = "/api/node/" + pdfNode.getStoreRef().getProtocol() + "/" + pdfNode.getStoreRef().getIdentifier() + "/" + pdfNode.getId() + "/content/thumbnails";
|
||||||
System.out.println(url);
|
|
||||||
|
|
||||||
JSONObject tn = new JSONObject();
|
JSONObject tn = new JSONObject();
|
||||||
tn.put("thumbnailName", "webpreview");
|
tn.put("thumbnailName", "webpreview");
|
||||||
System.out.println(tn.toString());
|
|
||||||
|
|
||||||
MockHttpServletResponse response = this.postRequest(url, 200, tn.toString(), "application/json");
|
MockHttpServletResponse response = this.postRequest(url, 200, tn.toString(), "application/json");
|
||||||
//JSONObject result = new JSONObject(response.getContentAsString());
|
|
||||||
|
|
||||||
System.out.println(response.getContentAsString());
|
System.out.println(response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do a image transformation (medium)
|
||||||
|
String url = "/api/node/" + jpgNode.getStoreRef().getProtocol() + "/" + jpgNode.getStoreRef().getIdentifier() + "/" + jpgNode.getId() + "/content/thumbnails";
|
||||||
|
JSONObject tn = new JSONObject();
|
||||||
|
tn.put("thumbnailName", "medium");
|
||||||
|
MockHttpServletResponse response = this.postRequest(url, 200, tn.toString(), "application/json");
|
||||||
|
System.out.println(response.getContentAsString());
|
||||||
|
JSONObject result = new JSONObject(response.getContentAsString());
|
||||||
|
String thumbnailUrl = result.getString("url").substring(17);
|
||||||
|
|
||||||
|
System.out.println(thumbnailUrl);
|
||||||
|
response = getRequest(thumbnailUrl, 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user