mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user