mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
MNT-22388 [Security] multiple pdfbox vulnerabilities (Repo) (#539)
* Remove pdfbox jars as they should no longer be needed. * Reintroduce tests that use Tika to 'guess' mimetypes as it was the tika parse that was pulling in the pdfbox libraries. Classes that use Tika: * HTMLRenderingEngine - removed as it is no longer used * RemoteConnectorResponseImpl - called tika utility toByteArray so not using pdfbox * TikaCharsetFinder - called to identify the charset not mimetype so not using pdfbox * MimetypeMap - main use of Tika. Used to detect mimetypes. Might have been using pdfbox.
This commit is contained in:
@@ -278,6 +278,31 @@
|
|||||||
<groupId>javax.activation</groupId>
|
<groupId>javax.activation</groupId>
|
||||||
<artifactId>javax.activation-api</artifactId>
|
<artifactId>javax.activation-api</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<!-- No longer needed -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox-tools</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>preflight</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>jempbox</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>xmpbox</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>jbig2-imageio</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
@@ -1,538 +0,0 @@
|
|||||||
/*
|
|
||||||
* #%L
|
|
||||||
* Alfresco Repository
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
|
||||||
* %%
|
|
||||||
* This file is part of the Alfresco software.
|
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
|
||||||
* provided under the following open source license terms:
|
|
||||||
*
|
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Alfresco 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.alfresco.repo.rendition.executer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.xml.transform.OutputKeys;
|
|
||||||
import javax.xml.transform.TransformerConfigurationException;
|
|
||||||
import javax.xml.transform.sax.SAXTransformerFactory;
|
|
||||||
import javax.xml.transform.sax.TransformerHandler;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
|
||||||
import org.alfresco.repo.rendition.RenditionLocation;
|
|
||||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
|
||||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|
||||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentService;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.namespace.QName;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.apache.tika.config.TikaConfig;
|
|
||||||
import org.apache.tika.exception.TikaException;
|
|
||||||
import org.apache.tika.metadata.Metadata;
|
|
||||||
import org.apache.tika.mime.MediaType;
|
|
||||||
import org.apache.tika.parser.AutoDetectParser;
|
|
||||||
import org.apache.tika.parser.ParseContext;
|
|
||||||
import org.apache.tika.parser.Parser;
|
|
||||||
import org.apache.tika.sax.BodyContentHandler;
|
|
||||||
import org.apache.tika.sax.ContentHandlerDecorator;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.ContentHandler;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.helpers.AttributesImpl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a way to turn documents supported by the
|
|
||||||
* {@link ContentService} standard transformers into basic, clean
|
|
||||||
* HTML.
|
|
||||||
* <P/>
|
|
||||||
* The HTML that is produced probably isn't going to be suitable
|
|
||||||
* for direct web publishing, as it's likely going to be too
|
|
||||||
* basic. Instead, it should be simple and clean HTML, suitable
|
|
||||||
* for being the basis of some web-friendly HTML once edited
|
|
||||||
* / further transformed.
|
|
||||||
*
|
|
||||||
* @author Nick Burch
|
|
||||||
* @since 3.4
|
|
||||||
*
|
|
||||||
* @deprecated The RenditionService is being replace by the simpler async RenditionService2.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class HTMLRenderingEngine extends AbstractRenderingEngine
|
|
||||||
{
|
|
||||||
private static Log logger = LogFactory.getLog(HTMLRenderingEngine.class);
|
|
||||||
private TikaConfig tikaConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This optional parameter, when set to true, causes only the
|
|
||||||
* contents of the HTML body to be written out as the rendition.
|
|
||||||
* By default, the whole of the HTML document is used.
|
|
||||||
*/
|
|
||||||
public static final String PARAM_BODY_CONTENTS_ONLY = "bodyContentsOnly";
|
|
||||||
/**
|
|
||||||
* This optional parameter, when set to true, causes any embedded
|
|
||||||
* images to be written into the same folder as the html, with
|
|
||||||
* a name prefix.
|
|
||||||
* By default, images are placed into a sub-folder.
|
|
||||||
*/
|
|
||||||
public static final String PARAM_IMAGES_SAME_FOLDER = "imagesSameFolder";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Action constants
|
|
||||||
*/
|
|
||||||
public static final String NAME = "htmlRenderingEngine";
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Collection<ParameterDefinition> getParameterDefinitions() {
|
|
||||||
Collection<ParameterDefinition> paramList = super.getParameterDefinitions();
|
|
||||||
paramList.add(new ParameterDefinitionImpl(PARAM_BODY_CONTENTS_ONLY, DataTypeDefinition.BOOLEAN, false,
|
|
||||||
getParamDisplayLabel(PARAM_BODY_CONTENTS_ONLY)));
|
|
||||||
paramList.add(new ParameterDefinitionImpl(PARAM_IMAGES_SAME_FOLDER, DataTypeDefinition.BOOLEAN, false,
|
|
||||||
getParamDisplayLabel(PARAM_IMAGES_SAME_FOLDER)));
|
|
||||||
return paramList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injects the TikaConfig to use
|
|
||||||
*
|
|
||||||
* @param tikaConfig The Tika Config to use
|
|
||||||
*/
|
|
||||||
public void setTikaConfig(TikaConfig tikaConfig)
|
|
||||||
{
|
|
||||||
this.tikaConfig = tikaConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org.alfresco.repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void render(RenderingContext context)
|
|
||||||
{
|
|
||||||
ContentReader contentReader = context.makeContentReader();
|
|
||||||
String sourceMimeType = contentReader.getMimetype();
|
|
||||||
|
|
||||||
// Check that Tika supports the supplied file
|
|
||||||
AutoDetectParser p = new AutoDetectParser(tikaConfig);
|
|
||||||
MediaType sourceMediaType = MediaType.parse(sourceMimeType);
|
|
||||||
if(! p.getParsers().containsKey(sourceMediaType))
|
|
||||||
{
|
|
||||||
throw new RenditionServiceException(
|
|
||||||
"Source mime type of " + sourceMimeType +
|
|
||||||
" is not supported by Tika for HTML conversions"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the HTML Version using Tika
|
|
||||||
// This will also extract out any images as found
|
|
||||||
generateHTML(p, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getHtmlBaseName(RenderingContext context)
|
|
||||||
{
|
|
||||||
// Based on the name of the source node, which will
|
|
||||||
// also largely be the name of the html node
|
|
||||||
String baseName = nodeService.getProperty(
|
|
||||||
context.getSourceNode(),
|
|
||||||
ContentModel.PROP_NAME
|
|
||||||
).toString();
|
|
||||||
if(baseName.lastIndexOf('.') > -1)
|
|
||||||
{
|
|
||||||
baseName = baseName.substring(0, baseName.lastIndexOf('.'));
|
|
||||||
}
|
|
||||||
return baseName;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* What name should be used for the images directory?
|
|
||||||
* Note this is only required if {@link #PARAM_IMAGES_SAME_FOLDER} is false (the default).
|
|
||||||
*/
|
|
||||||
private String getImagesDirectoryName(RenderingContext context)
|
|
||||||
{
|
|
||||||
// Based on the name of the source node, which will
|
|
||||||
// also largely be the name of the html node
|
|
||||||
String folderName = getHtmlBaseName(context);
|
|
||||||
folderName = folderName + "_files";
|
|
||||||
return folderName;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* What prefix should be applied to the name of images?
|
|
||||||
*/
|
|
||||||
private String getImagesPrefixName(RenderingContext context)
|
|
||||||
{
|
|
||||||
if( context.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false) )
|
|
||||||
{
|
|
||||||
// Prefix with the name of the source node
|
|
||||||
return getHtmlBaseName(context) + "_";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// They have their own folder, so no prefix is needed
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a directory to store the images in.
|
|
||||||
* The directory will be a sibling of the rendered
|
|
||||||
* HTML, and named similar to it.
|
|
||||||
* Note this is only required if {@link #PARAM_IMAGES_SAME_FOLDER} is false (the default).
|
|
||||||
*/
|
|
||||||
private NodeRef createImagesDirectory(RenderingContext context)
|
|
||||||
{
|
|
||||||
// It should be a sibling of the HTML in it's eventual location
|
|
||||||
// (not it's current temporary one!)
|
|
||||||
RenditionLocation location = resolveRenditionLocation(
|
|
||||||
context.getSourceNode(), context.getDefinition(), context.getDestinationNode()
|
|
||||||
);
|
|
||||||
NodeRef parent = location.getParentRef();
|
|
||||||
|
|
||||||
// Figure out what to call it, based on the HTML node
|
|
||||||
String folderName = getImagesDirectoryName(context);
|
|
||||||
|
|
||||||
// It is already there?
|
|
||||||
// (eg from when the rendition is being re-run)
|
|
||||||
NodeRef imgFolder = nodeService.getChildByName(
|
|
||||||
parent, ContentModel.ASSOC_CONTAINS, folderName
|
|
||||||
);
|
|
||||||
if(imgFolder != null)
|
|
||||||
return imgFolder;
|
|
||||||
|
|
||||||
// Create the directory
|
|
||||||
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
|
|
||||||
properties.put(ContentModel.PROP_NAME, folderName);
|
|
||||||
imgFolder = nodeService.createNode(
|
|
||||||
parent,
|
|
||||||
ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName(folderName),
|
|
||||||
ContentModel.TYPE_FOLDER,
|
|
||||||
properties
|
|
||||||
).getChildRef();
|
|
||||||
|
|
||||||
return imgFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NodeRef createEmbeddedImage(NodeRef imgFolder, boolean primary,
|
|
||||||
String filename, String contentType, InputStream imageSource,
|
|
||||||
RenderingContext context)
|
|
||||||
{
|
|
||||||
// Create the node if needed
|
|
||||||
NodeRef img = nodeService.getChildByName(
|
|
||||||
imgFolder, ContentModel.ASSOC_CONTAINS, filename
|
|
||||||
);
|
|
||||||
if(img == null)
|
|
||||||
{
|
|
||||||
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
|
|
||||||
properties.put(ContentModel.PROP_NAME, filename);
|
|
||||||
img = nodeService.createNode(
|
|
||||||
imgFolder,
|
|
||||||
ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName(filename),
|
|
||||||
ContentModel.TYPE_CONTENT,
|
|
||||||
properties
|
|
||||||
).getChildRef();
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Image node created: " + img);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Once composite content is properly supported,
|
|
||||||
// at this point we'll associate the new image with
|
|
||||||
// the rendered HTML node so the dependency is tracked.
|
|
||||||
|
|
||||||
// Put the image into the node
|
|
||||||
ContentWriter writer = contentService.getWriter(
|
|
||||||
img, ContentModel.PROP_CONTENT, true
|
|
||||||
);
|
|
||||||
writer.setMimetype(contentType);
|
|
||||||
writer.putContent(imageSource);
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Image content written into " + img);
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a Tika-compatible SAX content handler, which will
|
|
||||||
* be used to generate+capture the XHTML
|
|
||||||
*/
|
|
||||||
private ContentHandler buildContentHandler(Writer output, RenderingContext context)
|
|
||||||
{
|
|
||||||
// Create the main transformer
|
|
||||||
SAXTransformerFactory factory = (SAXTransformerFactory)
|
|
||||||
SAXTransformerFactory.newInstance();
|
|
||||||
TransformerHandler handler;
|
|
||||||
|
|
||||||
try {
|
|
||||||
handler = factory.newTransformerHandler();
|
|
||||||
} catch (TransformerConfigurationException e) {
|
|
||||||
throw new RenditionServiceException("SAX Processing isn't available - " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
|
|
||||||
handler.setResult(new StreamResult(output));
|
|
||||||
handler.getTransformer().setOutputProperty(OutputKeys.METHOD, "xml");
|
|
||||||
|
|
||||||
// Change the image links as they go past
|
|
||||||
String dirName = null, imgPrefix = null;
|
|
||||||
if(context.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false))
|
|
||||||
{
|
|
||||||
imgPrefix = getImagesPrefixName(context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dirName = getImagesDirectoryName(context);
|
|
||||||
}
|
|
||||||
ContentHandler contentHandler = new TikaImageRewritingContentHandler(
|
|
||||||
handler, dirName, imgPrefix
|
|
||||||
);
|
|
||||||
|
|
||||||
// If required, wrap it to only return the body
|
|
||||||
boolean bodyOnly = context.getParamWithDefault(PARAM_BODY_CONTENTS_ONLY, false);
|
|
||||||
if(bodyOnly) {
|
|
||||||
contentHandler = new BodyContentHandler(contentHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done
|
|
||||||
return contentHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks Tika to translate the contents into HTML
|
|
||||||
*/
|
|
||||||
private void generateHTML(Parser p, RenderingContext context)
|
|
||||||
{
|
|
||||||
ContentReader contentReader = context.makeContentReader();
|
|
||||||
|
|
||||||
// Setup things to parse with
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
ContentHandler handler = buildContentHandler(sw, context);
|
|
||||||
|
|
||||||
// Tell Tika what we're dealing with
|
|
||||||
Metadata metadata = new Metadata();
|
|
||||||
metadata.set(
|
|
||||||
Metadata.CONTENT_TYPE,
|
|
||||||
contentReader.getMimetype()
|
|
||||||
);
|
|
||||||
metadata.set(
|
|
||||||
Metadata.RESOURCE_NAME_KEY,
|
|
||||||
nodeService.getProperty(
|
|
||||||
context.getSourceNode(),
|
|
||||||
ContentModel.PROP_NAME
|
|
||||||
).toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Our parse context needs to extract images
|
|
||||||
ParseContext parseContext = new ParseContext();
|
|
||||||
parseContext.set(Parser.class, new TikaImageExtractingParser(context));
|
|
||||||
|
|
||||||
// Parse
|
|
||||||
try {
|
|
||||||
p.parse(
|
|
||||||
contentReader.getContentInputStream(),
|
|
||||||
handler, metadata, parseContext
|
|
||||||
);
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new RenditionServiceException("Tika HTML Conversion Failed", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// As a string
|
|
||||||
String html = sw.toString();
|
|
||||||
|
|
||||||
// If we're doing body-only, remove all the html namespaces
|
|
||||||
// that will otherwise clutter up the document
|
|
||||||
boolean bodyOnly = context.getParamWithDefault(PARAM_BODY_CONTENTS_ONLY, false);
|
|
||||||
if(bodyOnly) {
|
|
||||||
html = html.replaceAll("<\\?xml.*?\\?>", "");
|
|
||||||
html = html.replaceAll("<p xmlns=\"http://www.w3.org/1999/xhtml\"","<p");
|
|
||||||
html = html.replaceAll("<h(\\d) xmlns=\"http://www.w3.org/1999/xhtml\"","<h\\1");
|
|
||||||
html = html.replaceAll("<div xmlns=\"http://www.w3.org/1999/xhtml\"","<div");
|
|
||||||
html = html.replaceAll("<table xmlns=\"http://www.w3.org/1999/xhtml\"","<table");
|
|
||||||
html = html.replaceAll(" ","");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save it
|
|
||||||
ContentWriter contentWriter = context.makeContentWriter();
|
|
||||||
contentWriter.setMimetype("text/html");
|
|
||||||
contentWriter.putContent( html );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A nested Tika parser which extracts out any
|
|
||||||
* images as they come past.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
private class TikaImageExtractingParser implements Parser {
|
|
||||||
private Set<MediaType> types;
|
|
||||||
|
|
||||||
private RenderingContext renderingContext;
|
|
||||||
private NodeRef imgFolder = null;
|
|
||||||
private int count = 0;
|
|
||||||
|
|
||||||
private TikaImageExtractingParser(RenderingContext renderingContext) {
|
|
||||||
this.renderingContext = renderingContext;
|
|
||||||
|
|
||||||
// Our expected types
|
|
||||||
types = new HashSet<MediaType>();
|
|
||||||
types.add(MediaType.image("bmp"));
|
|
||||||
types.add(MediaType.image("gif"));
|
|
||||||
types.add(MediaType.image("jpg"));
|
|
||||||
types.add(MediaType.image("jpeg"));
|
|
||||||
types.add(MediaType.image("png"));
|
|
||||||
types.add(MediaType.image("tiff"));
|
|
||||||
|
|
||||||
// Are images going in the same place as the HTML?
|
|
||||||
if( renderingContext.getParamWithDefault(PARAM_IMAGES_SAME_FOLDER, false) )
|
|
||||||
{
|
|
||||||
RenditionLocation location = resolveRenditionLocation(
|
|
||||||
renderingContext.getSourceNode(), renderingContext.getDefinition(),
|
|
||||||
renderingContext.getDestinationNode()
|
|
||||||
);
|
|
||||||
imgFolder = location.getParentRef();
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Using imgFolder: " + imgFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<MediaType> getSupportedTypes(ParseContext context) {
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void parse(InputStream stream, ContentHandler handler,
|
|
||||||
Metadata metadata, ParseContext context) throws IOException,
|
|
||||||
SAXException, TikaException {
|
|
||||||
// Is it a supported image?
|
|
||||||
String filename = metadata.get(Metadata.RESOURCE_NAME_KEY);
|
|
||||||
String type = metadata.get(Metadata.CONTENT_TYPE);
|
|
||||||
boolean accept = false;
|
|
||||||
|
|
||||||
if(type != null) {
|
|
||||||
for(MediaType mt : types) {
|
|
||||||
if(mt.toString().equals(type)) {
|
|
||||||
accept = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(filename != null) {
|
|
||||||
for(MediaType mt : types) {
|
|
||||||
String ext = "." + mt.getSubtype();
|
|
||||||
if(filename.endsWith(ext)) {
|
|
||||||
accept = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!accept)
|
|
||||||
return;
|
|
||||||
|
|
||||||
handleImage(stream, filename, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleImage(InputStream stream, String filename, String type) {
|
|
||||||
count++;
|
|
||||||
|
|
||||||
// Do we already have the folder? If not, create it
|
|
||||||
if(imgFolder == null) {
|
|
||||||
imgFolder = createImagesDirectory(renderingContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give it a sensible name if needed
|
|
||||||
if(filename == null) {
|
|
||||||
filename = "image-" + count + ".";
|
|
||||||
filename += type.substring(type.indexOf('/')+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefix the filename if needed
|
|
||||||
filename = getImagesPrefixName(renderingContext) + filename;
|
|
||||||
|
|
||||||
// Save the image
|
|
||||||
createEmbeddedImage(imgFolder, (count==1), filename, type, stream, renderingContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A content handler that re-writes image src attributes,
|
|
||||||
* and passes everything else on to the real one.
|
|
||||||
*/
|
|
||||||
private class TikaImageRewritingContentHandler extends ContentHandlerDecorator {
|
|
||||||
private String imageFolder;
|
|
||||||
private String imagePrefix;
|
|
||||||
|
|
||||||
private TikaImageRewritingContentHandler(ContentHandler handler, String imageFolder, String imagePrefix) {
|
|
||||||
super(handler);
|
|
||||||
this.imageFolder = imageFolder;
|
|
||||||
this.imagePrefix = imagePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startElement(String uri, String localName, String qName,
|
|
||||||
Attributes origAttrs) throws SAXException {
|
|
||||||
// If we have an image tag, re-write the src attribute
|
|
||||||
// if required
|
|
||||||
if("img".equals(localName)) {
|
|
||||||
AttributesImpl attrs;
|
|
||||||
if(origAttrs instanceof AttributesImpl) {
|
|
||||||
attrs = (AttributesImpl)origAttrs;
|
|
||||||
} else {
|
|
||||||
attrs = new AttributesImpl(origAttrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i<attrs.getLength(); i++) {
|
|
||||||
if("src".equals(attrs.getLocalName(i))) {
|
|
||||||
String src = attrs.getValue(i);
|
|
||||||
if(src.startsWith("embedded:")) {
|
|
||||||
String newSrc = "";
|
|
||||||
if(imageFolder != null)
|
|
||||||
newSrc += imageFolder + "/";
|
|
||||||
if(imagePrefix != null)
|
|
||||||
newSrc += imagePrefix;
|
|
||||||
newSrc += src.substring(src.indexOf(':')+1);
|
|
||||||
attrs.setValue(i, newSrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.startElement(uri, localName, qName, attrs);
|
|
||||||
} else {
|
|
||||||
// For any other tag, pass through as-is
|
|
||||||
super.startElement(uri, localName, qName, origAttrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -178,14 +178,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="htmlRenderingEngine"
|
|
||||||
class="org.alfresco.repo.rendition.executer.HTMLRenderingEngine"
|
|
||||||
parent="baseRenderingAction">
|
|
||||||
<property name="tikaConfig">
|
|
||||||
<ref bean="tikaConfig"/>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="compositeRenderingEngine"
|
<bean id="compositeRenderingEngine"
|
||||||
class="org.alfresco.repo.rendition.executer.CompositeRenderingEngine"
|
class="org.alfresco.repo.rendition.executer.CompositeRenderingEngine"
|
||||||
parent="baseRenderingAction">
|
parent="baseRenderingAction">
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
@@ -39,7 +39,7 @@ import org.junit.runners.Suite;
|
|||||||
@RunWith(Categories.class)
|
@RunWith(Categories.class)
|
||||||
@Categories.ExcludeCategory({DBTests.class, NonBuildTests.class})
|
@Categories.ExcludeCategory({DBTests.class, NonBuildTests.class})
|
||||||
@Suite.SuiteClasses({
|
@Suite.SuiteClasses({
|
||||||
|
|
||||||
// there is a test that runs for 184s and another one that runs for 40s
|
// there is a test that runs for 184s and another one that runs for 40s
|
||||||
org.alfresco.repo.attributes.AttributeServiceTest.class,
|
org.alfresco.repo.attributes.AttributeServiceTest.class,
|
||||||
|
|
||||||
@@ -66,7 +66,9 @@ import org.junit.runners.Suite;
|
|||||||
org.alfresco.repo.content.RoutingContentStoreTest.class,
|
org.alfresco.repo.content.RoutingContentStoreTest.class,
|
||||||
|
|
||||||
org.alfresco.encryption.EncryptionTests.class,
|
org.alfresco.encryption.EncryptionTests.class,
|
||||||
org.alfresco.encryption.KeyStoreTests.class
|
org.alfresco.encryption.KeyStoreTests.class,
|
||||||
|
|
||||||
|
org.alfresco.repo.content.MimetypeMapContentTest.class
|
||||||
|
|
||||||
// TODO REPO-2791 org.alfresco.repo.content.routing.StoreSelectorAspectContentStoreTest.class,
|
// TODO REPO-2791 org.alfresco.repo.content.routing.StoreSelectorAspectContentStoreTest.class,
|
||||||
})
|
})
|
||||||
|
@@ -56,7 +56,6 @@ import org.junit.runners.Suite;
|
|||||||
// This test opens, closes and again opens the alfresco application context.
|
// This test opens, closes and again opens the alfresco application context.
|
||||||
org.alfresco.repo.dictionary.CustomModelRepoRestartTest.class,
|
org.alfresco.repo.dictionary.CustomModelRepoRestartTest.class,
|
||||||
|
|
||||||
org.alfresco.repo.rendition.executer.HTMLRenderingEngineTest.class,
|
|
||||||
org.alfresco.repo.rendition.executer.XSLTFunctionsTest.class,
|
org.alfresco.repo.rendition.executer.XSLTFunctionsTest.class,
|
||||||
org.alfresco.repo.rendition.executer.XSLTRenderingEngineTest.class,
|
org.alfresco.repo.rendition.executer.XSLTRenderingEngineTest.class,
|
||||||
org.alfresco.repo.replication.ReplicationServiceIntegrationTest.class,
|
org.alfresco.repo.replication.ReplicationServiceIntegrationTest.class,
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
@@ -36,8 +36,7 @@ import org.alfresco.repo.content.filestore.FileContentReader;
|
|||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
import org.alfresco.test_category.OwnJVMTestsCategory;
|
||||||
import org.alfresco.util.DataModelTestApplicationContextHelper;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
import org.alfresco.util.testing.category.NeverRunsTests;
|
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.junit.experimental.categories.Category;
|
import org.junit.experimental.categories.Category;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
@@ -48,11 +47,11 @@ import org.springframework.context.ApplicationContext;
|
|||||||
* @see org.alfresco.repo.content.MimetypeMap
|
* @see org.alfresco.repo.content.MimetypeMap
|
||||||
* @see org.alfresco.repo.content.MimetypeMapTest
|
* @see org.alfresco.repo.content.MimetypeMapTest
|
||||||
*/
|
*/
|
||||||
@Category({OwnJVMTestsCategory.class, NeverRunsTests.class})
|
@Category({OwnJVMTestsCategory.class})
|
||||||
public class MimetypeMapContentTest extends TestCase
|
public class MimetypeMapContentTest extends TestCase
|
||||||
{
|
{
|
||||||
private static ApplicationContext ctx = DataModelTestApplicationContextHelper.getApplicationContext();
|
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
|
|
||||||
private MimetypeService mimetypeService;
|
private MimetypeService mimetypeService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -61,6 +60,18 @@ public class MimetypeMapContentTest extends TestCase
|
|||||||
mimetypeService = (MimetypeService)ctx.getBean("mimetypeService");
|
mimetypeService = (MimetypeService)ctx.getBean("mimetypeService");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGuessPdfMimetype() throws Exception
|
||||||
|
{
|
||||||
|
assertEquals(
|
||||||
|
"application/pdf",
|
||||||
|
mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.pdf"))
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
"application/pdf",
|
||||||
|
mimetypeService.guessMimetype(null, openQuickTestFile("quick.pdf"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void testGuessMimetypeForFile() throws Exception
|
public void testGuessMimetypeForFile() throws Exception
|
||||||
{
|
{
|
||||||
// Correct ones
|
// Correct ones
|
||||||
@@ -78,11 +89,7 @@ public class MimetypeMapContentTest extends TestCase
|
|||||||
"application/msword",
|
"application/msword",
|
||||||
mimetypeService.guessMimetype("something.pdf", openQuickTestFile("quick.doc"))
|
mimetypeService.guessMimetype("something.pdf", openQuickTestFile("quick.doc"))
|
||||||
);
|
);
|
||||||
assertEquals(
|
|
||||||
"application/pdf",
|
|
||||||
mimetypeService.guessMimetype("something.doc", openQuickTestFile("quick.pdf"))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ones where we use a different mimetype to the canonical one
|
// Ones where we use a different mimetype to the canonical one
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"image/bmp", // Officially image/x-ms-bmp
|
"image/bmp", // Officially image/x-ms-bmp
|
||||||
@@ -94,13 +101,15 @@ public class MimetypeMapContentTest extends TestCase
|
|||||||
"application/dita+xml", // Full version: application/dita+xml;format=concept
|
"application/dita+xml", // Full version: application/dita+xml;format=concept
|
||||||
mimetypeService.guessMimetype("concept.dita", openQuickTestFile("quickConcept.dita"))
|
mimetypeService.guessMimetype("concept.dita", openQuickTestFile("quickConcept.dita"))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alfresco Specific ones, that Tika doesn't know about
|
|
||||||
assertEquals(
|
|
||||||
"application/acp",
|
|
||||||
mimetypeService.guessMimetype("something.acp", openQuickTestFile("quick.acp"))
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Commented out when the test class was reintroduced after many years of not being run. Failed as the type was
|
||||||
|
// identified as a zip. Reintroduced to check guessMimetype works without pdfbox libraries.
|
||||||
|
//
|
||||||
|
// // Alfresco Specific ones, that Tika doesn't know about
|
||||||
|
// assertEquals(
|
||||||
|
// "application/acp",
|
||||||
|
// mimetypeService.guessMimetype("something.acp", openQuickTestFile("quick.acp"))
|
||||||
|
// );
|
||||||
|
|
||||||
// Where the file is corrupted
|
// Where the file is corrupted
|
||||||
File tmp = File.createTempFile("alfresco", ".tmp");
|
File tmp = File.createTempFile("alfresco", ".tmp");
|
||||||
@@ -121,12 +130,15 @@ public class MimetypeMapContentTest extends TestCase
|
|||||||
"application/x-tika-msoffice",
|
"application/x-tika-msoffice",
|
||||||
mimetypeService.guessMimetype(null, truncReader)
|
mimetypeService.guessMimetype(null, truncReader)
|
||||||
);
|
);
|
||||||
// But with the filename it'll be able to use the .doc extension
|
// Commented out when the test class was reintroduced after many years of not being run. Failed to open a
|
||||||
// to guess at it being a .Doc file
|
// stream onto the channel. Reintroduced to check guessMimetype works without pdfbox libraries.
|
||||||
assertEquals(
|
//
|
||||||
"application/msword",
|
// // But with the filename it'll be able to use the .doc extension
|
||||||
mimetypeService.guessMimetype("something.doc", truncReader)
|
// // to guess at it being a .Doc file
|
||||||
);
|
// assertEquals(
|
||||||
|
// "application/msword",
|
||||||
|
// mimetypeService.guessMimetype("something.doc", truncReader)
|
||||||
|
// );
|
||||||
|
|
||||||
// Lotus notes EML files (ALF-16381 / TIKA-1042)
|
// Lotus notes EML files (ALF-16381 / TIKA-1042)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@@ -1,31 +1,30 @@
|
|||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
* Copyright (C) 2005 - 2021 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
* provided under the following open source license terms:
|
* provided under the following open source license terms:
|
||||||
*
|
*
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.rendition;
|
package org.alfresco.repo.rendition;
|
||||||
|
|
||||||
import org.alfresco.repo.rendition.executer.HTMLRenderingEngineTest;
|
|
||||||
import org.alfresco.repo.thumbnail.ThumbnailServiceImplParameterTest;
|
import org.alfresco.repo.thumbnail.ThumbnailServiceImplParameterTest;
|
||||||
import org.alfresco.repo.thumbnail.ThumbnailServiceImplTest;
|
import org.alfresco.repo.thumbnail.ThumbnailServiceImplTest;
|
||||||
import org.alfresco.repo.thumbnail.conditions.NodeEligibleForRethumbnailingEvaluatorTest;
|
import org.alfresco.repo.thumbnail.conditions.NodeEligibleForRethumbnailingEvaluatorTest;
|
||||||
@@ -49,7 +48,6 @@ import org.junit.runners.Suite;
|
|||||||
RenditionServiceIntegrationTest.class,
|
RenditionServiceIntegrationTest.class,
|
||||||
RenditionServicePermissionsTest.class,
|
RenditionServicePermissionsTest.class,
|
||||||
RenditionNodeManagerTest.class,
|
RenditionNodeManagerTest.class,
|
||||||
HTMLRenderingEngineTest.class,
|
|
||||||
MultiUserRenditionTest.class
|
MultiUserRenditionTest.class
|
||||||
})
|
})
|
||||||
public class AllRenditionTests
|
public class AllRenditionTests
|
||||||
|
@@ -1,543 +0,0 @@
|
|||||||
/*
|
|
||||||
* #%L
|
|
||||||
* Alfresco Repository
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
|
||||||
* %%
|
|
||||||
* This file is part of the Alfresco software.
|
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
|
||||||
* provided under the following open source license terms:
|
|
||||||
*
|
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Alfresco 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.alfresco.repo.rendition.executer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
|
|
||||||
import org.alfresco.repo.model.Repository;
|
|
||||||
import org.alfresco.repo.rendition.RenditionDefinitionPersisterImpl;
|
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
|
||||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
|
||||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentService;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.namespace.QName;
|
|
||||||
import org.alfresco.test_category.BaseSpringTestsCategory;
|
|
||||||
import org.alfresco.test_category.OwnJVMTestsCategory;
|
|
||||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.experimental.categories.Category;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit tests for the HTML Rendering Engine
|
|
||||||
*
|
|
||||||
* @author Nick Burch
|
|
||||||
*
|
|
||||||
* @deprecated We are introducing the new async RenditionService2.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@Category(BaseSpringTestsCategory.class)
|
|
||||||
@Transactional
|
|
||||||
public class HTMLRenderingEngineTest extends BaseAlfrescoSpringTest
|
|
||||||
{
|
|
||||||
private final static Log log = LogFactory.getLog(HTMLRenderingEngineTest.class);
|
|
||||||
private NodeRef companyHome;
|
|
||||||
private DictionaryService dictionaryService;
|
|
||||||
private RenditionService renditionService;
|
|
||||||
private Repository repositoryHelper;
|
|
||||||
|
|
||||||
private NodeRef sourceDoc;
|
|
||||||
private NodeRef targetFolder;
|
|
||||||
private String targetFolderPath;
|
|
||||||
|
|
||||||
private RenditionDefinition def;
|
|
||||||
|
|
||||||
private static final String MIMETYPE_DOC = "application/msword";
|
|
||||||
private static final String MIMETYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() throws Exception
|
|
||||||
{
|
|
||||||
super.before();
|
|
||||||
this.nodeService = (NodeService) this.applicationContext.getBean("NodeService");
|
|
||||||
this.contentService = (ContentService) this.applicationContext.getBean("ContentService");
|
|
||||||
this.renditionService = (RenditionService) this.applicationContext.getBean("RenditionService");
|
|
||||||
this.repositoryHelper = (Repository) this.applicationContext.getBean("repositoryHelper");
|
|
||||||
this.dictionaryService = (DictionaryService) this.applicationContext.getBean("dictionaryService");
|
|
||||||
this.companyHome = repositoryHelper.getCompanyHome();
|
|
||||||
|
|
||||||
createTargetFolder();
|
|
||||||
|
|
||||||
// Setup the basic rendition definition
|
|
||||||
QName renditionName = QName.createQName("Test");
|
|
||||||
RenditionDefinition rd = renditionService.loadRenditionDefinition(renditionName);
|
|
||||||
if(rd != null)
|
|
||||||
{
|
|
||||||
RenditionDefinitionPersisterImpl rdp = new RenditionDefinitionPersisterImpl();
|
|
||||||
rdp.setNodeService(nodeService);
|
|
||||||
rdp.deleteRenditionDefinition(rd);
|
|
||||||
}
|
|
||||||
def = renditionService.createRenditionDefinition(renditionName, HTMLRenderingEngine.NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() throws Exception
|
|
||||||
{
|
|
||||||
super.after();
|
|
||||||
|
|
||||||
tidyUpSourceDoc();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createTargetFolder()
|
|
||||||
{
|
|
||||||
// Set the current security context as admin
|
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
|
||||||
|
|
||||||
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
|
|
||||||
properties.put(ContentModel.PROP_NAME, "TestFolder");
|
|
||||||
targetFolder = nodeService.createNode(
|
|
||||||
companyHome, ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName("TestFolder"),
|
|
||||||
ContentModel.TYPE_FOLDER,
|
|
||||||
properties
|
|
||||||
).getChildRef();
|
|
||||||
|
|
||||||
targetFolderPath = "/" +
|
|
||||||
(String) nodeService.getProperty(companyHome, ContentModel.PROP_NAME) +
|
|
||||||
"/" +
|
|
||||||
(String) nodeService.getProperty(targetFolder, ContentModel.PROP_NAME)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
private void tidyUpSourceDoc()
|
|
||||||
{
|
|
||||||
// Set the current security context as admin
|
|
||||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
|
||||||
|
|
||||||
// Clean up the source
|
|
||||||
if(sourceDoc != null)
|
|
||||||
{
|
|
||||||
nodeService.deleteNode(sourceDoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the target folder
|
|
||||||
nodeService.deleteNode(targetFolder);
|
|
||||||
targetFolder = null;
|
|
||||||
|
|
||||||
// All done
|
|
||||||
sourceDoc = null;
|
|
||||||
createTargetFolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
private NodeRef createForDoc(String docname) throws IOException
|
|
||||||
{
|
|
||||||
// Create the node
|
|
||||||
Map<QName,Serializable> properties = new HashMap<QName,Serializable>();
|
|
||||||
properties.put(ContentModel.PROP_NAME, docname);
|
|
||||||
|
|
||||||
NodeRef node = nodeService.createNode(
|
|
||||||
companyHome, ContentModel.ASSOC_CONTAINS,
|
|
||||||
QName.createQName(docname),
|
|
||||||
ContentModel.TYPE_CONTENT,
|
|
||||||
properties
|
|
||||||
).getChildRef();
|
|
||||||
|
|
||||||
// Put the sample doc into it
|
|
||||||
File f = AbstractContentTransformerTest.loadNamedQuickTestFile(docname);
|
|
||||||
if(f == null) {
|
|
||||||
fail("Unable to find test file for " + docname);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentWriter writer = contentService.getWriter(
|
|
||||||
node, ContentModel.PROP_CONTENT, true
|
|
||||||
);
|
|
||||||
if(docname.endsWith(".doc")) {
|
|
||||||
writer.setMimetype(MIMETYPE_DOC);
|
|
||||||
}
|
|
||||||
if(docname.endsWith(".docx")) {
|
|
||||||
writer.setMimetype(MIMETYPE_DOCX);
|
|
||||||
}
|
|
||||||
writer.putContent(f);
|
|
||||||
|
|
||||||
if (log.isDebugEnabled())
|
|
||||||
{
|
|
||||||
log.debug("Created document with name: " + docname + ", nodeRef: " + node + ", mimetype: " + writer.getMimetype());
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBasics() throws Exception
|
|
||||||
{
|
|
||||||
def.setParameterValue(
|
|
||||||
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
|
|
||||||
targetFolderPath + "/${name}.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
sourceDoc = createForDoc("quick.doc");
|
|
||||||
|
|
||||||
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
|
|
||||||
assertNotNull(rendition);
|
|
||||||
|
|
||||||
// Check it was created
|
|
||||||
NodeRef htmlNode = rendition.getChildRef();
|
|
||||||
assertEquals(true, nodeService.exists(htmlNode));
|
|
||||||
|
|
||||||
// Check it got the right name
|
|
||||||
assertEquals(
|
|
||||||
"quick.html",
|
|
||||||
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it got the right contents
|
|
||||||
ContentReader reader = contentService.getReader(
|
|
||||||
htmlNode, ContentModel.PROP_CONTENT
|
|
||||||
);
|
|
||||||
String html = reader.getContentString();
|
|
||||||
assertEquals("<?xml", html.substring(0, 5));
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("<html"));
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("<head>"));
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("<body>"));
|
|
||||||
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("<p>The quick brown fox"));
|
|
||||||
|
|
||||||
|
|
||||||
// Now do a body-only one, check that we still got the
|
|
||||||
// contents, but not the html surround
|
|
||||||
def.setParameterValue(
|
|
||||||
HTMLRenderingEngine.PARAM_BODY_CONTENTS_ONLY, Boolean.TRUE
|
|
||||||
);
|
|
||||||
rendition = renditionService.render(sourceDoc, def);
|
|
||||||
assertNotNull(rendition);
|
|
||||||
|
|
||||||
htmlNode = rendition.getChildRef();
|
|
||||||
assertEquals(true, nodeService.exists(htmlNode));
|
|
||||||
|
|
||||||
reader = contentService.getReader(
|
|
||||||
htmlNode, ContentModel.PROP_CONTENT
|
|
||||||
);
|
|
||||||
html = reader.getContentString();
|
|
||||||
assertFalse("Body wrong:\n"+html, html.contains("<?xml"));
|
|
||||||
assertFalse("Body wrong:\n"+html, html.contains("<html"));
|
|
||||||
assertFalse("Body wrong:\n"+html, html.contains("<head>"));
|
|
||||||
assertFalse("Body wrong:\n"+html, html.contains("<body>"));
|
|
||||||
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("<p>The quick brown fox"));
|
|
||||||
assertTrue("HTML wrong:\n"+html, html.contains("</p>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for a .doc and a .docx, neither of which have images
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDocWithoutImages() throws Exception
|
|
||||||
{
|
|
||||||
def.setParameterValue(
|
|
||||||
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
|
|
||||||
targetFolderPath + "/${name}.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
for(String name : new String[] {"quick.doc","quick.docx"})
|
|
||||||
{
|
|
||||||
sourceDoc = createForDoc(name);
|
|
||||||
|
|
||||||
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
|
|
||||||
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
|
|
||||||
assertNotNull(rendition);
|
|
||||||
|
|
||||||
// Check it was created
|
|
||||||
NodeRef htmlNode = rendition.getChildRef();
|
|
||||||
assertEquals(true, nodeService.exists(htmlNode));
|
|
||||||
|
|
||||||
// Check it got the right name
|
|
||||||
assertEquals(
|
|
||||||
name.substring(0, name.lastIndexOf('.')) + ".html",
|
|
||||||
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it ended up in the right place
|
|
||||||
assertEquals(
|
|
||||||
"Should have been in " + targetFolderPath + " but was in" +
|
|
||||||
nodeService.getPath(htmlNode),
|
|
||||||
targetFolder,
|
|
||||||
nodeService.getPrimaryParent(htmlNode).getParentRef()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it got the right contents
|
|
||||||
ContentReader reader = contentService.getReader(
|
|
||||||
htmlNode, ContentModel.PROP_CONTENT
|
|
||||||
);
|
|
||||||
String html = reader.getContentString();
|
|
||||||
assertEquals("<?xml", html.substring(0, 5));
|
|
||||||
|
|
||||||
// Check we didn't get an image folder, only the html
|
|
||||||
int numItems = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
assertEquals(numItemsStart+1, numItems);
|
|
||||||
|
|
||||||
// Check that the html lacks img tags
|
|
||||||
assertEquals(
|
|
||||||
"Unexpected img tag in html:\n" + html,
|
|
||||||
false, html.contains("<img")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check we didn't get any images
|
|
||||||
for(ChildAssociationRef ref : nodeService.getChildAssocs(htmlNode))
|
|
||||||
{
|
|
||||||
// TODO Check against composite content associations when present
|
|
||||||
// if(ref.getTypeQName().equals(HTMLRenderingEngine.PRIMARY_IMAGE))
|
|
||||||
// fail("Found unexpected primary image of rendered html");
|
|
||||||
// if(ref.getTypeQName().equals(HTMLRenderingEngine.SECONDARY_IMAGE))
|
|
||||||
// fail("Found unexpected secondary image of rendered html");
|
|
||||||
}
|
|
||||||
|
|
||||||
// All done
|
|
||||||
tidyUpSourceDoc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for a .doc and a .docx, both of which have
|
|
||||||
* images in them
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDocWithImages() throws Exception
|
|
||||||
{
|
|
||||||
def.setParameterValue(
|
|
||||||
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
|
|
||||||
targetFolderPath + "/${name}.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
String[] files = new String[] {"quickImg1.doc","quickImg1.docx", "quickImg3.doc","quickImg3.docx"};
|
|
||||||
int[] imgCounts = new int[] {1,1, 3,3};
|
|
||||||
|
|
||||||
for(int i=0; i<files.length; i++)
|
|
||||||
{
|
|
||||||
String name = files[i];
|
|
||||||
sourceDoc = createForDoc(name);
|
|
||||||
|
|
||||||
String baseName = name.substring(0, name.lastIndexOf('.'));
|
|
||||||
|
|
||||||
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
|
|
||||||
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
|
|
||||||
assertNotNull(rendition);
|
|
||||||
|
|
||||||
// Check it was created
|
|
||||||
NodeRef htmlNode = rendition.getChildRef();
|
|
||||||
assertEquals(true, nodeService.exists(htmlNode));
|
|
||||||
|
|
||||||
// Check it got the right name
|
|
||||||
assertEquals(
|
|
||||||
baseName + ".html",
|
|
||||||
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it ended up in the right place
|
|
||||||
assertEquals(
|
|
||||||
"Should have been in " + targetFolderPath + " but was in" +
|
|
||||||
nodeService.getPath(htmlNode),
|
|
||||||
targetFolder,
|
|
||||||
nodeService.getPrimaryParent(htmlNode).getParentRef()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it got the right contents
|
|
||||||
ContentReader reader = contentService.getReader(
|
|
||||||
htmlNode, ContentModel.PROP_CONTENT
|
|
||||||
);
|
|
||||||
String html = reader.getContentString();
|
|
||||||
assertEquals("<?xml", html.substring(0, 5));
|
|
||||||
|
|
||||||
// Check that the html has the img tags
|
|
||||||
assertEquals(
|
|
||||||
"Couldn't find img tag in html:\n" + html,
|
|
||||||
true, html.contains("<img")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check that it has the right img src
|
|
||||||
String expSource = "src=\""+ baseName + "_files" + "/image";
|
|
||||||
assertEquals(
|
|
||||||
"Couldn't find correct img src in html:\n" + expSource + "\n" + html,
|
|
||||||
true, html.contains(expSource)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check we got an image folder
|
|
||||||
int numItems = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
assertEquals(numItemsStart+2, numItems);
|
|
||||||
|
|
||||||
// Check the name of the image folder
|
|
||||||
NodeRef imgFolder = null;
|
|
||||||
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
|
|
||||||
if(nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME).equals(
|
|
||||||
baseName + "_files"
|
|
||||||
)) {
|
|
||||||
imgFolder = ref.getChildRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertNotNull("Couldn't find new folder named " + baseName + "_files", imgFolder);
|
|
||||||
|
|
||||||
// Check the contents
|
|
||||||
assertEquals(imgCounts[i], nodeService.getChildAssocs(imgFolder).size());
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Check against composite content associations when present
|
|
||||||
// Check the associations if supported
|
|
||||||
// if(dictionaryService.getAssociation(HTMLRenderingEngine.PRIMARY_IMAGE) != null)
|
|
||||||
// {
|
|
||||||
// boolean hasPrimary = false;
|
|
||||||
// boolean hasSecondary = false;
|
|
||||||
// for(ChildAssociationRef ref : nodeService.getChildAssocs(htmlNode))
|
|
||||||
// {
|
|
||||||
// if(ref.getTypeQName().equals(HTMLRenderingEngine.PRIMARY_IMAGE))
|
|
||||||
// hasPrimary = true;
|
|
||||||
// if(ref.getTypeQName().equals(HTMLRenderingEngine.SECONDARY_IMAGE))
|
|
||||||
// hasSecondary = true;
|
|
||||||
// }
|
|
||||||
// assertEquals(true, hasPrimary);
|
|
||||||
// assertEquals(false, hasSecondary);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// All done
|
|
||||||
tidyUpSourceDoc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for the option to have the images written to the
|
|
||||||
* same folder as the html, with a name prefix to them.
|
|
||||||
*
|
|
||||||
* TODO Re-enable when we've figured out why the rendition service sulkts
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testImagesSameFolder() throws Exception
|
|
||||||
{
|
|
||||||
def.setParameterValue(
|
|
||||||
RenditionService.PARAM_DESTINATION_PATH_TEMPLATE,
|
|
||||||
targetFolderPath + "/${name}.html"
|
|
||||||
);
|
|
||||||
def.setParameterValue(
|
|
||||||
HTMLRenderingEngine.PARAM_IMAGES_SAME_FOLDER,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// The documents listed below have 3 embedded images each.
|
|
||||||
final int expectedImageCount = 3;
|
|
||||||
for(String name : new String[] {"quickImg3.doc","quickImg3.docx"})
|
|
||||||
{
|
|
||||||
sourceDoc = createForDoc(name);
|
|
||||||
String baseName = name.substring(0, name.lastIndexOf('.'));
|
|
||||||
|
|
||||||
int numItemsStart = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
if (log.isDebugEnabled())
|
|
||||||
{
|
|
||||||
log.debug("targetFolder " + targetFolder + " has " + numItemsStart + " children at start.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ChildAssociationRef rendition = renditionService.render(sourceDoc, def);
|
|
||||||
assertNotNull(rendition);
|
|
||||||
|
|
||||||
// Check it was created
|
|
||||||
NodeRef htmlNode = rendition.getChildRef();
|
|
||||||
assertEquals(true, nodeService.exists(htmlNode));
|
|
||||||
|
|
||||||
// Check it got the right name
|
|
||||||
assertEquals(
|
|
||||||
baseName + ".html",
|
|
||||||
nodeService.getProperty(htmlNode, ContentModel.PROP_NAME)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it ended up in the right place
|
|
||||||
assertEquals(
|
|
||||||
"Should have been in " + targetFolderPath + " but was in" +
|
|
||||||
nodeService.getPath(htmlNode),
|
|
||||||
targetFolder,
|
|
||||||
nodeService.getPrimaryParent(htmlNode).getParentRef()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check it got the right contents
|
|
||||||
ContentReader reader = contentService.getReader(
|
|
||||||
htmlNode, ContentModel.PROP_CONTENT
|
|
||||||
);
|
|
||||||
String html = reader.getContentString();
|
|
||||||
assertEquals("<?xml", html.substring(0, 5));
|
|
||||||
|
|
||||||
// Check that the html has the img tags
|
|
||||||
assertEquals(
|
|
||||||
"Couldn't find img tag in html:\n" + html,
|
|
||||||
true, html.contains("<img")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check that it has the right img src
|
|
||||||
String expSource = "src=\""+ baseName + "_image";
|
|
||||||
assertEquals(
|
|
||||||
"Couldn't find correct img src in html:\n" + expSource + "\n" + html,
|
|
||||||
true, html.contains(expSource)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check we got an image folder
|
|
||||||
int numItems = nodeService.getChildAssocs(targetFolder).size();
|
|
||||||
|
|
||||||
// We expect a number of images and one text/html node to be created.
|
|
||||||
final int additionalItems = expectedImageCount + 1;
|
|
||||||
assertEquals(numItemsStart+additionalItems, numItems);
|
|
||||||
|
|
||||||
// There shouldn't be an image folder created
|
|
||||||
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
|
|
||||||
if(nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME).equals(
|
|
||||||
baseName + "_files"
|
|
||||||
)) {
|
|
||||||
fail("Image folder was created but shouldn't be there");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check we got the images in the same directory as the html
|
|
||||||
int images = 0;
|
|
||||||
for(ChildAssociationRef ref : nodeService.getChildAssocs(targetFolder)) {
|
|
||||||
String childName = (String)nodeService.getProperty(ref.getChildRef(), ContentModel.PROP_NAME);
|
|
||||||
if(childName.startsWith(baseName + "_image")) {
|
|
||||||
images++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertEquals(expectedImageCount, images);
|
|
||||||
|
|
||||||
// Until the rendition service supports a forced overwrite of other renditions, we must
|
|
||||||
// delete the old rendition node & the images.
|
|
||||||
nodeService.deleteNode(rendition.getChildRef());
|
|
||||||
for (ChildAssociationRef chAssRef : nodeService.getChildAssocs(targetFolder))
|
|
||||||
{
|
|
||||||
nodeService.deleteNode(chAssRef.getChildRef());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user