/** * Relink the content data from a new node to an existing node to preserve the version history. * * @param tempNodeRef temp nodeRef * @param nodeToMoveRef NodeRef * @param newParentNodeRef NodeRef * @param newName new name */ public void relinkNode( NodeRef tempNodeRef, NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName) throws FileNotFoundException, FileExistsException { // Get the properties for the old and new nodes org.alfresco.service.cmr.model.FileInfo tempFileInfo = fileFolderService.getFileInfo(tempNodeRef); org.alfresco.service.cmr.model.FileInfo fileToMoveInfo = fileFolderService.getFileInfo(nodeToMoveRef); // Save the current name of the old node String tempName = tempFileInfo.getName(); try { // Rename operation will add or remove the sys:temporary aspect appropriately // rename temp file to the new name fileFolderService.rename(tempNodeRef, newName); // rename new file to old name fileFolderService.rename(nodeToMoveRef, tempName); } catch (org.alfresco.service.cmr.model.FileNotFoundException e) { throw new FileNotFoundException(e.getMessage()); } catch (org.alfresco.service.cmr.model.FileExistsException e) { throw new FileExistsException(e.getMessage()); } if (!tempFileInfo.isFolder() && !fileToMoveInfo.isFolder()) { // swap the content between the two ContentData oldContentData = tempFileInfo.getContentData(); if (oldContentData == null) { String mimetype = mimetypeService.guessMimetype(tempName); oldContentData = ContentData.setMimetype(null, mimetype); } ContentData newContentData = fileToMoveInfo.getContentData(); // Reset the mime type // TODO Pass the content along when guessing the mime type, so we're more accurate String mimetype = mimetypeService.guessMimetype(newName); newContentData = ContentData.setMimetype(newContentData, mimetype); nodeService.setProperty(tempNodeRef, ContentModel.PROP_CONTENT, newContentData); nodeService.setProperty(nodeToMoveRef, ContentModel.PROP_CONTENT, oldContentData); } }
@Override public String guessEncoding(InputStream in, String mimetype) { String encoding = "UTF-8"; try { if (in != null) { // The InputStream must support marks final BufferedInputStream bufferedInputStream = new BufferedInputStream(in); Charset charset = mimetypeService.getContentCharsetFinder().getCharset(bufferedInputStream, mimetype); encoding = charset.name(); } } finally { IOUtils.closeQuietly(in); } return encoding; }
/** * Streams content back to client from a given File. * * @param req The request * @param res The response * @param file The file whose content is to be streamed. * @param modifiedTime The modified datetime to use for the streamed content. If <tt>null</tt> the * file's timestamp will be used. * @param attach Indicates whether the content should be streamed as an attachment or not * @param attachFileName Optional file name to use when attach is <code>true</code> * @throws IOException */ public void streamContent( WebScriptRequest req, WebScriptResponse res, File file, Long modifiedTime, boolean attach, String attachFileName, Map<String, Object> model) throws IOException { if (logger.isDebugEnabled()) logger.debug( "Retrieving content from file " + file.getAbsolutePath() + " (attach: " + attach + ")"); // determine mimetype from file extension String filePath = file.getAbsolutePath(); String mimetype = MimetypeMap.MIMETYPE_BINARY; int extIndex = filePath.lastIndexOf('.'); if (extIndex != -1) { mimetype = mimetypeService.getMimetype(filePath.substring(extIndex + 1)); } // setup file reader and stream FileContentReader reader = new FileContentReader(file); reader.setMimetype(mimetype); reader.setEncoding("UTF-8"); long lastModified = modifiedTime == null ? file.lastModified() : modifiedTime; Date lastModifiedDate = new Date(lastModified); streamContentImpl( req, res, reader, null, null, attach, lastModifiedDate, String.valueOf(lastModifiedDate.getTime()), attachFileName, model); }
/** * Stream content implementation * * @param req The request * @param res The response * @param reader The reader * @param nodeRef The content nodeRef if applicable * @param propertyQName The content property if applicable * @param attach Indicates whether the content should be streamed as an attachment or not * @param modified Modified date of content * @param eTag ETag to use * @param attachFileName Optional file name to use when attach is <code>true</code> * @throws IOException */ public void streamContentImpl( WebScriptRequest req, WebScriptResponse res, ContentReader reader, final NodeRef nodeRef, final QName propertyQName, final boolean attach, final Date modified, String eTag, final String attachFileName, Map<String, Object> model) throws IOException { setAttachment(null, res, attach, attachFileName); // 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); mimetype = mimetypeService.getMimetype(ext); } } res.setHeader(HEADER_ACCEPT_RANGES, "bytes"); try { boolean processedRange = false; String range = req.getHeader(HEADER_CONTENT_RANGE); final long size = reader.getSize(); final String encoding = reader.getEncoding(); if (attach) { final String finalMimetype = mimetype; eventPublisher.publishEvent( new EventPreparator() { @Override public Event prepareEvent(String user, String networkId, String transactionId) { String siteId = siteService.getSiteShortName(nodeRef); return new ContentEventImpl( ContentEvent.DOWNLOAD, user, networkId, transactionId, nodeRef.getId(), siteId, propertyQName.toString(), Client.webclient, attachFileName, finalMimetype, size, encoding); } }); } if (range == null) { range = req.getHeader(HEADER_RANGE); } if (range != null) { if (logger.isDebugEnabled()) logger.debug("Found content range header: " + range); // ensure the range header is starts with "bytes=" and process the range(s) if (range.length() > 6) { if (range.indexOf(',') != -1 && (nodeRef == null || propertyQName == null)) { if (logger.isInfoEnabled()) logger.info("Multi-range only supported for nodeRefs"); } else { HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService); processedRange = rangeProcessor.processRange( res, reader, range.substring(6), nodeRef, propertyQName, mimetype, req.getHeader(HEADER_USER_AGENT)); } } } if (processedRange == false) { if (logger.isDebugEnabled()) logger.debug("Sending complete file content..."); // set mimetype for the content and the character encoding for the stream res.setContentType(mimetype); res.setContentEncoding(encoding); // return the complete entity range res.setHeader( HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size - 1L) + "/" + Long.toString(size)); res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size)); // set caching setResponseCache(res, modified, eTag, model); // 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. 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\tcontent: " + reader); } catch (ContentIOException e2) { if (logger.isInfoEnabled()) logger.info("Client aborted stream read:\n\tcontent: " + reader); } }
@Override public String guessMimetype(Resource resource) { return mimetypeService.guessMimetype(resource.getFilename()); }