Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)

125605 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
      125498 slanglois: MNT-16155 Update source headers - remove svn:eol-style property on Java and JSP source files


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@125783 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Raluca Munteanu
2016-04-26 13:03:25 +00:00
parent 8674e2bfc8
commit dc6b2852d0
830 changed files with 142585 additions and 142585 deletions

View File

@@ -1,85 +1,85 @@
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.XMPDM;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.mp3.Mp3Parser;
/**
* Extracts the following values from MP3 files:
* <pre>
* <b>songTitle:</b> -- cm:title
* <b>albumTitle:</b> -- audio:album
* <b>artist:</b> -- audio:artist, cm:author
* <b>description:</b> -- cm:description
* <b>comment:</b> --
* <b>yearReleased:</b> -- audio:releaseDate
* <b>trackNumber:</b> -- audio:trackNumber
* <b>genre:</b> -- audio:genre
* <b>composer:</b> -- audio:composer
* <b>lyrics:</b> --
* </pre>
*
* Note - XMPDM metadata keys are also emitted, in common with
* the other Tika powered extracters
*
* Uses Apache Tika
*
* @author Nick Burch
*/
public class MP3MetadataExtracter extends TikaAudioMetadataExtracter
{
private static final String KEY_SONG_TITLE = "songTitle";
private static final String KEY_ALBUM_TITLE = "albumTitle";
private static final String KEY_ARTIST = "artist";
private static final String KEY_COMMENT = "comment";
private static final String KEY_YEAR_RELEASED = "yearReleased";
private static final String KEY_TRACK_NUMBER = "trackNumber";
private static final String KEY_GENRE = "genre";
private static final String KEY_COMPOSER = "composer";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] { MimetypeMap.MIMETYPE_MP3 },
new Mp3Parser()
);
public MP3MetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
return new Mp3Parser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String,String> headers)
{
// Do the normal Audio mappings
super.extractSpecific(metadata, properties, headers);
// Now do the compatibility ones
// We only need these for people who had pre-existing mapping
// properties from before the proper audio model was added
putRawValue(KEY_ALBUM_TITLE, metadata.get(XMPDM.ALBUM), properties);
putRawValue(KEY_SONG_TITLE, metadata.get(Metadata.TITLE), properties);
putRawValue(KEY_ARTIST, metadata.get(XMPDM.ARTIST), properties);
putRawValue(KEY_COMMENT, metadata.get(XMPDM.LOG_COMMENT), properties);
putRawValue(KEY_TRACK_NUMBER, metadata.get(XMPDM.TRACK_NUMBER), properties);
putRawValue(KEY_GENRE, metadata.get(XMPDM.GENRE), properties);
putRawValue(KEY_YEAR_RELEASED, metadata.get(XMPDM.RELEASE_DATE), properties);
putRawValue(KEY_COMPOSER, metadata.get(XMPDM.COMPOSER), properties);
// All done
return properties;
}
}
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.XMPDM;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.mp3.Mp3Parser;
/**
* Extracts the following values from MP3 files:
* <pre>
* <b>songTitle:</b> -- cm:title
* <b>albumTitle:</b> -- audio:album
* <b>artist:</b> -- audio:artist, cm:author
* <b>description:</b> -- cm:description
* <b>comment:</b> --
* <b>yearReleased:</b> -- audio:releaseDate
* <b>trackNumber:</b> -- audio:trackNumber
* <b>genre:</b> -- audio:genre
* <b>composer:</b> -- audio:composer
* <b>lyrics:</b> --
* </pre>
*
* Note - XMPDM metadata keys are also emitted, in common with
* the other Tika powered extracters
*
* Uses Apache Tika
*
* @author Nick Burch
*/
public class MP3MetadataExtracter extends TikaAudioMetadataExtracter
{
private static final String KEY_SONG_TITLE = "songTitle";
private static final String KEY_ALBUM_TITLE = "albumTitle";
private static final String KEY_ARTIST = "artist";
private static final String KEY_COMMENT = "comment";
private static final String KEY_YEAR_RELEASED = "yearReleased";
private static final String KEY_TRACK_NUMBER = "trackNumber";
private static final String KEY_GENRE = "genre";
private static final String KEY_COMPOSER = "composer";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] { MimetypeMap.MIMETYPE_MP3 },
new Mp3Parser()
);
public MP3MetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
return new Mp3Parser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String,String> headers)
{
// Do the normal Audio mappings
super.extractSpecific(metadata, properties, headers);
// Now do the compatibility ones
// We only need these for people who had pre-existing mapping
// properties from before the proper audio model was added
putRawValue(KEY_ALBUM_TITLE, metadata.get(XMPDM.ALBUM), properties);
putRawValue(KEY_SONG_TITLE, metadata.get(Metadata.TITLE), properties);
putRawValue(KEY_ARTIST, metadata.get(XMPDM.ARTIST), properties);
putRawValue(KEY_COMMENT, metadata.get(XMPDM.LOG_COMMENT), properties);
putRawValue(KEY_TRACK_NUMBER, metadata.get(XMPDM.TRACK_NUMBER), properties);
putRawValue(KEY_GENRE, metadata.get(XMPDM.GENRE), properties);
putRawValue(KEY_YEAR_RELEASED, metadata.get(XMPDM.RELEASE_DATE), properties);
putRawValue(KEY_COMPOSER, metadata.get(XMPDM.COMPOSER), properties);
// All done
return properties;
}
}

View File

