mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merged V4.0-BUG-FIX to HEAD
33836: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock 33842: Fixes ALF-12797: i18n strings in activiti-admin login-screen escaped properly 33844: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock - batch touch to limit the in clause size generated 33845: Manually added extra core Share extensions needed for the V4.0 Records Management module from the development branch. - Refactored JSON property decorators for the Document Library data webscripts - Document List banners (e.g. working copy) moved into metadata template config - Ability to override default document/folder title within Document Library (<title> element in metadata template - unused in core code) - Additional extension point in surf-doclist to override remote data URL - Better handling for missing content property 33852: ALF-12725: Merged V3.4-BUG-FIX (3.4.9) to V4.0-BUG-FIX (4.0.1) 33849: Merged V3 (3.4.8) to V3.4-BUG-FIX (3.4.9) 33848: ALF-10976 (relates to ALF-10412) Fixed bug to do with preview being stuck as always being 'Content cannot be previewed. Do you wish to download?' or a 'blank preview after a transformer is not found' for all content with the same mimetype. Cache in ThumbnailRegistory.getThumbnailDefinitions() now understands that transformers may have an upper content size limit. The choice between the two options was based on the size of the first file previewed of each mimetype. Needed to add getMaxSourceSizeBytes() to support this (see below). - refactored (previous refactor was incomplete) ContentTransformer so that the two halfs of isTransformable is now split into sub methods isTransformableMimetypes and isTransformableSize. This is why there are so many files changed. - Moved getMaxSourceSizeBytes() from AbstractContentTransformerLimits to ContentTransformer as there were becomming too many places in the code that needed needed to check if the ContentTransformer was an instanceof AbstractContentTransformerLimits before calling this method. - TransformerDebug now uses KB MB GB values in output to make it simpler to read. - TransformerDebug now uses thousand separaters in millisecond values to make it simpler to read. - TransformerDebug now reports the 'parent' transformer name rather than the sub-transformer name when an unavailable transformer is found. Makes it simpler to tie up with the 'available transformer' list with the new pushIsTransformableSize() calls. - TransformerDebug now uses trace logging for calls from ThumbnailRegistory.isThumbnailDefinitionAvailable() as it is normally followed by a ContentService.transform() which is logged at debug level anyway. - TransformerDebug now turns logging level to trace if the file size is 0 bytes. Request from Jan. Not sure how one uploads such a file! - Modified ComplexContentTransformer.isTransformable() so that it checks the mimetypes before the sizes so that TransformerDebug does not report 'unavailable transformers' that don't support the mimetype conversion. - Modified ComplexContentTransformer.getLimits and ComplexContentTransformer.isPageLimitSupported() to include the limits from the first sub transformer. Was not an issue until ContentTransformer.getMaxSourceSizeBytes() was introduced. - Added logger to RhinoScriptProcessor to debug requests run javascript on the server. - Dropped the sourceUrl parameter from ThumbnailRegistry.getThumbnailDefinitions() which was introduced with limits as it is logicall not needed. 33853: DiskInterface.renameFile() can now throw PermissionDeniedException to return a different status to the client. Part of ALF-12717. 33856: Merged V3.4-BUG-FIX to V4.0-BUG-FIX 33835: ALF-12546: Remove references to retired RegPaths.exe from installed apply_amps.bat script 33843: Fix for ALF-12775 33855: Merged V3.4 to V3.4-BUG-FIX 33851: ALF-12588: Documents Intermittently Do Not Appear in Share - Fix by Alex Busel for regression I accidentally caused in 3.4.6 - Simple typo in mergeDeletions() caused path deletions to sometimes not get applied or get processed twice - Yikes! git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@33857 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -110,6 +110,24 @@
|
||||
<parameter property="namePattern" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
</parameterMap>
|
||||
|
||||
<parameterMap id="parameter_qnameIdAndMinMaxNodeId" type="map">
|
||||
<parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="minNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="maxNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</parameterMap>
|
||||
|
||||
<parameterMap id="parameter_nsIdAndMinMaxNodeId" type="map">
|
||||
<parameter property="nsId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="minNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="maxNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</parameterMap>
|
||||
|
||||
<parameterMap id="parameter_mimetypeIdAndMinMaxNodeId" type="map">
|
||||
<parameter property="mimetypeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="minNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="maxNodeId" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</parameterMap>
|
||||
|
||||
<!-- -->
|
||||
<!-- Selects -->
|
||||
<!-- -->
|
||||
@@ -469,6 +487,60 @@
|
||||
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
|
||||
</select>
|
||||
|
||||
<!-- Find nodes by type qname -->
|
||||
|
||||
<select id="select_NodesByTypeQName" parameterMap="parameter_qnameIdAndMinMaxNodeId" resultType="java.lang.Long" >
|
||||
select
|
||||
n.id
|
||||
from
|
||||
alf_node n
|
||||
where
|
||||
n.type_qname_id = #{qnameId}
|
||||
and n.id >= #{minNodeId}
|
||||
and n.id < #{maxNodeId}
|
||||
</select>
|
||||
|
||||
<select id="select_NodesByTypeUriId" parameterMap="parameter_nsIdAndMinMaxNodeId" resultType="java.lang.Long" >
|
||||
select
|
||||
n.id
|
||||
from
|
||||
alf_node n
|
||||
join alf_qname q on q.id = n.type_qname_id
|
||||
where
|
||||
q.ns_id = #{nsId}
|
||||
and n.id >= #{minNodeId}
|
||||
and n.id < #{maxNodeId}
|
||||
</select>
|
||||
|
||||
<!-- Find nodes by aspect qname -->
|
||||
|
||||
<select id="select_NodesByAspectQName" parameterMap="parameter_qnameIdAndMinMaxNodeId" resultType="java.lang.Long" >
|
||||
select
|
||||
n.id
|
||||
from
|
||||
alf_node n
|
||||
join alf_node_aspects a on n.id = a.node_id
|
||||
where
|
||||
a.qname_id = #{qnameId}
|
||||
and n.id >= #{minNodeId}
|
||||
and n.id < #{maxNodeId}
|
||||
</select>
|
||||
|
||||
<!-- Find nodes by content mimetype -->
|
||||
|
||||
<select id="select_NodesByContentMimetype" parameterMap="parameter_mimetypeIdAndMinMaxNodeId" resultType="long">
|
||||
select
|
||||
np.node_id
|
||||
from
|
||||
alf_node_properties np
|
||||
join alf_content_data cd on np.long_value = cd.id
|
||||
where
|
||||
cd.content_mimetype_id = #{mimetypeId}
|
||||
and (np.actual_type_n = 3 or np.actual_type_n = 21)
|
||||
and np.node_id >= #{minNodeId}
|
||||
and np.node_id < #{maxNodeId}
|
||||
</select>
|
||||
|
||||
<!-- -->
|
||||
<!-- Updates -->
|
||||
<!-- -->
|
||||
|
@@ -1070,11 +1070,14 @@
|
||||
<ref bean="patch.updateDmPermissions" />
|
||||
</list>
|
||||
</property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
<property name="patchDAO">
|
||||
<ref bean="patchDAO" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory" />
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO" />
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper" />
|
||||
</property>
|
||||
<property name="qnameDAO">
|
||||
<ref bean="qnameDAO" />
|
||||
@@ -1777,11 +1780,14 @@
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>4004</value></property>
|
||||
<property name="targetSchema"><value>4005</value></property>
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
<property name="patchDAO">
|
||||
<ref bean="patchDAO" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory" />
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO" />
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper" />
|
||||
</property>
|
||||
<property name="qnameDAO">
|
||||
<ref bean="qnameDAO" />
|
||||
@@ -1920,8 +1926,11 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory"/>
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO"/>
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper"/>
|
||||
</property>
|
||||
<property name="mimetypeMappings">
|
||||
<map>
|
||||
@@ -2301,8 +2310,11 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory"/>
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO"/>
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper"/>
|
||||
</property>
|
||||
<property name="mimetypeMappings">
|
||||
<map>
|
||||
@@ -2847,8 +2859,11 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory"/>
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO"/>
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper"/>
|
||||
</property>
|
||||
<property name="mimetypeMappings">
|
||||
<map>
|
||||
@@ -2906,8 +2921,11 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory"/>
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO"/>
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper"/>
|
||||
</property>
|
||||
<property name="mimetypeMappings">
|
||||
<map>
|
||||
@@ -2942,8 +2960,11 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory"/>
|
||||
<property name="nodeDAO">
|
||||
<ref bean="nodeDAO"/>
|
||||
</property>
|
||||
<property name="retryingTransactionHelper">
|
||||
<ref bean="retryingTransactionHelper"/>
|
||||
</property>
|
||||
<property name="mimetypeMappings">
|
||||
<map>
|
||||
|
@@ -464,6 +464,7 @@
|
||||
org.alfresco.service.cmr.repository.ContentService.getWriter=ACL_NODE.0.sys:base.WriteContent
|
||||
org.alfresco.service.cmr.repository.ContentService.isTransformable=ACL_ALLOW
|
||||
org.alfresco.service.cmr.repository.ContentService.getTransformer=ACL_ALLOW
|
||||
org.alfresco.service.cmr.repository.ContentService.getMaxSourceSizeBytes=ACL_ALLOW
|
||||
org.alfresco.service.cmr.repository.ContentService.getImageTransformer=ACL_ALLOW
|
||||
org.alfresco.service.cmr.repository.ContentService.transform=ACL_ALLOW
|
||||
org.alfresco.service.cmr.repository.ContentService.getTempWriter=ACL_ALLOW
|
||||
|
@@ -223,54 +223,19 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="usernamePropertyDecorator" class="org.alfresco.repo.jscript.app.UsernamePropertyDecorator">
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="tagPropertyDecorator" class="org.alfresco.repo.jscript.app.TagPropertyDecorator">
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="categoryPropertyDecorator" class="org.alfresco.repo.jscript.app.CategoryPropertyDecorator">
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
<bean id="applicationScriptUtils" parent="baseJavaScriptExtension" class="org.alfresco.repo.jscript.ApplicationScriptUtils">
|
||||
<property name="extensionName" value="appUtils" />
|
||||
<property name="jsonConversionComponent" ref="jsonConversionComponent" />
|
||||
</bean>
|
||||
|
||||
<bean id="applicationScriptUtils" parent="baseJavaScriptExtension" class="org.alfresco.repo.jscript.ApplicationScriptUtils">
|
||||
<property name="extensionName">
|
||||
<value>appUtils</value>
|
||||
</property>
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry"/>
|
||||
</property>
|
||||
<property name="decoratedProperties">
|
||||
<map>
|
||||
<entry key="cm:creator">
|
||||
<ref bean="usernamePropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:modifier">
|
||||
<ref bean="usernamePropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:workingCopyOwner">
|
||||
<ref bean="usernamePropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:lockOwner">
|
||||
<ref bean="usernamePropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:owner">
|
||||
<ref bean="usernamePropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:taggable">
|
||||
<ref bean="tagPropertyDecorator"/>
|
||||
</entry>
|
||||
<entry key="cm:categories">
|
||||
<ref bean="categoryPropertyDecorator"/>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<bean id="baseJsonConversionComponent" abstract="true">
|
||||
<property name="nodeService" ref="NodeService"/>
|
||||
<property name="publicServiceAccessService" ref="PublicServiceAccessService" />
|
||||
<property name="namespaceService" ref="NamespaceService" />
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="lockService" ref="LockService" />
|
||||
<property name="permissionService" ref="PermissionService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="userPermissions">
|
||||
<list>
|
||||
<value>CancelCheckOut</value>
|
||||
@@ -282,4 +247,48 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="jsonConversionComponent" class="org.alfresco.repo.jscript.app.JSONConversionComponent" parent="baseJsonConversionComponent">
|
||||
</bean>
|
||||
|
||||
<bean id="baseDecorator" abstract="true" init-method="init">
|
||||
<property name="nodeService" ref="NodeService"/>
|
||||
<property name="namespaceService" ref="NamespaceService"/>
|
||||
<property name="permissionService" ref="PermissionService"/>
|
||||
<property name="jsonConversionComponent" ref="jsonConversionComponent"/>
|
||||
</bean>
|
||||
|
||||
<bean id="usernamePropertiesDecorator" parent="baseDecorator" class="org.alfresco.repo.jscript.app.UsernamePropertyDecorator">
|
||||
<property name="personService" ref="PersonService" />
|
||||
<property name="propertyNames">
|
||||
<set>
|
||||
<value>cm:creator</value>
|
||||
<value>cm:modifier</value>
|
||||
<value>cm:workingCopyOwner</value>
|
||||
<value>cm:lockOwner</value>
|
||||
<value>cm:owner</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="ignorePropertiesDecorator" parent="baseDecorator" class="org.alfresco.repo.jscript.app.IgnorePropertyDecorator">
|
||||
<property name="propertyNames">
|
||||
<set>
|
||||
<value>cm:content</value>
|
||||
<value>sys:locale</value>
|
||||
<value>sys:node-uuid</value>
|
||||
<value>sys:store-protocol</value>
|
||||
<value>sys:node-dbid</value>
|
||||
<value>sys:store-identifier</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="tagPropertyDecorator" parent="baseDecorator" class="org.alfresco.repo.jscript.app.TagPropertyDecorator">
|
||||
<property name="propertyName" value="cm:taggable" />
|
||||
</bean>
|
||||
|
||||
<bean id="categoryPropertyDecorator" parent="baseDecorator" class="org.alfresco.repo.jscript.app.CategoryPropertyDecorator">
|
||||
<property name="propertyName" value="cm:categories" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -19,91 +19,134 @@
|
||||
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.domain.node.NodeDAO;
|
||||
import org.alfresco.repo.domain.patch.PatchDAO;
|
||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||
import org.alfresco.repo.search.Indexer;
|
||||
import org.alfresco.repo.search.IndexerAndSearcher;
|
||||
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* Patch usr:user and cm:person objects so that the user name properties are in the
|
||||
* index in untokenized form. If not authentication may fail in mixed language use.
|
||||
* Patch usr:user and cm:person objects so that the user name properties are in the index in untokenized form. If not
|
||||
* authentication may fail in mixed language use.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class CalendarModelUriPatch extends AbstractPatch
|
||||
{
|
||||
private static final String MSG_SUCCESS = "patch.calendarModelNamespacePatch.result";
|
||||
|
||||
private static final String URI_BEFORE = "com.infoaxon.alfresco.calendar";
|
||||
|
||||
private static final String URI_AFTER = "http://www.alfresco.org/model/calendar";
|
||||
|
||||
private ImporterBootstrap importerBootstrap;
|
||||
private IndexerAndSearcher indexerAndSearcher;
|
||||
private QNameDAO qnameDAO;
|
||||
|
||||
private PatchDAO patchDAO;
|
||||
|
||||
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
|
||||
{
|
||||
this.importerBootstrap = importerBootstrap;
|
||||
}
|
||||
private NodeDAO nodeDAO;
|
||||
|
||||
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
|
||||
{
|
||||
this.indexerAndSearcher = indexerAndSearcher;
|
||||
}
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
private static long BATCH_SIZE = 100000L;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param qnameDAO the qnameDAO to set
|
||||
*/
|
||||
public void setQnameDAO(QNameDAO qnameDAO)
|
||||
{
|
||||
this.qnameDAO = qnameDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param patchDAO the patchDAO to set
|
||||
*/
|
||||
public void setPatchDAO(PatchDAO patchDAO)
|
||||
{
|
||||
this.patchDAO = patchDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeDAO the nodeDAO to set
|
||||
*/
|
||||
public void setNodeDAO(NodeDAO nodeDAO)
|
||||
{
|
||||
this.nodeDAO = nodeDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param retryingTransactionHelper the retryingTransactionHelper to set
|
||||
*/
|
||||
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(patchDAO, "patchDAO");
|
||||
checkPropertyNotNull(qnameDAO, "qnameDAO");
|
||||
checkPropertyNotNull(nodeDAO, "nodeDAO");
|
||||
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
Long maxNodeId = patchDAO.getMaxAdmNodeID();
|
||||
long count = 0L;
|
||||
|
||||
// Make sure the old name spaces exists before we update it ...
|
||||
qnameDAO.getOrCreateNamespace(URI_BEFORE);
|
||||
Pair<Long, String> before = qnameDAO.getOrCreateNamespace(URI_BEFORE);
|
||||
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
|
||||
{
|
||||
Work work = new Work(before.getFirst(), i);
|
||||
count += retryingTransactionHelper.doInTransaction(work, false, true);
|
||||
}
|
||||
|
||||
// modify namespace for all calendar entries
|
||||
qnameDAO.updateNamespace(URI_BEFORE, URI_AFTER);
|
||||
|
||||
// reindex the calendar entries
|
||||
int count = reindex("TYPE:\\{" + AbstractLuceneQueryParser.escape(URI_BEFORE) + "\\}*", importerBootstrap.getStoreRef());
|
||||
return I18NUtil.getMessage(MSG_SUCCESS, count);
|
||||
}
|
||||
|
||||
private int reindex(String query, StoreRef store)
|
||||
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
|
||||
{
|
||||
SearchParameters sp = new SearchParameters();
|
||||
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
sp.setQuery(query);
|
||||
sp.addStore(store);
|
||||
Indexer indexer = indexerAndSearcher.getIndexer(store);
|
||||
ResultSet rs = null;
|
||||
int count = 0;
|
||||
try
|
||||
long nsId;
|
||||
|
||||
long lower;
|
||||
|
||||
Work(long nsId, long lower)
|
||||
{
|
||||
rs = searchService.query(sp);
|
||||
count = rs.length();
|
||||
for (ResultSetRow row : rs)
|
||||
{
|
||||
indexer.updateNode(row.getNodeRef());
|
||||
this.nsId = nsId;
|
||||
this.lower = lower;
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
|
||||
*/
|
||||
@Override
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
if (rs != null)
|
||||
{
|
||||
rs.close();
|
||||
List<Long> nodeIds = patchDAO.getNodesByTypeUriId(nsId, lower, lower + BATCH_SIZE);
|
||||
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
|
||||
return nodeIds.size();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -18,23 +18,15 @@
|
||||
*/
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.domain.mimetype.MimetypeDAO;
|
||||
import org.alfresco.repo.domain.node.NodeDAO;
|
||||
import org.alfresco.repo.domain.patch.PatchDAO;
|
||||
import org.alfresco.repo.search.Indexer;
|
||||
import org.alfresco.repo.search.IndexerAndSearcher;
|
||||
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
@@ -57,19 +49,22 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
|
||||
private static final String MSG_DONE_REINDEX = "patch.genericMimetypeUpdate.doneReindex";
|
||||
|
||||
/* Helper DAOs */
|
||||
private IndexerAndSearcher indexerAndSearcher;
|
||||
|
||||
private MimetypeDAO mimetypeDAO;
|
||||
|
||||
private PatchDAO patchDAO;
|
||||
|
||||
private NodeDAO nodeDAO;
|
||||
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
private static long BATCH_SIZE = 100000L;
|
||||
|
||||
|
||||
/** Mimetype mappings */
|
||||
private Map<String, String> mimetypeMappings;
|
||||
private boolean reindex;
|
||||
|
||||
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
|
||||
{
|
||||
this.indexerAndSearcher = indexerAndSearcher;
|
||||
}
|
||||
|
||||
public void setMimetypeDAO(MimetypeDAO mimetypeDAO)
|
||||
{
|
||||
this.mimetypeDAO = mimetypeDAO;
|
||||
@@ -90,31 +85,41 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
|
||||
this.reindex = reindex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param nodeDAO the nodeDAO to set
|
||||
*/
|
||||
public void setNodeDAO(NodeDAO nodeDAO)
|
||||
{
|
||||
this.nodeDAO = nodeDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param retryingTransactionHelper the retryingTransactionHelper to set
|
||||
*/
|
||||
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(indexerAndSearcher, "indexerAndSearcher");
|
||||
checkPropertyNotNull(mimetypeDAO, "mimetypeDAO");
|
||||
checkPropertyNotNull(patchDAO, "patchDAO");
|
||||
checkPropertyNotNull(mimetypeMappings, "mimetypeMappings");
|
||||
checkPropertyNotNull(nodeDAO, "nodeDAO");
|
||||
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
// First get all the available stores that we might want to reindex
|
||||
List<StoreRef> storeRefsList = nodeService.getStores();
|
||||
Set<StoreRef> storeRefs = new HashSet<StoreRef>();
|
||||
for (StoreRef storeRef : storeRefsList)
|
||||
{
|
||||
// We want workspace://SpacesStore or related MT stores
|
||||
if (storeRef.getIdentifier().endsWith("SpacesStore"))
|
||||
{
|
||||
storeRefs.add(storeRef);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder(I18NUtil.getMessage(MSG_START));
|
||||
|
||||
Long maxNodeId = patchDAO.getMaxAdmNodeID();
|
||||
|
||||
for (Map.Entry<String, String> element : mimetypeMappings.entrySet())
|
||||
{
|
||||
String oldMimetype = element.getKey();
|
||||
@@ -128,6 +133,19 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
|
||||
continue;
|
||||
}
|
||||
|
||||
// pull all affectsed nodes into a new transaction id indexed
|
||||
|
||||
if(reindex)
|
||||
{
|
||||
long count = 0L;
|
||||
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
|
||||
{
|
||||
Work work = new Work(oldMimetypePair.getFirst(), i);
|
||||
count += retryingTransactionHelper.doInTransaction(work, false, true);
|
||||
}
|
||||
result.append(I18NUtil.getMessage(MSG_INDEXED, count, "(All stores)"));
|
||||
}
|
||||
|
||||
// Check if the new mimetype exists
|
||||
Pair<Long, String> newMimetypePair = mimetypeDAO.getMimetype(newMimetype);
|
||||
int updateCount = 0;
|
||||
@@ -144,16 +162,6 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
|
||||
updateCount = patchDAO.updateContentMimetypeIds(oldMimetypeId, newMimetypeId);
|
||||
}
|
||||
result.append(I18NUtil.getMessage(MSG_UPDATED, updateCount, oldMimetype, newMimetype));
|
||||
if (reindex)
|
||||
{
|
||||
// Update Lucene
|
||||
int reindexCount = 0;
|
||||
for (StoreRef storeRef : storeRefs)
|
||||
{
|
||||
reindexCount += reindex(oldMimetype, storeRef);
|
||||
result.append(I18NUtil.getMessage(MSG_INDEXED, reindexCount, storeRef));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Done
|
||||
if (reindex)
|
||||
@@ -168,32 +176,29 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private int reindex(String oldMimetype, StoreRef store)
|
||||
|
||||
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
|
||||
{
|
||||
SearchParameters sp = new SearchParameters();
|
||||
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
sp.setQuery("@" + AbstractLuceneQueryParser.escape(ContentModel.PROP_CONTENT.toString()) +
|
||||
".mimetype:\"" + oldMimetype + "\"");
|
||||
sp.addStore(store);
|
||||
Indexer indexer = indexerAndSearcher.getIndexer(store);
|
||||
ResultSet rs = null;
|
||||
int count = 0;
|
||||
try
|
||||
long mimetypeId;
|
||||
|
||||
long lower;
|
||||
|
||||
Work(long mimetypeId, long lower)
|
||||
{
|
||||
rs = searchService.query(sp);
|
||||
count = rs.length();
|
||||
for (ResultSetRow row : rs)
|
||||
{
|
||||
indexer.updateNode(row.getNodeRef());
|
||||
this.mimetypeId = mimetypeId;
|
||||
this.lower = lower;
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
|
||||
*/
|
||||
@Override
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
if (rs != null)
|
||||
{
|
||||
rs.close();
|
||||
List<Long> nodeIds = patchDAO.getNodesByContentPropertyMimetypeId(mimetypeId, lower, lower + BATCH_SIZE);
|
||||
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
|
||||
return nodeIds.size();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -19,18 +19,15 @@
|
||||
|
||||
package org.alfresco.repo.admin.patch.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
import org.alfresco.repo.domain.node.NodeDAO;
|
||||
import org.alfresco.repo.domain.patch.PatchDAO;
|
||||
import org.alfresco.repo.domain.qname.QNameDAO;
|
||||
import org.alfresco.repo.importer.ImporterBootstrap;
|
||||
import org.alfresco.repo.search.Indexer;
|
||||
import org.alfresco.repo.search.IndexerAndSearcher;
|
||||
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
@@ -56,38 +53,50 @@ public class QNamePatch extends AbstractPatch
|
||||
private String qnameStringAfter;
|
||||
private String reindexClass;
|
||||
|
||||
/* Injected services */
|
||||
private ImporterBootstrap importerBootstrap;
|
||||
private IndexerAndSearcher indexerAndSearcher;
|
||||
private QNameDAO qnameDAO;
|
||||
|
||||
/**
|
||||
* Sets the importerBootstrap.
|
||||
* @param importerBootstrap.
|
||||
*/
|
||||
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
|
||||
{
|
||||
this.importerBootstrap = importerBootstrap;
|
||||
}
|
||||
private PatchDAO patchDAO;
|
||||
|
||||
private NodeDAO nodeDAO;
|
||||
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
private static long BATCH_SIZE = 100000L;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the IndexerAndSearcher.
|
||||
* @param indexerAndSearcher
|
||||
*/
|
||||
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
|
||||
{
|
||||
this.indexerAndSearcher = indexerAndSearcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the QNameDAO.
|
||||
* @param qnameDAO
|
||||
* @param qnameDAO the qnameDAO to set
|
||||
*/
|
||||
public void setQnameDAO(QNameDAO qnameDAO)
|
||||
{
|
||||
this.qnameDAO = qnameDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param patchDAO the patchDAO to set
|
||||
*/
|
||||
public void setPatchDAO(PatchDAO patchDAO)
|
||||
{
|
||||
this.patchDAO = patchDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeDAO the nodeDAO to set
|
||||
*/
|
||||
public void setNodeDAO(NodeDAO nodeDAO)
|
||||
{
|
||||
this.nodeDAO = nodeDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param retryingTransactionHelper the retryingTransactionHelper to set
|
||||
*/
|
||||
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the QName to be patched.
|
||||
* @param qnameStringBefore the long-form QName to be patched from. {namespaceURI}localName
|
||||
@@ -116,6 +125,17 @@ public class QNamePatch extends AbstractPatch
|
||||
this.reindexClass = reindexClass;
|
||||
}
|
||||
|
||||
protected void checkProperties()
|
||||
{
|
||||
super.checkProperties();
|
||||
checkPropertyNotNull(patchDAO, "patchDAO");
|
||||
checkPropertyNotNull(qnameDAO, "qnameDAO");
|
||||
checkPropertyNotNull(nodeDAO, "nodeDAO");
|
||||
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
|
||||
checkPropertyNotNull(qnameStringAfter, "qnameStringAfter");
|
||||
checkPropertyNotNull(qnameStringBefore, "qnameStringBefore");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
@@ -124,46 +144,61 @@ public class QNamePatch extends AbstractPatch
|
||||
QName qnameBefore = QName.createQName(this.qnameStringBefore);
|
||||
QName qnameAfter = QName.createQName(this.qnameStringAfter);
|
||||
|
||||
if (qnameDAO.getQName(qnameBefore) != null)
|
||||
Long maxNodeId = patchDAO.getMaxAdmNodeID();
|
||||
|
||||
Pair<Long, QName> before = qnameDAO.getQName(qnameBefore);
|
||||
|
||||
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
|
||||
{
|
||||
qnameDAO.updateQName(qnameBefore, qnameAfter);
|
||||
Work work = new Work(before.getFirst(), i);
|
||||
retryingTransactionHelper.doInTransaction(work, false, true);
|
||||
}
|
||||
|
||||
// Optionally perform a focussed reindexing of the removed QName.
|
||||
if ("TYPE".equals(reindexClass) ||
|
||||
"ASPECT".equals(reindexClass))
|
||||
if (before != null)
|
||||
{
|
||||
reindex(reindexClass + ":" + AbstractLuceneQueryParser.escape(qnameStringBefore), importerBootstrap.getStoreRef());
|
||||
qnameDAO.updateQName(qnameBefore, qnameAfter);
|
||||
}
|
||||
|
||||
return I18NUtil.getMessage(MSG_SUCCESS, qnameBefore, qnameAfter);
|
||||
}
|
||||
|
||||
private int reindex(String query, StoreRef store)
|
||||
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
|
||||
{
|
||||
SearchParameters sp = new SearchParameters();
|
||||
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
sp.setQuery(query);
|
||||
sp.addStore(store);
|
||||
Indexer indexer = indexerAndSearcher.getIndexer(store);
|
||||
ResultSet rs = null;
|
||||
int count = 0;
|
||||
try
|
||||
long qnameId;
|
||||
|
||||
long lower;
|
||||
|
||||
Work(long qnameId, long lower)
|
||||
{
|
||||
rs = searchService.query(sp);
|
||||
count = rs.length();
|
||||
for (ResultSetRow row : rs)
|
||||
{
|
||||
indexer.updateNode(row.getNodeRef());
|
||||
this.qnameId = qnameId;
|
||||
this.lower = lower;
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
|
||||
*/
|
||||
@Override
|
||||
public Integer execute() throws Throwable
|
||||
{
|
||||
if (rs != null)
|
||||
if ("TYPE".equals(reindexClass))
|
||||
{
|
||||
rs.close();
|
||||
List<Long> nodeIds = patchDAO.getNodesByTypeQNameId(qnameId, lower, lower + BATCH_SIZE);
|
||||
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
|
||||
return nodeIds.size();
|
||||
}
|
||||
else if ("ASPECT".equals(reindexClass))
|
||||
{
|
||||
List<Long> nodeIds = patchDAO.getNodesByAspectQNameId(qnameId, lower, lower + BATCH_SIZE);
|
||||
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
|
||||
return nodeIds.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing to do
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -33,6 +33,7 @@ import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy;
|
||||
import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
|
||||
import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner;
|
||||
import org.alfresco.repo.content.filestore.FileContentStore;
|
||||
import org.alfresco.repo.content.transform.AbstractContentTransformerLimits;
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
import org.alfresco.repo.content.transform.ContentTransformerRegistry;
|
||||
import org.alfresco.repo.content.transform.TransformerDebug;
|
||||
@@ -40,6 +41,7 @@ import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.ClassPolicyDelegate;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.avm.AVMService;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
@@ -628,6 +630,45 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public long getMaxSourceSizeBytes(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
long maxSourceSize = 0;
|
||||
transformerDebug.pushAvailable(null, sourceMimetype, targetMimetype);
|
||||
List<ContentTransformer> transformers = getActiveTransformers(sourceMimetype, 0, targetMimetype, options);
|
||||
for (ContentTransformer transformer: transformers)
|
||||
{
|
||||
long maxSourceSizeKBytes = transformer.getMaxSourceSizeKBytes(sourceMimetype, targetMimetype, options);
|
||||
if (maxSourceSize >= 0)
|
||||
{
|
||||
if (maxSourceSizeKBytes < 0)
|
||||
{
|
||||
maxSourceSize = -1;
|
||||
}
|
||||
else if (maxSourceSizeKBytes > 0 && maxSourceSize < maxSourceSizeKBytes)
|
||||
{
|
||||
maxSourceSize = maxSourceSizeKBytes;
|
||||
}
|
||||
}
|
||||
// if maxSourceSizeKBytes == 0 this implies the transformation is disabled
|
||||
}
|
||||
if (transformerDebug.isEnabled())
|
||||
{
|
||||
transformerDebug.availableTransformers(transformers, -1,
|
||||
"ContentService.getMaxSourceSizeBytes() = "+transformerDebug.fileSize(maxSourceSize*1024));
|
||||
}
|
||||
return (maxSourceSize > 0) ? maxSourceSize * 1024 : maxSourceSize;
|
||||
}
|
||||
finally
|
||||
{
|
||||
transformerDebug.popAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ContentTransformer> getActiveTransformers(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return getActiveTransformers(sourceMimetype, -1, targetMimetype, options);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -208,7 +208,9 @@ public abstract class AbstractContentTransformer implements ContentTransformer
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return isTransformable(sourceMimetype, targetMimetype, options);
|
||||
return
|
||||
isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
|
||||
isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +230,36 @@ public abstract class AbstractContentTransformer implements ContentTransformer
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the supplied mimetypes are supported by calling the deprecated
|
||||
* {@link #isTransformable(String, String, TransformationOptions)} method.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return isTransformable(sourceMimetype, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code true} to indicate size is not an issue.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformableSize(String sourceMimetype, long sourceSize,
|
||||
String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code -1} to indicate an unlimited size.
|
||||
*/
|
||||
@Override
|
||||
public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
|
||||
*/
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -84,6 +84,11 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
|
||||
this.transformerDebug = transformerDebug;
|
||||
}
|
||||
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
throw new IllegalStateException("Method should no longer be called. Override isTransformableMimetype in subclass.");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}<p>
|
||||
*
|
||||
@@ -91,14 +96,24 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
|
||||
* and then {@link #isTransformableSize(String, long, String, TransformationOptions)}.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return
|
||||
isTransformable(sourceMimetype, targetMimetype, options) &&
|
||||
isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
|
||||
isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this transformer is able to transform the given source mimetype
|
||||
* to the target mimetype.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return isTransformable(sourceMimetype, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this transformer is able to transform the given {@code sourceSize}.
|
||||
* The {@code maxSourceSizeKBytes} property may indicate that only small source files
|
||||
@@ -106,31 +121,45 @@ public abstract class AbstractContentTransformerLimits extends ContentTransforme
|
||||
* @param sourceSize size in bytes of the source. If negative, the source size is unknown.
|
||||
* @return {@code true} if the source is transformable.
|
||||
*/
|
||||
protected boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
boolean sizeOkay = true;
|
||||
if (sourceSize >= 0)
|
||||
{
|
||||
TransformationOptionLimits limits = getLimits(sourceMimetype, targetMimetype, options);
|
||||
|
||||
// The maxSourceSizeKbytes value is ignored if this transformer is able to use
|
||||
// page limits and the limits include a pageLimit. Normally used in the creation
|
||||
// of icons. Note the readLimitKBytes value is not checked as the combined limits
|
||||
// only have the max or limit kbytes value set (the smaller value is returned).
|
||||
if (!isPageLimitSupported() || limits.getPageLimit() <= 0)
|
||||
{
|
||||
// if maxSourceSizeKBytes == 0 this implies the transformation is disabled
|
||||
long maxSourceSizeKBytes = limits.getMaxSourceSizeKBytes();
|
||||
long maxSourceSizeKBytes = getMaxSourceSizeKBytes(sourceMimetype, targetMimetype, options);
|
||||
sizeOkay = maxSourceSizeKBytes < 0 || (maxSourceSizeKBytes > 0 && sourceSize <= maxSourceSizeKBytes*1024);
|
||||
if (!sizeOkay && transformerDebug.isEnabled())
|
||||
{
|
||||
transformerDebug.unavailableTransformer(this, maxSourceSizeKBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sizeOkay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum source size (in KBytes) allowed given the supplied values.
|
||||
* @return 0 if the the transformation is disabled, -1 if there is no limit, otherwise the size in KBytes.
|
||||
*/
|
||||
@Override
|
||||
public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
long maxSourceSizeKBytes = -1;
|
||||
|
||||
// The maxSourceSizeKbytes value is ignored if this transformer is able to use
|
||||
// page limits and the limits include a pageLimit. Normally used in the creation
|
||||
// of icons. Note the readLimitKBytes value is not checked as the combined limits
|
||||
// only have the max or limit KBytes value set (the smaller value is returned).
|
||||
TransformationOptionLimits limits = getLimits(sourceMimetype, targetMimetype, options);
|
||||
if (!isPageLimitSupported() || limits.getPageLimit() <= 0)
|
||||
{
|
||||
maxSourceSizeKBytes = limits.getMaxSourceSizeKBytes();
|
||||
}
|
||||
|
||||
return maxSourceSizeKBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timeout (ms) on the InputStream after which an IOExecption is thrown
|
||||
* to terminate very slow transformations or a subprocess is terminated (killed).
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -63,7 +63,7 @@ public class AbstractContentTransformerLimitsTest
|
||||
transformer = new AbstractContentTransformer2()
|
||||
{
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return false;
|
||||
@@ -214,6 +214,70 @@ public class AbstractContentTransformerLimitsTest
|
||||
assertEquals("Getter did not return set value", value, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxSourceSizeKBytes() throws Exception
|
||||
{
|
||||
long kValue = 12;
|
||||
long byteValue = kValue*1024;
|
||||
|
||||
// Not set mimetype limits yet
|
||||
assertTrue("No limits so should have been ok",
|
||||
transformer.isTransformableSize(A, byteValue+1, B, options));
|
||||
|
||||
// Set limit for A to B mimetypes and test
|
||||
limits.setMaxSourceSizeKBytes(kValue);
|
||||
addMimetypeLimits(A, B, limits);
|
||||
transformer.setMimetypeLimits(mimetypeLimits);
|
||||
|
||||
assertEquals("Expected to have set value returned", kValue,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// With a mimetype that does not have any specific limits
|
||||
assertEquals("Expected to have -1 (unlimited) returned", -1,
|
||||
transformer.getMaxSourceSizeKBytes(C, B, options));
|
||||
|
||||
|
||||
// Clear the mimetype limits and double check
|
||||
limits.setMaxSourceSizeKBytes(-1);
|
||||
|
||||
assertEquals("Expected to have -1 (unlimited) returned", -1,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// Check for combinations with transformer limits
|
||||
|
||||
// a) Using just transformer limit to start with
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
assertEquals("Expected to have transformer set value returned", kValue,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// b) combination where transformer limit is used
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
limits.setMaxSourceSizeKBytes(kValue+1);
|
||||
assertEquals("Expected to have transformer set value returned", kValue,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// c) combination where mimetype limit is used
|
||||
transformer.setMaxSourceSizeKBytes(kValue+1);
|
||||
limits.setMaxSourceSizeKBytes(kValue);
|
||||
assertEquals("Expected to have transformer set value returned", kValue,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// Check no limit when page limit set on a transformer that does not support page limit
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
limits.setMaxSourceSizeKBytes(kValue+1);
|
||||
limits.setPageLimit(1);
|
||||
assertEquals("Expected to ignore the page limit as the transformer does not support it", kValue,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
|
||||
// Check no limit when page limit set on a transformer that does support page limit
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
limits.setMaxSourceSizeKBytes(kValue+1);
|
||||
transformer.setPageLimitsSuported(true);
|
||||
limits.setPageLimit(1);
|
||||
assertEquals("Expected to have -1 (unlimited) returned when there are page limits", -1,
|
||||
transformer.getMaxSourceSizeKBytes(A, B, options));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsTransformableSize() throws Exception
|
||||
{
|
||||
@@ -260,16 +324,16 @@ public class AbstractContentTransformerLimitsTest
|
||||
transformer.isTransformableSize(A, byteValue+1, B, options));
|
||||
|
||||
// b) combination where transformer limit is used
|
||||
transformer.setMaxSourceSizeKBytes(kValue+1);
|
||||
limits.setMaxSourceSizeKBytes(kValue);
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
limits.setMaxSourceSizeKBytes(kValue+1);
|
||||
assertTrue("Size is equal to limit so should have been ok",
|
||||
transformer.isTransformableSize(A, byteValue, B, options));
|
||||
assertFalse("Size is greater than limit so should not have failed",
|
||||
transformer.isTransformableSize(A, byteValue+1, B, options));
|
||||
|
||||
// c) combination where mimetype limit is used
|
||||
transformer.setMaxSourceSizeKBytes(kValue);
|
||||
limits.setMaxSourceSizeKBytes(kValue+1);
|
||||
transformer.setMaxSourceSizeKBytes(kValue+1);
|
||||
limits.setMaxSourceSizeKBytes(kValue);
|
||||
assertTrue("Size is equal to limit so should have been ok",
|
||||
transformer.isTransformableSize(A, byteValue, B, options));
|
||||
assertFalse("Size is greater than limit so should not have failed",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -50,7 +50,8 @@ public class BinaryPassThroughContentTransformer extends AbstractContentTransfor
|
||||
|
||||
}
|
||||
|
||||
public boolean isTransformable(String sourceMimetype,
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype,
|
||||
String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (sourceMimetype.startsWith(StringExtractingContentTransformer.PREFIX_TEXT))
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -33,6 +33,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.content.filestore.FileContentWriter;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptionLimits;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
@@ -126,15 +127,32 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we can transform all the way along the chain of mimetypes
|
||||
*
|
||||
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
|
||||
* Overrides this method to avoid calling
|
||||
* {@link #isTransformableMimetype(String, String, TransformationOptions)}
|
||||
* twice on each transformer in the list, as
|
||||
* {@link #isTransformableSize(String, long, String, TransformationOptions)}
|
||||
* in this class must check the mimetype too.
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
boolean result = true;
|
||||
String currentSourceMimetype = sourceMimetype;
|
||||
overrideTransformationOptions(options);
|
||||
|
||||
// To make TransformerDebug output clearer, check the mimetypes and then the sizes.
|
||||
// If not done, 'unavailable' transformers due to size might be reported even
|
||||
// though they cannot transform the source to the target mimetype.
|
||||
|
||||
return
|
||||
isTransformableMimetype(sourceMimetype, targetMimetype, options) &&
|
||||
isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets any transformation option overrides it can.
|
||||
*/
|
||||
private void overrideTransformationOptions(TransformationOptions options)
|
||||
{
|
||||
// Set any transformation options overrides if we can
|
||||
if(options != null && transformationOptionOverrides != null)
|
||||
{
|
||||
@@ -177,8 +195,28 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return isTransformableMimetypeAndSize(sourceMimetype, -1, targetMimetype, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return (sourceSize < 0) ||
|
||||
super.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options) &&
|
||||
isTransformableMimetypeAndSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
private boolean isTransformableMimetypeAndSize(String sourceMimetype, long sourceSize,
|
||||
String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
boolean result = true;
|
||||
String currentSourceMimetype = sourceMimetype;
|
||||
|
||||
boolean first = true;
|
||||
Iterator<ContentTransformer> transformerIterator = transformers.iterator();
|
||||
Iterator<String> intermediateMimetypeIterator = intermediateMimetypes.iterator();
|
||||
while (transformerIterator.hasNext())
|
||||
@@ -196,27 +234,77 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
|
||||
currentTargetMimetype = intermediateMimetypeIterator.next();
|
||||
}
|
||||
|
||||
// check we can tranform the current stage (using -1 if not the first stage as we can't know the size)
|
||||
long size = first ? sourceSize : -1;
|
||||
if (transformer.isTransformable(currentSourceMimetype, size, currentTargetMimetype, options) == false)
|
||||
if (sourceSize < 0)
|
||||
{
|
||||
// check we can transform the current stage's mimetypes
|
||||
if (transformer.isTransformableMimetype(currentSourceMimetype, currentTargetMimetype, options) == false)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check we can transform the current stage's sizes
|
||||
try
|
||||
{
|
||||
transformerDebug.pushIsTransformableSize(this);
|
||||
// (using -1 if not the first stage as we can't know the size)
|
||||
if (transformer.isTransformableSize(currentSourceMimetype, sourceSize, currentTargetMimetype, options) == false)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// move on
|
||||
currentSourceMimetype = currentTargetMimetype;
|
||||
first = false;
|
||||
// As the size is unknown for the next stages stop.
|
||||
// In future we might guess sizes such as excl to pdf
|
||||
// is about 110% of the original size, in which case
|
||||
// we would continue.
|
||||
break;
|
||||
// sourceSize += sourceSize * 10 / 100;
|
||||
}
|
||||
finally
|
||||
{
|
||||
transformerDebug.popIsTransformableSize();
|
||||
}
|
||||
}
|
||||
|
||||
if (result && !isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
|
||||
{
|
||||
result = false;
|
||||
// move on
|
||||
currentSourceMimetype = currentTargetMimetype;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if 'page' limits are supported by the first transformer in the chain.
|
||||
* @return true if the first transformer supports them.
|
||||
*/
|
||||
protected boolean isPageLimitSupported()
|
||||
{
|
||||
ContentTransformer firstTransformer = transformers.iterator().next();
|
||||
return (firstTransformer instanceof AbstractContentTransformerLimits)
|
||||
? ((AbstractContentTransformerLimits)firstTransformer).isPageLimitSupported()
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the limits from this transformer combined with those of the first transformer in the chain.
|
||||
*/
|
||||
protected TransformationOptionLimits getLimits(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
TransformationOptionLimits limits = super.getLimits(sourceMimetype, targetMimetype, options);
|
||||
ContentTransformer firstTransformer = transformers.get(0);
|
||||
if (firstTransformer instanceof AbstractContentTransformerLimits)
|
||||
{
|
||||
String firstTargetMimetype = intermediateMimetypes.get(0);
|
||||
limits = limits.combine(((AbstractContentTransformerLimits) firstTransformer).
|
||||
getLimits(sourceMimetype, firstTargetMimetype, options));
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.content.transform.AbstractContentTransformer2#transformInternal(org.alfresco.service.cmr.repository.ContentReader, org.alfresco.service.cmr.repository.ContentWriter, org.alfresco.service.cmr.repository.TransformationOptions)
|
||||
*/
|
||||
@@ -263,15 +351,4 @@ public class ComplexContentTransformer extends AbstractContentTransformer2 imple
|
||||
{
|
||||
return Collections.unmodifiableList(intermediateMimetypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should no longer be called as the overloaded method
|
||||
* that calls it has the overridden.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -50,6 +50,33 @@ public interface ContentTransformer extends ContentWorker
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Sub component of {@link #isTransformable(String, long, String, TransformationOptions)
|
||||
* that checks just the mimetypes.
|
||||
* @param sourceMimetype the source mimetype
|
||||
* @param targetMimetype the target mimetype
|
||||
* @param options the transformation options
|
||||
* @return boolean true if this content transformer can satify the mimetypes, false otherwise
|
||||
*/
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Sub component of {@link #isTransformable(String, long, String, TransformationOptions)
|
||||
* that checks just the size limits.
|
||||
* @param sourceMimetype the source mimetype
|
||||
* @param sourceSize the size (bytes) of the source. If negative it is unknown.
|
||||
* @param targetMimetype the target mimetype
|
||||
* @param options the transformation options
|
||||
* @return boolean true if this content transformer can satify the mimetypes, false otherwise
|
||||
*/
|
||||
public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Returns the maximum source size (in KBytes) allowed given the supplied values.
|
||||
* @return 0 if the the transformation is disabled, -1 if there is no limit, otherwise the size in KBytes.
|
||||
*/
|
||||
public long getMaxSourceSizeKBytes(String sourceMimetype, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Indicates whether given the provided transformation parmaters this transformer can prvide an explict
|
||||
* transformation.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -111,6 +111,7 @@ public class ContentTransformerRegistry
|
||||
for (ContentTransformer transformer : transformers)
|
||||
{
|
||||
// Transformability can be dynamic, i.e. it may have become unusable
|
||||
// Don't know why we do this test as it has already been done by findTransformers(...)
|
||||
if (transformer.isTransformable(sourceMimetype, sourceSize, targetMimetype, options) == false)
|
||||
{
|
||||
// It is unreliable now.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -236,7 +236,7 @@ public class ContentTransformerRegistryTest extends AbstractContentTransformerTe
|
||||
disable = true;
|
||||
}
|
||||
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (disable) {
|
||||
return false;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -28,6 +28,7 @@ import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
// TODO Modify ContentTransformerWorker to understand transformer limits. At the moment no workers use them
|
||||
public interface ContentTransformerWorker
|
||||
{
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -46,7 +46,8 @@ import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
*/
|
||||
public class EMLTransformer extends AbstractContentTransformer2
|
||||
{
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!MimetypeMap.MIMETYPE_RFC822.equals(sourceMimetype) || !MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -79,37 +79,65 @@ public class FailoverContentTransformer extends AbstractContentTransformer2 impl
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, long sourceSize, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
|
||||
* Overrides super class method to avoid calling
|
||||
* {@link #isTransformableMimetype(String, String, TransformationOptions)}
|
||||
* twice on each transformer in the list, as
|
||||
* {@link #isTransformableSize(String, long, String, TransformationOptions)}
|
||||
* in this class must check the mimetype too.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
// For this transformer to be considered operational, there must be at least one transformer
|
||||
// in the chain that can perform for us.
|
||||
boolean result = false;
|
||||
return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return isTransformableMimetypeAndSize(sourceMimetype, -1, targetMimetype, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformableSize(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return (sourceSize < 0) || isTransformableMimetypeAndSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
private boolean isTransformableMimetypeAndSize(String sourceMimetype, long sourceSize,
|
||||
String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
boolean result = false;
|
||||
if (super.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
|
||||
{
|
||||
for (ContentTransformer ct : this.transformers)
|
||||
{
|
||||
if (ct.isTransformable(sourceMimetype, sourceSize, targetMimetype, options))
|
||||
transformerDebug.pushIsTransformableSize(this);
|
||||
if (ct.isTransformableMimetype(sourceMimetype, targetMimetype, options))
|
||||
{
|
||||
// There may be size limits on this transformer as well as those it contains.
|
||||
result = isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
if (sourceSize == -1)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ct.isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should no longer be called as the overloaded method
|
||||
* that calls it has the overridden.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
finally
|
||||
{
|
||||
return false;
|
||||
transformerDebug.popIsTransformableSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isExplicitTransformation(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -118,7 +118,8 @@ class DummyTestContentTransformer extends AbstractContentTransformer2 implements
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTransformable(String sourceMimetype,
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype,
|
||||
String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
// We'll arbitrarily claim to be able to transform PDF to PNG
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -50,7 +50,8 @@ public class HtmlParserContentTransformer extends AbstractContentTransformer2
|
||||
/**
|
||||
* Only support HTML to TEXT.
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!MimetypeMap.MIMETYPE_HTML.equals(sourceMimetype) ||
|
||||
!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(targetMimetype))
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -76,7 +76,9 @@ public class MediaWikiContentTransformer extends AbstractContentTransformer2
|
||||
* Only transform from mediawiki to html
|
||||
*
|
||||
* @see org.alfresco.repo.content.transform.ContentTransformer#isTransformable(java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.TransformationOptions)
|
||||
*/public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!MimetypeMap.MIMETYPE_TEXT_MEDIAWIKI.equals(sourceMimetype) ||
|
||||
!MimetypeMap.MIMETYPE_HTML.equals(targetMimetype))
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -53,7 +53,8 @@ public class PdfBoxPdfToImageContentTransformer extends AbstractContentTransform
|
||||
private static final String PDF_DEFAULT_PASSWORD = "";
|
||||
private static Log logger = LogFactory.getLog(PdfBoxPdfToImageContentTransformer.class);
|
||||
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
// only support PDF -> PNG OR Adobe Illustrator -> PNG.
|
||||
// Recent .ai file format is a .pdf file.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -53,7 +53,8 @@ public class PdfToImageContentTransformer extends AbstractContentTransformer2
|
||||
/**
|
||||
* Currently the only transformation performed is that of text extraction from PDF documents.
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
// only support PDF -> PNG OR Adobe Illustrator -> PNG.
|
||||
// .ai is really just a .pdf file anyway
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -72,28 +72,17 @@ public class PoiHssfContentTransformer extends TikaPoweredContentTransformer
|
||||
* We support transforming to HTML, XML, Text or CSV
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if(sourceMimeTypes.contains(sourceMimetype) &&
|
||||
MimetypeMap.MIMETYPE_TEXT_CSV.equals(targetMimetype))
|
||||
{
|
||||
// Special case for CSV
|
||||
return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise fall back on the default Tika rules
|
||||
return super.isTransformable(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should no longer be called as the overloaded method
|
||||
* that calls it has been overridden.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return isTransformable(sourceMimetype, -1, targetMimetype, options);
|
||||
return super.isTransformableMimetype(sourceMimetype, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +101,7 @@ public class PoiHssfContentTransformer extends TikaPoweredContentTransformer
|
||||
}
|
||||
|
||||
// Otherwise fall back on the default Tika rules
|
||||
return super.isTransformable(sourceMimetype, targetMimetype, options);
|
||||
return super.isTransformableMimetype(sourceMimetype, targetMimetype, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -58,7 +58,8 @@ public class ProxyContentTransformer extends AbstractContentTransformer2
|
||||
/**
|
||||
* @see DocumentFormatRegistry
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
return this.worker.isTransformable(sourceMimetype, targetMimetype, options);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -50,7 +50,8 @@ public class StringExtractingContentTransformer extends AbstractContentTransform
|
||||
* <p>
|
||||
* Extraction of text from binary data is wholly unreliable.
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if (!targetMimetype.equals(MimetypeMap.MIMETYPE_TEXT_PLAIN))
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -100,7 +100,8 @@ public class TextToPdfContentTransformer extends AbstractContentTransformer2
|
||||
/**
|
||||
* Only supports Text to PDF
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if ( (!MimetypeMap.MIMETYPE_TEXT_PLAIN.equals(sourceMimetype) &&
|
||||
!MimetypeMap.MIMETYPE_TEXT_CSV.equals(sourceMimetype) &&
|
||||
@@ -112,21 +113,10 @@ public class TextToPdfContentTransformer extends AbstractContentTransformer2
|
||||
}
|
||||
else
|
||||
{
|
||||
return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should no longer be called as the overloaded method
|
||||
* that calls it has the overridden.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transformInternal(
|
||||
ContentReader reader,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -87,7 +87,8 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
|
||||
* Can we do the requested transformation via Tika?
|
||||
* We support transforming to HTML, XML or Text
|
||||
*/
|
||||
public boolean isTransformable(String sourceMimetype, long sourceSize, String targetMimetype, TransformationOptions options)
|
||||
@Override
|
||||
public boolean isTransformableMimetype(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||
{
|
||||
if(! sourceMimeTypes.contains(sourceMimetype))
|
||||
{
|
||||
@@ -101,8 +102,7 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
|
||||
MimetypeMap.MIMETYPE_XML.equals(targetMimetype))
|
||||
{
|
||||
// We can output to this
|
||||
// But there may be size limits on this transformer.
|
||||
return isTransformableSize(sourceMimetype, sourceSize, targetMimetype, options);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -111,17 +111,6 @@ public abstract class TikaPoweredContentTransformer extends AbstractContentTrans
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should no longer be called as the overloaded method
|
||||
* that calls it has been overridden.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTransformable(String sourceMimetype, String targetMimetype,
|
||||
TransformationOptions options)
|
||||
{
|
||||
return isTransformable(sourceMimetype, -1, targetMimetype, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriate Tika ContentHandler for the
|
||||
* requested content type. Normally you'll let this
|
||||
|
@@ -18,10 +18,9 @@
|
||||
*/
|
||||
package org.alfresco.repo.content.transform;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Formatter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -74,6 +73,7 @@ public class TransformerDebug
|
||||
};
|
||||
|
||||
private final Deque<Frame> stack = new ArrayDeque<Frame>();
|
||||
private final Deque<String> isTransformableStack = new ArrayDeque<String>();
|
||||
private boolean debugOutput = true;
|
||||
|
||||
public static Deque<Frame> getStack()
|
||||
@@ -86,6 +86,11 @@ public class TransformerDebug
|
||||
return threadInfo.get().debugOutput;
|
||||
}
|
||||
|
||||
public static Deque<String> getIsTransformableStack()
|
||||
{
|
||||
return threadInfo.get().isTransformableStack;
|
||||
}
|
||||
|
||||
public static boolean setDebugOutput(boolean debugOutput)
|
||||
{
|
||||
ThreadInfo thisThreadInfo = threadInfo.get();
|
||||
@@ -103,6 +108,7 @@ public class TransformerDebug
|
||||
private final String fromUrl;
|
||||
private final String sourceMimetype;
|
||||
private final String targetMimetype;
|
||||
private final boolean origDebugOutput;
|
||||
private final long start;
|
||||
|
||||
private Call callType;
|
||||
@@ -111,13 +117,14 @@ public class TransformerDebug
|
||||
// See debug(String, Throwable) as to why this is commented out
|
||||
// private Throwable lastThrowable;
|
||||
|
||||
private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype, Call pushCall)
|
||||
private Frame(Frame parent, String fromUrl, String sourceMimetype, String targetMimetype, Call pushCall, boolean origDebugOutput)
|
||||
{
|
||||
this.id = parent == null ? uniqueId.getAndIncrement() : ++parent.childId;
|
||||
this.fromUrl = fromUrl;
|
||||
this.sourceMimetype = sourceMimetype;
|
||||
this.targetMimetype = targetMimetype;
|
||||
this.callType = pushCall;
|
||||
this.origDebugOutput = origDebugOutput;
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -196,6 +203,17 @@ public class TransformerDebug
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called prior to calling a nested isTransformable.
|
||||
*/
|
||||
public void pushIsTransformableSize(ContentTransformer transformer)
|
||||
{
|
||||
if (isEnabled())
|
||||
{
|
||||
ThreadInfo.getIsTransformableStack().push(getName(transformer));
|
||||
}
|
||||
}
|
||||
|
||||
private void push(String name, String fromUrl, String sourceMimetype, String targetMimetype, long sourceSize, Call callType)
|
||||
{
|
||||
Deque<Frame> ourStack = ThreadInfo.getStack();
|
||||
@@ -207,7 +225,9 @@ public class TransformerDebug
|
||||
}
|
||||
else
|
||||
{
|
||||
frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, callType);
|
||||
// Create a new frame. Logging level is set to trace if the file size is 0
|
||||
boolean origDebugOutput = ThreadInfo.setDebugOutput(ThreadInfo.getDebug() && sourceSize != 0);
|
||||
frame = new Frame(frame, fromUrl, sourceMimetype, targetMimetype, callType, origDebugOutput);
|
||||
ourStack.push(frame);
|
||||
|
||||
if (callType == Call.TRANSFORM)
|
||||
@@ -231,8 +251,11 @@ public class TransformerDebug
|
||||
|
||||
if (frame != null)
|
||||
{
|
||||
String name = getName(transformer);
|
||||
String reason = String.format("> %,dK", maxSourceSizeKBytes);
|
||||
Deque<String> isTransformableStack = ThreadInfo.getIsTransformableStack();
|
||||
String name = (!isTransformableStack.isEmpty())
|
||||
? isTransformableStack.getFirst()
|
||||
: getName(transformer);
|
||||
String reason = "> "+fileSize(maxSourceSizeKBytes*1024);
|
||||
boolean debug = (maxSourceSizeKBytes != 0);
|
||||
if (ourStack.size() == 1)
|
||||
{
|
||||
@@ -273,7 +296,7 @@ public class TransformerDebug
|
||||
String name = getName(trans);
|
||||
int pad = longestNameLength - name.length();
|
||||
log((c == 'a' ? "**" : " ") + (c++) + ") " +
|
||||
name + spaces(pad+1) + trans.getTransformationTime() + " ms");
|
||||
name + spaces(pad+1) + ms(trans.getTransformationTime()));
|
||||
}
|
||||
if (frame.unavailableTransformers != null)
|
||||
{
|
||||
@@ -317,7 +340,8 @@ public class TransformerDebug
|
||||
log(frame.fromUrl, firstLevel);
|
||||
}
|
||||
|
||||
log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) + String.format("%,dK ", (sourceSize/1024)) + message);
|
||||
log(getMimetypeExt(frame.sourceMimetype)+getMimetypeExt(frame.targetMimetype) +
|
||||
((sourceSize >= 0) ? fileSize(sourceSize)+' ' : "") + message);
|
||||
|
||||
log(frame.sourceMimetype+' '+frame.targetMimetype, false);
|
||||
}
|
||||
@@ -345,6 +369,17 @@ public class TransformerDebug
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after returning from a nested isTransformable.
|
||||
*/
|
||||
public void popIsTransformableSize()
|
||||
{
|
||||
if (isEnabled())
|
||||
{
|
||||
ThreadInfo.getIsTransformableStack().pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void pop(Call callType)
|
||||
{
|
||||
Deque<Frame> ourStack = ThreadInfo.getStack();
|
||||
@@ -358,12 +393,13 @@ public class TransformerDebug
|
||||
{
|
||||
boolean topFrame = ourStack.size() == 1;
|
||||
log("Finished in " +
|
||||
(System.currentTimeMillis() - frame.start) + " ms" +
|
||||
ms(System.currentTimeMillis() - frame.start) +
|
||||
(frame.callType == Call.AVAILABLE ? " Transformer NOT called" : "") +
|
||||
(topFrame ? "\n" : ""),
|
||||
topFrame);
|
||||
}
|
||||
|
||||
setDebugOutput(frame.origDebugOutput);
|
||||
ourStack.pop();
|
||||
|
||||
// See debug(String, Throwable) as to why this is commented out
|
||||
@@ -523,7 +559,7 @@ public class TransformerDebug
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getName(ContentTransformer transformer)
|
||||
public String getName(ContentTransformer transformer)
|
||||
{
|
||||
return
|
||||
(transformer instanceof AbstractContentTransformer2
|
||||
@@ -567,4 +603,51 @@ public class TransformerDebug
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String ms(long time)
|
||||
{
|
||||
return String.format("%,d ms", time);
|
||||
}
|
||||
|
||||
public String fileSize(long size)
|
||||
{
|
||||
if (size < 0)
|
||||
{
|
||||
return "unlimited";
|
||||
}
|
||||
if (size == 1)
|
||||
{
|
||||
return "1 byte";
|
||||
}
|
||||
final String[] units = new String[] { "bytes", "KB", "MB", "GB", "TB" };
|
||||
long divider = 1;
|
||||
for(int i = 0; i < units.length-1; i++)
|
||||
{
|
||||
long nextDivider = divider * 1024;
|
||||
if(size < nextDivider)
|
||||
{
|
||||
return fileSizeFormat(size, divider, units[i]);
|
||||
}
|
||||
divider = nextDivider;
|
||||
}
|
||||
return fileSizeFormat(size, divider, units[units.length-1]);
|
||||
}
|
||||
|
||||
private String fileSizeFormat(long size, long divider, String unit)
|
||||
{
|
||||
size = size * 10 / divider;
|
||||
int decimalPoint = (int) size % 10;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(size/10);
|
||||
if (decimalPoint != 0)
|
||||
{
|
||||
sb.append(".");
|
||||
sb.append(decimalPoint);
|
||||
}
|
||||
sb.append(' ');
|
||||
sb.append(unit);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -1437,6 +1437,32 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
||||
return updateNodeImpl(oldNode, nodeUpdate, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int touchNodes(Long txnId, List<Long> nodeIds)
|
||||
{
|
||||
// limit in clause to 1000 node ids
|
||||
int batchSize = 1000;
|
||||
|
||||
int touched = 0;
|
||||
ArrayList<Long> batch = new ArrayList<Long>(batchSize);
|
||||
for(Long nodeId : nodeIds)
|
||||
{
|
||||
invalidateNodeCaches(nodeId);
|
||||
batch.add(nodeId);
|
||||
if(batch.size() % batchSize == 0)
|
||||
{
|
||||
touched += updateNodes(txnId, batch);
|
||||
batch.clear();
|
||||
}
|
||||
}
|
||||
if(batch.size() > 0)
|
||||
{
|
||||
touched += updateNodes(txnId, batch);
|
||||
}
|
||||
return touched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the node's transaction and <b>cm:auditable</b> properties while
|
||||
* providing a convenient method to control cache entry invalidation.
|
||||
|
@@ -202,6 +202,14 @@ public interface NodeDAO extends NodeBulkLoader
|
||||
QName assocTypeQName,
|
||||
QName assocQName);
|
||||
|
||||
/**
|
||||
* Update the transaction associated with a lust of nodes
|
||||
* @param txnId - the tx id to set
|
||||
* @param nodeIds - the nodes to update
|
||||
* @return the number of nodes touched
|
||||
*/
|
||||
public int touchNodes(Long txnId, List<Long> nodeIds);
|
||||
|
||||
/**
|
||||
* @param nodeTypeQName the new type QName for the node or <tt>null</tt> to keep the existing one
|
||||
* @param nodeLocale the new locale for the node or <tt>null</tt> to keep the existing one
|
||||
|
@@ -244,4 +244,41 @@ public interface PatchDAO
|
||||
* @return Returns a count of the number of nodes that have either of the aspects
|
||||
*/
|
||||
public long getCountNodesWithAspects(Set<QName> qnames);
|
||||
|
||||
/**
|
||||
* Find all the nodes ids with the given type
|
||||
* @param typeQNameId - the id of the type qname
|
||||
* @param minNodeId - min node id in the result set - inclusive
|
||||
* @param maxNodeId - max node id in the result set - exclusive
|
||||
* @return
|
||||
*/
|
||||
public List<Long> getNodesByTypeQNameId(Long typeQNameId, Long minNodeId, Long maxNodeId);
|
||||
|
||||
/**
|
||||
* Find all the nodes ids with the given type uri
|
||||
* @param uriId - the id of the type qname uri
|
||||
* @param minNodeId - min node id in the result set - inclusive
|
||||
* @param maxNodeId - max node id in the result set - exclusive
|
||||
* @return
|
||||
*/
|
||||
public List<Long> getNodesByTypeUriId(Long uriId, Long minNodeId, Long maxNodeId);
|
||||
|
||||
/**
|
||||
* Find all the nodes ids with the given aspect
|
||||
* @param aspectQNameId - the id of the aspect qname
|
||||
* @param minNodeId - min node id in the result set - inclusive
|
||||
* @param maxNodeId - max node id in the result set - exclusive
|
||||
* @return
|
||||
*/
|
||||
public List<Long> getNodesByAspectQNameId(Long aspectQNameId, Long minNodeId, Long maxNodeId);
|
||||
|
||||
/**
|
||||
* Find all the nodes ids with the given content property set with the given mimetype
|
||||
* @param mimetypeId - the id of the content data mimetype
|
||||
* @param minNodeId - min node id in the result set - inclusive
|
||||
* @param maxNodeId - max node id in the result set - exclusive
|
||||
* @return
|
||||
*/
|
||||
public List<Long> getNodesByContentPropertyMimetypeId(Long mimetypeId, Long minNodeId, Long maxNodeId);
|
||||
|
||||
}
|
||||
|
@@ -104,6 +104,11 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl
|
||||
|
||||
private static final String SELECT_COUNT_NODES_WITH_ASPECTS = "alfresco.patch.select_CountNodesWithAspectIds";
|
||||
|
||||
private static final String SELECT_NODES_BY_TYPE_QNAME = "alfresco.patch.select_NodesByTypeQName";
|
||||
private static final String SELECT_NODES_BY_TYPE_URI = "alfresco.patch.select_NodesByTypeUriId";
|
||||
private static final String SELECT_NODES_BY_ASPECT_QNAME = "alfresco.patch.select_NodesByAspectQName";
|
||||
private static final String SELECT_NODES_BY_CONTENT_MIMETYPE = "alfresco.patch.select_NodesByContentMimetype";
|
||||
|
||||
private LocaleDAO localeDAO;
|
||||
|
||||
protected SqlSessionTemplate template;
|
||||
@@ -653,4 +658,49 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<Long> getNodesByTypeQNameId(Long typeQNameId, Long minNodeId, Long maxNodeId)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put("qnameId", typeQNameId);
|
||||
params.put("minNodeId", minNodeId);
|
||||
params.put("maxNodeId", maxNodeId);
|
||||
return (List<Long>) template.selectList(SELECT_NODES_BY_TYPE_QNAME, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<Long> getNodesByTypeUriId(Long nsId, Long minNodeId, Long maxNodeId)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put("nsId", nsId);
|
||||
params.put("minNodeId", minNodeId);
|
||||
params.put("maxNodeId", maxNodeId);
|
||||
return (List<Long>) template.selectList(SELECT_NODES_BY_TYPE_URI, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<Long> getNodesByAspectQNameId(Long aspectQNameId, Long minNodeId, Long maxNodeId)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put("qnameId", aspectQNameId);
|
||||
params.put("minNodeId", minNodeId);
|
||||
params.put("maxNodeId", maxNodeId);
|
||||
return (List<Long>) template.selectList(SELECT_NODES_BY_ASPECT_QNAME, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<Long> getNodesByContentPropertyMimetypeId(Long mimetypeId, Long minNodeId, Long maxNodeId)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put("mimetypeId", mimetypeId);
|
||||
params.put("minNodeId", minNodeId);
|
||||
params.put("maxNodeId", maxNodeId);
|
||||
return (List<Long>) template.selectList(SELECT_NODES_BY_CONTENT_MIMETYPE, params);
|
||||
}
|
||||
}
|
||||
|
@@ -18,24 +18,10 @@
|
||||
*/
|
||||
package org.alfresco.repo.jscript;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.jscript.app.PropertyDecorator;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
import org.alfresco.repo.jscript.app.JSONConversionComponent;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
|
||||
/**
|
||||
* Utility functions specifically for external application use.
|
||||
@@ -45,45 +31,18 @@ import java.util.*;
|
||||
|
||||
public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ApplicationScriptUtils.class);
|
||||
|
||||
/** Repository Service Registry */
|
||||
private ServiceRegistry services;
|
||||
private NodeService nodeService = null;
|
||||
private Map<String, Object> decoratedProperties;
|
||||
private String[] userPermissions;
|
||||
|
||||
/** Content download API URL */
|
||||
private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
/**
|
||||
* Set the service registry
|
||||
*
|
||||
* @param serviceRegistry the service registry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.services = serviceRegistry;
|
||||
this.nodeService = services.getNodeService();
|
||||
}
|
||||
/** JSON conversion component */
|
||||
private JSONConversionComponent jsonConversionComponent;
|
||||
|
||||
/**
|
||||
* Set the properties that require decorator beans
|
||||
*
|
||||
* @param decoratedProperties
|
||||
* @param jsonConversionComponent JSON conversion component
|
||||
*/
|
||||
public void setDecoratedProperties(Map<String, Object> decoratedProperties)
|
||||
public void setJsonConversionComponent(JSONConversionComponent jsonConversionComponent)
|
||||
{
|
||||
this.decoratedProperties = decoratedProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the list of user permissions to return in the JSON body
|
||||
*
|
||||
* @param userPermissions
|
||||
*/
|
||||
public void setUserPermissions(String[] userPermissions)
|
||||
{
|
||||
this.userPermissions = userPermissions;
|
||||
this.jsonConversionComponent = jsonConversionComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,168 +66,7 @@ public final class ApplicationScriptUtils extends BaseScopableProcessorExtension
|
||||
*/
|
||||
public String toJSON(ScriptNode node, boolean useShortQNames)
|
||||
{
|
||||
return this.toJSONObj(node, useShortQNames).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object representing the node.
|
||||
*
|
||||
* @param node the node to convert to JSON representation.
|
||||
* @param useShortQNames if true short-form qnames will be returned, else long-form.
|
||||
* @return The JSON representation of this node
|
||||
*/
|
||||
protected Object toJSONObj(ScriptNode node, boolean useShortQNames)
|
||||
{
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
if (this.nodeService.exists(nodeRef))
|
||||
{
|
||||
if (this.services.getPublicServiceAccessService().hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
|
||||
{
|
||||
try
|
||||
{
|
||||
String typeString = useShortQNames ? this.getShortQName(node.getQNameType()) : node.getType();
|
||||
boolean isLink = node.getIsLinkToContainer() || node.getIsLinkToDocument();
|
||||
|
||||
json.put("nodeRef", nodeRef.toString());
|
||||
json.put("type", typeString);
|
||||
json.put("isContainer", node.getIsContainer() || node.getIsLinkToContainer());
|
||||
json.put("isLink", isLink);
|
||||
json.put("isLocked", node.getIsLocked());
|
||||
|
||||
if (node.getIsDocument())
|
||||
{
|
||||
json.put("contentURL", this.getDownloadAPIUrl(node));
|
||||
json.put("mimetype", node.getMimetype());
|
||||
json.put("size", node.getSize());
|
||||
}
|
||||
|
||||
// permissions
|
||||
Map<String, Serializable> permissionsJSON = new LinkedHashMap<String, Serializable>(3);
|
||||
if (node.hasPermission("ReadPermissions"))
|
||||
{
|
||||
permissionsJSON.put("roles", node.retrieveAllSetPermissions(false, true));
|
||||
}
|
||||
permissionsJSON.put("inherited", node.inheritsPermissions());
|
||||
Map<String, Serializable> userPermissionJSON = new LinkedHashMap<String, Serializable>(this.userPermissions.length);
|
||||
for (String userPermission : this.userPermissions)
|
||||
{
|
||||
userPermissionJSON.put(userPermission, node.hasPermission(userPermission));
|
||||
}
|
||||
permissionsJSON.put("user", (Serializable) userPermissionJSON);
|
||||
json.put("permissions", permissionsJSON);
|
||||
|
||||
// add properties
|
||||
Map<QName, Serializable> nodeProperties = this.nodeService.getProperties(nodeRef);
|
||||
json.put("properties", this.parseToJSON(nodeRef, nodeProperties, useShortQNames));
|
||||
|
||||
// add aspects as an array
|
||||
Set<QName> nodeAspects = this.nodeService.getAspects(nodeRef);
|
||||
if (useShortQNames)
|
||||
{
|
||||
Set<String> nodeAspectsShortQNames = new LinkedHashSet<String>(nodeAspects.size());
|
||||
for (QName nextLongQName : nodeAspects)
|
||||
{
|
||||
String nextShortQName = this.getShortQName(nextLongQName);
|
||||
nodeAspectsShortQNames.add(nextShortQName);
|
||||
}
|
||||
json.put("aspects", nodeAspectsShortQNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put("aspects", nodeAspects);
|
||||
}
|
||||
|
||||
// link to document or folder?
|
||||
if (isLink)
|
||||
{
|
||||
NodeRef targetNodeRef = (NodeRef) nodeProperties.get(ContentModel.PROP_LINK_DESTINATION);
|
||||
if (targetNodeRef != null)
|
||||
{
|
||||
json.put("linkedNode", this.toJSONObj(new ScriptNode(targetNodeRef, this.services, node.scope), useShortQNames));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JSONException error)
|
||||
{
|
||||
error.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a long-form QName, this method uses the namespace service to create a
|
||||
* short-form QName string.
|
||||
*
|
||||
* @param longQName
|
||||
* @return the short form of the QName string, e.g. "cm:content"
|
||||
*/
|
||||
protected String getShortQName(QName longQName)
|
||||
{
|
||||
return longQName.toPrefixString(this.services.getNamespaceService());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a map of node properties to a format suitable for JSON output
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param properties
|
||||
* @param useShortQNames
|
||||
* @return a decorated map of properties suitable for JSON output
|
||||
*/
|
||||
protected Map<String, Serializable> parseToJSON(NodeRef nodeRef, Map<QName, Serializable> properties, boolean useShortQNames)
|
||||
{
|
||||
Map<String, Serializable> json = new LinkedHashMap<String, Serializable>(properties.size());
|
||||
|
||||
for (QName nextLongQName : properties.keySet())
|
||||
{
|
||||
try
|
||||
{
|
||||
String shortQName = this.getShortQName(nextLongQName);
|
||||
String key = useShortQNames ? shortQName : nextLongQName.toString();
|
||||
Serializable value = properties.get(nextLongQName);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Has a decorator has been registered for this property?
|
||||
if (this.decoratedProperties.containsKey(shortQName))
|
||||
{
|
||||
json.put(key, ((PropertyDecorator) this.decoratedProperties.get(shortQName)).decorate(nodeRef, shortQName, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Built-in data type processing
|
||||
if (value instanceof Date)
|
||||
{
|
||||
Map<String, Serializable> dateObj = new LinkedHashMap<String, Serializable>(1);
|
||||
dateObj.put("value", value);
|
||||
dateObj.put("iso8601", ISO8601DateFormat.format((Date)value));
|
||||
json.put(key, (Serializable)dateObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json.put(key, null);
|
||||
}
|
||||
}
|
||||
catch (NamespaceException ne)
|
||||
{
|
||||
// ignore properties that do not have a registered namespace
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Ignoring property '" + nextLongQName + "' as its namespace is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
return jsonConversionComponent.toJSON(node.getNodeRef(), useShortQNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -65,6 +65,7 @@ import org.springframework.util.FileCopyUtils;
|
||||
public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcessor, ScriptResourceLoader, InitializingBean
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(RhinoScriptProcessor.class);
|
||||
private static final Log callLogger = LogFactory.getLog(RhinoScriptProcessor.class.getName()+".calls");
|
||||
|
||||
private static final String PATH_CLASSPATH = "classpath:";
|
||||
|
||||
@@ -188,7 +189,13 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
}
|
||||
}
|
||||
|
||||
return executeScriptImpl(script, model, location.isSecure());
|
||||
String debugScriptName = null;
|
||||
if (callLogger.isDebugEnabled())
|
||||
{
|
||||
int i = path.lastIndexOf('/');
|
||||
debugScriptName = (i != -1) ? path.substring(i+1) : path;
|
||||
}
|
||||
return executeScriptImpl(script, model, location.isSecure(), debugScriptName);
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
@@ -238,7 +245,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
Context.exit();
|
||||
}
|
||||
|
||||
return executeScriptImpl(script, model, false);
|
||||
return executeScriptImpl(script, model, false, nodeRef.toString());
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
@@ -264,7 +271,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
{
|
||||
Context.exit();
|
||||
}
|
||||
return executeScriptImpl(script, model, true);
|
||||
return executeScriptImpl(script, model, true, "string script");
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
@@ -413,17 +420,19 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
* @param script The script to execute.
|
||||
* @param model Data model containing objects to be added to the root scope.
|
||||
* @param secure True if the script is considered secure and may access java.* libs directly
|
||||
* @param debugScriptName To identify the script in debug messages.
|
||||
*
|
||||
* @return result of the script execution, can be null.
|
||||
*
|
||||
* @throws AlfrescoRuntimeException
|
||||
*/
|
||||
private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure)
|
||||
private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure, String debugScriptName)
|
||||
throws AlfrescoRuntimeException
|
||||
{
|
||||
long startTime = 0;
|
||||
if (logger.isDebugEnabled())
|
||||
if (callLogger.isDebugEnabled())
|
||||
{
|
||||
callLogger.debug(debugScriptName+" Start");
|
||||
startTime = System.nanoTime();
|
||||
}
|
||||
|
||||
@@ -487,6 +496,10 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
}
|
||||
catch (WrappedException w)
|
||||
{
|
||||
if (callLogger.isDebugEnabled())
|
||||
{
|
||||
callLogger.debug(debugScriptName+" Exception", w);
|
||||
}
|
||||
Throwable err = w.getWrappedException();
|
||||
if (err instanceof RuntimeException)
|
||||
{
|
||||
@@ -496,16 +509,20 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
if (callLogger.isDebugEnabled())
|
||||
{
|
||||
callLogger.debug(debugScriptName+" Exception", err);
|
||||
}
|
||||
throw new AlfrescoRuntimeException(err.getMessage(), err);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.exit();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (callLogger.isDebugEnabled())
|
||||
{
|
||||
long endTime = System.nanoTime();
|
||||
logger.debug("Time to execute script: " + (endTime - startTime)/1000000f + "ms");
|
||||
callLogger.debug(debugScriptName+" End " + (endTime - startTime)/1000000 + " ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -2828,7 +2828,7 @@ public class ScriptNode implements Scopeable, NamespacePrefixResolverProvider
|
||||
if (contentReader != null)
|
||||
{
|
||||
String mimetype = contentReader.getMimetype();
|
||||
List<ThumbnailDefinition> thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentReader.getContentUrl(), mimetype, contentReader.getSize());
|
||||
List<ThumbnailDefinition> thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(mimetype, contentReader.getSize());
|
||||
for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
|
||||
{
|
||||
result.add(thumbnailDefinition.getName());
|
||||
|
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public abstract class BasePropertyDecorator implements PropertyDecorator
|
||||
{
|
||||
protected Set<QName> propertyNames;
|
||||
|
||||
protected NodeService nodeService;
|
||||
|
||||
protected NamespaceService namespaceService;
|
||||
|
||||
protected PermissionService permissionService;
|
||||
|
||||
protected JSONConversionComponent jsonConversionComponent;
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
public void setJsonConversionComponent(JSONConversionComponent jsonConversionComponent)
|
||||
{
|
||||
this.jsonConversionComponent = jsonConversionComponent;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
jsonConversionComponent.registerPropertyDecorator(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QName> getPropertyNames()
|
||||
{
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
public void setPropertyName(String propertyName)
|
||||
{
|
||||
propertyNames = new HashSet<QName>(1);
|
||||
propertyNames.add(QName.createQName(propertyName, namespaceService));
|
||||
}
|
||||
|
||||
public void setPropertyNames(Set<String> propertyNames)
|
||||
{
|
||||
this.propertyNames = new HashSet<QName>(propertyNames.size());
|
||||
for (String propertyName : propertyNames)
|
||||
{
|
||||
this.propertyNames.add(QName.createQName(propertyName, namespaceService));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -18,55 +18,46 @@
|
||||
*/
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Category property decorator class.
|
||||
*
|
||||
* @author Mike Hatfield
|
||||
*/
|
||||
public class CategoryPropertyDecorator implements PropertyDecorator
|
||||
public class CategoryPropertyDecorator extends BasePropertyDecorator
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(CategoryPropertyDecorator.class);
|
||||
|
||||
private ServiceRegistry services;
|
||||
private NodeService nodeService = null;
|
||||
private PermissionService permissionService = null;
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.services = serviceRegistry;
|
||||
this.nodeService = serviceRegistry.getNodeService();
|
||||
this.permissionService = serviceRegistry.getPermissionService();
|
||||
}
|
||||
|
||||
public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
|
||||
/**
|
||||
* @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
|
||||
{
|
||||
Collection<NodeRef> collection = (Collection<NodeRef>)value;
|
||||
Object[] array = new Object[collection.size()];
|
||||
int index = 0;
|
||||
JSONArray array = new JSONArray();
|
||||
|
||||
for (NodeRef obj : collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Map<String, Serializable> jsonObj = new LinkedHashMap<String, Serializable>(4);
|
||||
JSONObject jsonObj = new JSONObject();
|
||||
jsonObj.put("name", this.nodeService.getProperty(obj, ContentModel.PROP_NAME));
|
||||
jsonObj.put("path", this.getPath(obj));
|
||||
jsonObj.put("nodeRef", obj.toString());
|
||||
array[index++] = jsonObj;
|
||||
array.add(jsonObj);
|
||||
}
|
||||
catch (InvalidNodeRefException e)
|
||||
{
|
||||
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* 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.jscript.app;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.json.simple.JSONAware;
|
||||
|
||||
/**
|
||||
* Ignores a given property and doesn't output anything in the decoration. This means the property will not appear in the
|
||||
* resulting JSON.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class IgnorePropertyDecorator extends BasePropertyDecorator
|
||||
{
|
||||
/**
|
||||
* @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
|
||||
*/
|
||||
public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.lock.LockStatus;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.security.PublicServiceAccessService;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
|
||||
/**
|
||||
* JSON Conversion Component
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class JSONConversionComponent
|
||||
{
|
||||
/** Content download API URL template */
|
||||
private final static String CONTENT_DOWNLOAD_API_URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(JSONConversionComponent.class);
|
||||
|
||||
/** Registered decorators */
|
||||
protected Map<QName, PropertyDecorator> propertyDecorators = new HashMap<QName, PropertyDecorator>(3);
|
||||
|
||||
/** User permissions */
|
||||
protected String[] userPermissions;
|
||||
|
||||
/** Services */
|
||||
protected NodeService nodeService;
|
||||
protected PublicServiceAccessService publicServiceAccessService;
|
||||
protected NamespaceService namespaceService;
|
||||
protected FileFolderService fileFolderService;
|
||||
protected LockService lockService;
|
||||
protected ContentService contentService;
|
||||
protected PermissionService permissionService;
|
||||
|
||||
/**
|
||||
* @param nodeService node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publicServiceAccessService public service access service
|
||||
*/
|
||||
public void setPublicServiceAccessService(PublicServiceAccessService publicServiceAccessService)
|
||||
{
|
||||
this.publicServiceAccessService = publicServiceAccessService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param namespaceService namespace service
|
||||
*/
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileFolderService file folder service
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
this.fileFolderService = fileFolderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lockService lock service
|
||||
*/
|
||||
public void setLockService(LockService lockService)
|
||||
{
|
||||
this.lockService = lockService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissionService permission service
|
||||
*/
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userPermissions user permissions
|
||||
*/
|
||||
public void setUserPermissions(String[] userPermissions)
|
||||
{
|
||||
this.userPermissions = userPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentService content service
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a property decorator;
|
||||
*
|
||||
* @param propertyDecorator
|
||||
*/
|
||||
public void registerPropertyDecorator(PropertyDecorator propertyDecorator)
|
||||
{
|
||||
for (QName propertyName : propertyDecorator.getPropertyNames())
|
||||
{
|
||||
propertyDecorators.put(propertyName, propertyDecorator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a node reference to a JSON string. Selects the correct converter based on selection
|
||||
* implementation.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public String toJSON(NodeRef nodeRef, boolean useShortQNames)
|
||||
{
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
if (this.nodeService.exists(nodeRef) == true)
|
||||
{
|
||||
if (publicServiceAccessService.hasAccess(ServiceRegistry.NODE_SERVICE.getLocalName(), "getProperties", nodeRef) == AccessStatus.ALLOWED)
|
||||
{
|
||||
// Get node info
|
||||
FileInfo nodeInfo = fileFolderService.getFileInfo(nodeRef);
|
||||
|
||||
// Set root values
|
||||
setRootValues(nodeInfo, json, useShortQNames);
|
||||
|
||||
// add permissions
|
||||
json.put("permissions", permissionsToJSON(nodeRef));
|
||||
|
||||
// add properties
|
||||
json.put("properties", propertiesToJSON(nodeRef, useShortQNames));
|
||||
|
||||
// add aspects
|
||||
json.put("aspects", apsectsToJSON(nodeRef, useShortQNames));
|
||||
}
|
||||
}
|
||||
|
||||
return json.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeInfo
|
||||
* @param rootJSONObject
|
||||
* @param useShortQNames
|
||||
* @throws JSONException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setRootValues(FileInfo nodeInfo, JSONObject rootJSONObject, boolean useShortQNames)
|
||||
{
|
||||
NodeRef nodeRef = nodeInfo.getNodeRef();
|
||||
|
||||
rootJSONObject.put("nodeRef", nodeInfo.getNodeRef().toString());
|
||||
rootJSONObject.put("type", nameToString(nodeInfo.getType(), useShortQNames));
|
||||
rootJSONObject.put("isContainer", nodeInfo.isFolder()); //node.getIsContainer() || node.getIsLinkToContainer());
|
||||
rootJSONObject.put("isLocked", isLocked(nodeInfo.getNodeRef()));
|
||||
|
||||
rootJSONObject.put("isLink", nodeInfo.isLink());
|
||||
if (nodeInfo.isLink() == true)
|
||||
{
|
||||
NodeRef targetNodeRef = nodeInfo.getLinkNodeRef();
|
||||
if (targetNodeRef != null)
|
||||
{
|
||||
rootJSONObject.put("linkedNode", toJSON(targetNodeRef, useShortQNames));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should this be moved to the property output since we may have more than one content property
|
||||
// or a non-standard content property
|
||||
|
||||
if (nodeInfo.isFolder() == false)
|
||||
{
|
||||
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
||||
|
||||
if (reader != null)
|
||||
{
|
||||
String contentURL = MessageFormat.format(
|
||||
CONTENT_DOWNLOAD_API_URL, new Object[]{
|
||||
nodeRef.getStoreRef().getProtocol(),
|
||||
nodeRef.getStoreRef().getIdentifier(),
|
||||
nodeRef.getId(),
|
||||
URLEncoder.encode(nodeInfo.getName())});
|
||||
|
||||
rootJSONObject.put("contentURL", contentURL);
|
||||
rootJSONObject.put("mimetype", reader.getMimetype());
|
||||
rootJSONObject.put("encoding", reader.getEncoding());
|
||||
rootJSONObject.put("size", reader.getSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JSONObject permissionsToJSON(NodeRef nodeRef)
|
||||
{
|
||||
JSONObject permissionsJSON = new JSONObject();
|
||||
if (AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, PermissionService.READ_PERMISSIONS)) == true)
|
||||
{
|
||||
permissionsJSON.put("inherited", permissionService.getInheritParentPermissions(nodeRef));
|
||||
permissionsJSON.put("roles", allSetPermissionsToJSON(nodeRef));
|
||||
permissionsJSON.put("user", userPermissionsToJSON(nodeRef));
|
||||
}
|
||||
return permissionsJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JSONObject userPermissionsToJSON(NodeRef nodeRef)
|
||||
{
|
||||
JSONObject userPermissionJSON = new JSONObject();
|
||||
for (String userPermission : this.userPermissions)
|
||||
{
|
||||
boolean hasPermission = AccessStatus.ALLOWED.equals(permissionService.hasPermission(nodeRef, userPermission));
|
||||
userPermissionJSON.put(userPermission, hasPermission);
|
||||
}
|
||||
return userPermissionJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param useShortQNames
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JSONObject propertiesToJSON(NodeRef nodeRef, boolean useShortQNames)
|
||||
{
|
||||
JSONObject propertiesJSON = new JSONObject();
|
||||
|
||||
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
||||
for (QName propertyName : properties.keySet())
|
||||
{
|
||||
try
|
||||
{
|
||||
String key = nameToString(propertyName, useShortQNames);
|
||||
Serializable value = properties.get(propertyName);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
// Has a decorator has been registered for this property?
|
||||
if (propertyDecorators.containsKey(propertyName) == true)
|
||||
{
|
||||
JSONAware jsonAware = propertyDecorators.get(propertyName).decorate(propertyName, nodeRef, value);
|
||||
if (jsonAware != null)
|
||||
{
|
||||
propertiesJSON.put(key, jsonAware);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Built-in data type processing
|
||||
if (value instanceof Date)
|
||||
{
|
||||
JSONObject dateObj = new JSONObject();
|
||||
dateObj.put("value", JSONObject.escape(value.toString()));
|
||||
dateObj.put("iso8601", JSONObject.escape(ISO8601DateFormat.format((Date)value)));
|
||||
propertiesJSON.put(key, dateObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
propertiesJSON.put(key, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
propertiesJSON.put(key, null);
|
||||
}
|
||||
}
|
||||
catch (NamespaceException ne)
|
||||
{
|
||||
// ignore properties that do not have a registered namespace
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Ignoring property '" + propertyName + "' as its namespace is not registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return propertiesJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @param useShortQNames
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JSONArray apsectsToJSON(NodeRef nodeRef, boolean useShortQNames)
|
||||
{
|
||||
JSONArray aspectsJSON = new JSONArray();
|
||||
|
||||
Set<QName> aspects = this.nodeService.getAspects(nodeRef);
|
||||
for (QName aspect : aspects)
|
||||
{
|
||||
aspectsJSON.add(nameToString(aspect, useShortQNames));
|
||||
}
|
||||
|
||||
return aspectsJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JSONArray allSetPermissionsToJSON(NodeRef nodeRef)
|
||||
{
|
||||
Set<AccessPermission> acls = permissionService.getAllSetPermissions(nodeRef);
|
||||
JSONArray permissions = new JSONArray();
|
||||
for (AccessPermission permission : acls)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
buf.append(permission.getAccessStatus())
|
||||
.append(';')
|
||||
.append(permission.getAuthority())
|
||||
.append(';')
|
||||
.append(permission.getPermission())
|
||||
.append(';').append(permission.isSetDirectly() ? "DIRECT" : "INHERITED");
|
||||
permissions.add(buf.toString());
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param qname
|
||||
* @param isShortName
|
||||
* @return
|
||||
*/
|
||||
private String nameToString(QName qname, boolean isShortName)
|
||||
{
|
||||
String result = null;
|
||||
if (isShortName == true)
|
||||
{
|
||||
result = qname.toPrefixString(namespaceService);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = qname.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
*/
|
||||
private boolean isLocked(NodeRef nodeRef)
|
||||
{
|
||||
boolean locked = false;
|
||||
|
||||
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == true)
|
||||
{
|
||||
LockStatus lockStatus = lockService.getLockStatus(nodeRef);
|
||||
if (lockStatus == LockStatus.LOCKED || lockStatus == LockStatus.LOCK_OWNER)
|
||||
{
|
||||
locked = true;
|
||||
}
|
||||
}
|
||||
|
||||
return locked;
|
||||
}
|
||||
}
|
@@ -18,8 +18,12 @@
|
||||
*/
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.json.simple.JSONAware;
|
||||
|
||||
/**
|
||||
* Interface for property decorators used by ApplicationScriptUtils.toJSON()
|
||||
@@ -28,5 +32,7 @@ import java.io.Serializable;
|
||||
*/
|
||||
public interface PropertyDecorator
|
||||
{
|
||||
Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value);
|
||||
Set<QName> getPropertyNames();
|
||||
|
||||
JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value);
|
||||
}
|
||||
|
@@ -18,51 +18,45 @@
|
||||
*/
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Tag property decorator class.
|
||||
*
|
||||
* @author Mike Hatfield
|
||||
*/
|
||||
public class TagPropertyDecorator implements PropertyDecorator
|
||||
public class TagPropertyDecorator extends BasePropertyDecorator
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(TagPropertyDecorator.class);
|
||||
|
||||
private ServiceRegistry services;
|
||||
private NodeService nodeService = null;
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.services = serviceRegistry;
|
||||
this.nodeService = serviceRegistry.getNodeService();
|
||||
}
|
||||
|
||||
public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
|
||||
/**
|
||||
* @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
|
||||
{
|
||||
Collection<NodeRef> collection = (Collection<NodeRef>)value;
|
||||
Object[] array = new Object[collection.size()];
|
||||
int index = 0;
|
||||
JSONArray array = new JSONArray();
|
||||
|
||||
for (NodeRef obj : collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
Map<String, Serializable> jsonObj = new LinkedHashMap<String, Serializable>(2);
|
||||
JSONObject jsonObj = new JSONObject();
|
||||
jsonObj.put("name", this.nodeService.getProperty(obj, ContentModel.PROP_NAME));
|
||||
jsonObj.put("nodeRef", obj.toString());
|
||||
array[index++] = jsonObj;
|
||||
array.add(jsonObj);
|
||||
}
|
||||
catch (InvalidNodeRefException e)
|
||||
{
|
||||
|
@@ -19,40 +19,43 @@
|
||||
package org.alfresco.repo.jscript.app;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Username property decorator class.
|
||||
*
|
||||
* @author Mike Hatfield
|
||||
*/
|
||||
public class UsernamePropertyDecorator implements PropertyDecorator
|
||||
public class UsernamePropertyDecorator extends BasePropertyDecorator
|
||||
{
|
||||
private ServiceRegistry services;
|
||||
private NodeService nodeService = null;
|
||||
/** Person service */
|
||||
private PersonService personService = null;
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
/**
|
||||
* @param personService person service
|
||||
*/
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.services = serviceRegistry;
|
||||
this.nodeService = serviceRegistry.getNodeService();
|
||||
this.personService = serviceRegistry.getPersonService();
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
public Serializable decorate(NodeRef nodeRef, String propertyName, Serializable value)
|
||||
/**
|
||||
* @see org.alfresco.repo.jscript.app.PropertyDecorator#decorate(org.alfresco.service.cmr.repository.NodeRef, java.io.Serializable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public JSONAware decorate(QName propertyName, NodeRef nodeRef, Serializable value)
|
||||
{
|
||||
String username = value.toString();
|
||||
String firstName = null;
|
||||
String lastName = null;
|
||||
Map<String, Serializable> map = new LinkedHashMap<String, Serializable>(4);
|
||||
JSONObject map = new JSONObject();
|
||||
map.put("userName", username);
|
||||
|
||||
if (this.personService.personExists(username))
|
||||
@@ -70,12 +73,12 @@ public class UsernamePropertyDecorator implements PropertyDecorator
|
||||
else
|
||||
{
|
||||
map.put("isDeleted", true);
|
||||
return (Serializable)map;
|
||||
return map;
|
||||
}
|
||||
|
||||
map.put("firstName", firstName);
|
||||
map.put("lastName", lastName);
|
||||
map.put("displayName", (firstName != null ? firstName + " " : "" + lastName != null ? lastName : "").replaceAll("^\\s+|\\s+$", ""));
|
||||
return (Serializable)map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
@@ -3945,7 +3945,7 @@ public class IndexInfo implements IndexMonitor
|
||||
Searcher searcher = new IndexSearcher(reader);
|
||||
try
|
||||
{
|
||||
for (String stringRef : deletions)
|
||||
for (String stringRef : containerDeletions)
|
||||
{
|
||||
TermQuery query = new TermQuery(new Term("ANCESTOR", stringRef));
|
||||
Hits hits = searcher.search(query);
|
||||
|
@@ -157,7 +157,7 @@ public class SimpleThumbnailer extends TransactionListenerAdapter implements
|
||||
Serializable value = this.nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
ContentData contentData = DefaultTypeConverter.INSTANCE.convert(ContentData.class, value);
|
||||
List<ThumbnailDefinition> thumbnailDefinitions = this.thumbnailService.getThumbnailRegistry()
|
||||
.getThumbnailDefinitions(contentData.getContentUrl(), contentData.getMimetype(), contentData.getSize());
|
||||
.getThumbnailDefinitions(contentData.getMimetype(), contentData.getSize());
|
||||
for (final ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
|
||||
{
|
||||
final NodeRef existingThumbnail = this.thumbnailService.getThumbnailByName(nodeRef,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -66,8 +66,8 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
/** Map of thumbnail definition */
|
||||
private Map<String, ThumbnailDefinition> thumbnailDefinitions = new HashMap<String, ThumbnailDefinition>();
|
||||
|
||||
/** Cache to store mimetype to thumbnailDefinition mapping */
|
||||
private Map<String, List<ThumbnailDefinition>> mimetypeMap = new HashMap<String, List<ThumbnailDefinition>>(17);
|
||||
/** Cache to store mimetype to thumbnailDefinition mapping with max size limit */
|
||||
private Map<String, List<ThumbnailDefinitionLimits>> mimetypeMap = new HashMap<String, List<ThumbnailDefinitionLimits>>(17);
|
||||
|
||||
private ThumbnailRenditionConvertor thumbnailRenditionConvertor;
|
||||
|
||||
@@ -196,23 +196,24 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
*/
|
||||
public List<ThumbnailDefinition> getThumbnailDefinitions(String mimetype)
|
||||
{
|
||||
return getThumbnailDefinitions(null, mimetype, -1);
|
||||
return getThumbnailDefinitions(mimetype, -1);
|
||||
}
|
||||
|
||||
public List<ThumbnailDefinition> getThumbnailDefinitions(String sourceUrl, String mimetype, long sourceSize)
|
||||
public List<ThumbnailDefinition> getThumbnailDefinitions(String mimetype, long sourceSize)
|
||||
{
|
||||
List<ThumbnailDefinition> result = this.mimetypeMap.get(mimetype);
|
||||
List<ThumbnailDefinitionLimits> thumbnailDefinitionsLimitsForMimetype = this.mimetypeMap.get(mimetype);
|
||||
|
||||
if (result == null)
|
||||
if (thumbnailDefinitionsLimitsForMimetype == null)
|
||||
{
|
||||
boolean foundAtLeastOneTransformer = false;
|
||||
result = new ArrayList<ThumbnailDefinition>(7);
|
||||
thumbnailDefinitionsLimitsForMimetype = new ArrayList<ThumbnailDefinitionLimits>(7);
|
||||
|
||||
for (ThumbnailDefinition thumbnailDefinition : this.thumbnailDefinitions.values())
|
||||
{
|
||||
if (isThumbnailDefinitionAvailable(sourceUrl, mimetype, sourceSize, thumbnailDefinition))
|
||||
long maxSourceSizeBytes = getMaxSourceSizeBytes(mimetype, thumbnailDefinition);
|
||||
if (maxSourceSizeBytes != 0)
|
||||
{
|
||||
result.add(thumbnailDefinition);
|
||||
thumbnailDefinitionsLimitsForMimetype.add(new ThumbnailDefinitionLimits(thumbnailDefinition, maxSourceSizeBytes));
|
||||
foundAtLeastOneTransformer = true;
|
||||
}
|
||||
}
|
||||
@@ -229,7 +230,18 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
// been launched and that new transformers are available.
|
||||
if (foundAtLeastOneTransformer)
|
||||
{
|
||||
this.mimetypeMap.put(mimetype, result);
|
||||
this.mimetypeMap.put(mimetype, thumbnailDefinitionsLimitsForMimetype);
|
||||
}
|
||||
}
|
||||
|
||||
// Only return ThumbnailDefinition for this specific source - may be limited on size.
|
||||
List<ThumbnailDefinition> result = new ArrayList<ThumbnailDefinition>(thumbnailDefinitionsLimitsForMimetype.size());
|
||||
for (ThumbnailDefinitionLimits thumbnailDefinitionLimits: thumbnailDefinitionsLimitsForMimetype)
|
||||
{
|
||||
long maxSourceSizeBytes = thumbnailDefinitionLimits.getMaxSourceSizeBytes();
|
||||
if (sourceSize <= 0 || maxSourceSizeBytes < 0 || maxSourceSizeBytes >= sourceSize)
|
||||
{
|
||||
result.add(thumbnailDefinitionLimits.getThumbnailDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,11 +265,11 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
* is able to thumbnail the source mimetype. Typically used with Thumbnail Definitions
|
||||
* retrieved by name, and/or when dealing with transient {@link ContentTransformer}s.
|
||||
* @param sourceUrl The URL of the source (optional)
|
||||
* @param sourceMimeType The source mimetype
|
||||
* @param sourceMimetype The source mimetype
|
||||
* @param sourceSize the size (in bytes) of the source. Use -1 if unknown.
|
||||
* @param thumbnailDefinition The {@link ThumbnailDefinition} to check for
|
||||
*/
|
||||
public boolean isThumbnailDefinitionAvailable(String sourceUrl, String sourceMimeType, long sourceSize, ThumbnailDefinition thumbnailDefinition)
|
||||
public boolean isThumbnailDefinitionAvailable(String sourceUrl, String sourceMimetype, long sourceSize, ThumbnailDefinition thumbnailDefinition)
|
||||
{
|
||||
// Log the following getTransform() as trace so we can see the wood for the trees
|
||||
boolean orig = TransformerDebug.setDebugOutput(false);
|
||||
@@ -265,7 +277,7 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
{
|
||||
return this.contentService.getTransformer(
|
||||
sourceUrl,
|
||||
sourceMimeType,
|
||||
sourceMimetype,
|
||||
sourceSize,
|
||||
thumbnailDefinition.getMimetype(), thumbnailDefinition.getTransformationOptions()
|
||||
) != null;
|
||||
@@ -276,6 +288,28 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum source size of any content that may transformed between the supplied
|
||||
* sourceMimetype and thumbnailDefinition's targetMimetype using its transformation options.
|
||||
* @param sourceMimetype
|
||||
* @param thumbnailDefinition
|
||||
* @return 0 if there are no transformers, -1 if there is no limit or if positive the size in bytes.
|
||||
*/
|
||||
public long getMaxSourceSizeBytes(String sourceMimetype, ThumbnailDefinition thumbnailDefinition)
|
||||
{
|
||||
// Log the following getTransform() as trace so we can see the wood for the trees
|
||||
boolean orig = TransformerDebug.setDebugOutput(false);
|
||||
try
|
||||
{
|
||||
return contentService.getMaxSourceSizeBytes(sourceMimetype,
|
||||
thumbnailDefinition.getMimetype(), thumbnailDefinition.getTransformationOptions());
|
||||
}
|
||||
finally
|
||||
{
|
||||
TransformerDebug.setDebugOutput(orig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a thumbnail details
|
||||
*
|
||||
@@ -344,4 +378,30 @@ public class ThumbnailRegistry implements ApplicationContextAware, ApplicationLi
|
||||
// Intentionally empty
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links transformer limits (such as maximum size) to a ThumbnailDefinition.
|
||||
*
|
||||
*/
|
||||
private class ThumbnailDefinitionLimits
|
||||
{
|
||||
private ThumbnailDefinition thumbnailDefinition;
|
||||
private long maxSourceSizeBytes;
|
||||
|
||||
public ThumbnailDefinitionLimits(ThumbnailDefinition thumbnailDefinition, long maxSourceSizeBytes)
|
||||
{
|
||||
this.thumbnailDefinition = thumbnailDefinition;
|
||||
this.maxSourceSizeBytes = maxSourceSizeBytes;
|
||||
}
|
||||
|
||||
public ThumbnailDefinition getThumbnailDefinition()
|
||||
{
|
||||
return thumbnailDefinition;
|
||||
}
|
||||
|
||||
public long getMaxSourceSizeBytes()
|
||||
{
|
||||
return maxSourceSizeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -724,7 +724,7 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
public void testRegistry()
|
||||
{
|
||||
ThumbnailRegistry thumbnailRegistry = this.thumbnailService.getThumbnailRegistry();
|
||||
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumbnailDefinitions(null, MimetypeMap.MIMETYPE_HTML, -1);
|
||||
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumbnailDefinitions(MimetypeMap.MIMETYPE_HTML, -1);
|
||||
System.out.println("Definitions ...");
|
||||
for (ThumbnailDefinition def : defs)
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -19,10 +19,12 @@
|
||||
package org.alfresco.repo.version;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.alfresco.service.cmr.version.Version;
|
||||
|
||||
/**
|
||||
@@ -109,4 +111,39 @@ public class ContentServiceImplTest extends BaseVersionStoreTest
|
||||
// An exception should be raised
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetTransformer0()
|
||||
{
|
||||
ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 0,
|
||||
"application/x-shockwave-flash", new TransformationOptions());
|
||||
assertTrue("Found have found a transformer for 0 bytes", transformer != null);
|
||||
}
|
||||
|
||||
public void testGetTransformer10K()
|
||||
{
|
||||
ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*10,
|
||||
"application/x-shockwave-flash", new TransformationOptions());
|
||||
assertTrue("Found have found a transformer for 10 K", transformer != null);
|
||||
}
|
||||
|
||||
public void testGetTransformer1M()
|
||||
{
|
||||
ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*1024,
|
||||
"application/x-shockwave-flash", new TransformationOptions());
|
||||
assertTrue("Found have found a transformer for 1M", transformer != null);
|
||||
}
|
||||
|
||||
public void testGetTransformer10M()
|
||||
{
|
||||
ContentTransformer transformer = contentService.getTransformer("test", "application/vnd.ms-excel", 1024*1024*10,
|
||||
"application/x-shockwave-flash", new TransformationOptions());
|
||||
assertTrue("Found NOT have found a transformer for 10M as the is a 1M limit on xsl mimetype", transformer == null);
|
||||
}
|
||||
|
||||
public void testGetMaxSourceSizeByes()
|
||||
{
|
||||
long maxSourceSizeBytes = contentService.getMaxSourceSizeBytes("application/vnd.ms-excel",
|
||||
"application/x-shockwave-flash", new TransformationOptions());
|
||||
assertEquals("Found have found a transformer that can handle 1M", 1024*1024, maxSourceSizeBytes);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
@@ -249,6 +249,17 @@ public interface ContentService
|
||||
*/
|
||||
public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Returns the maximum source size of any content that may transformed between the supplied
|
||||
* mimetypes using the supplied options.
|
||||
* @param sourceMimetype
|
||||
* @param targetMimetype
|
||||
* @param options
|
||||
* @return 0 if there are no transformers, -1 if there is no limit or if positive number the size in bytes.
|
||||
*/
|
||||
@Auditable(parameters = {"sourceMimetype", "targetMimetype", "options"})
|
||||
public long getMaxSourceSizeBytes(String sourceMimetype, String targetMimetype, TransformationOptions options);
|
||||
|
||||
/**
|
||||
* Fetch all the transformers that are capable of transforming the content in the
|
||||
* given source mimetype to the given target mimetype with the provided transformation
|
||||
|
Reference in New Issue
Block a user