@@ -1,82 +1,82 @@
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.microsoft.OfficeParser;
/**
* Outlook MAPI format email meta-data extractor extracting the following values:
* <pre>
* <b>sentDate:</b> -- cm:sentdate
* <b>originator:</b> -- cm:originator, cm:author
* <b>addressee:</b> -- cm:addressee
* <b>addressees:</b> -- cm:addressees
* <b>subjectLine:</b> -- cm:subjectline, cm:description
* <b>toNames:</b> --
* <b>ccNames:</b> --
* <b>bccNames:</b> --
* </pre>
*
* TIKA note - to/cc/bcc go into the html part, not the metadata.
* Also, email addresses not included as yet.
*
* @since 2.1
* @author Kevin Roast
*/
public class MailMetadataExtracter extends TikaPoweredMetadataExtracter
{
private static final String KEY_SENT_DATE = "sentDate";
private static final String KEY_ORIGINATOR = "originator";
private static final String KEY_ADDRESSEE = "addressee";
private static final String KEY_ADDRESSEES = "addressees";
private static final String KEY_SUBJECT = "subjectLine";
private static final String KEY_TO_NAMES = "toNames";
private static final String KEY_CC_NAMES = "ccNames";
private static final String KEY_BCC_NAMES = "bccNames";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] {MimetypeMap.MIMETYPE_OUTLOOK_MSG},
(Parser[])null
);
public MailMetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
// The office parser does Outlook as well as Word, Excel etc
return new OfficeParser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String,String> headers)
{
putRawValue(KEY_ORIGINATOR, metadata.get(Metadata.AUTHOR), properties);
putRawValue(KEY_SUBJECT, metadata.get(Metadata.TITLE), properties);
putRawValue(KEY_DESCRIPTION, metadata.get(Metadata.SUBJECT), properties);
putRawValue(KEY_SENT_DATE, metadata.get(Metadata.LAST_SAVED), properties);
// Store the TO, but not cc/bcc in the addressee field
putRawValue(KEY_ADDRESSEE, metadata.get(Metadata.MESSAGE_TO), properties);
// Store each of To, CC and BCC in their own fields
putRawValue(KEY_TO_NAMES, metadata.getValues(Metadata.MESSAGE_TO), properties);
putRawValue(KEY_CC_NAMES, metadata.getValues(Metadata.MESSAGE_CC), properties);
putRawValue(KEY_BCC_NAMES, metadata.getValues(Metadata.MESSAGE_BCC), properties);
// But store all email addresses (to/cc/bcc) in the addresses field
putRawValue(KEY_ADDRESSEES, metadata.getValues(Metadata.MESSAGE_RECIPIENT_ADDRESS), properties);
return properties;
}
}
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.microsoft.OfficeParser;
/**
* Outlook MAPI format email meta-data extractor extracting the following values:
* <pre>
* <b>sentDate:</b> -- cm:sentdate
* <b>originator:</b> -- cm:originator, cm:author
* <b>addressee:</b> -- cm:addressee
* <b>addressees:</b> -- cm:addressees
* <b>subjectLine:</b> -- cm:subjectline, cm:description
* <b>toNames:</b> --
* <b>ccNames:</b> --
* <b>bccNames:</b> --
* </pre>
*
* TIKA note - to/cc/bcc go into the html part, not the metadata.
* Also, email addresses not included as yet.
*
* @since 2.1
* @author Kevin Roast
*/
public class MailMetadataExtracter extends TikaPoweredMetadataExtracter
{
private static final String KEY_SENT_DATE = "sentDate";
private static final String KEY_ORIGINATOR = "originator";
private static final String KEY_ADDRESSEE = "addressee";
private static final String KEY_ADDRESSEES = "addressees";
private static final String KEY_SUBJECT = "subjectLine";
private static final String KEY_TO_NAMES = "toNames";
private static final String KEY_CC_NAMES = "ccNames";
private static final String KEY_BCC_NAMES = "bccNames";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] {MimetypeMap.MIMETYPE_OUTLOOK_MSG},
(Parser[])null
);
public MailMetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
// The office parser does Outlook as well as Word, Excel etc
return new OfficeParser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String,String> headers)
{
putRawValue(KEY_ORIGINATOR, metadata.get(Metadata.AUTHOR), properties);
putRawValue(KEY_SUBJECT, metadata.get(Metadata.TITLE), properties);
putRawValue(KEY_DESCRIPTION, metadata.get(Metadata.SUBJECT), properties);
putRawValue(KEY_SENT_DATE, metadata.get(Metadata.LAST_SAVED), properties);
// Store the TO, but not cc/bcc in the addressee field
putRawValue(KEY_ADDRESSEE, metadata.get(Metadata.MESSAGE_TO), properties);
// Store each of To, CC and BCC in their own fields
putRawValue(KEY_TO_NAMES, metadata.getValues(Metadata.MESSAGE_TO), properties);
putRawValue(KEY_CC_NAMES, metadata.getValues(Metadata.MESSAGE_CC), properties);
putRawValue(KEY_BCC_NAMES, metadata.getValues(Metadata.MESSAGE_BCC), properties);
// But store all email addresses (to/cc/bcc) in the addresses field
putRawValue(KEY_ADDRESSEES, metadata.getValues(Metadata.MESSAGE_RECIPIENT_ADDRESS), properties);
return properties;
}
}

View File

@@ -1,33 +1,33 @@
package org.alfresco.repo.content.metadata;
import java.util.List;
import org.apache.tika.extractor.DocumentSelector;
import org.apache.tika.metadata.Metadata;
/**
* Tika 1.6 has the ability to parse embedded artifacts, such as images in a PDF,
* but this can be very resource intensive so adding this selector
* to parsers and transformers that handle formats with embedded artifacts
* will disable parsing of the specified content types.
*/
public class MediaTypeDisablingDocumentSelector implements DocumentSelector
{
private List<String> disabledMediaTypes;
public void setDisabledMediaTypes(List<String> disabledMediaTypes)
{
this.disabledMediaTypes = disabledMediaTypes;
}
@Override
public boolean select(Metadata metadata)
{
String contentType = metadata.get(Metadata.CONTENT_TYPE);
if (contentType == null || contentType.equals("") || disabledMediaTypes == null)
{
return true;
}
return !disabledMediaTypes.contains(contentType);
}
}
package org.alfresco.repo.content.metadata;
import java.util.List;
import org.apache.tika.extractor.DocumentSelector;
import org.apache.tika.metadata.Metadata;
/**
* Tika 1.6 has the ability to parse embedded artifacts, such as images in a PDF,
* but this can be very resource intensive so adding this selector
* to parsers and transformers that handle formats with embedded artifacts
* will disable parsing of the specified content types.
*/
public class MediaTypeDisablingDocumentSelector implements DocumentSelector
{
private List<String> disabledMediaTypes;
public void setDisabledMediaTypes(List<String> disabledMediaTypes)
{
this.disabledMediaTypes = disabledMediaTypes;
}
@Override
public boolean select(Metadata metadata)
{
String contentType = metadata.get(Metadata.CONTENT_TYPE);
if (contentType == null || contentType.equals("") || disabledMediaTypes == null)
{
return true;
}
return !disabledMediaTypes.contains(contentType);
}
}

View File

@@ -1,48 +1,48 @@
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.Map;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.repo.content.ContentWorker;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.namespace.QName;
/**
* Interface for writing metadata properties back into the content file.
*
* @author Ray Gauss II
*
*/
@AlfrescoPublicApi
public interface MetadataEmbedder extends ContentWorker {
/**
* Determines if the extracter works against the given mimetype.
*
* @param mimetype the document mimetype
* @return Returns <tt>true</tt> if the mimetype is supported, otherwise <tt>false</tt>.
*/
public boolean isEmbeddingSupported(String mimetype);
/**
* Embeds the given properties into the file specified by the given content writer.
* * <p>
* The embedding viability can be determined by an up front call to
* {@link #isEmbeddingSupported(String)}.
* <p>
* The source mimetype <b>must</b> be available on the
* {@link org.alfresco.service.cmr.repository.ContentAccessor#getMimetype()} method
* of the writer.
*
* @param properties the model properties to embed
* @param reader the reader for the original source content file
* @param writer the writer for the content after metadata has been embedded
* @throws ContentIOException
*/
public void embed(Map<QName, Serializable> properties, ContentReader reader, ContentWriter writer) throws ContentIOException;
}
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.Map;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.repo.content.ContentWorker;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.namespace.QName;
/**
* Interface for writing metadata properties back into the content file.
*
* @author Ray Gauss II
*
*/
@AlfrescoPublicApi
public interface MetadataEmbedder extends ContentWorker {
/**
* Determines if the extracter works against the given mimetype.
*
* @param mimetype the document mimetype
* @return Returns <tt>true</tt> if the mimetype is supported, otherwise <tt>false</tt>.
*/
public boolean isEmbeddingSupported(String mimetype);
/**
* Embeds the given properties into the file specified by the given content writer.
* * <p>
* The embedding viability can be determined by an up front call to
* {@link #isEmbeddingSupported(String)}.
* <p>
* The source mimetype <b>must</b> be available on the
* {@link org.alfresco.service.cmr.repository.ContentAccessor#getMimetype()} method
* of the writer.
*
* @param properties the model properties to embed
* @param reader the reader for the original source content file
* @param writer the writer for the content after metadata has been embedded
* @throws ContentIOException
*/
public void embed(Map<QName, Serializable> properties, ContentReader reader, ContentWriter writer) throws ContentIOException;
}

View File

@@ -1,37 +1,37 @@
package org.alfresco.repo.content.metadata;
import org.alfresco.api.AlfrescoPublicApi;
/**
* Represents maximum values (that result in exceptions if exceeded) or
* limits on values (that result in EOF (End Of File) being returned
* early). The only current option is for elapsed time.
*
* @author Ray Gauss II
*/
@AlfrescoPublicApi
public class MetadataExtracterLimits
{
private long timeoutMs = -1;
/**
* Gets the time in milliseconds after which the metadata extracter will be stopped.
*
* @return the timeout
*/
public long getTimeoutMs()
{
return timeoutMs;
}
/**
* Sets the time in milliseconds after which the metadata extracter will be stopped.
*
* @param timeoutMs the timeout
*/
public void setTimeoutMs(long timeoutMs)
{
this.timeoutMs = timeoutMs;
}
}
package org.alfresco.repo.content.metadata;
import org.alfresco.api.AlfrescoPublicApi;
/**
* Represents maximum values (that result in exceptions if exceeded) or
* limits on values (that result in EOF (End Of File) being returned
* early). The only current option is for elapsed time.
*
* @author Ray Gauss II
*/
@AlfrescoPublicApi
public class MetadataExtracterLimits
{
private long timeoutMs = -1;
/**
* Gets the time in milliseconds after which the metadata extracter will be stopped.
*
* @return the timeout
*/
public long getTimeoutMs()
{
return timeoutMs;
}
/**
* Sets the time in milliseconds after which the metadata extracter will be stopped.
*
* @param timeoutMs the timeout
*/
public void setTimeoutMs(long timeoutMs)
{
this.timeoutMs = timeoutMs;
}
}

View File

@@ -1,154 +1,154 @@
/*
* Copyright (C) 2005 Antti Jokipii
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.namespace.QName;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.odf.OpenDocumentParser;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* Metadata extractor for the
* {@link org.alfresco.repo.content.MimetypeMap#MIMETYPE_OPENDOCUMENT_TEXT MIMETYPE_OPENDOCUMENT_XXX}
* mimetypes.
* <pre>
* <b>creationDate:</b> -- cm:created
* <b>creator:</b> -- cm:author
* <b>date:</b>
* <b>description:</b> -- cm:description
* <b>generator:</b>
* <b>initialCreator:</b>
* <b>keyword:</b>
* <b>language:</b>
* <b>printDate:</b>
* <b>printedBy:</b>
* <b>subject:</b>
* <b>title:</b> -- cm:title
* <b>All user properties</b>
* </pre>
*
* Uses Apache Tika
*
* TODO decide if we need the few print info bits that
* Tika currently doesn't handle
*
* @author Antti Jokipii
* @author Derek Hulley
*/
public class OpenDocumentMetadataExtracter extends TikaPoweredMetadataExtracter
{
private static final String KEY_CREATION_DATE = "creationDate";
private static final String KEY_CREATOR = "creator";
private static final String KEY_DATE = "date";
private static final String KEY_GENERATOR = "generator";
private static final String KEY_INITIAL_CREATOR = "initialCreator";
private static final String KEY_KEYWORD = "keyword";
private static final String KEY_LANGUAGE = "language";
// private static final String KEY_PRINT_DATE = "printDate";
// private static final String KEY_PRINTED_BY = "printedBy";
private static final String CUSTOM_PREFIX = "custom:";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] {
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_GRAPHICS,
MimetypeMap.MIMETYPE_OPENDOCUMENT_GRAPHICS_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_PRESENTATION,
MimetypeMap.MIMETYPE_OPENDOCUMENT_PRESENTATION_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_SPREADSHEET,
MimetypeMap.MIMETYPE_OPENDOCUMENT_SPREADSHEET_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_CHART,
MimetypeMap.MIMETYPE_OPENDOCUMENT_CHART_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_IMAGE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_IMAGE_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_FORMULA,
MimetypeMap.MIMETYPE_OPENDOCUMENT_FORMULA_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_MASTER,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_WEB,
MimetypeMap.MIMETYPE_OPENDOCUMENT_DATABASE
}, new OpenDocumentParser()
);
private static final DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
public OpenDocumentMetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
return new OpenDocumentParser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String, String> headers)
{
putRawValue(KEY_CREATION_DATE, getDateOrNull(metadata.get(Metadata.CREATION_DATE)), properties);
putRawValue(KEY_CREATOR, metadata.get(Metadata.CREATOR), properties);
putRawValue(KEY_DATE, getDateOrNull(metadata.get(Metadata.DATE)), properties);
putRawValue(KEY_DESCRIPTION, metadata.get(Metadata.DESCRIPTION), properties);
putRawValue(KEY_GENERATOR, metadata.get("generator"), properties);
putRawValue(KEY_INITIAL_CREATOR, metadata.get("initial-creator"), properties);
putRawValue(KEY_KEYWORD, metadata.get(Metadata.KEYWORDS), properties);
putRawValue(KEY_LANGUAGE, metadata.get(Metadata.LANGUAGE), properties);
// putRawValue(KEY_PRINT_DATE, getDateOrNull(metadata.get(Metadata.)), rawProperties);
// putRawValue(KEY_PRINTED_BY, metadata.get(Metadata.), rawProperties);
// Handle user-defined properties dynamically
Map<String, Set<QName>> mapping = super.getMapping();
for (String key : mapping.keySet())
{
if (metadata.get(CUSTOM_PREFIX + key) != null)
{
putRawValue(key, metadata.get(CUSTOM_PREFIX + key), properties);
}
}
return properties;
}
private Date getDateOrNull(String dateString)
{
if (dateString != null && dateString.length() != 0)
{
try
{
return dateFormatter.parseDateTime(dateString).toDate();
}
catch (IllegalArgumentException e) {}
}
return null;
}
}
/*
* Copyright (C) 2005 Antti Jokipii
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.repo.content.metadata;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.namespace.QName;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.odf.OpenDocumentParser;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* Metadata extractor for the
* {@link org.alfresco.repo.content.MimetypeMap#MIMETYPE_OPENDOCUMENT_TEXT MIMETYPE_OPENDOCUMENT_XXX}
* mimetypes.
* <pre>
* <b>creationDate:</b> -- cm:created
* <b>creator:</b> -- cm:author
* <b>date:</b>
* <b>description:</b> -- cm:description
* <b>generator:</b>
* <b>initialCreator:</b>
* <b>keyword:</b>
* <b>language:</b>
* <b>printDate:</b>
* <b>printedBy:</b>
* <b>subject:</b>
* <b>title:</b> -- cm:title
* <b>All user properties</b>
* </pre>
*
* Uses Apache Tika
*
* TODO decide if we need the few print info bits that
* Tika currently doesn't handle
*
* @author Antti Jokipii
* @author Derek Hulley
*/
public class OpenDocumentMetadataExtracter extends TikaPoweredMetadataExtracter
{
private static final String KEY_CREATION_DATE = "creationDate";
private static final String KEY_CREATOR = "creator";
private static final String KEY_DATE = "date";
private static final String KEY_GENERATOR = "generator";
private static final String KEY_INITIAL_CREATOR = "initialCreator";
private static final String KEY_KEYWORD = "keyword";
private static final String KEY_LANGUAGE = "language";
// private static final String KEY_PRINT_DATE = "printDate";
// private static final String KEY_PRINTED_BY = "printedBy";
private static final String CUSTOM_PREFIX = "custom:";
public static ArrayList<String> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
new String[] {
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_GRAPHICS,
MimetypeMap.MIMETYPE_OPENDOCUMENT_GRAPHICS_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_PRESENTATION,
MimetypeMap.MIMETYPE_OPENDOCUMENT_PRESENTATION_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_SPREADSHEET,
MimetypeMap.MIMETYPE_OPENDOCUMENT_SPREADSHEET_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_CHART,
MimetypeMap.MIMETYPE_OPENDOCUMENT_CHART_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_IMAGE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_IMAGE_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_FORMULA,
MimetypeMap.MIMETYPE_OPENDOCUMENT_FORMULA_TEMPLATE,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_MASTER,
MimetypeMap.MIMETYPE_OPENDOCUMENT_TEXT_WEB,
MimetypeMap.MIMETYPE_OPENDOCUMENT_DATABASE
}, new OpenDocumentParser()
);
private static final DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
public OpenDocumentMetadataExtracter()
{
super(SUPPORTED_MIMETYPES);
}
@Override
protected Parser getParser()
{
return new OpenDocumentParser();
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Serializable> extractSpecific(Metadata metadata,
Map<String, Serializable> properties, Map<String, String> headers)
{
putRawValue(KEY_CREATION_DATE, getDateOrNull(metadata.get(Metadata.CREATION_DATE)), properties);
putRawValue(KEY_CREATOR, metadata.get(Metadata.CREATOR), properties);
putRawValue(KEY_DATE, getDateOrNull(metadata.get(Metadata.DATE)), properties);
putRawValue(KEY_DESCRIPTION, metadata.get(Metadata.DESCRIPTION), properties);
putRawValue(KEY_GENERATOR, metadata.get("generator"), properties);
putRawValue(KEY_INITIAL_CREATOR, metadata.get("initial-creator"), properties);
putRawValue(KEY_KEYWORD, metadata.get(Metadata.KEYWORDS), properties);
putRawValue(KEY_LANGUAGE, metadata.get(Metadata.LANGUAGE), properties);
// putRawValue(KEY_PRINT_DATE, getDateOrNull(metadata.get(Metadata.)), rawProperties);
// putRawValue(KEY_PRINTED_BY, metadata.get(Metadata.), rawProperties);
// Handle user-defined properties dynamically
Map<String, Set<QName>> mapping = super.getMapping();
for (String key : mapping.keySet())
{
if (metadata.get(CUSTOM_PREFIX + key) != null)
{
putRawValue(key, metadata.get(CUSTOM_PREFIX + key), properties);
}
}
return properties;
}
private Date getDateOrNull(String dateString)
{
if (dateString != null && dateString.length() != 0)
{
try
{
return dateFormatter.parseDateTime(dateString).toDate();
}
catch (IllegalArgumentException e) {}
}
return null;
}
}

View File

@@ -1,197 +1,197 @@
package org.alfresco.repo.content.replication;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.caching.CachingContentStore;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* </h1><u>Aggregating Content Store</u></h1>
* <p>
* A content store implementation that aggregates a set of stores. Content is not
* persisted by this store, but rather it relies on any number of
* child {@link org.alfresco.repo.content.ContentStore stores} to provide access
* to content readers and writers.
* <p>
* The order in which the stores appear in the list of stores participating is
* important. The first store in the list is known as the <i>primary store</i>.
<p>
* Content is written to the primary store only. The other stores are
* only used to retrieve content and the primary store is not updated with
* the content.
*
* @author Derek Hulley
* @author Mark Rogers
* @see CachingContentStore
*/
public class AggregatingContentStore extends AbstractContentStore
{
private static Log logger = LogFactory.getLog(AggregatingContentStore.class);
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
private Lock readLock;
private Lock writeLock;
/**
* Default constructor
*/
public AggregatingContentStore()
{
ReadWriteLock storeLock = new ReentrantReadWriteLock();
readLock = storeLock.readLock();
writeLock = storeLock.writeLock();
}
/**
* Set the primary store that content will be replicated to or from
*
* @param primaryStore the primary content store
*/
public void setPrimaryStore(ContentStore primaryStore)
{
this.primaryStore = primaryStore;
}
/**
* Set the secondary stores that this component will replicate to or from
*
* @param secondaryStores a list of stores to replicate to or from
*/
public void setSecondaryStores(List<ContentStore> secondaryStores)
{
this.secondaryStores = secondaryStores;
}
/**
* @return Returns <tt>true</tt> if the primary store supports writing
*/
public boolean isWriteSupported()
{
return primaryStore.isWriteSupported();
}
/**
* @return Returns <tt>true</tt> if the primary store supports the URL
*/
@Override
public boolean isContentUrlSupported(String contentUrl)
{
return primaryStore.isContentUrlSupported(contentUrl);
}
/**
* @return Return the primary store root location
*/
@Override
public String getRootLocation()
{
return primaryStore.getRootLocation();
}
/**
* Forwards the call directly to the first store in the list of stores.
*/
public ContentReader getReader(String contentUrl) throws ContentIOException
{
if (primaryStore == null)
{
throw new AlfrescoRuntimeException("ReplicatingContentStore not initialised");
}
// get a read lock so that we are sure that no replication is underway
readLock.lock();
try
{
// get a reader from the primary store
ContentReader primaryReader = primaryStore.getReader(contentUrl);
// give it straight back if the content is there
if (primaryReader.exists())
{
return primaryReader;
}
// the content is not in the primary reader so we have to go looking for it
ContentReader secondaryContentReader = null;
for (ContentStore store : secondaryStores)
{
ContentReader reader = store.getReader(contentUrl);
if (reader.exists())
{
// found the content in a secondary store
return reader;
}
}
return primaryReader;
}
finally
{
readLock.unlock();
}
}
public ContentWriter getWriter(ContentContext ctx)
{
// get the writer
ContentWriter writer = primaryStore.getWriter(ctx);
return writer;
}
/**
* Performs a delete on the local store and if outbound replication is on, propogates
* the delete to the other stores too.
*
* @return Returns the value returned by the delete on the primary store.
*/
public boolean delete(String contentUrl) throws ContentIOException
{
// delete on the primary store
boolean deleted = primaryStore.delete(contentUrl);
if (logger.isDebugEnabled())
{
logger.debug("Deleted content for URL: " + contentUrl);
}
return deleted;
}
/**
* Iterates over results as given by the primary store and all secondary stores. It is up to the handler to eliminate
* duplicates that will occur between the primary and secondary stores.
*/
@SuppressWarnings("deprecation")
public void getUrls(Date createdAfter, Date createdBefore, ContentUrlHandler handler) throws ContentIOException
{
// add in URLs from primary store
primaryStore.getUrls(createdAfter, createdBefore, handler);
// add in URLs from secondary stores (they are visible for reads)
for (ContentStore secondaryStore : secondaryStores)
{
secondaryStore.getUrls(createdAfter, createdBefore, handler);
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Iterated over content URLs: \n" +
" created after: " + createdAfter + "\n" +
" created before: " + createdBefore);
}
}
}
package org.alfresco.repo.content.replication;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.caching.CachingContentStore;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* </h1><u>Aggregating Content Store</u></h1>
* <p>
* A content store implementation that aggregates a set of stores. Content is not
* persisted by this store, but rather it relies on any number of
* child {@link org.alfresco.repo.content.ContentStore stores} to provide access
* to content readers and writers.
* <p>
* The order in which the stores appear in the list of stores participating is
* important. The first store in the list is known as the <i>primary store</i>.
<p>
* Content is written to the primary store only. The other stores are
* only used to retrieve content and the primary store is not updated with
* the content.
*
* @author Derek Hulley
* @author Mark Rogers
* @see CachingContentStore
*/
public class AggregatingContentStore extends AbstractContentStore
{
private static Log logger = LogFactory.getLog(AggregatingContentStore.class);
private ContentStore primaryStore;
private List<ContentStore> secondaryStores;
private Lock readLock;
private Lock writeLock;
/**
* Default constructor
*/
public AggregatingContentStore()
{
ReadWriteLock storeLock = new ReentrantReadWriteLock();
readLock = storeLock.readLock();
writeLock = storeLock.writeLock();
}
/**
* Set the primary store that content will be replicated to or from
*
* @param primaryStore the primary content store
*/
public void setPrimaryStore(ContentStore primaryStore)
{
this.primaryStore = primaryStore;
}
/**
* Set the secondary stores that this component will replicate to or from
*
* @param secondaryStores a list of stores to replicate to or from
*/
public void setSecondaryStores(List<ContentStore> secondaryStores)
{
this.secondaryStores = secondaryStores;
}
/**
* @return Returns <tt>true</tt> if the primary store supports writing
*/
public boolean isWriteSupported()
{
return primaryStore.isWriteSupported();
}
/**
* @return Returns <tt>true</tt> if the primary store supports the URL
*/
@Override
public boolean isContentUrlSupported(String contentUrl)
{
return primaryStore.isContentUrlSupported(contentUrl);
}
/**
* @return Return the primary store root location
*/
@Override
public String getRootLocation()
{
return primaryStore.getRootLocation();
}
/**
* Forwards the call directly to the first store in the list of stores.
*/
public ContentReader getReader(String contentUrl) throws ContentIOException
{
if (primaryStore == null)
{
throw new AlfrescoRuntimeException("ReplicatingContentStore not initialised");
}
// get a read lock so that we are sure that no replication is underway
readLock.lock();
try
{
// get a reader from the primary store
ContentReader primaryReader = primaryStore.getReader(contentUrl);
// give it straight back if the content is there
if (primaryReader.exists())
{
return primaryReader;
}
// the content is not in the primary reader so we have to go looking for it
ContentReader secondaryContentReader = null;
for (ContentStore store : secondaryStores)
{
ContentReader reader = store.getReader(contentUrl);
if (reader.exists())
{
// found the content in a secondary store
return reader;
}
}
return primaryReader;
}
finally
{
readLock.unlock();
}
}
public ContentWriter getWriter(ContentContext ctx)
{
// get the writer
ContentWriter writer = primaryStore.getWriter(ctx);
return writer;
}
/**
* Performs a delete on the local store and if outbound replication is on, propogates
* the delete to the other stores too.
*
* @return Returns the value returned by the delete on the primary store.
*/
public boolean delete(String contentUrl) throws ContentIOException
{
// delete on the primary store
boolean deleted = primaryStore.delete(contentUrl);
if (logger.isDebugEnabled())
{
logger.debug("Deleted content for URL: " + contentUrl);
}
return deleted;
}
/**
* Iterates over results as given by the primary store and all secondary stores. It is up to the handler to eliminate
* duplicates that will occur between the primary and secondary stores.
*/
@SuppressWarnings("deprecation")
public void getUrls(Date createdAfter, Date createdBefore, ContentUrlHandler handler) throws ContentIOException
{
// add in URLs from primary store
primaryStore.getUrls(createdAfter, createdBefore, handler);
// add in URLs from secondary stores (they are visible for reads)
for (ContentStore secondaryStore : secondaryStores)
{
secondaryStore.getUrls(createdAfter, createdBefore, handler);
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Iterated over content URLs: \n" +
" created after: " + createdAfter + "\n" +
" created before: " + createdBefore);
}
}
}

View File

@@ -1,26 +1,26 @@
package org.alfresco.repo.content.transform;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.microsoft.OfficeParser;
/**
* Uses <a href="http://tika.apache.org/">Apache Tika</a> and
* <a href="@link http://poi.apache.org/">Apache POI</a> to transform
* Outlook email msg files.
*
* @author Nick Burch
*/
public class MailContentTransformer extends TikaPoweredContentTransformer
{
public MailContentTransformer() {
super(new String[] {
MimetypeMap.MIMETYPE_OUTLOOK_MSG
});
}
@Override
protected Parser getParser() {
return new OfficeParser();
}
}
package org.alfresco.repo.content.transform;
import org.alfresco.repo.content.MimetypeMap;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.microsoft.OfficeParser;
/**
* Uses <a href="http://tika.apache.org/">Apache Tika</a> and
* <a href="@link http://poi.apache.org/">Apache POI</a> to transform
* Outlook email msg files.
*
* @author Nick Burch
*/
public class MailContentTransformer extends TikaPoweredContentTransformer
{
public MailContentTransformer() {
super(new String[] {
MimetypeMap.MIMETYPE_OUTLOOK_MSG
});
}
@Override
protected Parser getParser() {
return new OfficeParser();
}
}

View File

@@ -1,273 +1,273 @@
package org.alfresco.repo.content.transform;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.util.TempFileProvider;
import org.alfresco.util.exec.RuntimeExec;
import org.alfresco.util.exec.RuntimeExec.ExecutionResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* This configurable wrapper is able to execute any command line transformation that
* accepts an input and an output file on the command line.
* <p>
* The following parameters are use:
* <ul>
* <li><b>{@link #VAR_SOURCE target}</b> - full path to the source file</li>
* <li><b>{@link #VAR_TARGET source}</b> - full path to the target file</li>
* </ul>
* Provided that the command executed ultimately transforms the source file
* and leaves the result in the target file, the transformation should be
* successful.
* <p>
* <b>NOTE</b>: It is only the contents of the files that can be transformed.
* Any attempt to modify the source or target file metadata will, at best, have
* no effect, but may ultimately lead to the transformation failing. This is
* because the files provided are both temporary files that reside in a location
* outside the system's content store.
* <p>
* This transformer <b>requires</b> the setting of the <b>explicitTransformations</b>
* property.
*
* @see org.alfresco.util.exec.RuntimeExec
*
* @since 1.1
* @author Derek Hulley
*/
@AlfrescoPublicApi
public class RuntimeExecutableContentTransformerWorker extends ContentTransformerHelper implements ContentTransformerWorker, InitializingBean
{
public static final String VAR_SOURCE = "source";
public static final String VAR_TARGET = "target";
public static final String VAR_PAGE_RANGE = "pageRange";
private static Log logger = LogFactory.getLog(RuntimeExecutableContentTransformerWorker.class);
private boolean available;
private RuntimeExec checkCommand;
private RuntimeExec transformCommand;
/** Stores the output from the check command */
private String versionString;
public RuntimeExecutableContentTransformerWorker()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName())
.append("[ transform=").append(transformCommand).append("\n")
.append("]");
return sb.toString();
}
/**
* Set the runtime executer that will be called as part of the initialisation
* to determine if the transformer is able to function. This is optional, but allows
* the transformer registry to detect and avoid using this instance if it is not working.
* <p>
* The command will be considered to have failed if the
*
* @param checkCommand the initialisation check command
*/
public void setCheckCommand(RuntimeExec checkCommand)
{
this.checkCommand = checkCommand;
}
/**
* Set the runtime executer that will called to perform the actual transformation.
*
* @param transformCommand the runtime transform command
*/
public void setTransformCommand(RuntimeExec transformCommand)
{
this.transformCommand = transformCommand;
}
/**
* A comma or space separated list of values that, if returned by the executed command,
* indicate an error value. This defaults to <b>"1, 2"</b>.
*
* @param errCodesStr String
*/
public void setErrorCodes(String errCodesStr)
{
throw new AlfrescoRuntimeException("content.runtime_exec.property_moved");
}
/**
* Executes the check command, if present. Any errors will result in this component
* being rendered unusable within the transformer registry, but may still be called
* directly.
*/
public void afterPropertiesSet()
{
if (transformCommand == null)
{
throw new AlfrescoRuntimeException("Mandatory property 'transformCommand' not set");
}
// execute the command
if (checkCommand != null)
{
ExecutionResult result = checkCommand.execute();
// check the return code
if (this.available = result.getSuccess())
{
this.versionString = result.getStdOut().trim();
}
else
{
logger.error("Failed to start a runtime executable content transformer: \n" + result);
}
}
else
{
// no check - just assume it is available
available = true;
}
}
/**
* If the initialization failed, then it returns 0.0.
* Otherwise the explicit transformations are checked for the reliability.
*
* @return Returns 1.0 if initialization succeeded, otherwise 0.0.
*
* @see AbstractContentTransformer#setExplicitTransformations(List)
*/
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
return available;
}
@Override
public String getComments(boolean available)
{
return "";
}
/**
* Signals whether this transformer is available.
*
* @return true, if is available
*/
public boolean isAvailable()
{
return this.available;
}
/**
* Gets the version string captured from the check command.
*
* @return the version string
*/
public String getVersionString()
{
return this.versionString;
}
/**
* Converts the source and target content to temporary files with the
* correct extensions for the mimetype that they map to.
*
*/
public final void transform(
ContentReader reader,
ContentWriter writer,
TransformationOptions options) throws Exception
{
// get mimetypes
String sourceMimetype = getMimetype(reader);
String targetMimetype = getMimetype(writer);
// get the extensions to use
String sourceExtension = getMimetypeService().getExtension(sourceMimetype);
String targetExtension = getMimetypeService().getExtension(targetMimetype);
if (sourceExtension == null || targetExtension == null)
{
throw new AlfrescoRuntimeException("Unknown extensions for mimetypes: \n" +
" source mimetype: " + sourceMimetype + "\n" +
" source extension: " + sourceExtension + "\n" +
" target mimetype: " + targetMimetype + "\n" +
" target extension: " + targetExtension);
}
// create required temp files
File sourceFile = TempFileProvider.createTempFile(
getClass().getSimpleName() + "_source_",
"." + sourceExtension);
File targetFile = TempFileProvider.createTempFile(
getClass().getSimpleName() + "_target_",
"." + targetExtension);
Map<String, String> properties = new HashMap<String, String>(5);
// copy options over
Map<String, Object> optionsMap = options.toMap();
for (Map.Entry<String, Object> entry : optionsMap.entrySet())
{
String key = entry.getKey();
Object value = entry.getValue();
properties.put(key, (value == null ? null : value.toString()));
}
// add the source and target properties
properties.put(VAR_SOURCE, sourceFile.getAbsolutePath());
properties.put(VAR_TARGET, targetFile.getAbsolutePath());
properties.put(VAR_PAGE_RANGE, "0-"+(options.getPageLimit() >=0 ? options.getPageLimit() : ""));
// pull reader file into source temp file
reader.getContent(sourceFile);
// execute the transformation command
long timeoutMs = options.getTimeoutMs();
ExecutionResult result = null;
try
{
result = transformCommand.execute(properties, timeoutMs);
}
catch (Throwable e)
{
throw new ContentIOException("Transformation failed during command execution: \n" + transformCommand, e);
}
// check
if (!result.getSuccess())
{
throw new ContentIOException("Transformation failed - status indicates an error: \n" + result);
}
// check that the file was created
if (!targetFile.exists())
{
throw new ContentIOException("Transformation failed - target file doesn't exist: \n" + result);
}
// copy the target file back into the repo
writer.putContent(targetFile);
// done
if (logger.isDebugEnabled())
{
logger.debug("Transformation completed: \n" +
" source: " + reader + "\n" +
" target: " + writer + "\n" +
" options: " + options + "\n" +
" result: \n" + result);
}
}
}
package org.alfresco.repo.content.transform;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.api.AlfrescoPublicApi;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.util.TempFileProvider;
import org.alfresco.util.exec.RuntimeExec;
import org.alfresco.util.exec.RuntimeExec.ExecutionResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* This configurable wrapper is able to execute any command line transformation that
* accepts an input and an output file on the command line.
* <p>
* The following parameters are use:
* <ul>
* <li><b>{@link #VAR_SOURCE target}</b> - full path to the source file</li>
* <li><b>{@link #VAR_TARGET source}</b> - full path to the target file</li>
* </ul>
* Provided that the command executed ultimately transforms the source file
* and leaves the result in the target file, the transformation should be
* successful.
* <p>
* <b>NOTE</b>: It is only the contents of the files that can be transformed.
* Any attempt to modify the source or target file metadata will, at best, have
* no effect, but may ultimately lead to the transformation failing. This is
* because the files provided are both temporary files that reside in a location
* outside the system's content store.
* <p>
* This transformer <b>requires</b> the setting of the <b>explicitTransformations</b>
* property.
*
* @see org.alfresco.util.exec.RuntimeExec
*
* @since 1.1
* @author Derek Hulley
*/
@AlfrescoPublicApi
public class RuntimeExecutableContentTransformerWorker extends ContentTransformerHelper implements ContentTransformerWorker, InitializingBean
{
public static final String VAR_SOURCE = "source";
public static final String VAR_TARGET = "target";
public static final String VAR_PAGE_RANGE = "pageRange";
private static Log logger = LogFactory.getLog(RuntimeExecutableContentTransformerWorker.class);
private boolean available;
private RuntimeExec checkCommand;
private RuntimeExec transformCommand;
/** Stores the output from the check command */
private String versionString;
public RuntimeExecutableContentTransformerWorker()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName())
.append("[ transform=").append(transformCommand).append("\n")
.append("]");
return sb.toString();
}
/**
* Set the runtime executer that will be called as part of the initialisation
* to determine if the transformer is able to function. This is optional, but allows
* the transformer registry to detect and avoid using this instance if it is not working.
* <p>
* The command will be considered to have failed if the
*
* @param checkCommand the initialisation check command
*/
public void setCheckCommand(RuntimeExec checkCommand)
{
this.checkCommand = checkCommand;
}
/**
* Set the runtime executer that will called to perform the actual transformation.
*
* @param transformCommand the runtime transform command
*/
public void setTransformCommand(RuntimeExec transformCommand)
{
this.transformCommand = transformCommand;
}
/**
* A comma or space separated list of values that, if returned by the executed command,
* indicate an error value. This defaults to <b>"1, 2"</b>.
*
* @param errCodesStr String
*/
public void setErrorCodes(String errCodesStr)
{
throw new AlfrescoRuntimeException("content.runtime_exec.property_moved");
}
/**
* Executes the check command, if present. Any errors will result in this component
* being rendered unusable within the transformer registry, but may still be called
* directly.
*/
public void afterPropertiesSet()
{
if (transformCommand == null)
{
throw new AlfrescoRuntimeException("Mandatory property 'transformCommand' not set");
}
// execute the command
if (checkCommand != null)
{
ExecutionResult result = checkCommand.execute();
// check the return code
if (this.available = result.getSuccess())
{
this.versionString = result.getStdOut().trim();
}
else
{
logger.error("Failed to start a runtime executable content transformer: \n" + result);
}
}
else
{
// no check - just assume it is available
available = true;
}
}
/**
* If the initialization failed, then it returns 0.0.
* Otherwise the explicit transformations are checked for the reliability.
*
* @return Returns 1.0 if initialization succeeded, otherwise 0.0.
*
* @see AbstractContentTransformer#setExplicitTransformations(List)
*/
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
{
return available;
}
@Override
public String getComments(boolean available)
{
return "";
}
/**
* Signals whether this transformer is available.
*
* @return true, if is available
*/
public boolean isAvailable()
{
return this.available;
}
/**
* Gets the version string captured from the check command.
*
* @return the version string
*/
public String getVersionString()
{
return this.versionString;
}
/**
* Converts the source and target content to temporary files with the
* correct extensions for the mimetype that they map to.
*
*/
public final void transform(
ContentReader reader,
ContentWriter writer,
TransformationOptions options) throws Exception
{
// get mimetypes
String sourceMimetype = getMimetype(reader);
String targetMimetype = getMimetype(writer);
// get the extensions to use
String sourceExtension = getMimetypeService().getExtension(sourceMimetype);
String targetExtension = getMimetypeService().getExtension(targetMimetype);
if (sourceExtension == null || targetExtension == null)
{
throw new AlfrescoRuntimeException("Unknown extensions for mimetypes: \n" +
" source mimetype: " + sourceMimetype + "\n" +
" source extension: " + sourceExtension + "\n" +
" target mimetype: " + targetMimetype + "\n" +
" target extension: " + targetExtension);
}
// create required temp files
File sourceFile = TempFileProvider.createTempFile(
getClass().getSimpleName() + "_source_",
"." + sourceExtension);
File targetFile = TempFileProvider.createTempFile(
getClass().getSimpleName() + "_target_",
"." + targetExtension);
Map<String, String> properties = new HashMap<String, String>(5);
// copy options over
Map<String, Object> optionsMap = options.toMap();
for (Map.Entry<String, Object> entry : optionsMap.entrySet())
{
String key = entry.getKey();
Object value = entry.getValue();
properties.put(key, (value == null ? null : value.toString()));
}
// add the source and target properties
properties.put(VAR_SOURCE, sourceFile.getAbsolutePath());
properties.put(VAR_TARGET, targetFile.getAbsolutePath());
properties.put(VAR_PAGE_RANGE, "0-"+(options.getPageLimit() >=0 ? options.getPageLimit() : ""));
// pull reader file into source temp file
reader.getContent(sourceFile);
// execute the transformation command
long timeoutMs = options.getTimeoutMs();
ExecutionResult result = null;
try
{
result = transformCommand.execute(properties, timeoutMs);
}
catch (Throwable e)
{
throw new ContentIOException("Transformation failed during command execution: \n" + transformCommand, e);
}
// check
if (!result.getSuccess())
{
throw new ContentIOException("Transformation failed - status indicates an error: \n" + result);
}
// check that the file was created
if (!targetFile.exists())
{
throw new ContentIOException("Transformation failed - target file doesn't exist: \n" + result);
}
// copy the target file back into the repo
writer.putContent(targetFile);
// done
if (logger.isDebugEnabled())
{
logger.debug("Transformation completed: \n" +
" source: " + reader + "\n" +
" target: " + writer + "\n" +
" options: " + options + "\n" +
" result: \n" + result);
}
}
}