mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-15 15:02:20 +00:00
Merging DEV_TEMPORARY to HEAD (RenditionService)
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19103 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
<import resource="classpath*:alfresco/office-addin-context.xml"/>
|
||||
<import resource="classpath*:alfresco/portlets-context.xml"/>
|
||||
<import resource="classpath:alfresco/blog-context.xml"/>
|
||||
<import resource="classpath:alfresco/rendition-services-context.xml"/>
|
||||
<import resource="classpath:alfresco/thumbnail-service-context.xml"/>
|
||||
<import resource="classpath:alfresco/preference-service-context.xml"/>
|
||||
<import resource="classpath:alfresco/swf-transform-context.xml"/>
|
||||
|
BIN
config/alfresco/bootstrap/systemRenditionDefinitions.acp
Normal file
BIN
config/alfresco/bootstrap/systemRenditionDefinitions.acp
Normal file
Binary file not shown.
@@ -1068,6 +1068,7 @@
|
||||
|
||||
<!-- Content models -->
|
||||
<value>alfresco/model/contentModel.xml</value>
|
||||
<value>alfresco/model/renditionModel.xml</value>
|
||||
<value>alfresco/model/bpmModel.xml</value>
|
||||
<value>alfresco/model/wcmModel.xml</value>
|
||||
<value>alfresco/model/forumModel.xml</value>
|
||||
|
@@ -356,6 +356,7 @@
|
||||
<prop key="spaces.imap_templates.childname">${spaces.imap_templates.childname}</prop>
|
||||
<prop key="spaces.emailActions.childname">${spaces.emailActions.childname}</prop>
|
||||
<prop key="spaces.searchAction.childname">${spaces.searchAction.childname}</prop>
|
||||
<prop key="spaces.rendition.rendering_actions.childname">${spaces.rendition.rendering_actions.childname}</prop>
|
||||
<prop key="spaces.wcm_deployed.childname">${spaces.wcm_deployed.childname}</prop>
|
||||
</props>
|
||||
</property>
|
||||
@@ -565,6 +566,12 @@
|
||||
<prop key="location">alfresco/bootstrap/transferSpaces.xml</prop>
|
||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||
</props>
|
||||
|
||||
<props>
|
||||
<prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
|
||||
<prop key="location">alfresco/bootstrap/systemRenditionDefinitions.acp</prop>
|
||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||
</props>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
@@ -30,6 +30,9 @@ spaces.templates.email.description=Email templates
|
||||
spaces.templates.rss.name=RSS Templates
|
||||
spaces.templates.rss.description=RSS templates
|
||||
|
||||
spaces.rendition.rendering_actions.name=Rendering Actions Space
|
||||
spaces.rendition.rendering_actions.description=A space used by the system to persist rendering actions.
|
||||
|
||||
spaces.savedsearches.name=Saved Searches
|
||||
spaces.savedsearches.description=Saved Searches
|
||||
|
||||
|
@@ -96,6 +96,10 @@ patch.rssTemplatesFolder.description=Ensures the existence of the 'RSS Templates
|
||||
patch.rssTemplatesFolder.result.exists=The RSS Templates folder already exists: {0}. Re-applying guest permissions.
|
||||
patch.rssTemplatesFolder.result.created=The RSS Templates folder was successfully created: {0}
|
||||
|
||||
patch.rendition.rendering_actions.exists=The Rendering Actions folder already exists: {0}.
|
||||
patch.rendition.rendering_actions.created=The Rendering Actions folder was successfully created: {0}
|
||||
patch.rendition.rendering_actions.description=Creates the Rendering Actions folder.
|
||||
|
||||
patch.uifacetsAspectRemovalPatch.description=Removes the incorrectly applied uifacets aspect from presentation template files.
|
||||
patch.uifacetsAspectRemovalPatch.updated=Successfully removed the uifacets aspect from {0} presentation template files.
|
||||
|
||||
@@ -295,3 +299,6 @@ patch.transferDefinitions.result=Transfer definitions folder added to data dicti
|
||||
|
||||
patch.redeployNominatedInvitationProcessWithPropsForShare.description=Redeploy nominated invitation workflow
|
||||
patch.redeployNominatedInvitationProcessWithPropsForShare.result=Nominated invitation workflow redeployed
|
||||
|
||||
patch.thumbnailsAssocQName.description=Update the 'cm:thumbnails' association QName to 'rn:rendition'.
|
||||
patch.QNamePatch.result=Successfully updated the ''{0}'' QName to ''{1}''.
|
||||
|
4
config/alfresco/messages/rendition-config.properties
Normal file
4
config/alfresco/messages/rendition-config.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
# Rendering Actions
|
||||
|
||||
reformat.title=Reformat content
|
||||
reformat.description=Renders a piece of content in another format (MIME type).
|
@@ -418,26 +418,6 @@
|
||||
</mandatory-aspects>
|
||||
</type>
|
||||
|
||||
<!-- Thumbnail content type -->
|
||||
<type name="cm:thumbnail">
|
||||
<title>Thumbnail</title>
|
||||
<parent>cm:content</parent>
|
||||
<archive>true</archive>
|
||||
<includedInSuperTypeQuery>false</includedInSuperTypeQuery>
|
||||
<properties>
|
||||
<property name="cm:thumbnailName">
|
||||
<title>Thumbnail Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
</property>
|
||||
<property name="cm:contentPropertyName">
|
||||
<title>Thumbnailed Content Property Name</title>
|
||||
<type>d:qname</type>
|
||||
<mandatory>true</mandatory>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
</types>
|
||||
|
||||
|
||||
@@ -1008,32 +988,6 @@
|
||||
</mandatory-aspects>
|
||||
</aspect>
|
||||
|
||||
<!-- Thumbnailed aspect relates a content node to it's thumbnails -->
|
||||
<aspect name="cm:thumbnailed">
|
||||
<title>Thumbnailed</title>
|
||||
<properties>
|
||||
<property name="cm:automaticUpdate">
|
||||
<title>Automatic Update</title>
|
||||
<type>d:boolean</type>
|
||||
<mandatory>true</mandatory>
|
||||
<default>true</default>
|
||||
</property>
|
||||
</properties>
|
||||
<associations>
|
||||
<child-association name="cm:thumbnails">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>cm:thumbnail</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</target>
|
||||
</child-association>
|
||||
</associations>
|
||||
</aspect>
|
||||
|
||||
<aspect name="cm:storeSelector">
|
||||
<title>ContentStore Selector</title>
|
||||
<properties>
|
||||
@@ -1093,7 +1047,6 @@
|
||||
</property>
|
||||
</properties>
|
||||
</aspect>
|
||||
|
||||
</aspects>
|
||||
|
||||
</model>
|
||||
|
111
config/alfresco/model/renditionModel.xml
Normal file
111
config/alfresco/model/renditionModel.xml
Normal file
@@ -0,0 +1,111 @@
|
||||
<model name="rn:renditionmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
|
||||
<!-- The Alfresco Rendition Service Model (since 3.3) -->
|
||||
<description>Alfresco Rendition Model</description>
|
||||
<author>Alfresco</author>
|
||||
<published>2010-01-14</published>
|
||||
<version>1.0</version>
|
||||
|
||||
<imports>
|
||||
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
|
||||
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/model/rendition/1.0" prefix="rn"/>
|
||||
</namespaces>
|
||||
|
||||
<types>
|
||||
<!-- Thumbnail content type -->
|
||||
<type name="cm:thumbnail">
|
||||
<title>Thumbnail</title>
|
||||
<parent>cm:content</parent>
|
||||
<archive>true</archive>
|
||||
<includedInSuperTypeQuery>false</includedInSuperTypeQuery>
|
||||
<properties>
|
||||
<property name="cm:thumbnailName">
|
||||
<title>Thumbnail Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
</property>
|
||||
<property name="cm:contentPropertyName">
|
||||
<title>Thumbnailed Content Property Name</title>
|
||||
<type>d:qname</type>
|
||||
<mandatory>true</mandatory>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
</types>
|
||||
|
||||
<aspects>
|
||||
<!-- This aspect marks a node as a rendition. -->
|
||||
<aspect name="rn:rendition">
|
||||
<title>Rendition</title>
|
||||
</aspect>
|
||||
<!-- A hidden rendition is one which is located directly under its source node.
|
||||
-->
|
||||
<aspect name="rn:hiddenRendition">
|
||||
<title>Hidden Rendition</title>
|
||||
<parent>rn:rendition</parent>
|
||||
</aspect>
|
||||
<!-- A visible rendition is one which is located somewhere other than under its source node.
|
||||
-->
|
||||
<aspect name="rn:visibleRendition">
|
||||
<title>Visible Rendition</title>
|
||||
<parent>rn:rendition</parent>
|
||||
</aspect>
|
||||
|
||||
<!-- This aspect is applied to nodes which have been "rendered" using the rendition service.
|
||||
-->
|
||||
<aspect name="rn:renditioned">
|
||||
<title>Renditioned</title>
|
||||
<associations>
|
||||
<!-- This association links the source content node to the rendition -->
|
||||
<child-association name="rn:rendition">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>cm:content</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</target>
|
||||
</child-association>
|
||||
</associations>
|
||||
</aspect>
|
||||
|
||||
|
||||
|
||||
<!-- Thumbnailed aspect relates a content node to it's thumbnails -->
|
||||
|
||||
<aspect name="cm:thumbnailed">
|
||||
<title>Thumbnailed</title>
|
||||
<parent>rn:renditioned</parent>
|
||||
<properties>
|
||||
<property name="cm:automaticUpdate">
|
||||
<title>Automatic Update</title>
|
||||
<type>d:boolean</type>
|
||||
<mandatory>true</mandatory>
|
||||
<default>true</default>
|
||||
</property>
|
||||
</properties>
|
||||
|
||||
<!--
|
||||
<associations>
|
||||
<child-association name="cm:thumbnails">
|
||||
<source>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</source>
|
||||
<target>
|
||||
<class>cm:thumbnail</class>
|
||||
<mandatory>false</mandatory>
|
||||
<many>true</many>
|
||||
</target>
|
||||
</child-association>
|
||||
</associations>
|
||||
-->
|
||||
|
||||
</aspect>
|
||||
|
@@ -2020,6 +2020,64 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.rendition.rendering_actions" class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.rendition.rendering_actions</value></property>
|
||||
<property name="description"><value>patch.rendition.rendering_actions.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>4003</value></property>
|
||||
<property name="targetSchema"><value>4004</value></property>
|
||||
<!-- bootstrap view -->
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
<property name="checkPath">
|
||||
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.rendition.rendering_actions.childname}</value>
|
||||
</property>
|
||||
<property name="bootstrapView">
|
||||
<props>
|
||||
<prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
|
||||
<prop key="location">alfresco/bootstrap/systemRenditionDefinitions.acp</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- This patch updates Thumbnails from Alfresco 3.2.x and earlier to their Alfresco 3.3
|
||||
equivalents: renditions. It changes the QName of the old cm:thumbnails child-association
|
||||
to rn:rendition -->
|
||||
<bean id="patch.thumbnailsAssocQName" class="org.alfresco.repo.admin.patch.impl.QNamePatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.thumbnailsAssocQName</value></property>
|
||||
<property name="description"><value>patch.thumbnailsAssocQName.description</value></property>
|
||||
<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>
|
||||
<property name="indexerAndSearcher">
|
||||
<ref bean="indexerAndSearcherFactory" />
|
||||
</property>
|
||||
<property name="qnameDAO">
|
||||
<ref bean="qnameDAO" />
|
||||
</property>
|
||||
<property name="qnameBefore">
|
||||
<value>{http://www.alfresco.org/model/content/1.0}thumbnails</value>
|
||||
</property>
|
||||
<property name="qnameAfter">
|
||||
<value>{http://www.alfresco.org/model/rendition/1.0}rendition</value>
|
||||
</property>
|
||||
|
||||
<!-- This patch is of an association type QName and so no reindexing is necessary.
|
||||
However, if we wanted to reindex the QName that we'd changed we could do it like so
|
||||
<property name="reindexClass">
|
||||
<value>TYPE</value>
|
||||
or
|
||||
<value>ASPECT</value>
|
||||
</property>
|
||||
-->
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="patch.transferDefinitionsFolder" class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch" parent="basePatch" >
|
||||
<property name="id"><value>patch.transferServiceFolder</value></property>
|
||||
<property name="description"><value>patch.transferDefinitions.description</value></property>
|
||||
@@ -2042,4 +2100,5 @@
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
147
config/alfresco/rendition-services-context.xml
Normal file
147
config/alfresco/rendition-services-context.xml
Normal file
@@ -0,0 +1,147 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Rendition Service -->
|
||||
|
||||
<bean id="RenditionService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.service.cmr.rendition.RenditionService</value>
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="renditionService" />
|
||||
</property>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref local="RenditionService_transaction" />
|
||||
<idref bean="AuditMethodInterceptor" />
|
||||
<idref bean="exceptionTranslator" />
|
||||
<idref local="RenditionService_security" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Rendition service transaction bean -->
|
||||
<bean id="RenditionService_transaction"
|
||||
class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager">
|
||||
<ref bean="transactionManager" />
|
||||
</property>
|
||||
<property name="transactionAttributes">
|
||||
<props>
|
||||
<prop key="*">${server.transaction.mode.default}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Rendition service security bean -->
|
||||
<bean id="RenditionService_security"
|
||||
class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
||||
|
||||
<!-- Rendition Service base bean -->
|
||||
<bean id="renditionService" class="org.alfresco.repo.rendition.RenditionServiceImpl" >
|
||||
<property name="actionService" ref="ActionService"/>
|
||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||
<property name="dictionaryService" ref="dictionaryService" />
|
||||
<property name="renditionDefinitionPersister" ref="renditionDefinitionPersister" />
|
||||
</bean>
|
||||
|
||||
<bean id="perform-rendition" class="org.alfresco.repo.rendition.PerformRenditionActionExecuter" parent="action-executer">
|
||||
<property name="publicAction">
|
||||
<value>false</value>
|
||||
</property>
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="actionService" ref="ActionService"/>
|
||||
<property name="renditionService" ref="RenditionService" />
|
||||
<property name="renditionLocationResolver" ref="renditionLocationResolver" />
|
||||
</bean>
|
||||
|
||||
<bean id="renditionDefinitionPersister" class="org.alfresco.repo.rendition.RenditionDefinitionPersisterImpl" >
|
||||
<property name="runtimeActionService" ref="actionService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
<bean id="renditionLocationResolver" class="org.alfresco.repo.rendition.StandardRenditionLocationResolverImpl" >
|
||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- i18n -->
|
||||
|
||||
<bean id="renderingActionResourceBundles"
|
||||
class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
|
||||
<property name="resourceBundles">
|
||||
<list>
|
||||
<!-- <value>alfresco.messages.rendition-service</value> -->
|
||||
<value>alfresco.messages.rendition-config</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Rendering Action executor beans -->
|
||||
|
||||
<bean id="baseRenderingAction" abstract="true" parent="action-executer"
|
||||
class="org.alfresco.repo.rendition.executer.AbstractRenderingEngine">
|
||||
<property name="defaultRenditionContentProp"
|
||||
value="{http://www.alfresco.org/model/content/1.0}content" />
|
||||
<property name="defaultRenditionNodeType"
|
||||
value="{http://www.alfresco.org/model/content/1.0}content" />
|
||||
<property name="mimetypeMap" ref="mimetypeService" />
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService" />
|
||||
</property>
|
||||
<property name="contentService">
|
||||
<ref bean="ContentService" />
|
||||
</property>
|
||||
<property name="applicableTypes">
|
||||
<list>
|
||||
<value>{http://www.alfresco.org/model/content/1.0}content</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Rendering Engines -->
|
||||
<bean id="reformat"
|
||||
class="org.alfresco.repo.rendition.executer.ReformatRenderingEngine"
|
||||
parent="baseRenderingAction">
|
||||
</bean>
|
||||
|
||||
<bean id="imageRenderingEngine"
|
||||
class="org.alfresco.repo.rendition.executer.ImageRenderingEngine"
|
||||
parent="baseRenderingAction">
|
||||
</bean>
|
||||
|
||||
<bean id="templatingRenderingEngine"
|
||||
class="org.alfresco.repo.rendition.executer.TemplatingRenderingEngine"
|
||||
parent="baseRenderingAction">
|
||||
<property name="templateService">
|
||||
<ref bean="templateService" />
|
||||
</property>
|
||||
<property name="repositoryHelper">
|
||||
<ref bean="repositoryHelper" />
|
||||
</property>
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="compositeRenderingEngine"
|
||||
class="org.alfresco.repo.rendition.executer.CompositeRenderingEngine"
|
||||
parent="baseRenderingAction">
|
||||
<property name="actionService">
|
||||
<ref bean="actionService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Behaviours and policies for Renditions -->
|
||||
|
||||
<bean id="renditionedAspect" class="org.alfresco.repo.rendition.RenditionedAspect" init-method="init">
|
||||
<property name="nodeService" ref="NodeService"/>
|
||||
<property name="dictionaryService" ref="DictionaryService"/>
|
||||
<property name="policyComponent" ref="policyComponent"/>
|
||||
<property name="renditionService" ref="RenditionService"/>
|
||||
</bean>
|
||||
</beans>
|
@@ -315,6 +315,7 @@ spaces.content_forms.childname=app:forms
|
||||
spaces.user_homes.childname=app:user_homes
|
||||
spaces.sites.childname=st:sites
|
||||
spaces.templates.email.invite.childname=cm:invite
|
||||
spaces.rendition.rendering_actions.childname=app:rendering_actions
|
||||
spaces.wcm_deployed.childname=cm:wcm_deployed
|
||||
spaces.transfers.childname=app:transfers
|
||||
spaces.transfer_groups.childname=app:transfer_groups
|
||||
@@ -398,10 +399,8 @@ deployment.rmi.service.port=50507
|
||||
mbean.server.locateExistingServerIfPossible=true
|
||||
|
||||
# External executable locations
|
||||
#ooo.exe=/Applications/OpenOffice.org.app/Contents/MacOS/soffice
|
||||
ooo.exe=soffice
|
||||
ooo.user=${dir.root}/oouser
|
||||
|
||||
img.root=./ImageMagick
|
||||
img.dyn=${img.root}/lib
|
||||
img.exe=${img.root}/bin/convert
|
||||
|
@@ -36,11 +36,12 @@
|
||||
<!-- Thumbnail service security bean -->
|
||||
<bean id="ThumbnailService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
||||
|
||||
<!-- Thumbnail service implemenation bean -->
|
||||
<!-- Thumbnail service implementation bean -->
|
||||
<bean id="thumbnailService" class="org.alfresco.repo.thumbnail.ThumbnailServiceImpl">
|
||||
<property name="nodeService" ref="nodeService"/>
|
||||
<property name="contentService" ref="contentService"/>
|
||||
<property name="mimetypeMap" ref="mimetypeService"/>
|
||||
<property name="renditionService" ref="renditionService" />
|
||||
<property name="behaviourFilter" ref="policyBehaviourFilter" />
|
||||
<property name="thumbnailRegistry" ref="thumbnailRegistry" />
|
||||
</bean>
|
||||
@@ -48,95 +49,14 @@
|
||||
<!-- Thumbnail Register -->
|
||||
<bean id="thumbnailRegistry" class="org.alfresco.repo.thumbnail.ThumbnailRegistry">
|
||||
<property name="contentService" ref="ContentService"/>
|
||||
<property name="thumbnailDefinitions">
|
||||
<property name="renditionService" ref="renditionService" />
|
||||
<property name="thumbnails">
|
||||
<list>
|
||||
|
||||
<!-- Small image thumbnail options -->
|
||||
<bean class="org.alfresco.repo.thumbnail.ThumbnailDefinition">
|
||||
<property name="name" value="medium" />
|
||||
<property name="mimetype" value="image/jpeg"/>
|
||||
<property name="transformationOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageTransformationOptions">
|
||||
<property name="resizeOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageResizeOptions">
|
||||
<property name="width" value="100"/>
|
||||
<property name="height" value="100"/>
|
||||
<property name="maintainAspectRatio" value="true"/>
|
||||
<property name="resizeToThumbnail" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="placeHolderResourcePath" value="alfresco/thumbnail/thumbnail_placeholder_medium.jpg" />
|
||||
</bean>
|
||||
|
||||
<!-- Slingshot Document Library image thumbnail options -->
|
||||
<bean class="org.alfresco.repo.thumbnail.ThumbnailDefinition">
|
||||
<property name="name" value="doclib" />
|
||||
<property name="mimetype" value="image/png"/>
|
||||
<property name="transformationOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageTransformationOptions">
|
||||
<property name="resizeOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageResizeOptions">
|
||||
<property name="width" value="100"/>
|
||||
<property name="height" value="100"/>
|
||||
<property name="maintainAspectRatio" value="true"/>
|
||||
<property name="resizeToThumbnail" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="placeHolderResourcePath" value="alfresco/thumbnail/thumbnail_placeholder_doclib.png" />
|
||||
</bean>
|
||||
|
||||
<!-- Web Preview thumbnail options -->
|
||||
<bean class="org.alfresco.repo.thumbnail.ThumbnailDefinition">
|
||||
<property name="name" value="webpreview" />
|
||||
<property name="mimetype" value="application/x-shockwave-flash"/>
|
||||
<property name="transformationOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.swf.SWFTransformationOptions">
|
||||
<property name="flashVersion" value="9"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Image preview thumbnail options -->
|
||||
<bean class="org.alfresco.repo.thumbnail.ThumbnailDefinition">
|
||||
<property name="name" value="imgpreview" />
|
||||
<property name="mimetype" value="image/png"/>
|
||||
<property name="transformationOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageTransformationOptions">
|
||||
<property name="resizeOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageResizeOptions">
|
||||
<property name="width" value="480"/>
|
||||
<property name="height" value="480"/>
|
||||
<property name="maintainAspectRatio" value="true"/>
|
||||
<property name="resizeToThumbnail" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="placeHolderResourcePath" value="alfresco/thumbnail/thumbnail_placeholder_imgpreview.png" />
|
||||
</bean>
|
||||
|
||||
<!-- User avatar image thumbnail options -->
|
||||
<bean class="org.alfresco.repo.thumbnail.ThumbnailDefinition">
|
||||
<property name="name" value="avatar" />
|
||||
<property name="mimetype" value="image/png"/>
|
||||
<property name="transformationOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageTransformationOptions">
|
||||
<property name="resizeOptions">
|
||||
<bean class="org.alfresco.repo.content.transform.magick.ImageResizeOptions">
|
||||
<property name="width" value="64"/>
|
||||
<property name="height" value="64"/>
|
||||
<property name="maintainAspectRatio" value="true"/>
|
||||
<property name="resizeToThumbnail" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="placeHolderResourcePath" value="alfresco/thumbnail/thumbnail_placeholder_avatar.png" />
|
||||
</bean>
|
||||
<value>medium</value>
|
||||
<value>doclib</value>
|
||||
<value>webpreview</value>
|
||||
<value>imgpreview</value>
|
||||
<value>avatar</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
@@ -162,20 +82,14 @@
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService" />
|
||||
</property>
|
||||
<property name="renditionService">
|
||||
<ref bean="RenditionService" />
|
||||
</property>
|
||||
<property name="thumbnailService">
|
||||
<ref bean="ThumbnailService" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Thumbnailed aspect -->
|
||||
<bean id="thumbnailedAspect" class="org.alfresco.repo.thumbnail.ThumbnailedAspect" init-method="init">
|
||||
<property name="nodeService" ref="NodeService"/>
|
||||
<property name="dictionaryService" ref="DictionaryService"/>
|
||||
<property name="policyComponent" ref="policyComponent"/>
|
||||
<property name="actionService" ref="ActionService"/>
|
||||
<property name="thumbnailService" ref="ThumbnailService"/>
|
||||
</bean>
|
||||
|
||||
<!-- Thumbnail service script API -->
|
||||
<bean id="thumbnailServiceScript" parent="baseJavaScriptExtension" class="org.alfresco.repo.thumbnail.script.ScriptThumbnailService">
|
||||
<property name="extensionName">
|
||||
|
@@ -19,4 +19,4 @@ version.build=@build-number@
|
||||
|
||||
# Schema number
|
||||
|
||||
version.schema=4003
|
||||
version.schema=4005
|
||||
|
41
source/java/org/alfresco/model/RenditionModel.java
Normal file
41
source/java/org/alfresco/model/RenditionModel.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.model;
|
||||
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Rendition Model Constants
|
||||
*/
|
||||
public interface RenditionModel
|
||||
{
|
||||
static final QName ASPECT_RENDITION = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "rendition");
|
||||
static final QName ASPECT_HIDDEN_RENDITION = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "hiddenRendition");
|
||||
static final QName ASPECT_VISIBLE_RENDITION = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "visibleRendition");
|
||||
|
||||
static final QName ASPECT_RENDITIONED = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "renditioned");
|
||||
static final QName ASSOC_RENDITION = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "rendition");
|
||||
}
|
@@ -16,6 +16,7 @@
|
||||
* 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.action;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -34,8 +35,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class ActionImpl extends ParameterizedItemImpl
|
||||
implements Serializable, Action
|
||||
public class ActionImpl extends ParameterizedItemImpl implements Serializable, Action
|
||||
{
|
||||
/**
|
||||
* Serial version UID
|
||||
@@ -125,25 +125,45 @@ public class ActionImpl extends ParameterizedItemImpl
|
||||
* @param actionDefinitionName the action definition name
|
||||
* @param parameterValues the parameter values
|
||||
*/
|
||||
public ActionImpl(
|
||||
NodeRef nodeRef,
|
||||
String id,
|
||||
String actionDefinitionName,
|
||||
Map<String, Serializable> parameterValues)
|
||||
public ActionImpl(NodeRef nodeRef, String id, String actionDefinitionName, Map<String, Serializable> parameterValues)
|
||||
{
|
||||
super(id, parameterValues);
|
||||
this.nodeRef = nodeRef;
|
||||
this.actionDefinitionName = actionDefinitionName;
|
||||
}
|
||||
|
||||
public ActionImpl(Action action, String actionDefinitionName)
|
||||
{
|
||||
super(action.getId(), action.getParameterValues());
|
||||
this.actionDefinitionName = actionDefinitionName;
|
||||
this.actionConditions = action.getActionConditions();
|
||||
this.compensatingAction = action.getCompensatingAction();
|
||||
this.createdDate = action.getCreatedDate();
|
||||
this.creator = action.getCreator();
|
||||
this.description = action.getDescription();
|
||||
this.executeAsynchronously = action.getExecuteAsychronously();
|
||||
this.modifiedDate = action.getModifiedDate();
|
||||
this.modifier = action.getModifier();
|
||||
this.nodeRef = action.getNodeRef();
|
||||
this.title = action.getTitle();
|
||||
if (action instanceof ActionImpl)
|
||||
{
|
||||
ActionImpl actionImpl = (ActionImpl) action;
|
||||
this.runAsUserName = actionImpl.getRunAsUser();
|
||||
this.actionChain = actionImpl.actionChain;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionImpl(Action action)
|
||||
{
|
||||
this(action, action.getActionDefinitionName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Action")
|
||||
.append("[ id=").append(getId())
|
||||
.append(", node=").append(nodeRef)
|
||||
.append(" ]");
|
||||
sb.append("Action").append("[ id=").append(getId()).append(", node=").append(nodeRef).append(" ]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -184,7 +204,7 @@ public class ActionImpl extends ParameterizedItemImpl
|
||||
*/
|
||||
public boolean getExecuteAsychronously()
|
||||
{
|
||||
return this.executeAsynchronously ;
|
||||
return this.executeAsynchronously;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +352,8 @@ public class ActionImpl extends ParameterizedItemImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.Action#addActionCondition(int, org.alfresco.service.cmr.action.ActionCondition)
|
||||
* @see org.alfresco.service.cmr.action.Action#addActionCondition(int,
|
||||
* org.alfresco.service.cmr.action.ActionCondition)
|
||||
*/
|
||||
public void addActionCondition(int index, ActionCondition actionCondition)
|
||||
{
|
||||
@@ -340,7 +361,8 @@ public class ActionImpl extends ParameterizedItemImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.Action#setActionCondition(int, org.alfresco.service.cmr.action.ActionCondition)
|
||||
* @see org.alfresco.service.cmr.action.Action#setActionCondition(int,
|
||||
* org.alfresco.service.cmr.action.ActionCondition)
|
||||
*/
|
||||
public void setActionCondition(int index, ActionCondition actionCondition)
|
||||
{
|
||||
|
128
source/java/org/alfresco/repo/action/ActionListImpl.java
Normal file
128
source/java/org/alfresco/repo/action/ActionListImpl.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.action;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionList;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class ActionListImpl<A extends Action> implements ActionList<A>
|
||||
{
|
||||
/**
|
||||
* Serial Version UID
|
||||
*/
|
||||
private static final long serialVersionUID = -1578631012627795870L;
|
||||
|
||||
/**
|
||||
* The action list
|
||||
*/
|
||||
private final List<A> actions;
|
||||
|
||||
public ActionListImpl()
|
||||
{
|
||||
this.actions = new LinkedList<A>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#hasActions()
|
||||
*/
|
||||
public boolean hasActions()
|
||||
{
|
||||
return (this.actions.isEmpty() == false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#addAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(A action)
|
||||
{
|
||||
this.actions.add(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#addAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(int index, A action)
|
||||
{
|
||||
this.actions.add(index, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#setAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void setAction(int index, A action)
|
||||
{
|
||||
this.actions.set(index, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#indexOfAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public int indexOfAction(A action)
|
||||
{
|
||||
return this.actions.indexOf(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#getActions()
|
||||
*/
|
||||
public List<A> getActions()
|
||||
{
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#getAction(int)
|
||||
*/
|
||||
public A getAction(int index)
|
||||
{
|
||||
return this.actions.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#removeAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void removeAction(A action)
|
||||
{
|
||||
this.actions.remove(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#removeAllActions()
|
||||
*/
|
||||
public void removeAllActions()
|
||||
{
|
||||
this.actions.clear();
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -16,13 +16,14 @@
|
||||
* 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.action;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.action.executer.CompositeActionExecuter;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionList;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
@@ -38,10 +39,7 @@ public class CompositeActionImpl extends ActionImpl implements CompositeAction
|
||||
*/
|
||||
private static final long serialVersionUID = -5348203599304776812L;
|
||||
|
||||
/**
|
||||
* The action list
|
||||
*/
|
||||
private List<Action> actions = new ArrayList<Action>();
|
||||
private final ActionList<Action> actions = new ActionListImpl<Action>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -54,75 +52,88 @@ public class CompositeActionImpl extends ActionImpl implements CompositeAction
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#hasActions()
|
||||
*/
|
||||
public boolean hasActions()
|
||||
{
|
||||
return (this.actions.isEmpty() == false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#addAction(org.alfresco.service.cmr.action.Action)
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#addAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(Action action)
|
||||
{
|
||||
this.actions.add(action);
|
||||
this.actions.addAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#addAction(int, org.alfresco.service.cmr.action.Action)
|
||||
* @param index
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#addAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(int index, Action action)
|
||||
{
|
||||
this.actions.add(index, action);
|
||||
this.actions.addAction(index, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#setAction(int, org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void setAction(int index, Action action)
|
||||
{
|
||||
this.actions.set(index, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#indexOfAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public int indexOfAction(Action action)
|
||||
{
|
||||
return this.actions.indexOf(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#getActions()
|
||||
*/
|
||||
public List<Action> getActions()
|
||||
{
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#getAction(int)
|
||||
* @param index
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#getAction(int)
|
||||
*/
|
||||
public Action getAction(int index)
|
||||
{
|
||||
return this.actions.get(index);
|
||||
return this.actions.getAction(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#removeAction(org.alfresco.service.cmr.action.Action)
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#getActions()
|
||||
*/
|
||||
public List<Action> getActions()
|
||||
{
|
||||
return this.actions.getActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#hasActions()
|
||||
*/
|
||||
public boolean hasActions()
|
||||
{
|
||||
return this.actions.hasActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#indexOfAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public int indexOfAction(Action action)
|
||||
{
|
||||
return this.actions.indexOfAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#removeAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void removeAction(Action action)
|
||||
{
|
||||
this.actions.remove(action);
|
||||
this.actions.removeAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.CompositeAction#removeAllActions()
|
||||
* @see org.alfresco.service.cmr.action.ActionList#removeAllActions()
|
||||
*/
|
||||
public void removeAllActions()
|
||||
{
|
||||
this.actions.clear();
|
||||
this.actions.removeAllActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#setAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void setAction(int index, Action action)
|
||||
{
|
||||
this.actions.setAction(index, action);
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ import org.alfresco.service.cmr.action.ParameterizedItem;
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ParameterizedItemImpl implements ParameterizedItem, Serializable
|
||||
{
|
||||
/**
|
||||
|
@@ -98,7 +98,7 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
|
||||
{
|
||||
if (this.actionDefinition == null)
|
||||
{
|
||||
this.actionDefinition = new ActionDefinitionImpl(this.name);
|
||||
this.actionDefinition = createActionDefinition(this.name);
|
||||
((ActionDefinitionImpl)this.actionDefinition).setTitleKey(getTitleKey());
|
||||
((ActionDefinitionImpl)this.actionDefinition).setDescriptionKey(getDescriptionKey());
|
||||
((ActionDefinitionImpl)this.actionDefinition).setAdhocPropertiesAllowed(getAdhocPropertiesAllowed());
|
||||
@@ -109,6 +109,18 @@ public abstract class ActionExecuterAbstractBase extends ParameterizedItemAbstra
|
||||
return this.actionDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns an instance of an ActionDefinition implementation class. By default
|
||||
* this will be an {@link ActionDefinitionImpl}, but this could be overridden.
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
protected ActionDefinition createActionDefinition(String name)
|
||||
{
|
||||
return new ActionDefinitionImpl(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuter#execute(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
|
169
source/java/org/alfresco/repo/admin/patch/impl/QNamePatch.java
Normal file
169
source/java/org/alfresco/repo/admin/patch/impl/QNamePatch.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.admin.patch.impl;
|
||||
|
||||
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||
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.LuceneQueryParser;
|
||||
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.service.namespace.QName;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* A patch to update the value of a QName.
|
||||
* This patch will only succeed if the target QName has not been used i.e. if there is no content
|
||||
* that actually references the QName.
|
||||
* <P/>
|
||||
* A property 'reindexClass' can be optionally injected. If it is not injected then the QName is
|
||||
* updated and no reindexing is requested by this patch.
|
||||
* If it is set to either 'TYPE' or 'ASPECT' (as appropriate) then that String will be used to
|
||||
* locate out-of-date references to the old QName and have them reindexed in a targetted way.
|
||||
* <P/>
|
||||
* Please refer to the implementation in this class for the details of how this is achieved.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class QNamePatch extends AbstractPatch
|
||||
{
|
||||
private static final String MSG_SUCCESS = "patch.QNamePatch.result";
|
||||
|
||||
/* Injected properties */
|
||||
private String qnameStringBefore;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the IndexerAndSearcher.
|
||||
* @param indexerAndSearcher
|
||||
*/
|
||||
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
|
||||
{
|
||||
this.indexerAndSearcher = indexerAndSearcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the QNameDAO.
|
||||
* @param qnameDAO
|
||||
*/
|
||||
public void setQnameDAO(QNameDAO qnameDAO)
|
||||
{
|
||||
this.qnameDAO = qnameDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the QName to be patched.
|
||||
* @param qnameStringBefore the long-form QName to be patched from. {namespaceURI}localName
|
||||
*/
|
||||
public void setQnameBefore(String qnameStringBefore)
|
||||
{
|
||||
this.qnameStringBefore = qnameStringBefore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new QName value to be used.
|
||||
* @param qnameStringAfter the long-form QName to be patched to. {namespaceURI}localName
|
||||
*/
|
||||
public void setQnameAfter(String qnameStringAfter)
|
||||
{
|
||||
this.qnameStringAfter = qnameStringAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value for the class to reindex. This will be used in the Lucene query below and
|
||||
* should be either "TYPE" or "ASPECT" or not set if reindexing is not required.
|
||||
* @param reindexClass "TYPE" or "ASPECT" or not set.
|
||||
*/
|
||||
public void setReindexClass(String reindexClass)
|
||||
{
|
||||
this.reindexClass = reindexClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String applyInternal() throws Exception
|
||||
{
|
||||
// We don't need to catch the potential InvalidQNameException here as it will be caught
|
||||
// in AbstractPatch and correctly handled there
|
||||
QName qnameBefore = QName.createQName(this.qnameStringBefore);
|
||||
QName qnameAfter = QName.createQName(this.qnameStringAfter);
|
||||
|
||||
if (qnameDAO.getQName(qnameBefore) != null)
|
||||
{
|
||||
qnameDAO.updateQName(qnameBefore, qnameAfter);
|
||||
}
|
||||
|
||||
// Optionally perform a focussed reindexing of the removed QName.
|
||||
if ("TYPE".equals(reindexClass) ||
|
||||
"ASPECT".equals(reindexClass))
|
||||
{
|
||||
reindex(reindexClass + ":" + LuceneQueryParser.escape(qnameStringBefore), importerBootstrap.getStoreRef());
|
||||
}
|
||||
|
||||
return I18NUtil.getMessage(MSG_SUCCESS, qnameBefore, qnameAfter);
|
||||
}
|
||||
|
||||
private int reindex(String query, StoreRef store)
|
||||
{
|
||||
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
|
||||
{
|
||||
rs = searchService.query(sp);
|
||||
count = rs.length();
|
||||
for (ResultSetRow row : rs)
|
||||
{
|
||||
indexer.updateNode(row.getNodeRef());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (rs != null)
|
||||
{
|
||||
rs.close();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.content.metadata.xml;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -26,34 +27,35 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.content.selector.ContentWorkerSelector;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter;
|
||||
import org.alfresco.repo.content.metadata.MetadataExtracter;
|
||||
import org.alfresco.repo.content.selector.ContentWorkerSelector;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.springframework.extensions.surf.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.PropertyCheck;
|
||||
|
||||
/**
|
||||
* A metadata extractor that selects an appropiate workder for the extraction.
|
||||
* <p>
|
||||
* The {@linkplain #setSelectors(List) selectors} are used to find an extracter most
|
||||
* appropriate of a given XML document. The chosen extracter is then asked to extract
|
||||
* the values, passing through the {@linkplain MetadataExtracter.OverwritePolicy overwrite policy}
|
||||
* as {@linkplain #setOverwritePolicy(String)} on this instance. The overwrite policy of the
|
||||
* embedded extracters is not relevant unless they are used separately in another context.
|
||||
* The {@linkplain #setSelectors(List) selectors} are used to find an extracter
|
||||
* most appropriate of a given XML document. The chosen extracter is then asked
|
||||
* to extract the values, passing through the
|
||||
* {@linkplain MetadataExtracter.OverwritePolicy overwrite policy} as
|
||||
* {@linkplain #setOverwritePolicy(String)} on this instance. The overwrite
|
||||
* policy of the embedded extracters is not relevant unless they are used
|
||||
* separately in another context.
|
||||
*
|
||||
* @see ContentWorkerSelector
|
||||
* @see MetadataExtracter
|
||||
*
|
||||
* @since 2.1
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
public static String[] SUPPORTED_MIMETYPES = new String[] {MimetypeMap.MIMETYPE_XML};
|
||||
public static String[] SUPPORTED_MIMETYPES = new String[] { MimetypeMap.MIMETYPE_XML };
|
||||
|
||||
private static Log logger = LogFactory.getLog(XPathMetadataExtracter.class);
|
||||
|
||||
@@ -68,9 +70,9 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of metadata selectors to use to find the extracter to use, given
|
||||
* some content. The evaluations are done in the order that they occur in the
|
||||
* list.
|
||||
* Sets the list of metadata selectors to use to find the extracter to use,
|
||||
* given some content. The evaluations are done in the order that they occur
|
||||
* in the list.
|
||||
*
|
||||
* @param selectors A list of selectors
|
||||
*/
|
||||
@@ -88,7 +90,8 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
}
|
||||
|
||||
/**
|
||||
* It is not possible to have any default mappings, but something has to be returned.
|
||||
* It is not possible to have any default mappings, but something has to be
|
||||
* returned.
|
||||
*
|
||||
* @return Returns an empty map
|
||||
*/
|
||||
@@ -102,21 +105,18 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
* Selects and extracter to perform the work and redirects to it.
|
||||
*/
|
||||
@Override
|
||||
public Map<QName, Serializable> extract(
|
||||
ContentReader reader,
|
||||
OverwritePolicy overwritePolicy,
|
||||
Map<QName, Serializable> destination,
|
||||
Map<String, Set<QName>> mapping)
|
||||
public Map<QName, Serializable> extract(ContentReader reader, OverwritePolicy overwritePolicy,
|
||||
Map<QName, Serializable> destination, Map<String, Set<QName>> mapping)
|
||||
{
|
||||
// Check the content length
|
||||
if (reader.getSize() == 0)
|
||||
{
|
||||
// There is no content. We don't spoof any properties so there can be nothing extracted.
|
||||
// There is no content. We don't spoof any properties so there can
|
||||
// be nothing extracted.
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\n" +
|
||||
"XML document has zero length, so bypassing extraction: \n" +
|
||||
" Document: " + reader);
|
||||
logger.debug("\n" + "XML document has zero length, so bypassing extraction: \n" + " Document: "
|
||||
+ reader);
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
@@ -138,9 +138,8 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
if (reader.isChannelOpen())
|
||||
{
|
||||
logger.error("Content reader not closed by MetadataExtractor selector: \n" +
|
||||
" reader: " + reader + "\n" +
|
||||
" selector: " + selector);
|
||||
logger.error("Content reader not closed by MetadataExtractor selector: \n" + " reader: "
|
||||
+ reader + "\n" + " selector: " + selector);
|
||||
}
|
||||
}
|
||||
// Just take the first successful one
|
||||
@@ -148,10 +147,8 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\n" +
|
||||
"Found metadata extracter to process XML document: \n" +
|
||||
" Selector: " + selector + "\n" +
|
||||
" Document: " + reader);
|
||||
logger.debug("\n" + "Found metadata extracter to process XML document: \n" + " Selector: "
|
||||
+ selector + "\n" + " Document: " + reader);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -162,9 +159,7 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\n" +
|
||||
"No working metadata extractor could be found: \n" +
|
||||
" Document: " + reader);
|
||||
logger.debug("\n" + "No working metadata extractor could be found: \n" + " Document: " + reader);
|
||||
}
|
||||
// There will be no properties extracted
|
||||
modifiedProperties = destination;
|
||||
@@ -180,20 +175,16 @@ public class XmlMetadataExtracter extends AbstractMappingMetadataExtracter
|
||||
{
|
||||
if (reader.isChannelOpen())
|
||||
{
|
||||
logger.error("Content reader not closed by MetadataExtractor: \n" +
|
||||
" Reader: " + reader + "\n" +
|
||||
" extracter: " + extracter);
|
||||
logger.error("Content reader not closed by MetadataExtractor: \n" + " Reader: " + reader + "\n"
|
||||
+ " extracter: " + extracter);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("\n" +
|
||||
"XML metadata extractor redirected: \n" +
|
||||
" Reader: " + reader + "\n" +
|
||||
" Extracter: " + extracter + "\n" +
|
||||
" Metadata: " + modifiedProperties);
|
||||
logger.debug("\n" + "XML metadata extractor redirected: \n" + " Reader: " + reader + "\n"
|
||||
+ " Extracter: " + extracter + "\n" + " Metadata: " + modifiedProperties);
|
||||
}
|
||||
return modifiedProperties;
|
||||
}
|
||||
|
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.content.transform.magick;
|
||||
|
||||
/**
|
||||
* DTO used to store options for ImageMagick cropping.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class ImageCropOptions
|
||||
{
|
||||
private int height = -1;
|
||||
private int width = -1;
|
||||
private int xOffset = 0;
|
||||
private int yOffset = 0;
|
||||
private boolean isPercentageCrop = false;
|
||||
private String gravity = null;
|
||||
|
||||
/**
|
||||
* Gets the height of the cropped image. By default this is in pixels but if
|
||||
* <code>isPercentageCrop</code> is set to true then it changes to
|
||||
* percentage.
|
||||
*
|
||||
* @return the height
|
||||
*/
|
||||
public int getHeight()
|
||||
{
|
||||
return this.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height of the cropped image. By default this is in pixels but if
|
||||
* <code>isPercentageCrop</code> is set to true then it changes to
|
||||
* percentage.
|
||||
*
|
||||
* @param height the height to set
|
||||
*/
|
||||
public void setHeight(int height)
|
||||
{
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of the cropped image. By default this is in pixels but if
|
||||
* <code>isPercentageCrop</code> is set to true then it changes to
|
||||
* percentage.
|
||||
*
|
||||
* @return the width
|
||||
*/
|
||||
public int getWidth()
|
||||
{
|
||||
return this.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of the cropped image. By default this is in pixels but if
|
||||
* <code>isPercentageCrop</code> is set to true then it changes to
|
||||
* percentage.
|
||||
*
|
||||
* @param width the width to set
|
||||
*/
|
||||
public void setWidth(int width)
|
||||
{
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the horizontal offset. By default this starts fromt he top-left
|
||||
* corner of the image and moves right, however the <code>gravity</code>
|
||||
* property can change this.
|
||||
*
|
||||
* @return the xOffset
|
||||
*/
|
||||
public int getXOffset()
|
||||
{
|
||||
return this.xOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the horizontal offset. By default this starts fromt he top-left
|
||||
* corner of the image and moves right, however the <code>gravity</code>
|
||||
* property can change this.
|
||||
*
|
||||
* @param xOffset the xOffset to set
|
||||
*/
|
||||
public void setXOffset(int xOffset)
|
||||
{
|
||||
this.xOffset = xOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the vertical offset. By default this starts fromt he top-left corner
|
||||
* of the image and moves down, however the <code>gravity</code> property
|
||||
* can change this.
|
||||
*
|
||||
* @return the yOffset
|
||||
*/
|
||||
public int getYOffset()
|
||||
{
|
||||
return this.yOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertical offset. By default this starts fromt he top-left corner
|
||||
* of the image and moves down, however the <code>gravity</code> property
|
||||
* can change this.
|
||||
*
|
||||
* @param yOffset the yOffset to set
|
||||
*/
|
||||
public void setYOffset(int yOffset)
|
||||
{
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the isPercentageCrop
|
||||
*/
|
||||
public boolean isPercentageCrop()
|
||||
{
|
||||
return this.isPercentageCrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isPercentageCrop the isPercentageCrop to set
|
||||
*/
|
||||
public void setPercentageCrop(boolean isPercentageCrop)
|
||||
{
|
||||
this.isPercentageCrop = isPercentageCrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 'gravity' which determines how the offset is applied. It affects
|
||||
* both the origin of offset and the direction(s).
|
||||
*
|
||||
* @param gravity the gravity to set
|
||||
*/
|
||||
public void setGravity(String gravity)
|
||||
{
|
||||
this.gravity = gravity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'gravity' which determines how the offset is applied. It affects
|
||||
* both the origin of offset and the direction(s).
|
||||
*
|
||||
* @return the gravity
|
||||
*/
|
||||
public String getGravity()
|
||||
{
|
||||
return this.gravity;
|
||||
}
|
||||
}
|
@@ -149,8 +149,13 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
|
||||
if (options instanceof ImageTransformationOptions)
|
||||
{
|
||||
ImageTransformationOptions imageOptions = (ImageTransformationOptions)options;
|
||||
ImageCropOptions cropOptions = imageOptions.getCropOptions();
|
||||
ImageResizeOptions resizeOptions = imageOptions.getResizeOptions();
|
||||
String commandOptions = imageOptions.getCommandOptions();
|
||||
if (cropOptions != null)
|
||||
{
|
||||
commandOptions = commandOptions + " " + getImageCropCommandOptions(cropOptions);
|
||||
}
|
||||
if (resizeOptions != null)
|
||||
{
|
||||
commandOptions = commandOptions + " " + getImageResizeCommandOptions(resizeOptions);
|
||||
@@ -173,6 +178,59 @@ public class ImageMagickContentTransformerWorker extends AbstractImageMagickCont
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the imagemagick command string for the image crop options provided
|
||||
*
|
||||
* @param imageResizeOptions image resize options
|
||||
* @return String the imagemagick command options
|
||||
*/
|
||||
private String getImageCropCommandOptions(ImageCropOptions cropOptions)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(32);
|
||||
String gravity = cropOptions.getGravity();
|
||||
if(gravity!=null)
|
||||
{
|
||||
builder.append("-gravity ");
|
||||
builder.append(gravity);
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append("-crop ");
|
||||
int width = cropOptions.getWidth();
|
||||
if (width > -1)
|
||||
{
|
||||
builder.append(width);
|
||||
}
|
||||
|
||||
int height = cropOptions.getHeight();
|
||||
if (height > -1)
|
||||
{
|
||||
builder.append("x");
|
||||
builder.append(height);
|
||||
}
|
||||
|
||||
if (cropOptions.isPercentageCrop())
|
||||
{
|
||||
builder.append("%");
|
||||
}
|
||||
appendOffset(builder, cropOptions.getXOffset());
|
||||
appendOffset(builder, cropOptions.getYOffset());
|
||||
builder.append(" +repage");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param builder
|
||||
* @param xOffset
|
||||
*/
|
||||
private void appendOffset(StringBuilder builder, int xOffset)
|
||||
{
|
||||
if(xOffset>=0)
|
||||
{
|
||||
builder.append("+");
|
||||
}
|
||||
builder.append(xOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the imagemagick command string for the image resize options provided
|
||||
*
|
||||
|
@@ -33,6 +33,9 @@ public class ImageTransformationOptions extends TransformationOptions
|
||||
/** Image resize options */
|
||||
private ImageResizeOptions resizeOptions;
|
||||
|
||||
/** Image crop options */
|
||||
private ImageCropOptions cropOptions;
|
||||
|
||||
/**
|
||||
* Set the command string options
|
||||
*
|
||||
@@ -84,4 +87,20 @@ public class ImageTransformationOptions extends TransformationOptions
|
||||
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cropOptions the cropOptions to set
|
||||
*/
|
||||
public void setCropOptions(ImageCropOptions cropOptions)
|
||||
{
|
||||
this.cropOptions = cropOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cropOptions
|
||||
*/
|
||||
public ImageCropOptions getCropOptions()
|
||||
{
|
||||
return this.cropOptions;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.repo.thumbnail.ThumbnailServiceImplParameterTest;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailServiceImplTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
/**
|
||||
* This class is a holder for the various test classes associated with the Rendition Service.
|
||||
* It is not (at the time of writing) intended to be incorporated into the automatic build
|
||||
* which will find the various test classes and run them individually.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
RenditionServiceImplTest.class,
|
||||
ThumbnailServiceImplParameterTest.class,
|
||||
ThumbnailServiceImplTest.class,
|
||||
StandardRenditionLocationResolverTest.class,
|
||||
RenditionServiceIntegrationTest.class,
|
||||
RenditionServicePermissionsTest.class
|
||||
})
|
||||
public class AllRenditionTests
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.action.ActionListImpl;
|
||||
import org.alfresco.repo.rendition.executer.CompositeRenderingEngine;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionList;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.rendition.CompositeRenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class CompositeRenditionDefinitionImpl extends RenditionDefinitionImpl implements CompositeRenditionDefinition
|
||||
{
|
||||
/**
|
||||
* Serial Version UID
|
||||
*/
|
||||
private static final long serialVersionUID = -770880495976834168L;
|
||||
|
||||
private final ActionList<RenditionDefinition> actions = new ActionListImpl<RenditionDefinition>();
|
||||
|
||||
/**
|
||||
* @param nodeRef
|
||||
* @param id
|
||||
*/
|
||||
public CompositeRenditionDefinitionImpl(String id, QName renditionName)
|
||||
{
|
||||
super(id, renditionName, CompositeRenderingEngine.NAME);
|
||||
}
|
||||
|
||||
public CompositeRenditionDefinitionImpl(CompositeAction compositeAction)
|
||||
{
|
||||
super(compositeAction, CompositeRenderingEngine.NAME);
|
||||
for (Action action : compositeAction.getActions())
|
||||
{
|
||||
RenditionDefinition subDefinition;
|
||||
if (action instanceof CompositeAction)
|
||||
{
|
||||
CompositeAction compAction = (CompositeAction) action;
|
||||
subDefinition = new CompositeRenditionDefinitionImpl(compAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
subDefinition = new RenditionDefinitionImpl(action);
|
||||
}
|
||||
addAction(subDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#addAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(int index, RenditionDefinition action)
|
||||
{
|
||||
this.actions.addAction(index, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#addAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void addAction(RenditionDefinition action)
|
||||
{
|
||||
this.actions.addAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#getAction(int)
|
||||
*/
|
||||
public RenditionDefinition getAction(int index)
|
||||
{
|
||||
return this.actions.getAction(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#getActions()
|
||||
*/
|
||||
public List<RenditionDefinition> getActions()
|
||||
{
|
||||
return this.actions.getActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#hasActions()
|
||||
*/
|
||||
public boolean hasActions()
|
||||
{
|
||||
return this.actions.hasActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @return
|
||||
* @see org.alfresco.service.cmr.action.ActionList#indexOfAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public int indexOfAction(RenditionDefinition action)
|
||||
{
|
||||
return this.actions.indexOfAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#removeAction(org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void removeAction(RenditionDefinition action)
|
||||
{
|
||||
this.actions.removeAction(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.action.ActionList#removeAllActions()
|
||||
*/
|
||||
public void removeAllActions()
|
||||
{
|
||||
this.actions.removeAllActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @param action
|
||||
* @see org.alfresco.service.cmr.action.ActionList#setAction(int,
|
||||
* org.alfresco.service.cmr.action.Action)
|
||||
*/
|
||||
public void setAction(int index, RenditionDefinition action)
|
||||
{
|
||||
this.actions.setAction(index, action);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.cmis.CMISDictionaryService;
|
||||
import org.alfresco.cmis.CMISQueryService;
|
||||
import org.alfresco.cmis.CMISServices;
|
||||
import org.alfresco.mbeans.VirtServerRegistry;
|
||||
import org.alfresco.repo.forms.FormService;
|
||||
import org.alfresco.repo.imap.ImapService;
|
||||
import org.alfresco.repo.lock.JobLockService;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
import org.alfresco.service.cmr.audit.AuditService;
|
||||
import org.alfresco.service.cmr.avm.AVMService;
|
||||
import org.alfresco.service.cmr.avm.deploy.DeploymentService;
|
||||
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
|
||||
import org.alfresco.service.cmr.avmsync.AVMSyncService;
|
||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.invitation.InvitationService;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.ml.ContentFilterLanguagesService;
|
||||
import org.alfresco.service.cmr.ml.EditionService;
|
||||
import org.alfresco.service.cmr.ml.MultilingualContentService;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.CopyService;
|
||||
import org.alfresco.service.cmr.repository.CrossRepositoryCopyService;
|
||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.repository.TemplateService;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.alfresco.service.cmr.search.CategoryService;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.OwnableService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.security.PublicServiceAccessService;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.tagging.TaggingService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.cmr.version.VersionService;
|
||||
import org.alfresco.service.cmr.view.ExporterService;
|
||||
import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.workflow.WorkflowService;
|
||||
import org.alfresco.service.descriptor.DescriptorService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.wcm.asset.AssetService;
|
||||
import org.alfresco.wcm.preview.PreviewURIService;
|
||||
import org.alfresco.wcm.sandbox.SandboxService;
|
||||
import org.alfresco.wcm.webproject.WebProjectService;
|
||||
|
||||
public class MockedTestServiceRegistry implements ServiceRegistry
|
||||
{
|
||||
private final ActionService actionService = mock(ActionService.class);
|
||||
private final ContentService contentService = mock(ContentService.class);
|
||||
private final NodeService nodeService = mock(NodeService.class);
|
||||
private final TemplateService templateService = mock(TemplateService.class);
|
||||
private final PersonService personService = mock(PersonService.class);
|
||||
private final MutableAuthenticationService authenticationService = mock(MutableAuthenticationService.class);
|
||||
private final NamespaceService namespaceService = mock(NamespaceService.class);
|
||||
|
||||
public boolean isServiceProvided(QName service)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public WorkflowService getWorkflowService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public WebProjectService getWebProjectService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public VirtServerRegistry getVirtServerRegistry()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public VersionService getVersionService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public TransactionService getTransactionService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ThumbnailService getThumbnailService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public TemplateService getTemplateService()
|
||||
{
|
||||
return this.templateService;
|
||||
}
|
||||
|
||||
|
||||
public TaggingService getTaggingService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public SiteService getSiteService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Collection<QName> getServices()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Object getService(QName service)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public SearchService getSearchService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ScriptService getScriptService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public SandboxService getSandboxService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public RuleService getRuleService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public RetryingTransactionHelper getRetryingTransactionHelper()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public PublicServiceAccessService getPublicServiceAccessService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public PreviewURIService getPreviewURIService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public PersonService getPersonService()
|
||||
{
|
||||
return personService;
|
||||
}
|
||||
|
||||
|
||||
public PermissionService getPermissionService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public OwnableService getOwnableService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
|
||||
public NamespaceService getNamespaceService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return namespaceService;
|
||||
}
|
||||
|
||||
|
||||
public MultilingualContentService getMultilingualContentService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public MimetypeService getMimetypeService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public LockService getLockService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public JobLockService getJobLockService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public InvitationService getInvitationService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ImporterService getImporterService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ImapService getImapService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public FormService getFormService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public FileFolderService getFileFolderService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ExporterService getExporterService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public EditionService getEditionService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public DictionaryService getDictionaryService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public DescriptorService getDescriptorService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public DeploymentService getDeploymentService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CrossRepositoryCopyService getCrossRepositoryCopyService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CopyService getCopyService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ContentService getContentService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return contentService;
|
||||
}
|
||||
|
||||
|
||||
public ContentFilterLanguagesService getContentFilterLanguagesService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CheckOutCheckInService getCheckOutCheckInService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CategoryService getCategoryService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CMISServices getCMISService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CMISQueryService getCMISQueryService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public CMISDictionaryService getCMISDictionaryService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AuthorityService getAuthorityService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public MutableAuthenticationService getAuthenticationService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return authenticationService;
|
||||
}
|
||||
|
||||
|
||||
public AuditService getAuditService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AttributeService getAttributeService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AssetService getAssetService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ActionService getActionService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return actionService;
|
||||
}
|
||||
|
||||
|
||||
public AVMSyncService getAVMSyncService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AVMService getAVMService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AVMLockingService getAVMLockingService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public AVMService getAVMLockingAwareService()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import static org.alfresco.model.ContentModel.PROP_NODE_DBID;
|
||||
import static org.alfresco.model.ContentModel.PROP_NODE_REF;
|
||||
import static org.alfresco.model.ContentModel.PROP_NODE_UUID;
|
||||
import static org.alfresco.model.ContentModel.PROP_STORE_IDENTIFIER;
|
||||
import static org.alfresco.model.ContentModel.PROP_STORE_NAME;
|
||||
import static org.alfresco.model.ContentModel.PROP_STORE_PROTOCOL;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.executer.ActionExecuter;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.NodeLocator;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/*
|
||||
* This class is the action executer for the perform-rendition action. All renditions are
|
||||
* executed by this class as wrapping them all in a containing action facilitates
|
||||
* asynchronous renditions.
|
||||
* <P/>
|
||||
* Some of the logic is executed directly by this class (handling of rendition-related
|
||||
* aspects and associations) and the rest is executed by subordinate actions called
|
||||
* from within this action (the actual rendering code). These subordinate actions are
|
||||
* renditionDefinitions.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class PerformRenditionActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(PerformRenditionActionExecuter.class);
|
||||
|
||||
/** Action name and parameters */
|
||||
public static final String NAME = "perform-rendition";
|
||||
public static final String PARAM_RENDITION_DEFINITION = "renditionDefinition";
|
||||
|
||||
private static final String DEFAULT_RUN_AS_NAME = AuthenticationUtil.getSystemUserName();
|
||||
|
||||
private static final List<QName> unchangedProperties = Arrays.asList(PROP_NODE_DBID, PROP_NODE_REF, PROP_NODE_UUID,
|
||||
PROP_STORE_IDENTIFIER, PROP_STORE_NAME, PROP_STORE_PROTOCOL);
|
||||
/**
|
||||
* Default {@link NodeLocator} simply returns the source node.
|
||||
*/
|
||||
private final static NodeLocator defaultNodeLocator = new NodeLocator()
|
||||
{
|
||||
public NodeRef getNode(NodeRef sourceNode, Map<String, Serializable> params)
|
||||
{
|
||||
return sourceNode;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Injected beans
|
||||
*/
|
||||
private RenditionLocationResolver renditionLocationResolver;
|
||||
private ActionService actionService;
|
||||
private NodeService nodeService;
|
||||
private RenditionService renditionService;
|
||||
|
||||
private final NodeLocator temporaryParentNodeLocator;
|
||||
private final QName temporaryRenditionLinkType;
|
||||
|
||||
public PerformRenditionActionExecuter(NodeLocator temporaryParentNodeLocator, QName temporaryRenditionLinkType)
|
||||
{
|
||||
this.temporaryParentNodeLocator = temporaryParentNodeLocator != null ? temporaryParentNodeLocator
|
||||
: defaultNodeLocator;
|
||||
this.temporaryRenditionLinkType = temporaryRenditionLinkType != null ? temporaryRenditionLinkType
|
||||
: RenditionModel.ASSOC_RENDITION;
|
||||
}
|
||||
|
||||
public PerformRenditionActionExecuter()
|
||||
{
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the actionService bean.
|
||||
*
|
||||
* @param actionService
|
||||
* the actionService.
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the nodeService bean.
|
||||
*
|
||||
* @param nodeService
|
||||
* the nodeService.
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the renditionService bean.
|
||||
*
|
||||
* @param renditionService
|
||||
*/
|
||||
public void setRenditionService(RenditionService renditionService)
|
||||
{
|
||||
this.renditionService = renditionService;
|
||||
}
|
||||
|
||||
public void setRenditionLocationResolver(RenditionLocationResolver renditionLocationResolver)
|
||||
{
|
||||
this.renditionLocationResolver = renditionLocationResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeImpl(final Action containingAction, final NodeRef actionedUponNodeRef)
|
||||
{
|
||||
final RenditionDefinition renditionDefinition = getRenditionDefinition(containingAction);
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Rendering node ").append(actionedUponNodeRef).append(" with rendition definition ").append(
|
||||
renditionDefinition.getRenditionName());
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
|
||||
Serializable runAsParam = renditionDefinition.getParameterValue(AbstractRenderingEngine.PARAM_RUN_AS);
|
||||
String runAsName = runAsParam == null ? DEFAULT_RUN_AS_NAME : (String) runAsParam;
|
||||
|
||||
// Renditions should all be created by system by default.
|
||||
// When renditions are created by a user and are to be created under a
|
||||
// node
|
||||
// other than the source node, it is possible that the user will not
|
||||
// have
|
||||
// permissions to create content under that node.
|
||||
// For that reason, we execute all perform-rendition actions as system
|
||||
// by default.
|
||||
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
ChildAssociationRef result = null;
|
||||
try
|
||||
{
|
||||
setTemporaryRenditionProperties(actionedUponNodeRef, renditionDefinition);
|
||||
|
||||
// Adds the 'Renditioned' aspect to the source node if it
|
||||
// doesn't exist.
|
||||
if (!nodeService.hasAspect(actionedUponNodeRef, RenditionModel.ASPECT_RENDITIONED))
|
||||
{
|
||||
nodeService.addAspect(actionedUponNodeRef, RenditionModel.ASPECT_RENDITIONED, null);
|
||||
}
|
||||
ChildAssociationRef tempRendAssoc = executeRendition(actionedUponNodeRef, renditionDefinition);
|
||||
result = createOrUpdateRendition(actionedUponNodeRef, tempRendAssoc, renditionDefinition);
|
||||
containingAction.setParameterValue(PARAM_RESULT, result);
|
||||
} catch (Throwable t)
|
||||
{
|
||||
notifyCallbackOfException(renditionDefinition, t);
|
||||
throwWrappedException(t);
|
||||
}
|
||||
if (result != null)
|
||||
{
|
||||
notifyCallbackOfResult(renditionDefinition, result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, runAsName);
|
||||
}
|
||||
|
||||
private RenditionDefinition getRenditionDefinition(final Action containingAction)
|
||||
{
|
||||
Serializable rendDefObj = containingAction.getParameterValue(PARAM_RENDITION_DEFINITION);
|
||||
ParameterCheck.mandatory(PARAM_RENDITION_DEFINITION, rendDefObj);
|
||||
return (RenditionDefinition) rendDefObj;
|
||||
}
|
||||
|
||||
// Rendition has failed. If there is a callback, it needs to be notified
|
||||
private void notifyCallbackOfException(RenditionDefinition renditionDefinition, Throwable t)
|
||||
{
|
||||
if (renditionDefinition != null)
|
||||
{
|
||||
RenderCallback callback = renditionDefinition.getCallback();
|
||||
if (callback != null)
|
||||
{
|
||||
callback.handleFailedRendition(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and rethrow Exception
|
||||
private void throwWrappedException(Throwable t)
|
||||
{
|
||||
if (t instanceof AlfrescoRuntimeException)
|
||||
{
|
||||
throw (AlfrescoRuntimeException) t;
|
||||
} else
|
||||
{
|
||||
throw new RenditionServiceException(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyCallbackOfResult(RenditionDefinition renditionDefinition, ChildAssociationRef result)
|
||||
{
|
||||
// Rendition was successful. Notify the callback object.
|
||||
if (renditionDefinition != null)
|
||||
{
|
||||
RenderCallback callback = renditionDefinition.getCallback();
|
||||
if (callback != null)
|
||||
{
|
||||
callback.handleSuccessfulRendition(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the renditionParent and rendition assocType.
|
||||
*
|
||||
* @param sourceNode
|
||||
* @param definition
|
||||
*/
|
||||
private void setTemporaryRenditionProperties(NodeRef sourceNode, RenditionDefinition definition)
|
||||
{
|
||||
// Set the parent and assoc type for the temporary rendition to be
|
||||
// created.
|
||||
NodeRef parent = temporaryParentNodeLocator.getNode(sourceNode, definition.getParameterValues());
|
||||
definition.setRenditionParent(parent);
|
||||
definition.setRenditionAssociationType(temporaryRenditionLinkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sourceNode
|
||||
* @param definition
|
||||
* @return
|
||||
*/
|
||||
private ChildAssociationRef executeRendition(NodeRef sourceNode, RenditionDefinition definition)
|
||||
{
|
||||
actionService.executeAction(definition, sourceNode);
|
||||
// Extract the result from the action
|
||||
Serializable serializableResult = definition.getParameterValue(ActionExecuter.PARAM_RESULT);
|
||||
return (ChildAssociationRef) serializableResult;
|
||||
}
|
||||
|
||||
private ChildAssociationRef createOrUpdateRendition(NodeRef sourceNode, ChildAssociationRef tempRendition,
|
||||
RenditionDefinition renditionDefinition)
|
||||
{
|
||||
NodeRef tempRenditionNode = tempRendition.getChildRef();
|
||||
RenditionLocation location = getDestinationParentAssoc(sourceNode, renditionDefinition, tempRenditionNode);
|
||||
QName renditionQName = renditionDefinition.getRenditionName();
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
final String lineBreak = System.getProperty("line.separator", "\n");
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Creating/updating rendition based on:").append(lineBreak).append(" sourceNode: ").append(
|
||||
sourceNode).append(lineBreak).append(" tempRendition: ").append(tempRendition).append(
|
||||
lineBreak).append(" parentNode: ").append(location.getParentRef()).append(lineBreak).append(
|
||||
" childName: ").append(location.getChildName()).append(lineBreak).append(
|
||||
" renditionDefinition.name: ").append(renditionQName);
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
ChildAssociationRef primaryAssoc = findOrCreatePrimaryRenditionAssociation(sourceNode, renditionDefinition,
|
||||
location);
|
||||
|
||||
// Copy relevant properties from the temporary node to the new rendition
|
||||
// node.
|
||||
NodeRef renditionNode = primaryAssoc.getChildRef();
|
||||
transferNodeProperties(tempRenditionNode, renditionNode);
|
||||
|
||||
// Set the name property on the rendition if it has not already been
|
||||
// set.
|
||||
String renditionName = getRenditionName(tempRenditionNode, location, renditionDefinition);
|
||||
nodeService.setProperty(renditionNode, ContentModel.PROP_NAME, renditionName);
|
||||
|
||||
// Delete the temporary rendition.
|
||||
nodeService.removeChildAssociation(tempRendition);
|
||||
|
||||
// Handle the rendition aspects
|
||||
manageRenditionAspects(sourceNode, primaryAssoc);
|
||||
ChildAssociationRef renditionAssoc = renditionService.getRenditionByName(sourceNode, renditionQName);
|
||||
if (renditionAssoc == null)
|
||||
{
|
||||
String msg = "A rendition of type: " + renditionQName + " should have been created for source node: "
|
||||
+ sourceNode;
|
||||
throw new RenditionServiceException(msg);
|
||||
}
|
||||
return renditionAssoc;
|
||||
}
|
||||
|
||||
private void manageRenditionAspects(NodeRef sourceNode, ChildAssociationRef renditionParentAssoc)
|
||||
{
|
||||
NodeRef renditionNode = renditionParentAssoc.getChildRef();
|
||||
NodeRef primaryParent = renditionParentAssoc.getParentRef();
|
||||
|
||||
// If the rendition is located directly underneath its own source node
|
||||
if (primaryParent.equals(sourceNode))
|
||||
{
|
||||
// It should be a 'hidden' rendition.
|
||||
nodeService.addAspect(renditionNode, RenditionModel.ASPECT_HIDDEN_RENDITION, null);
|
||||
nodeService.removeAspect(renditionNode, RenditionModel.ASPECT_VISIBLE_RENDITION);
|
||||
// We remove the other aspect to cover the potential case where a
|
||||
// rendition
|
||||
// has been updated in a different location.
|
||||
} else
|
||||
{
|
||||
// Renditions stored underneath any node other than their source are
|
||||
// 'visible'.
|
||||
nodeService.addAspect(renditionNode, RenditionModel.ASPECT_VISIBLE_RENDITION, null);
|
||||
nodeService.removeAspect(renditionNode, RenditionModel.ASPECT_HIDDEN_RENDITION);
|
||||
}
|
||||
}
|
||||
|
||||
private String getRenditionName(NodeRef tempRenditionNode, RenditionLocation location,
|
||||
RenditionDefinition renditionDefinition)
|
||||
{
|
||||
// If a location name is set then use it.
|
||||
String locName = location.getChildName();
|
||||
if (locName != null && locName.length() > 0)
|
||||
{
|
||||
return locName;
|
||||
}
|
||||
// Else if the temporary rendition specifies a name property use that.
|
||||
Serializable tempName = nodeService.getProperty(tempRenditionNode, ContentModel.PROP_NAME);
|
||||
if (tempName != null)
|
||||
{
|
||||
return (String) tempName;
|
||||
}
|
||||
// Otherwise use the rendition definition local name.
|
||||
return renditionDefinition.getRenditionName().getLocalName();
|
||||
}
|
||||
|
||||
private ChildAssociationRef findOrCreatePrimaryRenditionAssociation(NodeRef sourceNode,
|
||||
RenditionDefinition renditionDefinition, RenditionLocation location)
|
||||
{
|
||||
// Get old Rendition if exists.
|
||||
QName renditionName = renditionDefinition.getRenditionName();
|
||||
ChildAssociationRef oldRenditionAssoc = renditionService.getRenditionByName(sourceNode, renditionName);
|
||||
// If no rendition already exists create anew rendition node and
|
||||
// association.
|
||||
if (oldRenditionAssoc == null)
|
||||
{
|
||||
return getSpecifiedRenditionOrCreateNewRendition(sourceNode, location, renditionName);
|
||||
}
|
||||
// If a rendition exists and is already in the correct location then
|
||||
// return that renditions primary parent association
|
||||
NodeRef oldRendition = oldRenditionAssoc.getChildRef();
|
||||
if (renditionLocationMatches(oldRendition, location))
|
||||
{
|
||||
return nodeService.getPrimaryParent(oldRendition);
|
||||
}
|
||||
// If the old rendition is in the wrong location and the 'orphan
|
||||
// existing rendition' param is set to true or the RenditionLocation
|
||||
// specifies a destination NodeRef then ldelete the old
|
||||
// rendition association and create a new rendition node.
|
||||
if (orphanExistingRendition(renditionDefinition, location))
|
||||
{
|
||||
orphanRendition(oldRenditionAssoc);
|
||||
return getSpecifiedRenditionOrCreateNewRendition(sourceNode, location, renditionName);
|
||||
}
|
||||
// If the old rendition is in the wrong place and the 'orphan existing
|
||||
// rendition' param is not set to true then move the existing rendition
|
||||
// to the correct location.
|
||||
return moveRendition(oldRendition, location, renditionName);
|
||||
}
|
||||
|
||||
private ChildAssociationRef moveRendition(NodeRef renditionNode, RenditionLocation location, QName associationName)
|
||||
{
|
||||
ChildAssociationRef assoc = nodeService.moveNode(renditionNode, location.getParentRef(),
|
||||
ContentModel.ASSOC_CONTAINS, associationName);
|
||||
return assoc;
|
||||
}
|
||||
|
||||
private void orphanRendition(ChildAssociationRef oldRenditionAssoc)
|
||||
{
|
||||
NodeRef oldRendition = oldRenditionAssoc.getChildRef();
|
||||
nodeService.removeAspect(oldRendition, RenditionModel.ASPECT_HIDDEN_RENDITION);
|
||||
nodeService.removeAspect(oldRendition, RenditionModel.ASPECT_VISIBLE_RENDITION);
|
||||
nodeService.removeChildAssociation(oldRenditionAssoc);
|
||||
}
|
||||
|
||||
private boolean orphanExistingRendition(RenditionDefinition renditionDefinition, RenditionLocation location)
|
||||
{
|
||||
if (location.getChildRef() != null)
|
||||
return true;
|
||||
else
|
||||
return AbstractRenderingEngine.getParamWithDefault(RenditionService.PARAM_ORPHAN_EXISTING_RENDITION,
|
||||
Boolean.FALSE, renditionDefinition);
|
||||
}
|
||||
|
||||
private boolean renditionLocationMatches(NodeRef oldRendition, RenditionLocation location)
|
||||
{
|
||||
NodeRef destination = location.getChildRef();
|
||||
if (destination != null)
|
||||
{
|
||||
return destination.equals(oldRendition);
|
||||
}
|
||||
ChildAssociationRef oldParentAssoc = nodeService.getPrimaryParent(oldRendition);
|
||||
NodeRef oldParent = oldParentAssoc.getParentRef();
|
||||
if (oldParent.equals(location.getParentRef()))
|
||||
{
|
||||
String childName = location.getChildName();
|
||||
if (childName == null)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
Serializable oldName = nodeService.getProperty(oldRendition, ContentModel.PROP_NAME);
|
||||
return childName.equals(oldName);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ChildAssociationRef getSpecifiedRenditionOrCreateNewRendition(NodeRef sourceNode,
|
||||
RenditionLocation location, QName renditionName)
|
||||
{
|
||||
NodeRef destination = location.getChildRef();
|
||||
if (destination != null)
|
||||
return nodeService.getPrimaryParent(destination);
|
||||
else
|
||||
return createNewRendition(sourceNode, location, renditionName);
|
||||
}
|
||||
|
||||
private ChildAssociationRef createNewRendition(NodeRef sourceNode, RenditionLocation location, QName renditionName)
|
||||
{
|
||||
NodeRef parentRef = location.getParentRef();
|
||||
boolean parentIsSource = parentRef.equals(sourceNode);
|
||||
QName renditionType = RenditionModel.ASSOC_RENDITION;
|
||||
QName assocTypeQName = parentIsSource ? renditionType : ContentModel.ASSOC_CONTAINS;
|
||||
QName nodeTypeQName = ContentModel.TYPE_CONTENT;
|
||||
ChildAssociationRef primaryAssoc = nodeService.createNode(parentRef, assocTypeQName, renditionName,
|
||||
nodeTypeQName);
|
||||
|
||||
// If the new rendition is not directly under the source node then add
|
||||
// the rendition association.
|
||||
if (parentIsSource == false)
|
||||
{
|
||||
NodeRef rendition = primaryAssoc.getChildRef();
|
||||
nodeService.addChild(sourceNode, rendition, renditionType, renditionName);
|
||||
}
|
||||
return primaryAssoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sourceNode
|
||||
* @param targetNode
|
||||
*/
|
||||
private void transferNodeProperties(NodeRef sourceNode, NodeRef targetNode)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Transferring some properties from ").append(sourceNode).append(" to ").append(targetNode);
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
|
||||
Map<QName, Serializable> newProps = nodeService.getProperties(sourceNode);
|
||||
for (QName propKey : unchangedProperties)
|
||||
{
|
||||
newProps.remove(propKey);
|
||||
}
|
||||
nodeService.setProperties(targetNode, newProps);
|
||||
}
|
||||
|
||||
private RenditionLocation getDestinationParentAssoc(NodeRef sourceNode, RenditionDefinition definition,
|
||||
NodeRef tempRendition)
|
||||
{
|
||||
return renditionLocationResolver.getRenditionLocation(sourceNode, definition, tempRendition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RENDITION_DEFINITION, DataTypeDefinition.ANY, true,
|
||||
getParamDisplayLabel(PARAM_RENDITION_DEFINITION)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RESULT, DataTypeDefinition.CHILD_ASSOC_REF, false,
|
||||
getParamDisplayLabel(PARAM_RESULT)));
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.repo.action.ActionDefinitionImpl;
|
||||
import org.alfresco.service.cmr.rendition.RenderingEngineDefinition;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
* @since 3.3
|
||||
*/
|
||||
public class RenderingEngineDefinitionImpl extends ActionDefinitionImpl implements RenderingEngineDefinition
|
||||
{
|
||||
/**
|
||||
* Serial version UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RenderingEngineDefinitionImpl(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class RenditionDefinitionImpl extends ActionImpl implements RenditionDefinition
|
||||
{
|
||||
|
||||
/**
|
||||
* Serial version UID
|
||||
*/
|
||||
private static final long serialVersionUID = 4336392868488634875L;
|
||||
protected static final String RENDITION_DEFINITION_NAME = "renderingActionName";
|
||||
|
||||
public NodeRef renditionParent;
|
||||
public QName renditionAssociationType;
|
||||
private RenderCallback renderCallback;
|
||||
|
||||
/**
|
||||
* @param id the action id
|
||||
* @param renditionName a unique name for the rendering action.
|
||||
* @param renderingEngineName the name of the rendering action definition
|
||||
*/
|
||||
public RenditionDefinitionImpl(String id, QName renditionName, String renderingEngineName)
|
||||
{
|
||||
super(null, id, renderingEngineName);
|
||||
setParameterValue(RENDITION_DEFINITION_NAME, renditionName);
|
||||
}
|
||||
|
||||
public RenditionDefinitionImpl(Action action)
|
||||
{
|
||||
super(action);
|
||||
}
|
||||
|
||||
public RenditionDefinitionImpl(Action action, String renderingEngineName)
|
||||
{
|
||||
super(action, renderingEngineName);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionDefinition#getRenditionName()
|
||||
*/
|
||||
public QName getRenditionName()
|
||||
{
|
||||
return (QName) getParameterValue(RENDITION_DEFINITION_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionDefinition#getRenditionParent
|
||||
* ()
|
||||
*/
|
||||
public NodeRef getRenditionParent()
|
||||
{
|
||||
return this.renditionParent;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionDefinition#setRenditionParent
|
||||
* (org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public void setRenditionParent(NodeRef renditionParent)
|
||||
{
|
||||
this.renditionParent = renditionParent;
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.service.cmr.rendition.RenditionDefinition#
|
||||
* getRenditionAssociationType()
|
||||
*/
|
||||
public QName getRenditionAssociationType()
|
||||
{
|
||||
return this.renditionAssociationType;
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.service.cmr.rendition.RenditionDefinition#
|
||||
* setRenditionAssociationType(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public void setRenditionAssociationType(QName renditionAssociationType)
|
||||
{
|
||||
this.renditionAssociationType = renditionAssociationType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionDefinition#setCallback(org.alfresco.service.cmr.rendition.RenderCallback)
|
||||
*/
|
||||
public void setCallback(RenderCallback callback)
|
||||
{
|
||||
this.renderCallback = callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionDefinition#setCallback(org.alfresco.service.cmr.rendition.RenderCallback)
|
||||
*/
|
||||
public RenderCallback getCallback()
|
||||
{
|
||||
return this.renderCallback;
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* This class provides the implementation of RenditionDefinition persistence.
|
||||
*
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public interface RenditionDefinitionPersister
|
||||
{
|
||||
/**
|
||||
* This method serializes the {@link RenditionDefinition} and stores it in
|
||||
* the repository. {@link RenditionDefinition}s saved in this way may be
|
||||
* retrieved using the <code>load()</code> method.
|
||||
*
|
||||
* @param renditionDefinition The {@link RenditionDefinition} to be
|
||||
* persisted.
|
||||
*/
|
||||
void saveRenditionDefinition(RenditionDefinition renditionDefinition);
|
||||
|
||||
/**
|
||||
* This method retrieves a {@link RenditionDefinition} that has been stored
|
||||
* in the repository using the <code>save()</code> method. If no
|
||||
* {@link RenditionDefinition} exists in the repository with the specified
|
||||
* rendition name then this method returns null.
|
||||
*
|
||||
* @param renditionName The unique identifier used to specify the
|
||||
* {@link RenditionDefinition} to retrieve.
|
||||
* @return The specified {@link RenditionDefinition} or null.
|
||||
*/
|
||||
RenditionDefinition loadRenditionDefinition(QName renditionName);
|
||||
|
||||
/**
|
||||
* This method retrieves the {@link RenditionDefinition}s that have been
|
||||
* stored in the repository using the <code>save()</code> method.
|
||||
* <P/>
|
||||
* If there are no such {@link RenditionDefinition}s, an empty list is
|
||||
* returned.
|
||||
*
|
||||
* @return The {@link RenditionDefinition}s.
|
||||
*/
|
||||
List<RenditionDefinition> loadRenditionDefinitions();
|
||||
|
||||
/**
|
||||
* This method retrieves the stored {@link RenditionDefinition}s that have
|
||||
* been registered for the specified rendering engine name.
|
||||
* <P/>
|
||||
* If there are no such rendering {@link RenditionDefinition}s, an empty
|
||||
* list is returned.
|
||||
*
|
||||
* @param renderingEngineName the name of a rendering engine. This is
|
||||
* usually the spring bean name.
|
||||
* @return The {@link RenditionDefinition}s.
|
||||
* @throws NullPointerException if the renderingEngineName is null.
|
||||
* @see #saveRenditionDefinition(RenditionDefinition)
|
||||
*/
|
||||
List<RenditionDefinition> loadRenditionDefinitions(String renderingEngineName);
|
||||
}
|
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionModel;
|
||||
import org.alfresco.repo.action.RuntimeActionService;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* This class provides the implementation of RenditionDefinition persistence.
|
||||
*
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class RenditionDefinitionPersisterImpl implements RenditionDefinitionPersister
|
||||
{
|
||||
/** Reference to the rendering action space node */
|
||||
private static final StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
|
||||
protected static final NodeRef RENDERING_ACTION_ROOT_NODE_REF = new NodeRef(SPACES_STORE, "rendering_actions_space");
|
||||
|
||||
/* Injected services */
|
||||
private NodeService nodeService;
|
||||
private RuntimeActionService runtimeActionService;
|
||||
|
||||
/**
|
||||
* Injects the NodeService bean.
|
||||
*
|
||||
* @param nodeService the NodeService.
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the RuntimeActionService bean.
|
||||
*
|
||||
* @param runtimeActionService the RuntimeActionService.
|
||||
*/
|
||||
public void setRuntimeActionService(RuntimeActionService runtimeActionService)
|
||||
{
|
||||
this.runtimeActionService = runtimeActionService;
|
||||
}
|
||||
|
||||
public List<RenditionDefinition> loadRenditionDefinitions()
|
||||
{
|
||||
checkRenderingActionRootNodeExists();
|
||||
|
||||
// Note that in the call to getChildAssocs below, only the specified
|
||||
// types are included.
|
||||
// Subtypes of the type action:action will not be returned.
|
||||
Set<QName> actionTypes = new HashSet<QName>();
|
||||
actionTypes.add(ActionModel.TYPE_ACTION);
|
||||
|
||||
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(RENDERING_ACTION_ROOT_NODE_REF, actionTypes);
|
||||
|
||||
List<RenditionDefinition> renderingActions = new ArrayList<RenditionDefinition>(childAssocs.size());
|
||||
for (ChildAssociationRef actionAssoc : childAssocs)
|
||||
{
|
||||
Action nextAction = runtimeActionService.createAction(actionAssoc.getChildRef());
|
||||
renderingActions.add(new RenditionDefinitionImpl(nextAction));
|
||||
}
|
||||
|
||||
return renderingActions;
|
||||
}
|
||||
|
||||
public List<RenditionDefinition> loadRenditionDefinitions(String renditionEngineName)
|
||||
{
|
||||
if (renditionEngineName == null)
|
||||
{
|
||||
throw new NullPointerException("Unexpected null renditionEngineName");
|
||||
}
|
||||
|
||||
List<RenditionDefinition> allRenditionDefinitions = this.loadRenditionDefinitions();
|
||||
|
||||
List<RenditionDefinition> filteredRenditionDefinitions = new ArrayList<RenditionDefinition>();
|
||||
for (RenditionDefinition renderAction : allRenditionDefinitions)
|
||||
{
|
||||
if (renditionEngineName.equals(renderAction.getActionDefinitionName()))
|
||||
{
|
||||
filteredRenditionDefinitions.add(renderAction);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredRenditionDefinitions;
|
||||
}
|
||||
|
||||
|
||||
public RenditionDefinition loadRenditionDefinition(QName renderingActionName)
|
||||
{
|
||||
NodeRef actionNode = findActionNode(renderingActionName);
|
||||
if (actionNode != null)
|
||||
{
|
||||
Action action = runtimeActionService.createAction(actionNode);
|
||||
if (action instanceof CompositeAction)
|
||||
{
|
||||
CompositeAction compAction = (CompositeAction) action;
|
||||
return new CompositeRenditionDefinitionImpl(compAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RenditionDefinitionImpl(action);
|
||||
}
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void saveRenditionDefinition(RenditionDefinition renderingAction)
|
||||
{
|
||||
NodeRef actionNodeRef = findOrCreateActionNode(renderingAction);
|
||||
|
||||
// TODO Serialize using JSON content instead.
|
||||
// The current serialization mechanism creates a complex content model
|
||||
// structure which is verbose and a JSON-based approach using a simplified
|
||||
// content model perhaps could offer performance improvements.
|
||||
runtimeActionService.saveActionImpl(actionNodeRef, renderingAction);
|
||||
}
|
||||
|
||||
private NodeRef findActionNode(QName renderingActionName)
|
||||
{
|
||||
checkRenderingActionRootNodeExists();
|
||||
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(//
|
||||
RENDERING_ACTION_ROOT_NODE_REF,//
|
||||
ContentModel.ASSOC_CONTAINS,//
|
||||
renderingActionName);
|
||||
if (childAssocs.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (childAssocs.size() > 1)
|
||||
{//
|
||||
throw new RenditionServiceException("Multiple rendering actions with the name: " + renderingActionName
|
||||
+ " exist!");
|
||||
}
|
||||
return childAssocs.get(0).getChildRef();
|
||||
}
|
||||
}
|
||||
|
||||
private NodeRef findOrCreateActionNode(RenditionDefinition renderingAction)
|
||||
{
|
||||
QName actionName = renderingAction.getRenditionName();
|
||||
NodeRef actionNode = findActionNode(actionName);
|
||||
if (actionNode == null)
|
||||
{
|
||||
actionNode = runtimeActionService.createActionNodeRef(//
|
||||
renderingAction,//
|
||||
RENDERING_ACTION_ROOT_NODE_REF,//
|
||||
ContentModel.ASSOC_CONTAINS,//
|
||||
actionName);
|
||||
}
|
||||
return actionNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the folder containing Rendering Action nodes
|
||||
* exists.
|
||||
*
|
||||
* @throws RenditionServiceException if the folder node does not exist.
|
||||
*/
|
||||
private void checkRenderingActionRootNodeExists()
|
||||
{
|
||||
if (nodeService.exists(RENDERING_ACTION_ROOT_NODE_REF) == false)
|
||||
{
|
||||
throw new RenditionServiceException("Unable to find rendering action root node.");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
public interface RenditionLocation
|
||||
{
|
||||
NodeRef getParentRef();
|
||||
|
||||
NodeRef getChildRef();
|
||||
|
||||
String getChildName();
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
public class RenditionLocationImpl implements RenditionLocation
|
||||
{
|
||||
private final NodeRef parentRef;
|
||||
private final NodeRef childRef;
|
||||
private final String childName;
|
||||
|
||||
public RenditionLocationImpl(NodeRef parentRef, NodeRef childRef, String childName)
|
||||
{
|
||||
this.parentRef = parentRef;
|
||||
this.childRef = childRef;
|
||||
this.childName = childName;
|
||||
}
|
||||
|
||||
public String getChildName()
|
||||
{
|
||||
return childName;
|
||||
}
|
||||
|
||||
public NodeRef getParentRef()
|
||||
{
|
||||
return parentRef;
|
||||
}
|
||||
|
||||
public NodeRef getChildRef()
|
||||
{
|
||||
return childRef;
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
public interface RenditionLocationResolver
|
||||
{
|
||||
|
||||
RenditionLocation getRenditionLocation(NodeRef sourceNode, RenditionDefinition definition, NodeRef tempRenditionLocation);
|
||||
|
||||
}
|
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.rendition.CompositeRenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenderingEngineDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class RenditionServiceImpl implements RenditionService, RenditionDefinitionPersister
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(RenditionServiceImpl.class);
|
||||
|
||||
private ActionService actionService;
|
||||
private ContentService contentService;
|
||||
private DictionaryService dictionaryService;
|
||||
private NodeService nodeService;
|
||||
|
||||
private RenditionDefinitionPersisterImpl renditionDefinitionPersister;
|
||||
|
||||
/**
|
||||
* Injects the RenditionDefinitionPersister bean.
|
||||
* @param renditionDefinitionPersister
|
||||
*/
|
||||
public void setRenditionDefinitionPersister(RenditionDefinitionPersisterImpl renditionDefinitionPersister)
|
||||
{
|
||||
this.renditionDefinitionPersister = renditionDefinitionPersister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the ServiceRegistry bean.
|
||||
* @param serviceRegistry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.contentService = serviceRegistry.getContentService();
|
||||
this.nodeService = serviceRegistry.getNodeService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the ActionService bean.
|
||||
* @param actionService
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the DictionaryService bean.
|
||||
* @param dictionaryService
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenderingEngineDefinition(java.lang.String)
|
||||
*/
|
||||
public RenderingEngineDefinition getRenderingEngineDefinition(String name)
|
||||
{
|
||||
ActionDefinition actionDefinition = actionService.getActionDefinition(name);
|
||||
if (actionDefinition instanceof RenderingEngineDefinition)
|
||||
{
|
||||
return (RenderingEngineDefinition) actionDefinition;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenderingEngineDefinitions()
|
||||
*/
|
||||
public List<RenderingEngineDefinition> getRenderingEngineDefinitions()
|
||||
{
|
||||
List<RenderingEngineDefinition> results = new ArrayList<RenderingEngineDefinition>();
|
||||
List<ActionDefinition> actionDefs = actionService.getActionDefinitions();
|
||||
for (ActionDefinition actionDef : actionDefs)
|
||||
{
|
||||
if (actionDef instanceof RenderingEngineDefinition)
|
||||
{
|
||||
RenderingEngineDefinition renderingDef = (RenderingEngineDefinition) actionDef;
|
||||
results.add(renderingDef);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#createRenditionDefinition
|
||||
* (org.alfresco.service.namespace.QName, java.lang.String)
|
||||
*/
|
||||
public RenditionDefinition createRenditionDefinition(QName renderingActionName, String actionDefinitionName)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Creating rendition definition ")
|
||||
.append(renderingActionName)
|
||||
.append(" ")
|
||||
.append(actionDefinitionName);
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
return new RenditionDefinitionImpl(GUID.generate(), renderingActionName, actionDefinitionName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#createCompositeRenditionDefinition(org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public CompositeRenditionDefinition createCompositeRenditionDefinition(QName renditionName)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Creating composite rendition definition ")
|
||||
.append(renditionName);
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
return new CompositeRenditionDefinitionImpl(GUID.generate(), renditionName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#render(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.rendition.RenditionDefinition)
|
||||
*/
|
||||
public ChildAssociationRef render(NodeRef sourceNode, RenditionDefinition definition)
|
||||
{
|
||||
ChildAssociationRef result = createAndExecuteRenditionAction(sourceNode, definition, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void render(NodeRef sourceNode, RenditionDefinition definition,
|
||||
RenderCallback callback)
|
||||
{
|
||||
// The asynchronous render can't return a ChildAssociationRef as it is created
|
||||
// asynchronously after this method returns.
|
||||
definition.setCallback(callback);
|
||||
|
||||
createAndExecuteRenditionAction(sourceNode, definition, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private ChildAssociationRef createAndExecuteRenditionAction(NodeRef sourceNode,
|
||||
RenditionDefinition definition, boolean asynchronous)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
if (asynchronous)
|
||||
{
|
||||
msg.append("Asynchronously");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.append("Synchronously");
|
||||
}
|
||||
msg.append(" rendering node ").append(sourceNode)
|
||||
.append(" with ").append(definition.getRenditionName());
|
||||
log.debug(msg.toString());
|
||||
}
|
||||
Action performRenditionAction = actionService.createAction(PerformRenditionActionExecuter.NAME);
|
||||
performRenditionAction.setParameterValue(PerformRenditionActionExecuter.PARAM_RENDITION_DEFINITION, definition);
|
||||
|
||||
final boolean checkConditions = false;
|
||||
actionService.executeAction(performRenditionAction, sourceNode, checkConditions, asynchronous);
|
||||
|
||||
ChildAssociationRef result = (ChildAssociationRef)performRenditionAction.getParameterValue(PerformRenditionActionExecuter.PARAM_RESULT);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#saveRenditionDefinition
|
||||
* (org.alfresco.service.cmr.rendition.RenditionDefinition)
|
||||
*/
|
||||
public void saveRenditionDefinition(RenditionDefinition renderingAction)
|
||||
{
|
||||
this.renditionDefinitionPersister.saveRenditionDefinition(renderingAction);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#loadRenderingAction
|
||||
* (org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public RenditionDefinition loadRenditionDefinition(QName renderingActionName)
|
||||
{
|
||||
return this.renditionDefinitionPersister.loadRenditionDefinition(renderingActionName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#loadRenditionDefinitions()
|
||||
*/
|
||||
public List<RenditionDefinition> loadRenditionDefinitions()
|
||||
{
|
||||
return this.renditionDefinitionPersister.loadRenditionDefinitions();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#loadRenderingActions
|
||||
* (java.lang.String)
|
||||
*/
|
||||
public List<RenditionDefinition> loadRenditionDefinitions(String renditionEngineName)
|
||||
{
|
||||
return this.loadRenditionDefinitions(renditionEngineName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#getRenditions(org
|
||||
* .alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public List<ChildAssociationRef> getRenditions(NodeRef node)
|
||||
{
|
||||
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
||||
|
||||
// Check that the node has the renditioned aspect applied
|
||||
if (nodeService.hasAspect(node, RenditionModel.ASPECT_RENDITIONED) == true)
|
||||
{
|
||||
// Get all the renditions that match the given rendition name
|
||||
result = nodeService.getChildAssocs(node, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.alfresco.service.cmr.rendition.RenditionService#getRenditions(org
|
||||
* .alfresco.service.cmr.repository.NodeRef, java.lang.String)
|
||||
*/
|
||||
public List<ChildAssociationRef> getRenditions(NodeRef node, String mimeTypePrefix)
|
||||
{
|
||||
List<ChildAssociationRef> allRenditions = this.getRenditions(node);
|
||||
List<ChildAssociationRef> filteredResults = new ArrayList<ChildAssociationRef>();
|
||||
|
||||
for (ChildAssociationRef chAssRef : allRenditions)
|
||||
{
|
||||
NodeRef renditionNode = chAssRef.getChildRef();
|
||||
|
||||
QName contentProperty = ContentModel.PROP_CONTENT;
|
||||
Serializable contentPropertyName = nodeService.getProperty(renditionNode,
|
||||
ContentModel.PROP_CONTENT_PROPERTY_NAME);
|
||||
if (contentPropertyName != null)
|
||||
{
|
||||
contentProperty = (QName) contentPropertyName;
|
||||
}
|
||||
|
||||
ContentReader reader = contentService.getReader(renditionNode, contentProperty);
|
||||
if (reader != null && reader.exists())
|
||||
{
|
||||
String readerMimeType = reader.getMimetype();
|
||||
if (readerMimeType.startsWith(mimeTypePrefix))
|
||||
{
|
||||
filteredResults.add(chAssRef);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return filteredResults;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#getRenditionByName(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
|
||||
*/
|
||||
public ChildAssociationRef getRenditionByName(NodeRef node, QName renditionName)
|
||||
{
|
||||
List<ChildAssociationRef> renditions = new ArrayList<ChildAssociationRef>();
|
||||
|
||||
// Check that the node has the renditioned aspect applied
|
||||
if (nodeService.hasAspect(node, RenditionModel.ASPECT_RENDITIONED) == true)
|
||||
{
|
||||
// Get all the renditions that match the given rendition name -
|
||||
// there should only be 1 (or 0)
|
||||
renditions = this.nodeService.getChildAssocs(node, RenditionModel.ASSOC_RENDITION, renditionName);
|
||||
}
|
||||
if (renditions.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return renditions.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#isRendition(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public boolean isRendition(NodeRef node)
|
||||
{
|
||||
final QName aspectToCheckFor = RenditionModel.ASPECT_RENDITION;
|
||||
|
||||
Set<QName> existingAspects = nodeService.getAspects(node);
|
||||
for (QName nextAspect : existingAspects)
|
||||
{
|
||||
if (nextAspect.equals(aspectToCheckFor) || dictionaryService.isSubClass(nextAspect, aspectToCheckFor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.rendition.RenditionService#getSourceNode(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public ChildAssociationRef getSourceNode(NodeRef renditionNode)
|
||||
{
|
||||
// In normal circumstances only a node which is itself a rendition can have
|
||||
// a source node - as linked by the rn:rendition association.
|
||||
//
|
||||
// However there are some circumstances where a node which is not
|
||||
// technically a rendition can still have a source. One such example is the case
|
||||
// of thumbnail nodes created in a pre-3.3 Alfresco which have not been patched
|
||||
// to have the correct rendition aspect applied.
|
||||
// This will also occur *during* execution of the webscript patch and so the
|
||||
// decision was made not to throw an exception or log a warning if such a
|
||||
// situation is encountered.
|
||||
|
||||
// A rendition node should have 1 and only 1 source node.
|
||||
List<ChildAssociationRef> parents = nodeService.getParentAssocs(renditionNode,
|
||||
RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
|
||||
if (parents.size() > 1)
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("NodeRef ")
|
||||
.append(renditionNode)
|
||||
.append(" unexpectedly has ")
|
||||
.append(parents.size())
|
||||
.append(" rendition parents.");
|
||||
if (log.isWarnEnabled())
|
||||
{
|
||||
log.warn(msg.toString());
|
||||
}
|
||||
throw new RenditionServiceException(msg.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return parents.isEmpty() ? null : parents.get(0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.repo.action.ActionDefinitionImpl;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.rendition.RenderingEngineDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class RenditionServiceImplTest extends TestCase
|
||||
{
|
||||
private final static String ENGINE_NAME = "Engine Name";
|
||||
|
||||
private ServiceRegistry serviceRegistry = new MockedTestServiceRegistry();
|
||||
private ActionService actionService = mock(ActionService.class);
|
||||
|
||||
private final RenditionDefinitionPersisterImpl renditionDefinitionPersister = mock(RenditionDefinitionPersisterImpl.class);
|
||||
private RenditionServiceImpl renditionService;
|
||||
|
||||
private final QName ACTION_NAME = QName.createQName(NamespaceService.ALFRESCO_URI, "testName");
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
renditionService = new RenditionServiceImpl();
|
||||
renditionService.setServiceRegistry(serviceRegistry);
|
||||
renditionService.setActionService(actionService);
|
||||
renditionService.setRenditionDefinitionPersister(renditionDefinitionPersister);
|
||||
}
|
||||
|
||||
public void testGetRenderingEngineDefinition() throws Exception
|
||||
{
|
||||
// Check returns null when unknown name specified.
|
||||
assertNull(renditionService.getRenderingEngineDefinition(""));
|
||||
|
||||
// Check returns null if action service returns an ActionDefinition
|
||||
// which does not implement RenderingActionDefinition.
|
||||
ActionDefinition actionDefinition = new ActionDefinitionImpl(ENGINE_NAME);
|
||||
when(actionService.getActionDefinition(ENGINE_NAME)).thenReturn(actionDefinition);
|
||||
assertNull(renditionService.getRenderingEngineDefinition(ENGINE_NAME));
|
||||
|
||||
// Check returns the definition if the action service returns an
|
||||
// ActionDefinition
|
||||
// which does implement RenderingActionDefinition.
|
||||
ActionDefinition renderingDefinition = new RenderingEngineDefinitionImpl(ENGINE_NAME);
|
||||
when(actionService.getActionDefinition(ENGINE_NAME)).thenReturn(renderingDefinition);
|
||||
assertSame(renderingDefinition, renditionService.getRenderingEngineDefinition(ENGINE_NAME));
|
||||
}
|
||||
|
||||
public void testGetRenderingEngineDefinitions() throws Exception
|
||||
{
|
||||
LinkedList<ActionDefinition> actionDefs = new LinkedList<ActionDefinition>();
|
||||
when(actionService.getActionDefinitions()).thenReturn(actionDefs);
|
||||
|
||||
// Check case where no action definitions returned.
|
||||
List<RenderingEngineDefinition> engineDefs = renditionService.getRenderingEngineDefinitions();
|
||||
assertTrue("The list of rendering action definitions should be empty!", engineDefs.isEmpty());
|
||||
|
||||
// Check that when the action service returns a rendering engine
|
||||
// definition then the rendering service includes this in the list of
|
||||
// returned values.
|
||||
ActionDefinition renderingDefinition = new RenderingEngineDefinitionImpl(ENGINE_NAME);
|
||||
actionDefs.add(renderingDefinition);
|
||||
engineDefs = renditionService.getRenderingEngineDefinitions();
|
||||
assertEquals(1, engineDefs.size());
|
||||
assertSame(renderingDefinition, engineDefs.get(0));
|
||||
|
||||
// Check that when the action service returns a non-rendering action
|
||||
// definition then the rendering service does not include it.
|
||||
ActionDefinition actionDefinition = new ActionDefinitionImpl(ENGINE_NAME);
|
||||
actionDefs.add(actionDefinition);
|
||||
engineDefs = renditionService.getRenderingEngineDefinitions();
|
||||
assertEquals(1, engineDefs.size());
|
||||
assertSame(renderingDefinition, engineDefs.get(0));
|
||||
}
|
||||
|
||||
public void testCreateRenditionDefinition() throws Exception
|
||||
{
|
||||
RenditionDefinition renderingAction = renditionService.createRenditionDefinition(ACTION_NAME, ENGINE_NAME);
|
||||
assertNotNull(renderingAction);
|
||||
assertEquals(ENGINE_NAME, renderingAction.getActionDefinitionName());
|
||||
assertEquals(ACTION_NAME, renderingAction.getRenditionName());
|
||||
String id = renderingAction.getId();
|
||||
assertNotNull(id);
|
||||
assertTrue(id.length() > 0);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class RenditionServicePermissionsTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(RenditionServicePermissionsTest.class);
|
||||
|
||||
private final static QName RESCALE_RENDER_DEFN_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
ImageRenderingEngine.NAME + System.currentTimeMillis());
|
||||
|
||||
private NodeRef nodeWithImageContent;
|
||||
private NodeRef testFolder;
|
||||
|
||||
private PermissionService permissionService;
|
||||
private PersonService personService;
|
||||
private RenditionService renditionService;
|
||||
private Repository repositoryHelper;
|
||||
private RetryingTransactionHelper transactionHelper;
|
||||
private String testFolderName;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
this.permissionService = (PermissionService)this.applicationContext.getBean("PermissionService");
|
||||
this.personService = (PersonService)this.applicationContext.getBean("PersonService");
|
||||
this.renditionService = (RenditionService) this.applicationContext.getBean("renditionService");
|
||||
this.repositoryHelper = (Repository) this.applicationContext.getBean("repositoryHelper");
|
||||
this.transactionHelper = (RetryingTransactionHelper) this.applicationContext
|
||||
.getBean("retryingTransactionHelper");
|
||||
|
||||
NodeRef companyHome = this.repositoryHelper.getCompanyHome();
|
||||
|
||||
// Create the test folder used for these tests
|
||||
this.testFolderName= "Test-folder-"+ System.currentTimeMillis();
|
||||
this.testFolder = nodeService.createNode(companyHome,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.APP_MODEL_1_0_URI,testFolderName),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
nodeService.setProperty(testFolder, ContentModel.PROP_NAME, testFolderName);
|
||||
// Create the node used as a content supplier for tests
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, "Test-image-node-" + System.currentTimeMillis());
|
||||
|
||||
String testImageNodeName = "testImageNode" + System.currentTimeMillis();
|
||||
this.nodeWithImageContent = nodeService.createNode(companyHome, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.APP_MODEL_1_0_URI, testImageNodeName),
|
||||
ContentModel.TYPE_CONTENT, props).getChildRef();
|
||||
// Stream some well-known image content into the node.
|
||||
URL url = RenditionServicePermissionsTest.class.getClassLoader().getResource("images/gray21.512.png");
|
||||
assertNotNull("url of test image was null", url);
|
||||
File imageFile = new File(url.getFile());
|
||||
assertTrue(imageFile.exists());
|
||||
|
||||
nodeService.setProperty(nodeWithImageContent, ContentModel.PROP_CONTENT, new ContentData(null,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG, 0L, null));
|
||||
ContentWriter writer = contentService.getWriter(nodeWithImageContent, ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(MimetypeMap.MIMETYPE_IMAGE_PNG);
|
||||
writer.setEncoding("UTF-8");
|
||||
writer.putContent(imageFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onTearDownInTransaction() throws Exception
|
||||
{
|
||||
nodeService.deleteNode(nodeWithImageContent);
|
||||
nodeService.deleteNode(testFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test method uses the RenditionService to render a test document and place the
|
||||
* rendition under a folder for which the user does not have write permissions.
|
||||
* This should be allowed as all renditions are performed as system.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testRenditionAccessPermissions() throws Exception
|
||||
{
|
||||
this.setComplete();
|
||||
this.endTransaction();
|
||||
|
||||
final String normalUser = "renditionUser";
|
||||
|
||||
// As admin, create a user who has read-only access to the testFolder
|
||||
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Set the current security context as admin
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
assertEquals("admin", authenticationService.getCurrentUserName());
|
||||
|
||||
if (authenticationService.authenticationExists(normalUser) == false)
|
||||
{
|
||||
authenticationService.createAuthentication(normalUser, "PWD".toCharArray());
|
||||
|
||||
PropertyMap personProperties = new PropertyMap();
|
||||
personProperties.put(ContentModel.PROP_USERNAME, normalUser);
|
||||
personProperties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, "title" + normalUser);
|
||||
personProperties.put(ContentModel.PROP_FIRSTNAME, "firstName");
|
||||
personProperties.put(ContentModel.PROP_LASTNAME, "lastName");
|
||||
personProperties.put(ContentModel.PROP_EMAIL, "email@email.com");
|
||||
personProperties.put(ContentModel.PROP_JOBTITLE, "jobTitle");
|
||||
|
||||
personService.createPerson(personProperties);
|
||||
}
|
||||
|
||||
// Restrict write access to the test folder
|
||||
permissionService.setPermission(testFolder, normalUser, PermissionService.CONSUMER, true);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// As the user, render a piece of content with the rendition going to testFolder
|
||||
final NodeRef rendition = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Set the current security context as a rendition user
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(normalUser);
|
||||
assertEquals(normalUser, authenticationService.getCurrentUserName());
|
||||
|
||||
assertFalse("Source node has unexpected renditioned aspect.", nodeService.hasAspect(nodeWithImageContent,
|
||||
RenditionModel.ASPECT_RENDITIONED));
|
||||
|
||||
String path = testFolderName+"/testRendition.png";
|
||||
// Create the rendering action.
|
||||
RenditionDefinition action = makeRescaleImageAction();
|
||||
action.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, path);
|
||||
|
||||
// Perform the action with an explicit destination folder
|
||||
logger.debug("Creating rendition of: " + nodeWithImageContent);
|
||||
ChildAssociationRef renditionAssoc = renditionService.render(nodeWithImageContent, action);
|
||||
logger.debug("Created rendition: " + renditionAssoc.getChildRef());
|
||||
|
||||
NodeRef renditionNode = renditionAssoc.getChildRef();
|
||||
|
||||
assertEquals("The parent node was not correct", nodeWithImageContent, renditionAssoc.getParentRef());
|
||||
logger.debug("rendition's primary parent: " + nodeService.getPrimaryParent(renditionNode));
|
||||
assertEquals("The parent node was not correct", testFolder, nodeService.getPrimaryParent(renditionNode).getParentRef());
|
||||
|
||||
// Now the source content node should have the rn:renditioned aspect
|
||||
assertTrue("Source node is missing renditioned aspect.", nodeService.hasAspect(nodeWithImageContent,
|
||||
RenditionModel.ASPECT_RENDITIONED));
|
||||
|
||||
return renditionNode;
|
||||
}
|
||||
});
|
||||
|
||||
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
// Set the current security context as admin
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
|
||||
|
||||
final Serializable renditionCreator = nodeService.getProperty(rendition, ContentModel.PROP_CREATOR);
|
||||
assertEquals("Incorrect creator", normalUser, renditionCreator);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a RenditionDefinition for the RescaleImageActionExecutor.
|
||||
*
|
||||
* @return A new RenderingAction.
|
||||
*/
|
||||
private RenditionDefinition makeRescaleImageAction()
|
||||
{
|
||||
RenditionDefinition result = renditionService.createRenditionDefinition(RESCALE_RENDER_DEFN_NAME,
|
||||
ImageRenderingEngine.NAME);
|
||||
result.setParameterValue(ImageRenderingEngine.PARAM_RESIZE_WIDTH, 42);
|
||||
return result;
|
||||
}
|
||||
}
|
360
source/java/org/alfresco/repo/rendition/RenditionedAspect.java
Normal file
360
source/java/org/alfresco/repo/rendition/RenditionedAspect.java
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.copy.CopyBehaviourCallback;
|
||||
import org.alfresco.repo.copy.CopyDetails;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies;
|
||||
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.Behaviour;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenderCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Renditioned aspect behaviour bean.
|
||||
* When any node with the renditioned aspect has a property updated, then all
|
||||
* associated renditions are eligible for re-rendering.
|
||||
* Each rendition (as identified by the name in its rn:rendition association) will
|
||||
* be loaded and if the renditionDefinition exists, the rendition will be updated
|
||||
* asynchronously, subject to the defined update policy.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class RenditionedAspect implements NodeServicePolicies.OnUpdatePropertiesPolicy,
|
||||
CopyServicePolicies.OnCopyNodePolicy
|
||||
{
|
||||
/** logger */
|
||||
private static final Log logger = LogFactory.getLog(RenditionedAspect.class);
|
||||
|
||||
/** Services */
|
||||
private PolicyComponent policyComponent;
|
||||
private NodeService nodeService;
|
||||
private DictionaryService dictionaryService;
|
||||
private RenditionService renditionService;
|
||||
|
||||
/**
|
||||
* Set the policy component
|
||||
*
|
||||
* @param policyComponent policy component
|
||||
*/
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rendition service
|
||||
*
|
||||
* @param renditionService rendition service
|
||||
*/
|
||||
public void setRenditionService(RenditionService renditionService)
|
||||
{
|
||||
this.renditionService = renditionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dictionary service
|
||||
*
|
||||
* @param dictionaryService dictionary service
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise method
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
|
||||
RenditionModel.ASPECT_RENDITIONED,
|
||||
new JavaBehaviour(this, "onUpdateProperties", Behaviour.NotificationFrequency.TRANSACTION_COMMIT));
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
|
||||
RenditionModel.ASPECT_RENDITIONED,
|
||||
new JavaBehaviour(this, "getCopyCallback"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
|
||||
*/
|
||||
public void onUpdateProperties(
|
||||
NodeRef nodeRef,
|
||||
Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after)
|
||||
{
|
||||
// Ignore working copies
|
||||
if (this.nodeService.exists(nodeRef) == true &&
|
||||
this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
|
||||
{
|
||||
|
||||
// Find the changed properties
|
||||
List<QName> changedProperties = getChangedProperties(before, after);
|
||||
|
||||
// There may be a different policy for different rendition kinds.
|
||||
List<ChildAssociationRef> renditions = this.renditionService.getRenditions(nodeRef);
|
||||
for (ChildAssociationRef chAssRef : renditions)
|
||||
{
|
||||
QName renditionAssocName = chAssRef.getQName();
|
||||
RenditionDefinition rendDefn = this.renditionService.loadRenditionDefinition(renditionAssocName);
|
||||
if (rendDefn == null)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Cannot update rendition ")
|
||||
.append(renditionAssocName)
|
||||
.append(" on node ").append(nodeRef)
|
||||
.append(" as the renditionDefinition could not be loaded.");
|
||||
logger.debug(msg.toString());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Serializable updateRenditionsPolicy = rendDefn.getParameterValue(AbstractRenderingEngine.PARAM_UPDATE_RENDITIONS_ON_ANY_PROPERTY_CHANGE);
|
||||
boolean updateRenditionsAlways = updateRenditionsPolicy == null ? false : (Boolean)updateRenditionsPolicy;
|
||||
|
||||
boolean renditionUpdateRequired = false;
|
||||
|
||||
for (QName qname : changedProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
PropertyDefinition propertyDef = dictionaryService.getProperty(qname);
|
||||
if (propertyDef == null)
|
||||
{
|
||||
// the property is not recognised
|
||||
continue;
|
||||
}
|
||||
else if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
|
||||
{
|
||||
// not a content type
|
||||
if (updateRenditionsAlways)
|
||||
{
|
||||
renditionUpdateRequired = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it is a content property. We always update renditions for changes to content.
|
||||
renditionUpdateRequired = true;
|
||||
}
|
||||
} catch (ClassCastException ccx)
|
||||
{
|
||||
// the property does not confirm to the model
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (renditionUpdateRequired)
|
||||
{
|
||||
this.queueUpdate(nodeRef, rendDefn, chAssRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<QName> getChangedProperties(Map<QName, Serializable> before, Map<QName, Serializable> after)
|
||||
{
|
||||
List<QName> results = new ArrayList<QName>();
|
||||
for (QName propQName : before.keySet())
|
||||
{
|
||||
if (after.keySet().contains(propQName) == false)
|
||||
{
|
||||
// property was deleted
|
||||
results.add(propQName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serializable beforeValue = before.get(propQName);
|
||||
Serializable afterValue = after.get(propQName);
|
||||
if (EqualsHelper.nullSafeEquals(beforeValue, afterValue) == false)
|
||||
{
|
||||
// Property was changed
|
||||
results.add(propQName);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (QName propQName : after.keySet())
|
||||
{
|
||||
if (before.containsKey(propQName) == false)
|
||||
{
|
||||
// property was added
|
||||
results.add(propQName);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue the update to happen asynchronously
|
||||
*
|
||||
* @param sourceNodeRef node reference
|
||||
*/
|
||||
private void queueUpdate(final NodeRef sourceNodeRef, final RenditionDefinition rendDefn,
|
||||
final ChildAssociationRef renditionAssoc)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Queueing rendition update for node ").append(sourceNodeRef).append(": ").append(rendDefn.getRenditionName());
|
||||
logger.debug(msg.toString());
|
||||
}
|
||||
|
||||
if (rendDefn != null)
|
||||
{
|
||||
renditionService.render(sourceNodeRef, rendDefn, new RenderCallback()
|
||||
{
|
||||
public void handleFailedRendition(Throwable t)
|
||||
{
|
||||
// In the event of a failed re-rendition, we will delete the rendition node
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Re-rendering of node ")
|
||||
.append(sourceNodeRef)
|
||||
.append(" with renditionDefinition ")
|
||||
.append(rendDefn.getRenditionName())
|
||||
.append(" failed. Deleting defunct rendition. ")
|
||||
.append("The following exception is shown for informational purposes only ")
|
||||
.append("and does not affect operation of the system.");
|
||||
logger.debug(msg.toString(), t);
|
||||
}
|
||||
|
||||
if (nodeService.exists(renditionAssoc.getChildRef()))
|
||||
{
|
||||
nodeService.deleteNode(renditionAssoc.getChildRef());
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSuccessfulRendition(ChildAssociationRef primaryParentOfNewRendition)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns {@link RenditionedAspectCopyBehaviourCallback}
|
||||
*/
|
||||
public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
|
||||
{
|
||||
return RenditionedAspectCopyBehaviourCallback.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaviour for the {@link RenditionModel#ASPECT_RENDITIONED <b>rn:renditioned</b>} aspect.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @author Neil McErlean
|
||||
* @since 3.2
|
||||
*/
|
||||
private static class RenditionedAspectCopyBehaviourCallback extends DefaultCopyBehaviourCallback
|
||||
{
|
||||
private static final CopyBehaviourCallback INSTANCE = new RenditionedAspectCopyBehaviourCallback();
|
||||
|
||||
/**
|
||||
* @return Returns <tt>true</tt> always
|
||||
*/
|
||||
@Override
|
||||
public boolean getMustCopy(QName classQName, CopyDetails copyDetails)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy rendition-related associations, {@link RenditionModel#ASSOC_RENDITION} regardless of
|
||||
* cascade options.
|
||||
*/
|
||||
@Override
|
||||
public ChildAssocCopyAction getChildAssociationCopyAction(
|
||||
QName classQName,
|
||||
CopyDetails copyDetails,
|
||||
CopyChildAssociationDetails childAssocCopyDetails)
|
||||
{
|
||||
ChildAssociationRef childAssocRef = childAssocCopyDetails.getChildAssocRef();
|
||||
if (childAssocRef.getTypeQName().equals(RenditionModel.ASSOC_RENDITION))
|
||||
{
|
||||
return ChildAssocCopyAction.COPY_CHILD;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"Behaviour should have been invoked: \n" +
|
||||
" Aspect: " + this.getClass().getName() + "\n" +
|
||||
" " + childAssocCopyDetails + "\n" +
|
||||
" " + copyDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy only the {@link ContentModel#PROP_AUTOMATIC_UPDATE}
|
||||
*/
|
||||
@Override
|
||||
public Map<QName, Serializable> getCopyProperties(
|
||||
QName classQName,
|
||||
CopyDetails copyDetails,
|
||||
Map<QName, Serializable> properties)
|
||||
{
|
||||
Map<QName, Serializable> newProperties = new HashMap<QName, Serializable>(5);
|
||||
// Serializable value = properties.get(ContentModel.PROP_AUTOMATIC_UPDATE);
|
||||
// newProperties.put(ContentModel.PROP_AUTOMATIC_UPDATE, value);
|
||||
return newProperties;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.TemplateException;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.util.FreeMarkerUtil;
|
||||
import org.alfresco.util.XMLUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import freemarker.ext.dom.NodeModel;
|
||||
import freemarker.template.SimpleDate;
|
||||
import freemarker.template.SimpleHash;
|
||||
|
||||
public class StandardRenditionLocationResolverImpl implements RenditionLocationResolver
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(StandardRenditionLocationResolverImpl.class);
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private String companyHomePath = "/app:company_home";
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public void setCompanyHomePath(String companyHomePath)
|
||||
{
|
||||
this.companyHomePath = companyHomePath;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @seeorg.alfresco.repo.rendition.RenditionLocationResolver#
|
||||
* resolveRenditionPrimaryParentAssoc
|
||||
* (org.alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.service.cmr.rendition.RenditionDefinition,
|
||||
* org.alfresco.service.cmr.repository.ChildAssociationRef)
|
||||
*/
|
||||
public RenditionLocation getRenditionLocation(NodeRef sourceNode, RenditionDefinition definition, NodeRef tempRenditionLocation)
|
||||
{
|
||||
// If a destination NodeRef is specified then don't botther to find the location as one has already been specified.
|
||||
NodeRef destination = AbstractRenderingEngine.getCheckedParam(RenditionService.PARAM_DESTINATION_NODE, NodeRef.class, definition);
|
||||
if(destination!=null)
|
||||
{
|
||||
RenditionLocationImpl location = createNodeLocation(destination);
|
||||
return location;
|
||||
}
|
||||
// If the templated path has been specified and can be resolved then
|
||||
// find or create the templated path location and return it.
|
||||
String pathTemplate = (String) definition.getParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE);
|
||||
if (pathTemplate != null)
|
||||
{
|
||||
|
||||
NodeRef companyHome = getCompanyHomeNode(sourceNode.getStoreRef());
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
Serializable companyHomeName = nodeService.getProperty(companyHome, ContentModel.PROP_NAME);
|
||||
String path = renderPathTemplate(pathTemplate, sourceNode, tempRenditionLocation, companyHomeName);
|
||||
if(path!=null)
|
||||
{
|
||||
return findOrCreateTemplatedPath(sourceNode, path, companyHome);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise the rendition will be created as a child of the source content node.
|
||||
return new RenditionLocationImpl(sourceNode, null, null);
|
||||
}
|
||||
|
||||
private RenditionLocationImpl createNodeLocation(NodeRef destination)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
if(nodeService.exists(destination)==false)
|
||||
throw new RenditionServiceException("The rendition destination node does not exist! NodeRef: "+destination);
|
||||
NodeRef parentRef = nodeService.getPrimaryParent(destination).getParentRef();
|
||||
String childName = (String) nodeService.getProperty(destination, ContentModel.PROP_NAME);
|
||||
RenditionLocationImpl location = new RenditionLocationImpl(parentRef, destination, childName);
|
||||
return location;
|
||||
}
|
||||
|
||||
private RenditionLocationImpl findOrCreateTemplatedPath(NodeRef sourceNode, String path, NodeRef companyHome)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
|
||||
List<String> pathElements = Arrays.asList(path.split("/"));
|
||||
LinkedList<String> folderElements = new LinkedList<String>(pathElements);
|
||||
|
||||
// Remove empty folder caused by path starting with / .
|
||||
if(folderElements.getFirst().length() == 0)
|
||||
{
|
||||
folderElements.removeFirst();
|
||||
}
|
||||
// Remove 'Company Home' if it is at the start of the path.
|
||||
Serializable companyHomeName = nodeService.getProperty(companyHome, ContentModel.PROP_NAME);
|
||||
if(folderElements.getFirst().equals(companyHomeName))
|
||||
{
|
||||
folderElements.removeFirst();
|
||||
}
|
||||
|
||||
String fileName = folderElements.removeLast();
|
||||
if (fileName == null || fileName.length() == 0)
|
||||
{
|
||||
throw new RenditionServiceException("The path must include a valid filename! Path: " + path);
|
||||
}
|
||||
FileFolderService fileFolderService = serviceRegistry.getFileFolderService();
|
||||
FileInfo parentInfo = FileFolderServiceImpl.makeFolders(fileFolderService,
|
||||
companyHome, folderElements,
|
||||
ContentModel.TYPE_FOLDER);
|
||||
NodeRef parent = parentInfo.getNodeRef();
|
||||
NodeRef child = fileFolderService.searchSimple(parent, fileName);
|
||||
return new RenditionLocationImpl(parent, child, fileName);
|
||||
}
|
||||
|
||||
private String renderPathTemplate(String pathTemplate, NodeRef sourceNode, NodeRef tempRenditionLocation, Serializable companyHomeName)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
NamespaceService namespaceService = serviceRegistry.getNamespaceService();
|
||||
|
||||
final Map<String, Object> root = new HashMap<String, Object>();
|
||||
ChildAssociationRef sourceAssoc = nodeService.getPrimaryParent(sourceNode);
|
||||
String fullSourceName = sourceAssoc.getQName().getLocalName();
|
||||
String trimmedSourceName = fullSourceName;
|
||||
String sourceExtension = "";
|
||||
int extensionIndex = fullSourceName.lastIndexOf('.');
|
||||
if (extensionIndex != -1)
|
||||
{
|
||||
trimmedSourceName = (extensionIndex == 0) ? "" : fullSourceName.substring(0, extensionIndex);
|
||||
sourceExtension = (extensionIndex == fullSourceName.length() - 1) ? "" : fullSourceName
|
||||
.substring(extensionIndex + 1);
|
||||
}
|
||||
|
||||
Path sourcePath = nodeService.getPath(sourceNode);
|
||||
|
||||
StoreRef store = sourceNode.getStoreRef();
|
||||
getCompanyHomeNode( store);
|
||||
|
||||
root.put("name", trimmedSourceName);
|
||||
root.put("extension", sourceExtension);
|
||||
root.put("date", new SimpleDate(new Date(), SimpleDate.DATETIME));
|
||||
root.put("cwd", sourcePath.toPrefixString(namespaceService));
|
||||
root.put("companyHome", companyHomeName);
|
||||
root.put("sourceNode", new TemplateNode(sourceNode, serviceRegistry, null));
|
||||
root.put("sourceContentType", nodeService.getType(sourceNode).getLocalName());
|
||||
root.put("renditionContentType", nodeService.getType(tempRenditionLocation).getLocalName());
|
||||
NodeRef person = serviceRegistry.getPersonService().getPerson(AuthenticationUtil.getFullyAuthenticatedUser());
|
||||
root.put("person", new TemplateNode(person, serviceRegistry, null));
|
||||
|
||||
if (sourceNodeIsXml(sourceNode))
|
||||
{
|
||||
try
|
||||
{
|
||||
Document xml = XMLUtil.parse(sourceNode, serviceRegistry.getContentService());
|
||||
pathTemplate = FreeMarkerUtil.buildNamespaceDeclaration(xml) + pathTemplate;
|
||||
root.put("xml", NodeModel.wrap(xml));
|
||||
} catch (Exception ex)
|
||||
{
|
||||
log.warn("Failed to parse XML content into path template model: Node = " + sourceNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Path template model: " + root);
|
||||
}
|
||||
|
||||
String result = null;
|
||||
try
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Processing " + pathTemplate + " using source node " + sourcePath);
|
||||
}
|
||||
result = serviceRegistry.getTemplateService().processTemplateString("freemarker", pathTemplate,
|
||||
new SimpleHash(root));
|
||||
} catch (TemplateException te)
|
||||
{
|
||||
log.error("Error while trying to process rendition path template: " + pathTemplate);
|
||||
log.error(te.getMessage(), te);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("processed pattern " + pathTemplate + " as " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private NodeRef getCompanyHomeNode(StoreRef store)
|
||||
{
|
||||
SearchService searchService = serviceRegistry.getSearchService();
|
||||
ResultSet result = searchService.query(store, SearchService.LANGUAGE_XPATH, companyHomePath);
|
||||
if(result.length()==0)
|
||||
return null;
|
||||
else
|
||||
return result.getNodeRef(0);
|
||||
}
|
||||
|
||||
protected boolean sourceNodeIsXml(NodeRef sourceNode)
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
// TODO: BJR 20100211: We can do better than this...
|
||||
ContentReader reader = serviceRegistry.getContentService().getReader(sourceNode, ContentModel.PROP_CONTENT);
|
||||
if ((reader != null) && reader.exists())
|
||||
{
|
||||
result = (reader.getContentData().getMimetype().equals("text/xml"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
|
||||
/**
|
||||
* @author Brian Remmington
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class StandardRenditionLocationResolverTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private NodeRef companyHome;
|
||||
private StandardRenditionLocationResolverImpl locationResolver;
|
||||
private RenditionService renditionService;
|
||||
private SearchService searchService;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the required services
|
||||
this.serviceRegistry = (ServiceRegistry) this.getApplicationContext().getBean("ServiceRegistry");
|
||||
this.nodeService=serviceRegistry.getNodeService();
|
||||
this.searchService = serviceRegistry.getSearchService();
|
||||
this.renditionService = (RenditionService) this.getApplicationContext().getBean("RenditionService");
|
||||
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_XPATH,
|
||||
"/app:company_home");
|
||||
if (rs.length() != 1)
|
||||
{
|
||||
fail("Could not find company home");
|
||||
}
|
||||
companyHome = rs.getNodeRef(0);
|
||||
locationResolver = new StandardRenditionLocationResolverImpl();
|
||||
locationResolver.setServiceRegistry(serviceRegistry);
|
||||
}
|
||||
|
||||
public void testChildAssociationFinder()
|
||||
{
|
||||
QName renditionKind = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "test");
|
||||
NodeRef sourceNode = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
NodeRef tempRenditionNode = makeNode(sourceNode, ContentModel.TYPE_CONTENT);
|
||||
|
||||
RenditionDefinition renditionDef = renditionService.createRenditionDefinition(renditionKind,
|
||||
"brians_test_engine");
|
||||
|
||||
RenditionLocation location =
|
||||
locationResolver.getRenditionLocation(sourceNode,renditionDef, tempRenditionNode);
|
||||
|
||||
assertEquals(sourceNode, location.getParentRef());
|
||||
assertNull(location.getChildName());
|
||||
assertNull(location.getChildRef());
|
||||
|
||||
NodeRef targetFolder = makeNode(companyHome, ContentModel.TYPE_FOLDER);
|
||||
String companyHomeName = (String) nodeService.getProperty(companyHome, ContentModel.PROP_NAME);
|
||||
String targetFolderName = (String) nodeService.getProperty(targetFolder, ContentModel.PROP_NAME);
|
||||
String template = "/"+companyHomeName+"/"+targetFolderName+"/brian.xml";
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, template);
|
||||
location = locationResolver.getRenditionLocation(sourceNode, renditionDef, tempRenditionNode);
|
||||
|
||||
assertEquals(targetFolder, location.getParentRef());
|
||||
assertEquals("brian.xml", location.getChildName());
|
||||
assertNull(location.getChildRef());
|
||||
|
||||
template=targetFolderName+"/test-${sourceContentType}.xml";
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, template);
|
||||
location = locationResolver.getRenditionLocation(sourceNode, renditionDef, tempRenditionNode);
|
||||
|
||||
assertEquals(targetFolder, location.getParentRef());
|
||||
assertEquals("test-"+ContentModel.PROP_CONTENT.getLocalName()+".xml", location.getChildName());
|
||||
assertNull(location.getChildRef());
|
||||
|
||||
// Test that when the template path specifies an existing node then that
|
||||
// node is set as the 'childRef' property on the RenditionLocation.
|
||||
NodeRef destinationNode = makeNode(targetFolder, ContentModel.TYPE_CONTENT);
|
||||
String destinationName = (String) nodeService.getProperty(destinationNode, ContentModel.PROP_NAME);
|
||||
template = targetFolderName + "/" + destinationName;
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, template);
|
||||
location = locationResolver.getRenditionLocation(sourceNode, renditionDef, tempRenditionNode);
|
||||
|
||||
assertEquals(targetFolder, location.getParentRef());
|
||||
assertEquals(destinationName, location.getChildName());
|
||||
assertEquals(destinationNode, location.getChildRef());
|
||||
|
||||
// Test that the 'destination node' param takes precedence over them 'template path' param.
|
||||
template = "/" + targetFolderName + "/brian.xml";
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, template);
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_NODE, destinationNode);
|
||||
location = locationResolver.getRenditionLocation(sourceNode, renditionDef, tempRenditionNode);
|
||||
|
||||
assertEquals(targetFolder, location.getParentRef());
|
||||
assertEquals(destinationName, location.getChildName());
|
||||
assertEquals(destinationNode, location.getChildRef());
|
||||
}
|
||||
|
||||
public void testCreatesFoldersForTemplatedLocation() throws Exception
|
||||
{
|
||||
QName fooName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFooFolder");
|
||||
QName barName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testBarFolder");
|
||||
String fooPath = "/testFooFolder";
|
||||
String barPath = fooPath + "/testBarFolder";
|
||||
|
||||
List<ChildAssociationRef> childAssocs = nodeService.getChildAssocs(companyHome, ContentModel.ASSOC_CONTAINS,
|
||||
fooName);
|
||||
assertTrue("Folder " + fooPath + " should not exist!", childAssocs.isEmpty());
|
||||
|
||||
QName renditionKind = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "test");
|
||||
NodeRef sourceNode = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
NodeRef tempRenditionNode = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
|
||||
RenditionDefinition renditionDef = renditionService.createRenditionDefinition(renditionKind,
|
||||
"nicks_test_engine");
|
||||
|
||||
String pathTemplate = barPath + "/nick.xml";
|
||||
renditionDef.setParameterValue(RenditionService.PARAM_DESTINATION_PATH_TEMPLATE, pathTemplate);
|
||||
|
||||
RenditionLocation location =
|
||||
locationResolver.getRenditionLocation(sourceNode,renditionDef, tempRenditionNode);
|
||||
|
||||
NodeRef fooNode = checkFolder(fooName, companyHome, "Foo");
|
||||
NodeRef barNode = checkFolder(barName, fooNode, "Bar");
|
||||
|
||||
assertEquals("Bar is not the rendition parent!", barNode, location.getParentRef());
|
||||
assertEquals("nick.xml", location.getChildName());
|
||||
}
|
||||
|
||||
// public void testOldRenditionIsOrphaned() throws Exception
|
||||
// {
|
||||
// QName renditionKind = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "test");
|
||||
// NodeRef sourceNode = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
// NodeRef tempRenditionNode = makeNode(sourceNode, ContentModel.TYPE_CONTENT);
|
||||
// ChildAssociationRef tempRenditionLocation=nodeService.getPrimaryParent(tempRenditionNode);
|
||||
//
|
||||
// RenditionDefinition definition = renditionService.createRenditionDefinition(renditionKind,
|
||||
// "nicks_test_engine");
|
||||
// ChildAssociationRef oldRendition =
|
||||
// nodeService.createNode(sourceNode, RenditionModel.ASSOC_RENDITION, definition.getRenditionName(), ContentModel.TYPE_CONTENT);
|
||||
// definition.setParameterValue(RenditionService.PARAM_ORPHAN_EXISTING_RENDITION, true);
|
||||
//
|
||||
// //Test deletes old rendition if it's under source Node and new rendition is not.
|
||||
// locationResolver.getRenditionLocation(sourceNode, definition, tempRenditionLocation);
|
||||
//
|
||||
// List<ChildAssociationRef> sourceChildren = nodeService.getChildAssocs(sourceNode);
|
||||
// assertFalse("The old rendition association should ahve been removed!", sourceChildren.contains(oldRendition));
|
||||
// assertFalse("The old rendition should have been deleted!", nodeService.exists(oldRendition.getChildRef()) );
|
||||
// }
|
||||
|
||||
private NodeRef checkFolder(QName folderName, NodeRef parentName, String folderMessageName)
|
||||
{
|
||||
List<ChildAssociationRef> folderAssocs = nodeService.getChildAssocs(parentName, ContentModel.ASSOC_CONTAINS, folderName);
|
||||
assertEquals("Folder " + folderMessageName + " should exist!", 1, folderAssocs.size());
|
||||
NodeRef folderNode = folderAssocs.get(0).getChildRef();
|
||||
assertEquals(folderMessageName+" node is wrong type!", ContentModel.TYPE_FOLDER, nodeService.getType(folderNode));
|
||||
assertEquals(folderMessageName+" node has wrong name!", folderName.getLocalName(),
|
||||
nodeService.getProperty(folderNode, ContentModel.PROP_NAME));
|
||||
return folderNode;
|
||||
}
|
||||
|
||||
private NodeRef makeNode(NodeRef parent, QName nodeType)
|
||||
{
|
||||
String uuid = GUID.generate();
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, uuid);
|
||||
ChildAssociationRef assoc = nodeService.createNode(parent, ContentModel.ASSOC_CONTAINS, QName.createQName(
|
||||
NamespaceService.APP_MODEL_1_0_URI, uuid), nodeType, props);
|
||||
return assoc.getChildRef();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import static org.alfresco.service.cmr.rendition.RenditionService.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.rendition.RenderingEngineDefinitionImpl;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* This class adds some new behaviour to the standard ActionExecuterAbstractBase
|
||||
* in order to support the RenditionService.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @author Nick Smith
|
||||
* @since 3.3
|
||||
*/
|
||||
public abstract class AbstractRenderingEngine extends ActionExecuterAbstractBase
|
||||
{
|
||||
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(AbstractRenderingEngine.class);
|
||||
|
||||
protected static final String CONTENT_READER_NOT_FOUND_MESSAGE = "Cannot find Content Reader for document. Operation can't be performed";
|
||||
|
||||
// A word on the default* fields below:
|
||||
//
|
||||
// RenditionExecuters can be executed with or without two optional
|
||||
// parameters: "rendition node type"
|
||||
// and a "rendition content property" parameter.
|
||||
// These parameters can be specified on a per-action basis.
|
||||
// If no value is specified, then the default is used.
|
||||
// That default can be injected via Spring.
|
||||
// If no default is injected via spring, then there is a "default default"
|
||||
// for the two params
|
||||
|
||||
/**
|
||||
* This is the default default node type for renditions - used if no value
|
||||
* is injected from spring.
|
||||
*/
|
||||
private static final QName DEFAULT_DEFAULT_RENDITION_NODE_TYPE = ContentModel.TYPE_CONTENT;
|
||||
|
||||
/**
|
||||
* This is the default default property used to specify where rendition
|
||||
* content is stored - used if no value is injected from spring.
|
||||
*/
|
||||
private static final QName DEFAULT_DEFAULT_RENDITION_CONTENT_PROP = ContentModel.PROP_CONTENT;
|
||||
|
||||
private static final String DEFAULT_MIMETYPE = MimetypeMap.MIMETYPE_TEXT_PLAIN;
|
||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
/**
|
||||
* This is the default node type that is used when creating rendition
|
||||
* objects.
|
||||
*/
|
||||
private QName defaultRenditionNodeType = DEFAULT_DEFAULT_RENDITION_NODE_TYPE;
|
||||
|
||||
/**
|
||||
* This is the default property that is used to store rendition objects'
|
||||
* content.
|
||||
*/
|
||||
private QName defaultRenditionContentProp = DEFAULT_DEFAULT_RENDITION_CONTENT_PROP;
|
||||
|
||||
/**
|
||||
* This is the default content property.
|
||||
*/
|
||||
private static final QName DEFAULT_CONTENT_PROPERTY = ContentModel.TYPE_CONTENT;
|
||||
|
||||
/* Injected Services */
|
||||
protected ContentService contentService;
|
||||
protected MimetypeMap mimetypeMap;
|
||||
protected NodeService nodeService;
|
||||
|
||||
/* Parameter names common to all Rendering Actions */
|
||||
//TODO javadoc these
|
||||
public static final String PARAM_PLACEHOLDER_RESOURCE_PATH = "placeHolderResourcePath";
|
||||
public static final String PARAM_SOURCE_CONTENT_PROPERTY = "sourceContentProperty";
|
||||
public static final String PARAM_TARGET_CONTENT_PROPERTY = "targetContentProperty";
|
||||
public static final String PARAM_UPDATE_RENDITIONS_ON_ANY_PROPERTY_CHANGE = "update-renditions-on-any-property-change";
|
||||
public static final String PARAM_RUN_AS = "runAs";
|
||||
|
||||
/*
|
||||
* mime-type is not a common parameter on all Rendering Actions, but it is
|
||||
* common to many and is used in some common handling code in this class.
|
||||
*/
|
||||
public static final String PARAM_MIME_TYPE = "mime-type";
|
||||
public static final String PARAM_ENCODING = "encoding";
|
||||
|
||||
/**
|
||||
* Sets the default rendition-node type.
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
public void setDefaultRenditionNodeType(String type)
|
||||
{
|
||||
QName qname;
|
||||
try
|
||||
{
|
||||
qname = QName.createQName(type);
|
||||
}
|
||||
catch (NamespaceException nx)
|
||||
{
|
||||
if (logger.isErrorEnabled())
|
||||
{
|
||||
logger.error("Error when setting default rendition node type: ", nx);
|
||||
}
|
||||
throw nx;
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("Using default rendition node type: " + qname);
|
||||
}
|
||||
this.defaultRenditionNodeType = qname;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the type of the default rendition node type.
|
||||
*
|
||||
* @return the QName representing the type of the default rendition node
|
||||
* type.
|
||||
*/
|
||||
protected QName getDefaultRenditionNodeType()
|
||||
{
|
||||
return defaultRenditionNodeType;
|
||||
}
|
||||
|
||||
protected String getTargetMimeType(RenderingContext context)
|
||||
{
|
||||
return context.getParamWithDefault(PARAM_MIME_TYPE, DEFAULT_MIMETYPE);
|
||||
}
|
||||
|
||||
protected String getTargetEncoding(RenderingContext context)
|
||||
{
|
||||
return context.getParamWithDefault(PARAM_ENCODING, DEFAULT_ENCODING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default rendition content property.
|
||||
*
|
||||
* @param prop
|
||||
*/
|
||||
public void setDefaultRenditionContentProp(String prop)
|
||||
{
|
||||
QName qname;
|
||||
try
|
||||
{
|
||||
qname = QName.createQName(prop);
|
||||
}
|
||||
catch (NamespaceException nx)
|
||||
{
|
||||
if (logger.isErrorEnabled())
|
||||
{
|
||||
logger.error("Error when setting default rendition content property: ", nx);
|
||||
}
|
||||
throw nx;
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("Using default rendition content property: " + qname);
|
||||
}
|
||||
this.defaultRenditionContentProp = qname;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the QName of the property that defines the location
|
||||
* of the rendition content. An example would be cm:content.
|
||||
*
|
||||
* @return the QName the property defining the location of the rendition
|
||||
* content.
|
||||
*/
|
||||
protected QName getDefaultRenditionContentProp()
|
||||
{
|
||||
return defaultRenditionContentProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content service
|
||||
*
|
||||
* @param contentService the content service
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the nodeService.
|
||||
*
|
||||
* @param nodeService the namespaceService
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setMimetypeMap(MimetypeMap mimetypeMap)
|
||||
{
|
||||
this.mimetypeMap = mimetypeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionDefinition createActionDefinition(String definitionName)
|
||||
{
|
||||
return new RenderingEngineDefinitionImpl(definitionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef sourceNode)
|
||||
{
|
||||
checkParameterValues(action);
|
||||
checkActionIsRenditionDefinition(action);
|
||||
checkSourceNodeExists(sourceNode);
|
||||
RenditionDefinition renditionDefinition = (RenditionDefinition) action;
|
||||
|
||||
ChildAssociationRef renditionAssoc = createRenditionNodeAssoc(sourceNode, renditionDefinition);
|
||||
QName targetContentProp = getRenditionContentProperty(renditionDefinition);
|
||||
NodeRef destinationNode = renditionAssoc.getChildRef();
|
||||
RenderingContext context = new RenderingContext(sourceNode,//
|
||||
destinationNode,//
|
||||
renditionDefinition,//
|
||||
targetContentProp);
|
||||
render(context);
|
||||
// This is a workaround for the fact that actions don't have return
|
||||
// values.
|
||||
action.getParameterValues().put(PARAM_RESULT, renditionAssoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be overridden by subclasses to provide checking of parameter
|
||||
* values.
|
||||
* If a parameter value is illegal or inappropriate, an exception
|
||||
* should be thrown.
|
||||
*/
|
||||
protected void checkParameterValues(Action action)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renditionDefinition
|
||||
* @return
|
||||
*/
|
||||
protected QName getRenditionContentProperty(RenditionDefinition renditionDefinition)
|
||||
{
|
||||
return getParamWithDefault(PARAM_TARGET_CONTENT_PROPERTY, defaultRenditionContentProp, renditionDefinition);
|
||||
}
|
||||
|
||||
protected abstract void render(RenderingContext context);
|
||||
|
||||
/**
|
||||
* @param actionedUponNodeRef
|
||||
*/
|
||||
protected void checkSourceNodeExists(NodeRef actionedUponNodeRef)
|
||||
{
|
||||
if (nodeService.exists(actionedUponNodeRef) == false)
|
||||
{
|
||||
String msg = "Cannot execute action as node does not exist: " + actionedUponNodeRef;
|
||||
logger.warn(msg);
|
||||
throw new RenditionServiceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action
|
||||
*/
|
||||
protected void checkActionIsRenditionDefinition(Action action)
|
||||
{
|
||||
if (action instanceof RenditionDefinition == false)
|
||||
{
|
||||
String msg = "Cannot execute action as it is not a RenditionDefinition: " + action;
|
||||
logger.warn(msg);
|
||||
throw new RenditionServiceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If no rendition node type is specified, then the default is used
|
||||
*
|
||||
* @param renditionDefinition
|
||||
* @return
|
||||
*/
|
||||
public QName getRenditionNodeType(RenditionDefinition renditionDefinition)
|
||||
{
|
||||
return getParamWithDefault(PARAM_RENDITION_NODETYPE, defaultRenditionNodeType, renditionDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
final protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
paramList.addAll(getParameterDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplies the list of parameters required by this rendering engine.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Collection<ParameterDefinition> getParameterDefinitions()
|
||||
{
|
||||
List<ParameterDefinition> paramList = new ArrayList<ParameterDefinition>();
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RUN_AS, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_RUN_AS)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_UPDATE_RENDITIONS_ON_ANY_PROPERTY_CHANGE, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_UPDATE_RENDITIONS_ON_ANY_PROPERTY_CHANGE)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RENDITION_NODETYPE, DataTypeDefinition.QNAME, false,
|
||||
getParamDisplayLabel(PARAM_RENDITION_NODETYPE)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_PLACEHOLDER_RESOURCE_PATH, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_PLACEHOLDER_RESOURCE_PATH)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_SOURCE_CONTENT_PROPERTY, DataTypeDefinition.QNAME, false,
|
||||
getParamDisplayLabel(PARAM_SOURCE_CONTENT_PROPERTY)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_TARGET_CONTENT_PROPERTY, DataTypeDefinition.QNAME, false,
|
||||
getParamDisplayLabel(PARAM_TARGET_CONTENT_PROPERTY)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_DESTINATION_PATH_TEMPLATE, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_DESTINATION_PATH_TEMPLATE)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_ORPHAN_EXISTING_RENDITION, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_ORPHAN_EXISTING_RENDITION)));
|
||||
return paramList;
|
||||
}
|
||||
|
||||
private ChildAssociationRef createRenditionNodeAssoc(NodeRef sourceNode, RenditionDefinition renditionDefinition)
|
||||
{
|
||||
QName renditionName = renditionDefinition.getRenditionName();
|
||||
|
||||
// The ThumbnailService puts a cm:name property on its thumbnail nodes.
|
||||
Map<QName, Serializable> nodeProps = new HashMap<QName, Serializable>();
|
||||
nodeProps.put(ContentModel.PROP_NAME, renditionName.getLocalName());
|
||||
nodeProps.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, getDefaultRenditionContentProp());
|
||||
QName assocName = QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, GUID.generate());
|
||||
NodeRef parentNode = renditionDefinition.getRenditionParent();
|
||||
QName assocType = renditionDefinition.getRenditionAssociationType();
|
||||
QName nodeType = getRenditionNodeType(renditionDefinition);
|
||||
ChildAssociationRef childAssoc = nodeService.createNode(parentNode, assocType, assocName, nodeType, nodeProps);
|
||||
return childAssoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for the named parameter. Checks the type of the parameter
|
||||
* is correct and throws a {@link RenditionServiceException} if it isn't.
|
||||
* Returns <code>null</code> if the parameter value is <code>null</code>
|
||||
*
|
||||
* @param paramName the name of the parameter being checked.
|
||||
* @param clazz the expected {@link Class} of the parameter value.
|
||||
* @param definition the {@link RenditionDefinition} containing the
|
||||
* parameters.
|
||||
* @return the parameter value or <code>null</code>.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getCheckedParam(String paramName, Class<T> clazz, RenditionDefinition definition)
|
||||
{
|
||||
Serializable value = definition.getParameterValue(paramName);
|
||||
if (value == null)
|
||||
return null;
|
||||
else
|
||||
{
|
||||
Class<? extends Serializable> valueClass = value.getClass();
|
||||
if (!valueClass.isAssignableFrom(clazz))
|
||||
{
|
||||
throw new RenditionServiceException("The parameter: " + paramName + " must be of type: "
|
||||
+ clazz.getName() + "but was of type: " + valueClass.getName());
|
||||
}
|
||||
else
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for the named parameter. Checks the type of the parameter
|
||||
* is the same as the type of <code>defaultValue</code> and throws a
|
||||
* {@link RenditionServiceException} if it isn't. Returns
|
||||
* <code>defaultValue</code> if the parameter value is <code>null</code>
|
||||
*
|
||||
* @param <T>
|
||||
* @param paramName
|
||||
* @param defaultValue
|
||||
* @param definition
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getParamWithDefault(String paramName, T defaultValue, RenditionDefinition definition)
|
||||
{
|
||||
Class<? extends T> clazz = (Class<? extends T>) defaultValue.getClass();
|
||||
T result = getCheckedParam(paramName, clazz, definition);
|
||||
if (result == null)
|
||||
result = defaultValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected class RenderingContext
|
||||
{
|
||||
private final NodeRef sourceNode;
|
||||
private final NodeRef destinationNode;
|
||||
private final RenditionDefinition definition;
|
||||
private final QName renditionContentProperty;
|
||||
|
||||
/**
|
||||
* @param sourceNode
|
||||
* @param destinationNode
|
||||
* @param definition
|
||||
* @param renditionContentProperty
|
||||
*/
|
||||
public RenderingContext(NodeRef sourceNode,//
|
||||
NodeRef destinationNode,//
|
||||
RenditionDefinition definition,//
|
||||
QName renditionContentProperty)
|
||||
{
|
||||
this.sourceNode = sourceNode;
|
||||
this.destinationNode = destinationNode;
|
||||
this.definition = definition;
|
||||
this.renditionContentProperty = renditionContentProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sourceNode
|
||||
*/
|
||||
public NodeRef getSourceNode()
|
||||
{
|
||||
return this.sourceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destinationNode
|
||||
*/
|
||||
public NodeRef getDestinationNode()
|
||||
{
|
||||
return this.destinationNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition
|
||||
*/
|
||||
public RenditionDefinition getDefinition()
|
||||
{
|
||||
return this.definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for the named parameter from the . Checks the type of
|
||||
* the parameter is correct and throws and Exception if it isn't.
|
||||
* Returns <code>null</code> if the parameter value is <code>null</code>
|
||||
*
|
||||
* @param paramName the name of the parameter being checked.
|
||||
* @param clazz the expected {@link Class} of the parameter value.
|
||||
* @return the parameter value or <code>null</code>.
|
||||
*/
|
||||
public <T> T getCheckedParam(String paramName, Class<T> clazz)
|
||||
{
|
||||
return AbstractRenderingEngine.getCheckedParam(paramName, clazz, definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for the named parameter. Checks the type of the
|
||||
* parameter is the same as the type of <code>defaultValue</code> and
|
||||
* throws a {@link RenditionServiceException} if it isn't. Returns
|
||||
* <code>defaultValue</code> if the parameter value is <code>null</code>
|
||||
*
|
||||
* @param <T>
|
||||
* @param paramName
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public <T> T getParamWithDefault(String paramName, T defaultValue)
|
||||
{
|
||||
return AbstractRenderingEngine.getParamWithDefault(paramName, defaultValue, definition);
|
||||
}
|
||||
|
||||
public ContentReader makeContentReader()
|
||||
{
|
||||
QName srcContentProp = getParamWithDefault(PARAM_SOURCE_CONTENT_PROPERTY, DEFAULT_CONTENT_PROPERTY);
|
||||
ContentReader contentReader = contentService.getReader(sourceNode, srcContentProp);
|
||||
if (contentReader == null || !contentReader.exists())
|
||||
{
|
||||
throw new RenditionServiceException(CONTENT_READER_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
return contentReader;
|
||||
}
|
||||
|
||||
public ContentWriter makeContentWriter()
|
||||
{
|
||||
ContentWriter contentWriter = contentService.getWriter(destinationNode, renditionContentProperty, true);
|
||||
String mimetype = getTargetMimeType(this);
|
||||
contentWriter.setMimetype(mimetype);
|
||||
String encoding = getTargetEncoding(this);
|
||||
contentWriter.setEncoding(encoding);
|
||||
return contentWriter;
|
||||
}
|
||||
|
||||
public int getIntegerParam(String key, int defaultValue)
|
||||
{
|
||||
Serializable serializable = definition.getParameterValue(key);
|
||||
if (serializable == null)
|
||||
return defaultValue;
|
||||
else
|
||||
{
|
||||
Number number = (Number) serializable;
|
||||
return number.intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NoTransformerException;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public abstract class AbstractTransformationRenderingEngine extends AbstractRenderingEngine
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(AbstractTransformationRenderingEngine.class);
|
||||
|
||||
/* Error messages */
|
||||
private static final String TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN = "Transformer for '%s' source mime type and '%s' target mime type was not found. Operation can't be performed";
|
||||
private static final String NOT_TRANSFORMABLE_MESSAGE_PATTERN = "Content not transformable for '%s' source mime type and '%s' target mime type. Operation can't be performed";
|
||||
private static final String TRANSFORMING_ERROR_MESSAGE = "Some error occurred during document transforming. Error message: ";
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org.alfresco.repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
|
||||
*/
|
||||
@Override
|
||||
protected void render(RenderingContext context)
|
||||
{
|
||||
ContentReader contentReader = context.makeContentReader();
|
||||
String sourceMimeType = contentReader.getMimetype();
|
||||
String targetMimeType = getTargetMimeType(context);
|
||||
|
||||
TransformationOptions options = getTransformOptions(context);
|
||||
|
||||
ContentTransformer transformer = this.contentService.getTransformer(sourceMimeType, targetMimeType, options);
|
||||
|
||||
// Actually perform the rendition.
|
||||
if (null == transformer)
|
||||
{
|
||||
throw new RenditionServiceException(String.format(TRANSFORMER_NOT_EXISTS_MESSAGE_PATTERN, sourceMimeType,
|
||||
targetMimeType));
|
||||
}
|
||||
|
||||
if (transformer.isTransformable(sourceMimeType, targetMimeType, options))
|
||||
{
|
||||
ContentWriter contentWriter = context.makeContentWriter();
|
||||
try
|
||||
{
|
||||
contentService.transform(contentReader, contentWriter, options);
|
||||
}
|
||||
catch (NoTransformerException ntx)
|
||||
{
|
||||
{
|
||||
logger.debug("No transformer found to execute rule: \n" + " reader: " + contentReader + "\n"
|
||||
+ " writer: " + contentWriter + "\n" + " action: " + this);
|
||||
}
|
||||
throw new RenditionServiceException(TRANSFORMING_ERROR_MESSAGE + ntx.getMessage(), ntx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RenditionServiceException(String.format(NOT_TRANSFORMABLE_MESSAGE_PATTERN, sourceMimeType, targetMimeType));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract TransformationOptions getTransformOptions(RenderingContext context);
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.rendition.CompositeRenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This RenderingEngine is used for rendering
|
||||
* {@link CompositeRenditionDefinition}s, which specify a list of
|
||||
* {@link RenditionDefinition}s. The {@link CompositeRenderingEngine} iterates
|
||||
* over the {@link RenditionDefinition}s sequentially and feeds the output of
|
||||
* one definition in as the input of the next definition. The output of the last
|
||||
* definition executed is the output of this rendering engine.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class CompositeRenderingEngine extends AbstractRenderingEngine
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(CompositeRenderingEngine.class);
|
||||
|
||||
public static final String NAME = "compositeRenderingEngine";
|
||||
|
||||
private ActionService actionService;
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.repo.rendition.executer.AbstractRenderingEngine#executeImpl
|
||||
* (org.alfresco.service.cmr.action.Action,
|
||||
* org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef sourceNode)
|
||||
{
|
||||
checkSourceNodeExists(sourceNode);
|
||||
if (action instanceof CompositeRenditionDefinition)
|
||||
{
|
||||
CompositeRenditionDefinition compositeDefinition = (CompositeRenditionDefinition) action;
|
||||
ChildAssociationRef renditionAssoc = executeCompositeRendition(compositeDefinition, sourceNode);
|
||||
|
||||
// Setting result.
|
||||
compositeDefinition.setParameterValue(PARAM_RESULT, renditionAssoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
String msg = "This method requires that the RenditionDefinition be of type CompositeRenditionDefinition";
|
||||
logger.warn(msg);
|
||||
throw new RenditionServiceException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private ChildAssociationRef executeCompositeRendition(CompositeRenditionDefinition definition, NodeRef sourceNode)
|
||||
{
|
||||
NodeRef source = sourceNode;
|
||||
ChildAssociationRef result = null;
|
||||
QName assocType = definition.getRenditionAssociationType();
|
||||
NodeRef parent = definition.getRenditionParent();
|
||||
for (RenditionDefinition subDefinition : definition.getActions())
|
||||
{
|
||||
ChildAssociationRef newResult = executeSubDefinition(source, subDefinition, parent, assocType);
|
||||
if (result != null)
|
||||
{
|
||||
// Clean up temporary renditions.
|
||||
nodeService.removeChild(parent, result.getChildRef());
|
||||
}
|
||||
result = newResult;
|
||||
source = newResult.getChildRef();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ChildAssociationRef executeSubDefinition(NodeRef source,//
|
||||
RenditionDefinition subDefinition,//
|
||||
NodeRef parent,//
|
||||
QName assocType)
|
||||
{
|
||||
subDefinition.setRenditionParent(parent);
|
||||
subDefinition.setRenditionAssociationType(assocType);
|
||||
actionService.executeAction(subDefinition, source);
|
||||
ChildAssociationRef newResult = (ChildAssociationRef) subDefinition.getParameterValue(PARAM_RESULT);
|
||||
return newResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org
|
||||
* .alfresco
|
||||
* .repo.rendition.executer.AbstractRenderingEngine.RenderingContext)
|
||||
*/
|
||||
@Override
|
||||
protected void render(RenderingContext data)
|
||||
{
|
||||
throw new RenditionServiceException("This method should never be caleld!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param actionService the actionService to set
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.content.transform.magick.ImageCropOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
|
||||
/**
|
||||
* This class is the implementation of the {@link RenditionService}'s
|
||||
* "imageRenderingEngine" rendering engine. This action renders a piece of
|
||||
* content in the same MIME type as its source node, having been rescaled as
|
||||
* requested.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class ImageRenderingEngine extends AbstractTransformationRenderingEngine
|
||||
{
|
||||
// TODO This rendering engine should only take input of MIME type image/*
|
||||
// However, we'll defer the addition of an EngineInputFilter until after
|
||||
// Sprint 3.
|
||||
|
||||
public static final String NAME = "imageRenderingEngine";
|
||||
|
||||
// Resize params
|
||||
public static final String PARAM_RESIZE_WIDTH = "xsize";
|
||||
public static final String PARAM_RESIZE_HEIGHT = "ysize";
|
||||
public static final String PARAM_IS_PERCENT_RESIZE = "isAbsolute";
|
||||
public static final String PARAM_MAINTAIN_ASPECT_RATIO = "maintainAspectRatio";
|
||||
public static final String PARAM_RESIZE_TO_THUMBNAIL = "resizeToThumbnail";
|
||||
|
||||
// Crop params
|
||||
public static final String PARAM_CROP_WIDTH = "crop_width";
|
||||
public static final String PARAM_CROP_HEIGHT = "crop_height";
|
||||
public static final String PARAM_CROP_X_OFFSET = "crop_x";
|
||||
public static final String PARAM_CROP_Y_OFFSET = "crop_y";
|
||||
public static final String PARAM_CROP_GRAVITY = "crop_gravity";
|
||||
public static final String PARAM_IS_PERCENT_CROP = "percent_crop";
|
||||
|
||||
public static final String PARAM_COMMAND_OPTIONS = "commandOptions";
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.repo.rendition.executer.ReformatRenderingEngine#
|
||||
* getTransformOptions
|
||||
* (org.alfresco.repo.rendition.executer.AbstractRenderingEngine
|
||||
* .RenderingContext)
|
||||
*/
|
||||
@Override
|
||||
protected TransformationOptions getTransformOptions(RenderingContext context)
|
||||
{
|
||||
String commandOptions = context.getCheckedParam(PARAM_COMMAND_OPTIONS, String.class);
|
||||
ImageResizeOptions imageResizeOptions = getImageResizeOptions(context);
|
||||
ImageCropOptions cropOptions = getImageCropOptions(context);
|
||||
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
imageTransformationOptions.setCropOptions(cropOptions);
|
||||
if (commandOptions != null)
|
||||
{
|
||||
imageTransformationOptions.setCommandOptions(commandOptions);
|
||||
}
|
||||
return imageTransformationOptions;
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.repo.rendition.executer.ReformatRenderingEngine#
|
||||
* getTargetMimeType
|
||||
* (org.alfresco.repo.rendition.executer.AbstractRenderingEngine
|
||||
* .RenderingContext)
|
||||
*/
|
||||
@Override
|
||||
protected String getTargetMimeType(RenderingContext context)
|
||||
{
|
||||
String sourceMimeType = context.makeContentReader().getMimetype();
|
||||
return context.getParamWithDefault(PARAM_MIME_TYPE, sourceMimeType);
|
||||
}
|
||||
|
||||
private ImageResizeOptions getImageResizeOptions(RenderingContext context)
|
||||
{
|
||||
int newHeight = context.getIntegerParam(PARAM_RESIZE_WIDTH, -1);
|
||||
int newWidth = context.getIntegerParam(PARAM_RESIZE_HEIGHT, -1);
|
||||
if (newHeight == -1 && newWidth == -1)
|
||||
{
|
||||
return null; // Image is not being resized!
|
||||
}
|
||||
boolean isPercentResize = context.getParamWithDefault(PARAM_IS_PERCENT_RESIZE, false);
|
||||
boolean maintainAspectRatio = context.getParamWithDefault(PARAM_MAINTAIN_ASPECT_RATIO, false);
|
||||
|
||||
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
|
||||
imageResizeOptions.setMaintainAspectRatio(maintainAspectRatio);
|
||||
imageResizeOptions.setWidth(newHeight);
|
||||
imageResizeOptions.setHeight(newWidth);
|
||||
imageResizeOptions.setPercentResize(isPercentResize);
|
||||
return imageResizeOptions;
|
||||
}
|
||||
|
||||
private ImageCropOptions getImageCropOptions(RenderingContext context)
|
||||
{
|
||||
int newWidth = context.getIntegerParam(PARAM_CROP_WIDTH, -1);
|
||||
int newHeight = context.getIntegerParam(PARAM_CROP_HEIGHT, -1);
|
||||
if (newHeight == -1 && newWidth == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int xOffset = context.getIntegerParam(PARAM_CROP_X_OFFSET, 0);
|
||||
int yOffset = context.getIntegerParam(PARAM_CROP_Y_OFFSET, 0);
|
||||
|
||||
boolean isPercentCrop = context.getParamWithDefault(PARAM_IS_PERCENT_CROP, false);
|
||||
String gravity = context.getCheckedParam(PARAM_CROP_GRAVITY, String.class);
|
||||
|
||||
ImageCropOptions cropOptions = new ImageCropOptions();
|
||||
cropOptions.setGravity(gravity);
|
||||
cropOptions.setHeight(newHeight);
|
||||
cropOptions.setPercentageCrop(isPercentCrop);
|
||||
cropOptions.setWidth(newWidth);
|
||||
cropOptions.setXOffset(xOffset);
|
||||
cropOptions.setYOffset(yOffset);
|
||||
return cropOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkParameterValues(Action action)
|
||||
{
|
||||
// Some numerical parameters should not be zero or negative.
|
||||
checkNumericalParameterIsPositive(action, PARAM_RESIZE_WIDTH);
|
||||
checkNumericalParameterIsPositive(action, PARAM_RESIZE_HEIGHT);
|
||||
checkNumericalParameterIsPositive(action, PARAM_CROP_HEIGHT);
|
||||
checkNumericalParameterIsPositive(action, PARAM_CROP_WIDTH);
|
||||
|
||||
// Target mime type should only be an image MIME type
|
||||
String mimeTypeParam = (String)action.getParameterValue(PARAM_MIME_TYPE);
|
||||
if (mimeTypeParam != null && !mimeTypeParam.startsWith("image"))
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Parameter ").append(PARAM_MIME_TYPE)
|
||||
.append(" had illegal non-image MIME type: ").append(mimeTypeParam);
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks that if the specified parameter is non-null, that it has a
|
||||
* positive numerical value. That is it is non-zero and positive.
|
||||
*
|
||||
* @param action
|
||||
* @param numericalParamName must be an instance of java.lang.Number or null.
|
||||
*/
|
||||
private void checkNumericalParameterIsPositive(Action action, String numericalParamName)
|
||||
{
|
||||
Number param = (Number)action.getParameterValue(numericalParamName);
|
||||
if (param != null && param.longValue() <= 0)
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Parameter ").append(numericalParamName)
|
||||
.append(" had illegal non-positive value: ").append(param.intValue());
|
||||
throw new IllegalArgumentException(msg.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.repo.rendition.executer.AbstractRenderingEngine#
|
||||
* getParameterDefinitions()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<ParameterDefinition> getParameterDefinitions()
|
||||
{
|
||||
Collection<ParameterDefinition> paramList = super.getParameterDefinitions();
|
||||
|
||||
//Resize Params
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RESIZE_WIDTH, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_RESIZE_WIDTH)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RESIZE_HEIGHT, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_RESIZE_HEIGHT)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_IS_PERCENT_RESIZE, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_IS_PERCENT_RESIZE)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_MAINTAIN_ASPECT_RATIO, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_MAINTAIN_ASPECT_RATIO)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_RESIZE_TO_THUMBNAIL, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_RESIZE_TO_THUMBNAIL)));
|
||||
|
||||
//Crop Params
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CROP_GRAVITY, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_CROP_GRAVITY)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CROP_HEIGHT, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_CROP_HEIGHT)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CROP_WIDTH, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_CROP_WIDTH)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CROP_X_OFFSET, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_CROP_X_OFFSET)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CROP_Y_OFFSET, DataTypeDefinition.INT, false,
|
||||
getParamDisplayLabel(PARAM_CROP_Y_OFFSET)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_IS_PERCENT_CROP, DataTypeDefinition.BOOLEAN, false,
|
||||
getParamDisplayLabel(PARAM_IS_PERCENT_CROP)));
|
||||
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_COMMAND_OPTIONS, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_COMMAND_OPTIONS)));
|
||||
return paramList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* This class is the implementation of the {@link RenditionService}'s "reformat"
|
||||
* action/rendering. This action renders a piece of content in the specified
|
||||
* target MIME type. This is achieved using one of the standard transformers
|
||||
* within the {@link ContentService}.
|
||||
* <P/>
|
||||
* Reformatting in this way is a simple conversion of one MIME type to another
|
||||
* MIME type, without any other changes to the content. Therefore there is no
|
||||
* support within this action for altering the content e.g. image
|
||||
* cropping/resizing.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @since 3.3
|
||||
*/
|
||||
public class ReformatRenderingEngine extends AbstractTransformationRenderingEngine
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ReformatRenderingEngine.class);
|
||||
|
||||
/**
|
||||
* This parameter is only necessary when converting from pdf to flash.
|
||||
*/
|
||||
public static final String PARAM_FLASH_VERSION = "flashVersion";
|
||||
|
||||
/*
|
||||
* Action constants
|
||||
*/
|
||||
public static final String NAME = "reformat";
|
||||
|
||||
@Override
|
||||
protected String getTargetMimeType(RenderingContext context)
|
||||
{
|
||||
String targetMimeType = context.getCheckedParam(PARAM_MIME_TYPE, String.class);
|
||||
if (targetMimeType == null)
|
||||
{
|
||||
String msg = "The parameter: " + PARAM_MIME_TYPE + " must be explicitly set for this rendering engine!";
|
||||
logger.warn(msg);
|
||||
throw new RenditionServiceException(msg);
|
||||
}
|
||||
return targetMimeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransformationOptions getTransformOptions(RenderingContext context)
|
||||
{
|
||||
NodeRef sourceNode = context.getSourceNode();
|
||||
NodeRef destinationNode = context.getDestinationNode();
|
||||
return new TransformationOptions(sourceNode, null, destinationNode, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.alfresco.repo.rendition.executer.AbstractRenderingEngine#
|
||||
* getParameterDefinitions()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<ParameterDefinition> getParameterDefinitions()
|
||||
{
|
||||
Collection<ParameterDefinition> paramList = super.getParameterDefinitions();
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_MIME_TYPE, DataTypeDefinition.TEXT, true,
|
||||
getParamDisplayLabel(PARAM_MIME_TYPE)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_FLASH_VERSION, DataTypeDefinition.TEXT, false,
|
||||
getParamDisplayLabel(PARAM_FLASH_VERSION)));
|
||||
return paramList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.TemplateImageResolver;
|
||||
import org.alfresco.service.cmr.repository.TemplateService;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class TemplateModelHelper
|
||||
{
|
||||
public static final String KEY_NODE = "node";
|
||||
|
||||
private final Repository repository;
|
||||
private final ServiceRegistry serviceRegistry;
|
||||
private final TemplateService templateService;
|
||||
|
||||
/**
|
||||
* @param templateService
|
||||
* @param repository
|
||||
* @param serviceRegistry
|
||||
*/
|
||||
public TemplateModelHelper(TemplateService templateService, Repository repository, ServiceRegistry serviceRegistry)
|
||||
{
|
||||
super();
|
||||
this.templateService = templateService;
|
||||
this.repository = repository;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up the model map used by the {@link TemplateService} to process
|
||||
* FreeMarker templates.
|
||||
*
|
||||
* @param sourceNode the node containing the content to be processed by the
|
||||
* template.
|
||||
* @param templateNode the node containing the template. Can be
|
||||
* <code>null</code>.
|
||||
* @param imgResolver the image resolver used to process images. Can be
|
||||
* <code>null</code>.
|
||||
* @param paramMap a map of parameters to add to the model. Can be
|
||||
* <code>null</code>.
|
||||
* @return the populated model {@link Map}.
|
||||
*/
|
||||
public Map<String, Object> buildModelMap(NodeRef sourceNode,//
|
||||
NodeRef templateNode,//
|
||||
TemplateImageResolver imgResolver,//
|
||||
Map<String, Serializable> paramMap)
|
||||
{
|
||||
Map<String, Object> model = buildDefaultModel(templateNode, imgResolver);
|
||||
TemplateNode sourceTemplateNode = new TemplateNode(sourceNode, serviceRegistry, null);
|
||||
// TODO Add xml dom here.
|
||||
// model.put("xml", NodeModel.wrap(null));
|
||||
model.put(KEY_NODE, sourceTemplateNode);
|
||||
if (paramMap != null)
|
||||
model.putAll(paramMap);
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the default model populated with the current user, company home
|
||||
* and user home.
|
||||
*
|
||||
* @param templateNode the node containing the template. Can be
|
||||
* <code>null</code>.
|
||||
* @param imgResolver the image resolver used to process images. Can be
|
||||
* <code>null</code>.
|
||||
* @return the default model {@link Map}.
|
||||
*/
|
||||
public Map<String, Object> buildDefaultModel(NodeRef templateNode, TemplateImageResolver imgResolver)
|
||||
{
|
||||
// The templateNode can be null.
|
||||
NodeRef companyHome = repository.getCompanyHome();
|
||||
|
||||
// The fully authenticated user below is the username of the person who logged in and
|
||||
// who requested the execution of the current rendition. This will not be the
|
||||
// same person as the current user as renditions are executed by the system user.
|
||||
String fullyAuthenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
NodeRef person = serviceRegistry.getPersonService().getPerson(fullyAuthenticatedUser);
|
||||
|
||||
NodeRef userHome = repository.getUserHome(person);
|
||||
Map<String, Object> model = templateService.buildDefaultModel(person, companyHome, userHome, templateNode,
|
||||
imgResolver);
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.rendition.executer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.TemplateImageResolver;
|
||||
import org.alfresco.service.cmr.repository.TemplateService;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class TemplatingRenderingEngine//
|
||||
extends AbstractRenderingEngine//
|
||||
implements InitializingBean
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(TemplatingRenderingEngine.class);
|
||||
|
||||
public static final String NAME = "templatingRenderingEngine";
|
||||
public static final String PARAM_MODEL = "model";
|
||||
public static final String PARAM_TEMPLATE = "template_string";
|
||||
public static final String PARAM_TEMPLATE_NODE = "template_node";
|
||||
public static final String PARAM_TEMPLATE_PATH = "template_path";
|
||||
private static final String PARAM_IMAGE_RESOLVER = "image_resolver";
|
||||
|
||||
private TemplateService templateService;
|
||||
private Repository repository;
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private TemplateModelHelper modelHelper;
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.alfresco.repo.rendition.executer.AbstractRenderingEngine#render(org
|
||||
* .alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.service.cmr.rendition.RenditionDefinition,
|
||||
* org.alfresco.service.cmr.repository.ContentReader,
|
||||
* org.alfresco.service.cmr.repository.ChildAssociationRef)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void render(RenderingContext context)
|
||||
{
|
||||
NodeRef sourceNode = context.getSourceNode();
|
||||
NodeRef templateNode = getTemplateNode(context);
|
||||
Map<String, Serializable> paramMap = context.getCheckedParam(PARAM_MODEL, Map.class);
|
||||
TemplateImageResolver imgResolver = context.getCheckedParam(PARAM_IMAGE_RESOLVER, TemplateImageResolver.class);
|
||||
Map<String, Object> model = modelHelper.buildModelMap(sourceNode, templateNode, imgResolver, paramMap);
|
||||
|
||||
processTemplate(context, templateNode, model);
|
||||
}
|
||||
|
||||
private void processTemplate(RenderingContext context, NodeRef templateNode, Map<String, Object> model)
|
||||
{
|
||||
String template = context.getCheckedParam(PARAM_TEMPLATE, String.class);
|
||||
if ((template == null) && (templateNode == null))
|
||||
{
|
||||
throwTemplateParamsNotFoundException();
|
||||
}
|
||||
|
||||
ContentWriter contentWriter = context.makeContentWriter();
|
||||
Writer writer = new OutputStreamWriter(contentWriter.getContentOutputStream());
|
||||
try
|
||||
{
|
||||
if (template != null)
|
||||
{
|
||||
templateService.processTemplateString("freemarker", template, model, writer);
|
||||
}
|
||||
else if (templateNode != null)
|
||||
{
|
||||
templateService.processTemplate("freemarker", templateNode.toString(), model, writer);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
writer.close();
|
||||
} catch (IOException ex)
|
||||
{
|
||||
// Nothing that can be done. Log it and move on.
|
||||
log.warn("Failed to close content writer: ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void throwTemplateParamsNotFoundException()
|
||||
{
|
||||
StringBuilder msg = new StringBuilder("This action requires that either the ");
|
||||
msg.append(PARAM_TEMPLATE);
|
||||
msg.append(" parameter or the ");
|
||||
msg.append(PARAM_TEMPLATE_NODE);
|
||||
msg.append(" parameter be specified. ");
|
||||
throw new RenditionServiceException(msg.toString());
|
||||
}
|
||||
|
||||
private NodeRef getTemplateNode(RenderingContext context)
|
||||
{
|
||||
NodeRef node = context.getCheckedParam(PARAM_TEMPLATE_NODE, NodeRef.class);
|
||||
if (node == null)
|
||||
{
|
||||
String path = context.getCheckedParam(PARAM_TEMPLATE_PATH, String.class);
|
||||
if (path != null && path.length() > 0)
|
||||
{
|
||||
SearchService searchService = serviceRegistry.getSearchService();
|
||||
StoreRef storeRef = context.getDestinationNode().getStoreRef();
|
||||
ResultSet result = searchService.query(storeRef, SearchService.LANGUAGE_XPATH, path);
|
||||
if (result.length() != 1)
|
||||
{
|
||||
throw new RenditionServiceException("Could not find template node for path: " + path);
|
||||
}
|
||||
node = result.getNodeRef(0);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* @seeorg.alfresco.repo.rendition.executer.AbstractRenderingEngine#
|
||||
* getParameterDefinitions()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<ParameterDefinition> getParameterDefinitions()
|
||||
{
|
||||
Collection<ParameterDefinition> paramList = super.getParameterDefinitions();
|
||||
ParameterDefinitionImpl modelParamDef = new ParameterDefinitionImpl(//
|
||||
PARAM_MODEL,//
|
||||
DataTypeDefinition.ANY,//
|
||||
false,//
|
||||
getParamDisplayLabel(PARAM_MODEL));
|
||||
ParameterDefinitionImpl templateParamDef = new ParameterDefinitionImpl(//
|
||||
PARAM_TEMPLATE,//
|
||||
DataTypeDefinition.TEXT,//
|
||||
false,//
|
||||
getParamDisplayLabel(PARAM_TEMPLATE));
|
||||
ParameterDefinitionImpl templateNodeParamDef = new ParameterDefinitionImpl(//
|
||||
PARAM_TEMPLATE_NODE,//
|
||||
DataTypeDefinition.NODE_REF,//
|
||||
false,//
|
||||
getParamDisplayLabel(PARAM_TEMPLATE_NODE));
|
||||
ParameterDefinitionImpl templatePathParamDef = new ParameterDefinitionImpl(//
|
||||
PARAM_TEMPLATE_PATH,//
|
||||
DataTypeDefinition.TEXT,//
|
||||
false,//
|
||||
getParamDisplayLabel(PARAM_TEMPLATE_PATH));
|
||||
ParameterDefinitionImpl imgResolverParamDef = new ParameterDefinitionImpl(//
|
||||
PARAM_IMAGE_RESOLVER,//
|
||||
DataTypeDefinition.ANY,//
|
||||
false,//
|
||||
getParamDisplayLabel(PARAM_IMAGE_RESOLVER));
|
||||
paramList.add(modelParamDef);
|
||||
paramList.add(templateParamDef);
|
||||
paramList.add(templateNodeParamDef);
|
||||
paramList.add(templatePathParamDef);
|
||||
paramList.add(imgResolverParamDef);
|
||||
return paramList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param templateService the templateService to set
|
||||
*/
|
||||
public void setTemplateService(TemplateService templateService)
|
||||
{
|
||||
this.templateService = templateService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param repository the repository to set
|
||||
*/
|
||||
public void setRepositoryHelper(Repository repository)
|
||||
{
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry the serviceRegistry to set
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up {@link TemplateModelHelper}.
|
||||
*/
|
||||
public void afterPropertiesSet()
|
||||
{
|
||||
this.modelHelper = new TemplateModelHelper(templateService, repository, serviceRegistry);
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<h6>Test Template 1</h6>
|
||||
|
||||
<#-- Title is used in test code to ensure that updates to source node rerender properly -->
|
||||
<#-- The xxx xxx demarcation here is used by the test code -->
|
||||
TestTitle= xxx${node.properties["cm:title"]?string}xxx
|
||||
|
||||
<#-- Test basic properties -->
|
||||
${node.id}<br>
|
||||
${node.name}<br>
|
||||
${node.properties?size}<br>
|
||||
${node.children?size}<br>
|
||||
|
||||
<#if node.assocs["cm:translations"]?exists>
|
||||
node.assocs<br>
|
||||
</#if>
|
||||
${node.aspects?size}<br>
|
||||
<#if node.isContainer>node.isContainer</#if><br>
|
||||
<#if node.isDocument>node.isDocument</#if><br>
|
||||
<#--${node.content}<br>-->
|
||||
${node.url}<br>
|
||||
${node.displayPath}<br>
|
||||
${node.icon16}<br>
|
||||
${node.icon32}<br>
|
||||
<#if node.mimetype?exists>node.mimetype</#if><br>
|
||||
<#if node.size?exists>node.size</#if><br>
|
||||
<#if node.isLocked>node.isLocked</#if><br>
|
||||
|
||||
<#-- Test child walking and property resolving -->
|
||||
<table>
|
||||
<#list node.children as child>
|
||||
<#-- show properties of each child -->
|
||||
<#assign props = child.properties?keys>
|
||||
<#list props as t>
|
||||
<#-- If the property exists -->
|
||||
<#if child.properties[t]?exists>
|
||||
<#-- If it is a date, format it accordingly-->
|
||||
<#if child.properties[t]?is_date>
|
||||
<tr><td>${t} = ${child.properties[t]?date}</td></tr>
|
||||
|
||||
<#-- If it is a boolean, format it accordingly-->
|
||||
<#elseif child.properties[t]?is_boolean>
|
||||
<tr><td>${t} = ${child.properties[t]?string("yes", "no")}</td></tr>
|
||||
|
||||
<#-- Otherwise treat it as a string -->
|
||||
<#else>
|
||||
<tr><td>${t} = ${child.properties[t]}</td></tr>
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
|
||||
</#list>
|
||||
</table>
|
||||
|
||||
<#-- Test XPath -->
|
||||
<#list node.childrenByXPath["//*[@sys:store-protocol='workspace']"] as child>
|
||||
${child.name}
|
||||
</#list>
|
||||
|
||||
<h6>End Test Template 1</h6>
|
@@ -44,6 +44,7 @@ import org.springframework.context.ApplicationContext;
|
||||
*/
|
||||
public class TemplateServiceImplTest extends TestCase
|
||||
{
|
||||
private static final String TEMPLATE_1 = "org/alfresco/repo/template/test_template1.ftl";
|
||||
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private TemplateService templateService;
|
||||
@@ -127,5 +128,4 @@ public class TemplateServiceImplTest extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
private static final String TEMPLATE_1 = "org/alfresco/repo/template/test_template1.ftl";
|
||||
}
|
||||
|
@@ -19,26 +19,39 @@
|
||||
package org.alfresco.repo.thumbnail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Registry of all the thumbnail details available
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ThumbnailRegistry
|
||||
{
|
||||
/** Content service */
|
||||
private ContentService contentService;
|
||||
|
||||
/** Map of thumbnail defintion */
|
||||
private Map<String, ThumbnailDefinition> thumbnailDefinitions = new HashMap<String, ThumbnailDefinition>(7);
|
||||
/** Rendition service */
|
||||
private RenditionService renditionService;
|
||||
|
||||
private List<String> thumbnails;
|
||||
|
||||
/** This flag indicates whether the thumbnail definitions have been lazily loaded or not. */
|
||||
private boolean thumbnailDefinitionsInited = false;
|
||||
|
||||
/** 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);
|
||||
@@ -54,36 +67,63 @@ public class ThumbnailRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a number of thumbnail defintions
|
||||
* Rendition service
|
||||
*
|
||||
* @param thumbnailDefinitions list of thumbnail details
|
||||
* @param renditionService rendition service
|
||||
*/
|
||||
public void setThumbnailDefinitions(List<ThumbnailDefinition> thumbnailDefinitions)
|
||||
public void setRenditionService(RenditionService renditionService)
|
||||
{
|
||||
for (ThumbnailDefinition value : thumbnailDefinitions)
|
||||
{
|
||||
addThumbnailDefinition(value);
|
||||
this.renditionService = renditionService;
|
||||
}
|
||||
|
||||
public void setThumbnails(final List<String> thumbnails)
|
||||
{
|
||||
this.thumbnails = thumbnails;
|
||||
|
||||
// We'll not populate the data fields in the ThumbnailRegistry here, instead preferring
|
||||
// to do it lazily later.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all the thumbnail defintions
|
||||
* Get a list of all the thumbnail definitions
|
||||
*
|
||||
* @return Collection<ThumbnailDefinition> colleciton of thumbnail defintions
|
||||
* @return Collection<ThumbnailDefinition> collection of thumbnail definitions
|
||||
*/
|
||||
public List<ThumbnailDefinition> getThumbnailDefinitions()
|
||||
{
|
||||
if (thumbnailDefinitionsInited == false)
|
||||
{
|
||||
this.initThumbnailDefinitions();
|
||||
thumbnailDefinitionsInited = true;
|
||||
}
|
||||
return new ArrayList<ThumbnailDefinition>(this.thumbnailDefinitions.values());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mimetype
|
||||
* @return
|
||||
*/
|
||||
public List<ThumbnailDefinition> getThumnailDefintions(String mimetype)
|
||||
private void initThumbnailDefinitions()
|
||||
{
|
||||
List<ThumbnailDefinition> result = this.mimetypeMap.get(mimetype);;
|
||||
ThumbnailRenditionConvertor thumbnailRenditionConvertor = new ThumbnailRenditionConvertor();
|
||||
|
||||
for (String thumbnailDefinitionName : this.thumbnails)
|
||||
{
|
||||
QName qName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailDefinitionName);
|
||||
RenditionDefinition rAction = renditionService
|
||||
.loadRenditionDefinition(qName);
|
||||
|
||||
ThumbnailDefinition thDefn = thumbnailRenditionConvertor.convert(rAction);
|
||||
|
||||
thumbnailDefinitions.put(thumbnailDefinitionName, thDefn);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ThumbnailDefinition> getThumbnailDefinitions(String mimetype)
|
||||
{
|
||||
if (thumbnailDefinitionsInited == false)
|
||||
{
|
||||
this.initThumbnailDefinitions();
|
||||
thumbnailDefinitionsInited = true;
|
||||
}
|
||||
|
||||
List<ThumbnailDefinition> result = this.mimetypeMap.get(mimetype);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
@@ -107,12 +147,28 @@ public class ThumbnailRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a thumnail details
|
||||
*
|
||||
* @param mimetype
|
||||
* @return
|
||||
* @deprecated Use {@link #getThumbnailDefinitions(String)} instead.
|
||||
*/
|
||||
public List<ThumbnailDefinition> getThumnailDefintions(String mimetype)
|
||||
{
|
||||
return this.getThumbnailDefinitions(mimetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a thumbnail details
|
||||
*
|
||||
* @param thumbnailDetails thumbnail details
|
||||
*/
|
||||
public void addThumbnailDefinition(ThumbnailDefinition thumbnailDetails)
|
||||
{
|
||||
if (thumbnailDefinitionsInited == false)
|
||||
{
|
||||
this.initThumbnailDefinitions();
|
||||
thumbnailDefinitionsInited = true;
|
||||
}
|
||||
String thumbnailName = thumbnailDetails.getName();
|
||||
if (thumbnailName == null)
|
||||
{
|
||||
@@ -130,6 +186,11 @@ public class ThumbnailRegistry
|
||||
*/
|
||||
public ThumbnailDefinition getThumbnailDefinition(String thumbnailName)
|
||||
{
|
||||
if (thumbnailDefinitionsInited == false)
|
||||
{
|
||||
this.initThumbnailDefinitions();
|
||||
thumbnailDefinitionsInited = true;
|
||||
}
|
||||
return this.thumbnailDefinitions.get(thumbnailName);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.thumbnail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.content.transform.swf.SWFTransformationOptions;
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
|
||||
import org.alfresco.repo.rendition.executer.ReformatRenderingEngine;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
|
||||
|
||||
/**
|
||||
* A helper class to convert {@link TransformationOptions transformationOptions} (a thumbnail-specific
|
||||
* class) to rendition-specific parameters and vice versa.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ThumbnailRenditionConvertor
|
||||
{
|
||||
public Map<String, Serializable> convert(TransformationOptions transformationOptions, ThumbnailParentAssociationDetails assocDetails)
|
||||
{
|
||||
Map<String, Serializable> parameters = new HashMap<String, Serializable>();
|
||||
|
||||
// parameters common to all transformations
|
||||
putParameterIfNotNull(AbstractRenderingEngine.PARAM_SOURCE_CONTENT_PROPERTY, transformationOptions.getSourceContentProperty(), parameters);
|
||||
putParameterIfNotNull(AbstractRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY, transformationOptions.getTargetContentProperty(), parameters);
|
||||
putParameterIfNotNull(RenditionService.PARAM_DESTINATION_NODE, transformationOptions.getTargetNodeRef(), parameters);
|
||||
|
||||
// putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_NAME, assocDetails.getAssociationName(), parameters);
|
||||
// putParameterIfNotNull(ImageRenderingEngine.PARAM_ASSOC_TYPE, assocDetails.getAssociationType(), parameters);
|
||||
|
||||
if (transformationOptions instanceof SWFTransformationOptions)
|
||||
{
|
||||
SWFTransformationOptions swfTransformationOptions = (SWFTransformationOptions)transformationOptions;
|
||||
putParameterIfNotNull(ReformatRenderingEngine.PARAM_FLASH_VERSION, swfTransformationOptions.getFlashVersion(), parameters);
|
||||
}
|
||||
else if (transformationOptions instanceof ImageTransformationOptions)
|
||||
{
|
||||
ImageTransformationOptions imTransformationOptions = (ImageTransformationOptions)transformationOptions;
|
||||
putParameterIfNotNull(ImageRenderingEngine.PARAM_COMMAND_OPTIONS, imTransformationOptions.getCommandOptions(), parameters);
|
||||
|
||||
ImageResizeOptions imgResizeOptions = imTransformationOptions.getResizeOptions();
|
||||
if (imgResizeOptions != null)
|
||||
{
|
||||
int width = imgResizeOptions.getWidth();
|
||||
parameters.put(ImageRenderingEngine.PARAM_RESIZE_WIDTH, width);
|
||||
|
||||
int height = imgResizeOptions.getHeight();
|
||||
parameters.put(ImageRenderingEngine.PARAM_RESIZE_HEIGHT, height);
|
||||
|
||||
boolean maintainAspectRatio = imgResizeOptions.isMaintainAspectRatio();
|
||||
parameters.put(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO, maintainAspectRatio);
|
||||
|
||||
boolean percentResize = imgResizeOptions.isPercentResize();
|
||||
parameters.put(ImageRenderingEngine.PARAM_IS_PERCENT_RESIZE, percentResize);
|
||||
|
||||
boolean resizeToThumbnail = imgResizeOptions.isResizeToThumbnail();
|
||||
parameters.put(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL, resizeToThumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private void putParameterIfNotNull(String paramName, Serializable paramValue, Map<String, Serializable> params)
|
||||
{
|
||||
if (paramValue != null)
|
||||
{
|
||||
params.put(paramName, paramValue);
|
||||
}
|
||||
}
|
||||
|
||||
public ThumbnailDefinition convert(RenditionDefinition renditionDefinition)
|
||||
{
|
||||
ThumbnailDefinition thDefn = new ThumbnailDefinition();
|
||||
|
||||
Map<String, Serializable> params = renditionDefinition.getParameterValues();
|
||||
|
||||
//parameters common to all the built-in thumbnail definitions
|
||||
Serializable mimeTypeParam = params.get(AbstractRenderingEngine.PARAM_MIME_TYPE);
|
||||
thDefn.setMimetype((String) mimeTypeParam);
|
||||
thDefn.setName(renditionDefinition.getRenditionName().getLocalName());
|
||||
|
||||
Serializable placeHolderResourcePathParam = params.get(AbstractRenderingEngine.PARAM_PLACEHOLDER_RESOURCE_PATH);
|
||||
if (placeHolderResourcePathParam != null)
|
||||
{
|
||||
thDefn.setPlaceHolderResourcePath((String)placeHolderResourcePathParam);
|
||||
}
|
||||
|
||||
//TODO src/target contentProp & nodeRef
|
||||
|
||||
TransformationOptions transformationOptions = null;
|
||||
Serializable flashVersion = renditionDefinition.getParameterValue(ReformatRenderingEngine.PARAM_FLASH_VERSION);
|
||||
if (flashVersion != null)
|
||||
{
|
||||
// Thumbnails based on SWFTransformationOptions
|
||||
transformationOptions = new SWFTransformationOptions();
|
||||
SWFTransformationOptions swfTranOpts = (SWFTransformationOptions)transformationOptions;
|
||||
swfTranOpts.setFlashVersion((String)flashVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Thumbnails based on ImageTransformationOptions
|
||||
transformationOptions = new ImageTransformationOptions();
|
||||
ImageTransformationOptions imgTrOpts = (ImageTransformationOptions)transformationOptions;
|
||||
|
||||
ImageResizeOptions resizeOptions = new ImageResizeOptions();
|
||||
Serializable xsize = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_WIDTH);
|
||||
if (xsize != null)
|
||||
{
|
||||
// Saved actions with int parameters seem to be coming back as Longs. TODO Investigate
|
||||
resizeOptions.setWidth(((Long) xsize).intValue());
|
||||
}
|
||||
|
||||
Serializable ysize = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_HEIGHT);
|
||||
if (ysize != null)
|
||||
{
|
||||
resizeOptions.setHeight(((Long) ysize).intValue());
|
||||
}
|
||||
|
||||
Serializable maintainAspectRatio = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO);
|
||||
if (maintainAspectRatio != null)
|
||||
{
|
||||
resizeOptions.setMaintainAspectRatio((Boolean) maintainAspectRatio);
|
||||
}
|
||||
|
||||
Serializable resizeToThumbnail = renditionDefinition.getParameterValue(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL);
|
||||
if (resizeToThumbnail != null)
|
||||
{
|
||||
resizeOptions.setResizeToThumbnail((Boolean) resizeToThumbnail);
|
||||
}
|
||||
|
||||
imgTrOpts.setResizeOptions(resizeOptions);
|
||||
}
|
||||
|
||||
thDefn.setTransformationOptions(transformationOptions);
|
||||
|
||||
return thDefn;
|
||||
}
|
||||
}
|
@@ -19,21 +19,24 @@
|
||||
package org.alfresco.repo.thumbnail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.content.transform.swf.SWFTransformationOptions;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
|
||||
import org.alfresco.repo.rendition.executer.ReformatRenderingEngine;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionServiceException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||
@@ -42,14 +45,14 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ThumbnailServiceImpl implements ThumbnailService
|
||||
{
|
||||
@@ -79,6 +82,19 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
/** Thumbnail registry */
|
||||
private ThumbnailRegistry thumbnailRegistry;
|
||||
|
||||
/** Rendition service */
|
||||
private RenditionService renditionService;
|
||||
|
||||
/**
|
||||
* Set the rendition service.
|
||||
*
|
||||
* @param renditionService
|
||||
*/
|
||||
public void setRenditionService(RenditionService renditionService)
|
||||
{
|
||||
this.renditionService = renditionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
@@ -168,118 +184,89 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
logger.debug("Creating thumbnail: There is already a thumbnail with the name '" + thumbnailName + "' (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype);
|
||||
}
|
||||
|
||||
// We can't continue because there is already an thumbnail with the given name for that content property
|
||||
// We can't continue because there is already a thumbnail with the given name for that content property
|
||||
throw new ThumbnailException(ERR_DUPLICATE_NAME);
|
||||
}
|
||||
|
||||
NodeRef thumbnail = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
|
||||
ChildAssociationRef thumbnailRef = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ChildAssociationRef>()
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
public ChildAssociationRef doWork() throws Exception
|
||||
{
|
||||
NodeRef thumbnail;
|
||||
// Need a variable scoped to this inner class in order to assign a new value to it.
|
||||
String localThumbnailName = thumbnailName;
|
||||
// Get the name of the thumbnail and add to properties map
|
||||
if (localThumbnailName == null || localThumbnailName.length() == 0)
|
||||
{
|
||||
localThumbnailName = GUID.generate();
|
||||
}
|
||||
|
||||
// Apply the thumbnailed aspect to the node if it doesn't already have it
|
||||
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == false)
|
||||
// We're prepending the cm namespace here.
|
||||
QName thumbnailQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, localThumbnailName);
|
||||
|
||||
RenditionDefinition renderingAction = renditionService.loadRenditionDefinition(thumbnailQName);
|
||||
if (renderingAction == null)
|
||||
{
|
||||
// Ensure we do not update the 'modifier' due to thumbnail addition
|
||||
behaviourFilter.disableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
|
||||
// If the provided thumbnailName does not map to a built-in rendition definition
|
||||
// then we must create a dynamic rendition definition for this thumbnail.
|
||||
// To do this we must have a renderingEngineName.
|
||||
//
|
||||
// The transformation will either be a imageRenderingEngine or a reformat (pdf2swf)
|
||||
String renderingEngineName = getRenderingEngineNameFor(transformationOptions);
|
||||
|
||||
renderingAction = renditionService.createRenditionDefinition(thumbnailQName, renderingEngineName);
|
||||
}
|
||||
Map<String, Serializable> params = new ThumbnailRenditionConvertor().convert(transformationOptions, assocDetails);
|
||||
for (String key : params.keySet())
|
||||
{
|
||||
renderingAction.setParameterValue(key, params.get(key));
|
||||
}
|
||||
|
||||
|
||||
ChildAssociationRef chAssRef = null;
|
||||
try
|
||||
{
|
||||
nodeService.addAspect(node, ContentModel.ASPECT_THUMBNAILED, null);
|
||||
}
|
||||
finally
|
||||
chAssRef = renditionService.render(node, renderingAction);
|
||||
} catch (RenditionServiceException rsx)
|
||||
{
|
||||
behaviourFilter.enableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
throw new ThumbnailException(rsx.getMessage(), rsx);
|
||||
}
|
||||
|
||||
// Get the name of the thumbnail and add to properties map
|
||||
String thumbName = thumbnailName;
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(4);
|
||||
if (thumbName == null || thumbName.length() == 0)
|
||||
{
|
||||
thumbName = GUID.generate();
|
||||
}
|
||||
else
|
||||
{
|
||||
String thumbnailFileName = generateThumbnailFileName(thumbName, mimetype);
|
||||
properties.put(ContentModel.PROP_NAME, thumbnailFileName);
|
||||
}
|
||||
properties.put(ContentModel.PROP_THUMBNAIL_NAME, thumbName);
|
||||
|
||||
// Add the name of the content property
|
||||
properties.put(ContentModel.PROP_CONTENT_PROPERTY_NAME, contentProperty);
|
||||
|
||||
// See if parent association details have been specified for the thumbnail
|
||||
if (assocDetails == null)
|
||||
{
|
||||
// Create the thumbnail using the thumbnails child association
|
||||
thumbnail = nodeService.createNode(
|
||||
node,
|
||||
ContentModel.ASSOC_THUMBNAILS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName),
|
||||
ContentModel.TYPE_THUMBNAIL,
|
||||
properties).getChildRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the thumbnail using the specified parent assoc details
|
||||
thumbnail = nodeService.createNode(
|
||||
assocDetails.getParent(),
|
||||
assocDetails.getAssociationType(),
|
||||
assocDetails.getAssociationName(),
|
||||
ContentModel.TYPE_THUMBNAIL,
|
||||
properties).getChildRef();
|
||||
|
||||
// Associate the new thumbnail to the source
|
||||
nodeService.addChild(
|
||||
node,
|
||||
thumbnail,
|
||||
ContentModel.ASSOC_THUMBNAILS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbName));
|
||||
}
|
||||
|
||||
// Get the content reader and writer for content nodes
|
||||
ContentReader reader = contentService.getReader(node, contentProperty);
|
||||
ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(mimetype);
|
||||
writer.setEncoding(reader.getEncoding());
|
||||
|
||||
// Catch the failure to create the thumbnail
|
||||
if (contentService.isTransformable(reader, writer, transformationOptions) == false)
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Creating thumbnail: There is no transformer to generate the thumbnail required (node=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")");
|
||||
}
|
||||
|
||||
// Throw exception indicating that the thumbnail could not be created
|
||||
throw new ThumbnailException(MessageFormat.format(ERR_NO_CREATE, reader.getMimetype(), writer.getMimetype()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do the thumbnail transformation
|
||||
contentService.transform(reader, writer, transformationOptions);
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
return chAssRef;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
// Return the created thumbnail
|
||||
return thumbnail;
|
||||
return getThumbnailNode(thumbnailRef);
|
||||
}
|
||||
|
||||
private String getRenderingEngineNameFor(TransformationOptions options)
|
||||
{
|
||||
if (options instanceof ImageTransformationOptions)
|
||||
{
|
||||
return ImageRenderingEngine.NAME;
|
||||
}
|
||||
else if (options instanceof SWFTransformationOptions)
|
||||
{
|
||||
return ReformatRenderingEngine.NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO What can we do here? Can we treat this as an error?
|
||||
// Isn't this a 'standard' TransformationOptions?
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the thumbnail name from the name and destination mimertype
|
||||
* This method returns the NodeRef for the thumbnail, using the ChildAssociationRef
|
||||
* that links the sourceNode to its associated Thumbnail node.
|
||||
*
|
||||
* @param thumbnailName the thumbnail name
|
||||
* @param destinationMimetype the destination name
|
||||
* @return String the thumbnail file name
|
||||
* @param thumbnailRef the ChildAssociationRef containing the child NodeRef.
|
||||
* @return the NodeRef of the thumbnail itself.
|
||||
*/
|
||||
private String generateThumbnailFileName(String thumbnailName, String destinationMimetype)
|
||||
public NodeRef getThumbnailNode(ChildAssociationRef thumbnailRef)
|
||||
{
|
||||
return thumbnailName + "." + this.mimetypeMap.getExtension(destinationMimetype);
|
||||
return thumbnailRef.getChildRef();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,64 +274,53 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
*/
|
||||
public void updateThumbnail(final NodeRef thumbnail, final TransformationOptions transformationOptions)
|
||||
{
|
||||
// Seeing as how this always gives its own options, maybe this should be a delete and recreate?
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Updating thumbnail (thumbnail=" + thumbnail.toString() + ")");
|
||||
}
|
||||
|
||||
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
// First check that we are dealing with a thumbnail
|
||||
if (ContentModel.TYPE_THUMBNAIL.equals(nodeService.getType(thumbnail)) == true)
|
||||
// First check that we are dealing with a rendition object
|
||||
if (renditionService.isRendition(thumbnail))
|
||||
{
|
||||
// Get the node that is the source of the thumbnail
|
||||
NodeRef node = null;
|
||||
List<ChildAssociationRef> parents = nodeService.getParentAssocs(thumbnail, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL);
|
||||
if (parents.size() == 0)
|
||||
ChildAssociationRef parentAssoc = renditionService.getSourceNode(thumbnail);
|
||||
|
||||
if (parentAssoc == null)
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
||||
{
|
||||
logger.debug("Updating thumbnail: The thumbnails parent cannot be found (thumbnail=" + thumbnail.toString() + ")");
|
||||
}
|
||||
|
||||
throw new ThumbnailException(ERR_NO_PARENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = parents.get(0).getParentRef();
|
||||
}
|
||||
|
||||
final QName renditionAssociationName = parentAssoc.getQName();
|
||||
NodeRef sourceNode = parentAssoc.getParentRef();
|
||||
|
||||
// Get the content property
|
||||
QName contentProperty = (QName)nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME);
|
||||
|
||||
// Get the reader and writer
|
||||
ContentReader reader = contentService.getReader(node, contentProperty);
|
||||
ContentWriter writer = contentService.getWriter(thumbnail, ContentModel.PROP_CONTENT, true);
|
||||
|
||||
// Set the basic detail of the transformation options
|
||||
transformationOptions.setSourceNodeRef(node);
|
||||
transformationOptions.setSourceNodeRef(sourceNode);
|
||||
transformationOptions.setSourceContentProperty(contentProperty);
|
||||
transformationOptions.setTargetNodeRef(thumbnail);
|
||||
transformationOptions.setTargetContentProperty(ContentModel.PROP_CONTENT);
|
||||
|
||||
// Catch the failure to create the thumbnail
|
||||
if (contentService.isTransformable(reader, writer, transformationOptions) == false)
|
||||
// Do the thumbnail transformation
|
||||
RenditionDefinition rendDefn = renditionService.loadRenditionDefinition(renditionAssociationName);
|
||||
if (rendDefn == null)
|
||||
{
|
||||
if (logger.isDebugEnabled() == true)
|
||||
String renderingEngineName = getRenderingEngineNameFor(transformationOptions);
|
||||
|
||||
rendDefn = renditionService.createRenditionDefinition(parentAssoc.getQName(), renderingEngineName);
|
||||
}
|
||||
Map<String, Serializable> params = new ThumbnailRenditionConvertor().convert(transformationOptions, null);
|
||||
for (String key : params.keySet())
|
||||
{
|
||||
logger.debug("Updating thumbnail: there is not transformer to update the thumbnail with (thumbnail=" + thumbnail.toString() + ")");
|
||||
rendDefn.setParameterValue(key, params.get(key));
|
||||
}
|
||||
|
||||
// Throw exception indicating that the thumbnail could not be created
|
||||
throw new ThumbnailException(MessageFormat.format(ERR_NO_CREATE, reader.getMimetype(), writer.getMimetype()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do the thumbnail transformation
|
||||
contentService.transform(reader, writer, transformationOptions);
|
||||
}
|
||||
renditionService.render(sourceNode, rendDefn);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -353,9 +329,6 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
logger.debug("Updating thumbnail: cannot update a thumbnail node that isn't the correct thumbnail type (thumbnail=" + thumbnail.toString() + ")");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,8 +336,6 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
*/
|
||||
public NodeRef getThumbnailByName(NodeRef node, QName contentProperty, String thumbnailName)
|
||||
{
|
||||
NodeRef thumbnail = null;
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
//
|
||||
@@ -377,21 +348,21 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
logger.debug("Getting thumbnail by name (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; thumbnailName=" + thumbnailName + ")");
|
||||
}
|
||||
|
||||
// Check that the node has the thumbnailed aspect applied
|
||||
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
|
||||
{
|
||||
// Get all the thumbnails that match the thumbnail name
|
||||
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(node, ContentModel.ASSOC_THUMBNAILS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName));
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
// Thumbnails have a cm: prefix.
|
||||
QName namespacedThumbnailName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, thumbnailName);
|
||||
|
||||
ChildAssociationRef existingRendition = renditionService.getRenditionByName(node, namespacedThumbnailName);
|
||||
NodeRef thumbnail = null;
|
||||
|
||||
// Check the child to see if it matches the content property we are concerned about.
|
||||
// We can assume there will only ever be one per content property since createThumbnail enforces this.
|
||||
NodeRef child = assoc.getChildRef();
|
||||
if (contentProperty.equals(this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME)) == true)
|
||||
if (existingRendition != null)
|
||||
{
|
||||
NodeRef child = existingRendition.getChildRef();
|
||||
Serializable contentPropertyName = this.nodeService.getProperty(child, ContentModel.PROP_CONTENT_PROPERTY_NAME);
|
||||
if (contentProperty.equals(contentPropertyName) == true)
|
||||
{
|
||||
thumbnail = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,12 +388,9 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
logger.debug("Getting thumbnails (nodeRef=" + node.toString() + "; contentProperty=" + contentProperty.toString() + "; mimetype=" + mimetype + ")");
|
||||
}
|
||||
|
||||
// Check that the node has the thumbnailed aspect applied
|
||||
if (nodeService.hasAspect(node, ContentModel.ASPECT_THUMBNAILED) == true)
|
||||
{
|
||||
// Get all the thumbnails that match the thumbnail name
|
||||
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(node, ContentModel.ASSOC_THUMBNAILS, RegexQNamePattern.MATCH_ALL);
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
List<ChildAssociationRef> renditions = this.renditionService.getRenditions(node);
|
||||
|
||||
for (ChildAssociationRef assoc : renditions)
|
||||
{
|
||||
// Check the child to see if it matches the content property we are concerned about.
|
||||
// We can assume there will only ever be one per content property since createThumbnail enforces this.
|
||||
@@ -433,8 +401,8 @@ public class ThumbnailServiceImpl implements ThumbnailService
|
||||
thumbnails.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Ensure this doesn't return non-thumbnail renditions.
|
||||
return thumbnails;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.thumbnail;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.ActionImpl;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.rendition.PerformRenditionActionExecuter;
|
||||
import org.alfresco.repo.rendition.RenditionServiceImpl;
|
||||
import org.alfresco.repo.rendition.executer.AbstractRenderingEngine;
|
||||
import org.alfresco.repo.rendition.executer.ImageRenderingEngine;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.rendition.RenditionDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/**
|
||||
* Thumbnail service implementation unit test
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ThumbnailServiceImplParameterTest
|
||||
{
|
||||
// Mocked services.
|
||||
private ActionService mockActionService = mock(ActionService.class);
|
||||
|
||||
// Real services - backed by mocked services.
|
||||
private RenditionServiceImpl renditionService;
|
||||
private ThumbnailService thumbnailService;
|
||||
|
||||
private final NodeRef dummyNodeRef1 = new NodeRef("workspace", "dummy", "dummyID_1");
|
||||
private final NodeRef dummyNodeRef2 = new NodeRef("workspace", "dummy", "dummyID_2");
|
||||
private final NodeRef dummyNodeRef3 = new NodeRef("workspace", "dummy", "dummyID_3");
|
||||
|
||||
@Before
|
||||
public void initMockObjects()
|
||||
{
|
||||
when(mockActionService.createAction(PerformRenditionActionExecuter.NAME))
|
||||
.thenReturn(new ActionImpl(dummyNodeRef2, "id", PerformRenditionActionExecuter.NAME, new HashMap<String, Serializable>()));
|
||||
renditionService = new RenditionServiceImpl()
|
||||
{
|
||||
@Override
|
||||
public RenditionDefinition loadRenditionDefinition(QName renderingActionName)
|
||||
{
|
||||
// We're intentionally returning null for this test.
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
renditionService.setActionService(mockActionService);
|
||||
|
||||
ThumbnailServiceImpl thumbs = new ThumbnailServiceImpl()
|
||||
{
|
||||
@Override
|
||||
public NodeRef getThumbnailByName(NodeRef node,
|
||||
QName contentProperty, String thumbnailName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* In this test the thumbnailRef will be null, so we need to ensure
|
||||
* it is not dereferenced here.
|
||||
*/
|
||||
@Override
|
||||
public NodeRef getThumbnailNode(ChildAssociationRef thumbnailRef)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
thumbs.setRenditionService(renditionService);
|
||||
thumbnailService = thumbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* This test method ensures that the parameters on thumbnail-create are
|
||||
* passed through the RenditionService to the ActionService
|
||||
*/
|
||||
@Test
|
||||
public void createThumbnailPassesParametersToActionService()
|
||||
{
|
||||
// As most of the services are mocked out, the actual values used here
|
||||
// don't matter.
|
||||
final Map<String, Serializable> parametersUnderTest = new HashMap<String, Serializable>();
|
||||
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_WIDTH, new Integer(42));
|
||||
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_HEIGHT, new Integer(93));
|
||||
parametersUnderTest.put(ImageRenderingEngine.PARAM_COMMAND_OPTIONS, "foo");
|
||||
parametersUnderTest.put(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO, Boolean.TRUE);
|
||||
parametersUnderTest.put(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL, Boolean.FALSE);
|
||||
parametersUnderTest.put(AbstractRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY, ContentModel.PROP_CONTENT);
|
||||
parametersUnderTest.put(RenditionService.PARAM_DESTINATION_NODE, dummyNodeRef2);
|
||||
|
||||
|
||||
ImageTransformationOptions imageTransOpts = new ImageTransformationOptions();
|
||||
imageTransOpts.setTargetNodeRef(dummyNodeRef2);
|
||||
|
||||
imageTransOpts.setTargetContentProperty((QName) parametersUnderTest.get(ImageRenderingEngine.PARAM_TARGET_CONTENT_PROPERTY));
|
||||
imageTransOpts.setCommandOptions((String) parametersUnderTest.get(ImageRenderingEngine.PARAM_COMMAND_OPTIONS));
|
||||
|
||||
ImageResizeOptions resizeOptions = new ImageResizeOptions();
|
||||
resizeOptions.setHeight((Integer) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_HEIGHT));
|
||||
resizeOptions.setWidth((Integer) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_WIDTH));
|
||||
resizeOptions.setMaintainAspectRatio((Boolean) parametersUnderTest.get(ImageRenderingEngine.PARAM_MAINTAIN_ASPECT_RATIO));
|
||||
resizeOptions.setResizeToThumbnail((Boolean) parametersUnderTest.get(ImageRenderingEngine.PARAM_RESIZE_TO_THUMBNAIL));
|
||||
imageTransOpts.setResizeOptions(resizeOptions);
|
||||
|
||||
ThumbnailParentAssociationDetails assocDetails = new ThumbnailParentAssociationDetails(dummyNodeRef3,
|
||||
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
"homerSimpson"));
|
||||
|
||||
// Now request the creation of the the thumbnail.
|
||||
thumbnailService.createThumbnail(dummyNodeRef1, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransOpts, "bartSimpson", assocDetails);
|
||||
|
||||
|
||||
ArgumentCaptor<Action> argument = ArgumentCaptor.forClass(Action.class);
|
||||
verify(mockActionService).executeAction(argument.capture(), any(NodeRef.class), anyBoolean(), anyBoolean());
|
||||
final Action performRenditionAction = argument.getValue();
|
||||
final RenditionDefinition renditionDefn = (RenditionDefinition) performRenditionAction.getParameterValue(PerformRenditionActionExecuter.PARAM_RENDITION_DEFINITION);
|
||||
Map<String, Serializable> parameters = renditionDefn.getParameterValues();
|
||||
|
||||
for (String s : parametersUnderTest.keySet())
|
||||
{
|
||||
if (parameters.keySet().contains(s) == false || parameters.get(s) == null || parameters.get(s).toString().length() == 0)
|
||||
{
|
||||
fail("Missing parameter " + s);
|
||||
}
|
||||
assertEquals("Parameter " + s + " had wrong value.",
|
||||
parametersUnderTest.get(s), parameters.get(s));
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@
|
||||
* 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.thumbnail;
|
||||
|
||||
import java.io.File;
|
||||
@@ -26,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
|
||||
import org.alfresco.repo.content.transform.ContentTransformer;
|
||||
@@ -33,13 +35,16 @@ import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||
import org.alfresco.repo.jscript.ClasspathScriptLocation;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.ScriptLocation;
|
||||
import org.alfresco.service.cmr.repository.ScriptService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailException;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailParentAssociationDetails;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -50,9 +55,11 @@ import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
* Thumbnail service implementation unit test
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
private RenditionService renditionService;
|
||||
private ThumbnailService thumbnailService;
|
||||
private ScriptService scriptService;
|
||||
private MimetypeMap mimetypeMap;
|
||||
@@ -61,49 +68,90 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the required services
|
||||
this.thumbnailService = (ThumbnailService)this.applicationContext.getBean("ThumbnailService");
|
||||
this.mimetypeMap = (MimetypeMap)this.applicationContext.getBean("mimetypeService");
|
||||
this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService");
|
||||
this.renditionService = (RenditionService) this.applicationContext.getBean("RenditionService");
|
||||
this.thumbnailService = (ThumbnailService) this.applicationContext.getBean("ThumbnailService");
|
||||
this.mimetypeMap = (MimetypeMap) this.applicationContext.getBean("mimetypeService");
|
||||
this.scriptService = (ScriptService) this.applicationContext.getBean("ScriptService");
|
||||
|
||||
// Create a folder and some content
|
||||
Map<QName, Serializable> folderProps = new HashMap<QName, Serializable>(1);
|
||||
folderProps.put(ContentModel.PROP_NAME, "testFolder");
|
||||
this.folder = this.nodeService.createNode(
|
||||
this.rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
this.folder = this.nodeService.createNode(this.rootNodeRef, ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testFolder"), ContentModel.TYPE_FOLDER)
|
||||
.getChildRef();
|
||||
}
|
||||
|
||||
private void checkTransformer()
|
||||
{
|
||||
ContentTransformer transformer = this.contentService.getImageTransformer();
|
||||
if (transformer == null)
|
||||
{
|
||||
fail("No transformer returned for 'getImageTransformer'");
|
||||
}
|
||||
assertNotNull("No transformer returned for 'getImageTransformer'", transformer);
|
||||
|
||||
// Check that it is working
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
if (!transformer.isTransformable(
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
if (!transformer.isTransformable(MimetypeMap.MIMETYPE_IMAGE_JPEG, MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions))
|
||||
{
|
||||
fail("Image transformer is not working. Please check your image conversion command setup.");
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateRenditionThumbnailFromImage() throws Exception
|
||||
{
|
||||
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
|
||||
ThumbnailDefinition details = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(
|
||||
qname.getLocalName());
|
||||
assertEquals("doclib", details.getName());
|
||||
assertEquals("image/png", details.getMimetype());
|
||||
assertEquals("alfresco/thumbnail/thumbnail_placeholder_doclib.png", details.getPlaceHolderResourcePath());
|
||||
|
||||
checkTransformer();
|
||||
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
|
||||
NodeRef thumbnail0 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, details.getTransformationOptions(), "doclib");
|
||||
assertNotNull(thumbnail0);
|
||||
checkRenditioned(jpgOrig, "doclib");
|
||||
checkRendition("doclib", thumbnail0);
|
||||
outputThumbnailTempContentLocation(thumbnail0, "jpg", "doclib test");
|
||||
}
|
||||
|
||||
public void testCreateRenditionThumbnailFromPdf() throws Exception
|
||||
{
|
||||
QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "doclib");
|
||||
|
||||
ThumbnailDefinition details = thumbnailService.getThumbnailRegistry().getThumbnailDefinition(
|
||||
qname.getLocalName());
|
||||
assertEquals("doclib", details.getName());
|
||||
assertEquals("image/png", details.getMimetype());
|
||||
assertEquals("alfresco/thumbnail/thumbnail_placeholder_doclib.png", details.getPlaceHolderResourcePath());
|
||||
|
||||
checkTransformer();
|
||||
|
||||
NodeRef pdfOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
|
||||
|
||||
NodeRef thumbnail0 = this.thumbnailService.createThumbnail(pdfOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, details.getTransformationOptions(), "doclib");
|
||||
assertNotNull(thumbnail0);
|
||||
checkRenditioned(pdfOrig, "doclib");
|
||||
checkRendition("doclib", thumbnail0);
|
||||
outputThumbnailTempContentLocation(thumbnail0, "jpg", "doclib test");
|
||||
}
|
||||
|
||||
public void testCreateThumbnailFromImage() throws Exception
|
||||
{
|
||||
checkTransformer();
|
||||
|
||||
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef gifOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef gifOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
|
||||
|
||||
// ===== small: 64x64, marked as thumbnail ====
|
||||
|
||||
@@ -113,15 +161,13 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
imageResizeOptions.setResizeToThumbnail(true);
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
//ThumbnailDetails createOptions = new ThumbnailDetails();
|
||||
// ThumbnailDetails createOptions = new ThumbnailDetails();
|
||||
|
||||
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions,
|
||||
"small");
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
|
||||
assertNotNull(thumbnail1);
|
||||
checkThumbnailed(jpgOrig, "small");
|
||||
checkThumbnail("small", thumbnail1);
|
||||
checkRenditioned(jpgOrig, "small");
|
||||
checkRendition("small", thumbnail1);
|
||||
outputThumbnailTempContentLocation(thumbnail1, "jpg", "small - 64x64, marked as thumbnail");
|
||||
|
||||
// ===== small2: 64x64, aspect not maintained ====
|
||||
@@ -132,13 +178,11 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
imageResizeOptions2.setMaintainAspectRatio(false);
|
||||
ImageTransformationOptions imageTransformationOptions2 = new ImageTransformationOptions();
|
||||
imageTransformationOptions2.setResizeOptions(imageResizeOptions2);
|
||||
//ThumbnailDetails createOptions2 = new ThumbnailDetails();
|
||||
// ThumbnailDetails createOptions2 = new ThumbnailDetails();
|
||||
NodeRef thumbnail2 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions2,
|
||||
"small2");
|
||||
checkThumbnailed(jpgOrig, "small2");
|
||||
checkThumbnail("small2", thumbnail2);
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions2, "small2");
|
||||
checkRenditioned(jpgOrig, "small2");
|
||||
checkRendition("small2", thumbnail2);
|
||||
outputThumbnailTempContentLocation(thumbnail2, "jpg", "small2 - 64x64, aspect not maintained");
|
||||
|
||||
// ===== half: 50%x50 =====
|
||||
@@ -151,14 +195,11 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
imageTransformationOptions3.setResizeOptions(imageResizeOptions3);
|
||||
// ThumbnailDetails createOptions3 = new ThumbnailDetails();
|
||||
NodeRef thumbnail3 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions3,
|
||||
"half");
|
||||
checkThumbnailed(jpgOrig, "half");
|
||||
checkThumbnail("half", thumbnail3);
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions3, "half");
|
||||
checkRenditioned(jpgOrig, "half");
|
||||
checkRendition("half", thumbnail3);
|
||||
outputThumbnailTempContentLocation(thumbnail3, "jpg", "half - 50%x50%");
|
||||
|
||||
|
||||
// ===== half2: 50%x50 from gif =====
|
||||
|
||||
ImageResizeOptions imageResizeOptions4 = new ImageResizeOptions();
|
||||
@@ -169,41 +210,34 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
imageTransformationOptions4.setResizeOptions(imageResizeOptions4);
|
||||
// ThumbnailDetails createOptions4 = new ThumbnailDetails();
|
||||
NodeRef thumbnail4 = this.thumbnailService.createThumbnail(gifOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions4,
|
||||
"half2");
|
||||
checkThumbnailed(gifOrig, "half2");
|
||||
checkThumbnail("half2", thumbnail4);
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions4, "half2");
|
||||
checkRenditioned(gifOrig, "half2");
|
||||
checkRendition("half2", thumbnail4);
|
||||
outputThumbnailTempContentLocation(thumbnail4, "jpg", "half2 - 50%x50%, from gif");
|
||||
}
|
||||
|
||||
public void testDuplicationNames()
|
||||
throws Exception
|
||||
public void testDuplicationNames() throws Exception
|
||||
{
|
||||
checkTransformer();
|
||||
|
||||
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
|
||||
imageResizeOptions.setWidth(64);
|
||||
imageResizeOptions.setHeight(64);
|
||||
imageResizeOptions.setResizeToThumbnail(true);
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
//ThumbnailDetails createOptions = new ThumbnailDetails();
|
||||
// ThumbnailDetails createOptions = new ThumbnailDetails();
|
||||
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions,
|
||||
"small");
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
|
||||
assertNotNull(thumbnail1);
|
||||
checkThumbnailed(jpgOrig, "small");
|
||||
checkThumbnail("small", thumbnail1);
|
||||
checkRenditioned(jpgOrig, "small");
|
||||
checkRendition("small", thumbnail1);
|
||||
|
||||
try
|
||||
{
|
||||
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions,
|
||||
"small");
|
||||
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions, "small");
|
||||
fail("A duplicate exception should have been raised");
|
||||
}
|
||||
catch (ThumbnailException exception)
|
||||
@@ -212,13 +246,12 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
}
|
||||
|
||||
public void testThumbnailUpdate()
|
||||
throws Exception
|
||||
public void testThumbnailUpdate() throws Exception
|
||||
{
|
||||
checkTransformer();
|
||||
|
||||
// First create a thumbnail
|
||||
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
|
||||
imageResizeOptions.setWidth(64);
|
||||
imageResizeOptions.setHeight(64);
|
||||
@@ -226,20 +259,17 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions,
|
||||
"small");
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "small");
|
||||
|
||||
// Update the thumbnail
|
||||
this.thumbnailService.updateThumbnail(thumbnail1, imageTransformationOptions);
|
||||
}
|
||||
|
||||
public void testGetThumbnailByName()
|
||||
throws Exception
|
||||
public void testGetThumbnailByName() throws Exception
|
||||
{
|
||||
checkTransformer();
|
||||
|
||||
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
|
||||
// Check for missing thumbnail
|
||||
NodeRef result1 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "small");
|
||||
@@ -252,46 +282,50 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
imageResizeOptions.setResizeToThumbnail(true);
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions,
|
||||
"small");
|
||||
this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
imageTransformationOptions, "small");
|
||||
|
||||
// Try and retrieve the thumbnail
|
||||
NodeRef result2 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "small");
|
||||
assertNotNull(result2);
|
||||
checkThumbnail("small", result2);
|
||||
checkRendition("small", result2);
|
||||
|
||||
// Check for an other thumbnail that doesn't exist
|
||||
NodeRef result3 = this.thumbnailService.getThumbnailByName(jpgOrig, ContentModel.PROP_CONTENT, "anotherone");
|
||||
assertNull("The thumbnail 'anotherone' should have been missing", result3);
|
||||
}
|
||||
|
||||
// TODO test getThumbnails
|
||||
|
||||
private void checkThumbnailed(NodeRef thumbnailed, String assocName)
|
||||
private void checkRenditioned(NodeRef thumbnailed, String assocName)
|
||||
{
|
||||
assertTrue("Thumbnailed aspect should have been applied", this.nodeService.hasAspect(thumbnailed, ContentModel.ASPECT_THUMBNAILED));
|
||||
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(thumbnailed, RegexQNamePattern.MATCH_ALL, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName));
|
||||
assertTrue("Renditioned aspect should have been applied", this.nodeService.hasAspect(thumbnailed,
|
||||
RenditionModel.ASPECT_RENDITIONED));
|
||||
if (assocName != null)
|
||||
{
|
||||
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(thumbnailed, RegexQNamePattern.MATCH_ALL,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, assocName));
|
||||
assertNotNull(assocs);
|
||||
assertEquals(1, assocs.size());
|
||||
}
|
||||
|
||||
private void checkThumbnail(String thumbnailName, NodeRef thumbnail)
|
||||
{
|
||||
// Check the thumbnail is of the correct type
|
||||
assertEquals(ContentModel.TYPE_THUMBNAIL, this.nodeService.getType(thumbnail));
|
||||
|
||||
// Check the name
|
||||
assertEquals(thumbnailName, this.nodeService.getProperty(thumbnail, ContentModel.PROP_THUMBNAIL_NAME));
|
||||
|
||||
// Check the contet property value
|
||||
assertEquals(ContentModel.PROP_CONTENT, this.nodeService.getProperty(thumbnail, ContentModel.PROP_CONTENT_PROPERTY_NAME));
|
||||
|
||||
}
|
||||
|
||||
private void outputThumbnailTempContentLocation(NodeRef thumbnail, String ext, String message)
|
||||
throws IOException
|
||||
private void checkRendition(String thumbnailName, NodeRef thumbnail)
|
||||
{
|
||||
// Check the thumbnail is of the correct type
|
||||
assertTrue("Thumbnail should have been a rendition",
|
||||
renditionService.isRendition(thumbnail));
|
||||
|
||||
// Check the name
|
||||
if (thumbnailName != null)
|
||||
{
|
||||
assertEquals(thumbnailName, this.nodeService.getProperty(thumbnail, ContentModel.PROP_NAME));
|
||||
}
|
||||
|
||||
// Check the content property value
|
||||
assertEquals(ContentModel.PROP_CONTENT, this.nodeService.getProperty(thumbnail,
|
||||
ContentModel.PROP_CONTENT_PROPERTY_NAME));
|
||||
}
|
||||
|
||||
private void outputThumbnailTempContentLocation(NodeRef thumbnail, String ext, String message) throws IOException
|
||||
{
|
||||
File tempFile = File.createTempFile("thumbnailServiceImpTest", "." + ext);
|
||||
ContentReader reader = this.contentService.getReader(thumbnail, ContentModel.PROP_CONTENT);
|
||||
@@ -299,20 +333,25 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
System.out.println(message + ": " + tempFile.getPath());
|
||||
}
|
||||
|
||||
private NodeRef createOrigionalContent(NodeRef folder, String mimetype)
|
||||
throws IOException
|
||||
/**
|
||||
* This method creates a node under the specified folder whose content is
|
||||
* taken from the quick file corresponding to the specified MIME type.
|
||||
*
|
||||
* @param parentFolder
|
||||
* @param mimetype
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private NodeRef createOriginalContent(NodeRef parentFolder, String mimetype) throws IOException
|
||||
{
|
||||
String ext = this.mimetypeMap.getExtension(mimetype);
|
||||
File origFile = AbstractContentTransformerTest.loadQuickTestFile(ext);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
|
||||
props.put(ContentModel.PROP_NAME, "origional." + ext);
|
||||
NodeRef node = this.nodeService.createNode(
|
||||
folder,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "origional." + ext),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
props).getChildRef();
|
||||
NodeRef node = this.nodeService.createNode(parentFolder, ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "original." + ext),
|
||||
ContentModel.TYPE_CONTENT, props).getChildRef();
|
||||
|
||||
ContentWriter writer = this.contentService.getWriter(node, ContentModel.PROP_CONTENT, true);
|
||||
writer.setMimetype(mimetype);
|
||||
@@ -322,15 +361,17 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
return node;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testAutoUpdate() throws Exception
|
||||
{
|
||||
checkTransformer();
|
||||
|
||||
final NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
final NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
|
||||
ThumbnailDefinition details = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("medium");
|
||||
@SuppressWarnings("unused")
|
||||
final NodeRef thumbnail = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, details.getMimetype(), details.getTransformationOptions(), details.getName());
|
||||
final NodeRef thumbnail = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT, details
|
||||
.getMimetype(), details.getTransformationOptions(), details.getName());
|
||||
|
||||
setComplete();
|
||||
endTransaction();
|
||||
@@ -342,7 +383,8 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
String ext = ThumbnailServiceImplTest.this.mimetypeMap.getExtension(MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
File origFile = AbstractContentTransformerTest.loadQuickTestFile(ext);
|
||||
|
||||
ContentWriter writer = ThumbnailServiceImplTest.this.contentService.getWriter(jpgOrig, ContentModel.PROP_CONTENT, true);
|
||||
ContentWriter writer = ThumbnailServiceImplTest.this.contentService.getWriter(jpgOrig,
|
||||
ContentModel.PROP_CONTENT, true);
|
||||
writer.putContent(origFile);
|
||||
|
||||
return null;
|
||||
@@ -350,24 +392,23 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
});
|
||||
|
||||
// TODO
|
||||
// this test should wait for the async action to run .. will need to commit transaction for that thou!
|
||||
// this test should wait for the async action to run .. will need to
|
||||
// commit transaction for that thou!
|
||||
|
||||
//Thread.sleep(1000);
|
||||
// Thread.sleep(1000);
|
||||
}
|
||||
|
||||
public void testHTMLToImageAndSWF() throws Exception
|
||||
{
|
||||
NodeRef nodeRef = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_HTML);
|
||||
NodeRef nodeRef = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_HTML);
|
||||
ThumbnailDefinition def = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("medium");
|
||||
|
||||
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def.getMimetype(), def.getTransformationOptions()) != null)
|
||||
ContentTransformer transformer = this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def
|
||||
.getMimetype(), def.getTransformationOptions());
|
||||
if (transformer != null)
|
||||
{
|
||||
NodeRef thumb = this.thumbnailService.createThumbnail(
|
||||
nodeRef,
|
||||
ContentModel.PROP_CONTENT,
|
||||
def.getMimetype(),
|
||||
def.getTransformationOptions(),
|
||||
def.getName());
|
||||
NodeRef thumb = this.thumbnailService.createThumbnail(nodeRef, ContentModel.PROP_CONTENT,
|
||||
def.getMimetype(), def.getTransformationOptions(), def.getName());
|
||||
assertNotNull(thumb);
|
||||
ContentReader reader = this.contentService.getReader(thumb, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(reader);
|
||||
@@ -375,16 +416,11 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
assertTrue(reader.getSize() != 0);
|
||||
}
|
||||
|
||||
|
||||
def = this.thumbnailService.getThumbnailRegistry().getThumbnailDefinition("webpreview");
|
||||
if (this.contentService.getTransformer(MimetypeMap.MIMETYPE_HTML, def.getMimetype(), def.getTransformationOptions()) != null)
|
||||
if (transformer != null)
|
||||
{
|
||||
NodeRef thumb = this.thumbnailService.createThumbnail(
|
||||
nodeRef,
|
||||
ContentModel.PROP_CONTENT,
|
||||
def.getMimetype(),
|
||||
def.getTransformationOptions(),
|
||||
def.getName());
|
||||
NodeRef thumb = this.thumbnailService.createThumbnail(nodeRef, ContentModel.PROP_CONTENT,
|
||||
def.getMimetype(), def.getTransformationOptions(), def.getName());
|
||||
assertNotNull(thumb);
|
||||
ContentReader reader = this.contentService.getReader(thumb, ContentModel.PROP_CONTENT);
|
||||
assertNotNull(reader);
|
||||
@@ -393,10 +429,89 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
}
|
||||
|
||||
public void testThumbnailServiceCreateApi() throws Exception
|
||||
{
|
||||
// Create a second folder
|
||||
Map<QName, Serializable> folderProps = new HashMap<QName, Serializable>();
|
||||
folderProps.put(ContentModel.PROP_NAME, "otherTestFolder");
|
||||
NodeRef otherFolder = this.nodeService.createNode(this.rootNodeRef, ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "otherTestFolder"), ContentModel.TYPE_FOLDER)
|
||||
.getChildRef();
|
||||
|
||||
checkTransformer();
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
|
||||
ImageResizeOptions imageResizeOptions = new ImageResizeOptions();
|
||||
imageResizeOptions.setWidth(64);
|
||||
imageResizeOptions.setHeight(64);
|
||||
imageResizeOptions.setResizeToThumbnail(true);
|
||||
ImageTransformationOptions imageTransformationOptions = new ImageTransformationOptions();
|
||||
imageTransformationOptions.setResizeOptions(imageResizeOptions);
|
||||
|
||||
// Create thumbnail - same MIME type
|
||||
NodeRef thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG, imageTransformationOptions, "smallJpeg");
|
||||
assertNotNull(thumbnail1);
|
||||
checkRenditioned(jpgOrig, "smallJpeg");
|
||||
checkRendition("smallJpeg", thumbnail1);
|
||||
outputThumbnailTempContentLocation(thumbnail1, "jpg", "smallJpeg - 64x64, marked as thumbnail");
|
||||
|
||||
// Create thumbnail - different MIME type
|
||||
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "smallPng");
|
||||
assertNotNull(thumbnail1);
|
||||
checkRenditioned(jpgOrig, "smallPng");
|
||||
checkRendition("smallPng", thumbnail1);
|
||||
outputThumbnailTempContentLocation(thumbnail1, "png", "smallPng - 64x64, marked as thumbnail");
|
||||
|
||||
// Create thumbnail - different content property
|
||||
// TODO
|
||||
|
||||
// Create thumbnail - different command options
|
||||
// We'll pass illegal command options to ImageMagick in order to trigger an exception
|
||||
Exception x = null;
|
||||
try
|
||||
{
|
||||
imageTransformationOptions.setCommandOptions("-noSuchOption");
|
||||
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "smallCO");
|
||||
} catch (ContentIOException ciox)
|
||||
{
|
||||
x = ciox;
|
||||
ciox.printStackTrace();
|
||||
}
|
||||
assertNotNull("Expected exception from ImageMagick due to invalid option", x);
|
||||
// Reset the command options
|
||||
imageTransformationOptions.setCommandOptions("");
|
||||
|
||||
|
||||
// Create thumbnail - different target assoc details
|
||||
ThumbnailParentAssociationDetails tpad
|
||||
= new ThumbnailParentAssociationDetails(otherFolder,
|
||||
QName.createQName(NamespaceService.RENDITION_MODEL_1_0_URI, "foo"),
|
||||
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "bar"));
|
||||
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, "targetDetails", tpad);
|
||||
assertNotNull(thumbnail1);
|
||||
checkRenditioned(jpgOrig, "targetDetails");
|
||||
checkRendition("targetDetails", thumbnail1);
|
||||
outputThumbnailTempContentLocation(thumbnail1, "png", "targetDetails - 64x64, marked as thumbnail");
|
||||
|
||||
|
||||
|
||||
// Create thumbnail - null thumbnail name
|
||||
thumbnail1 = this.thumbnailService.createThumbnail(jpgOrig, ContentModel.PROP_CONTENT,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG, imageTransformationOptions, null);
|
||||
assertNotNull(thumbnail1);
|
||||
checkRenditioned(jpgOrig, null);
|
||||
checkRendition(null, thumbnail1);
|
||||
outputThumbnailTempContentLocation(thumbnail1, "png", "'null' - 64x64, marked as thumbnail");
|
||||
}
|
||||
|
||||
public void testRegistry()
|
||||
{
|
||||
ThumbnailRegistry thumbnailRegistry = this.thumbnailService.getThumbnailRegistry();
|
||||
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumnailDefintions(MimetypeMap.MIMETYPE_HTML);
|
||||
List<ThumbnailDefinition> defs = thumbnailRegistry.getThumbnailDefinitions(MimetypeMap.MIMETYPE_HTML);
|
||||
System.out.println("Definitions ...");
|
||||
for (ThumbnailDefinition def : defs)
|
||||
{
|
||||
@@ -404,16 +519,14 @@ public class ThumbnailServiceImplTest extends BaseAlfrescoSpringTest
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// == Test the JavaScript API ==
|
||||
|
||||
public void testJSAPI() throws Exception
|
||||
{
|
||||
NodeRef jpgOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef gifOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
|
||||
NodeRef pdfOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
|
||||
NodeRef docOrig = createOrigionalContent(this.folder, MimetypeMap.MIMETYPE_WORD);
|
||||
NodeRef jpgOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_JPEG);
|
||||
NodeRef gifOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_IMAGE_GIF);
|
||||
NodeRef pdfOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_PDF);
|
||||
NodeRef docOrig = createOriginalContent(this.folder, MimetypeMap.MIMETYPE_WORD);
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>(2);
|
||||
model.put("jpgOrig", jpgOrig);
|
||||
|
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.thumbnail;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.copy.CopyBehaviourCallback;
|
||||
import org.alfresco.repo.copy.CopyDetails;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies;
|
||||
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.Behaviour;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.action.CompositeAction;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
|
||||
/**
|
||||
* Thumbnailed aspect behaviour bean
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public class ThumbnailedAspect implements NodeServicePolicies.OnUpdatePropertiesPolicy,
|
||||
CopyServicePolicies.OnCopyNodePolicy
|
||||
{
|
||||
/** Services */
|
||||
private PolicyComponent policyComponent;
|
||||
private ThumbnailService thumbnailService;
|
||||
private ActionService actionService;
|
||||
private NodeService nodeService;
|
||||
private DictionaryService dictionaryService;
|
||||
|
||||
/**
|
||||
* Set the policy component
|
||||
*
|
||||
* @param policyComponent policy component
|
||||
*/
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action service
|
||||
*
|
||||
* @param actionService action service
|
||||
*/
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thumbnail service
|
||||
*
|
||||
* @param thumbnailService thumbnail service
|
||||
*/
|
||||
public void setThumbnailService(ThumbnailService thumbnailService)
|
||||
{
|
||||
this.thumbnailService = thumbnailService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dictionary service
|
||||
*
|
||||
* @param dictionaryService dictionary service
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise method
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),
|
||||
ContentModel.ASPECT_THUMBNAILED,
|
||||
new JavaBehaviour(this, "onUpdateProperties", Behaviour.NotificationFrequency.TRANSACTION_COMMIT));
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "getCopyCallback"),
|
||||
ContentModel.ASPECT_THUMBNAILED,
|
||||
new JavaBehaviour(this, "getCopyCallback"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy#onUpdateProperties(org.alfresco.service.cmr.repository.NodeRef, java.util.Map, java.util.Map)
|
||||
*/
|
||||
public void onUpdateProperties(
|
||||
NodeRef nodeRef,
|
||||
Map<QName, Serializable> before,
|
||||
Map<QName, Serializable> after)
|
||||
{
|
||||
// Ignore working copies
|
||||
if (this.nodeService.exists(nodeRef) == true &&
|
||||
this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY) == false)
|
||||
{
|
||||
// check if any of the content properties have changed
|
||||
for (QName propertyQName : after.keySet())
|
||||
{
|
||||
// is this a content property?
|
||||
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
|
||||
if (propertyDef == null)
|
||||
{
|
||||
// the property is not recognised
|
||||
continue;
|
||||
}
|
||||
if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
|
||||
{
|
||||
// not a content type
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ContentData beforeValue = (ContentData) before.get(propertyQName);
|
||||
ContentData afterValue = (ContentData) after.get(propertyQName);
|
||||
|
||||
// Figure out if the content is new or not
|
||||
boolean newContent = false;
|
||||
String beforeContentUrl = null;
|
||||
if (beforeValue != null)
|
||||
{
|
||||
beforeContentUrl = beforeValue.getContentUrl();
|
||||
}
|
||||
String afterContentUrl = null;
|
||||
if (afterValue != null)
|
||||
{
|
||||
afterContentUrl = afterValue.getContentUrl();
|
||||
}
|
||||
if (beforeContentUrl == null && afterContentUrl != null)
|
||||
{
|
||||
newContent = true;
|
||||
}
|
||||
|
||||
if (afterValue != null && afterValue.getContentUrl() == null)
|
||||
{
|
||||
// no URL - ignore
|
||||
}
|
||||
else if (newContent == false && EqualsHelper.nullSafeEquals(beforeValue, afterValue) == false)
|
||||
{
|
||||
// Queue the update
|
||||
queueUpdate(nodeRef, propertyQName);
|
||||
}
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
// properties don't conform to model
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue the update to happen asynchronously
|
||||
*
|
||||
* @param nodeRef node reference
|
||||
* @param contentProperty content property
|
||||
*/
|
||||
private void queueUpdate(NodeRef nodeRef, QName contentProperty)
|
||||
{
|
||||
Boolean automaticUpdate = (Boolean)this.nodeService.getProperty(nodeRef, ContentModel.PROP_AUTOMATIC_UPDATE);
|
||||
if (automaticUpdate != null && automaticUpdate.booleanValue() == true)
|
||||
{
|
||||
CompositeAction compositeAction = actionService.createCompositeAction();
|
||||
List<NodeRef> thumbnails = this.thumbnailService.getThumbnails(nodeRef, contentProperty, null, null);
|
||||
|
||||
for (NodeRef thumbnail : thumbnails)
|
||||
{
|
||||
// Execute the update thumbnail action async for each thumbnail
|
||||
Action action = actionService.createAction(UpdateThumbnailActionExecuter.NAME);
|
||||
action.setParameterValue(UpdateThumbnailActionExecuter.PARAM_CONTENT_PROPERTY, contentProperty);
|
||||
action.setParameterValue(UpdateThumbnailActionExecuter.PARAM_THUMBNAIL_NODE, thumbnail);
|
||||
compositeAction.addAction(action);
|
||||
}
|
||||
|
||||
actionService.executeAction(compositeAction, nodeRef, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns {@link ThumbnailedAspectCopyBehaviourCallback}
|
||||
*/
|
||||
public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
|
||||
{
|
||||
return ThumbnailedAspectCopyBehaviourCallback.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaviour for the {@link ContentModel#ASPECT_THUMBNAILED <b>cm:thumbnailed</b>} aspect.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
private static class ThumbnailedAspectCopyBehaviourCallback extends DefaultCopyBehaviourCallback
|
||||
{
|
||||
private static final CopyBehaviourCallback INSTANCE = new ThumbnailedAspectCopyBehaviourCallback();
|
||||
|
||||
/**
|
||||
* @return Returns <tt>true</tt> always
|
||||
*/
|
||||
@Override
|
||||
public boolean getMustCopy(QName classQName, CopyDetails copyDetails)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy thumbnail-related associations, {@link ContentModel#ASSOC_THUMBNAILS} regardless of
|
||||
* cascade options.
|
||||
*/
|
||||
@Override
|
||||
public ChildAssocCopyAction getChildAssociationCopyAction(
|
||||
QName classQName,
|
||||
CopyDetails copyDetails,
|
||||
CopyChildAssociationDetails childAssocCopyDetails)
|
||||
{
|
||||
ChildAssociationRef childAssocRef = childAssocCopyDetails.getChildAssocRef();
|
||||
if (childAssocRef.getTypeQName().equals(ContentModel.ASSOC_THUMBNAILS))
|
||||
{
|
||||
return ChildAssocCopyAction.COPY_CHILD;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"Behaviour should have been invoked: \n" +
|
||||
" Aspect: " + this.getClass().getName() + "\n" +
|
||||
" " + childAssocCopyDetails + "\n" +
|
||||
" " + copyDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy only the {@link ContentModel#PROP_AUTOMATIC_UPDATE}
|
||||
*/
|
||||
@Override
|
||||
public Map<QName, Serializable> getCopyProperties(
|
||||
QName classQName,
|
||||
CopyDetails copyDetails,
|
||||
Map<QName, Serializable> properties)
|
||||
{
|
||||
Map<QName, Serializable> newProperties = new HashMap<QName, Serializable>(5);
|
||||
Serializable value = properties.get(ContentModel.PROP_AUTOMATIC_UPDATE);
|
||||
newProperties.put(ContentModel.PROP_AUTOMATIC_UPDATE, value);
|
||||
return newProperties;
|
||||
}
|
||||
}
|
||||
}
|
@@ -27,20 +27,31 @@ import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.rendition.RenditionService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Update thumbnail action executer.
|
||||
*
|
||||
* NOTE: This action is used to facilitate the async update of thumbnails. It is not intended for genereral usage.
|
||||
* NOTE: This action is used to facilitate the async update of thumbnails. It is not intended for general usage.
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(UpdateThumbnailActionExecuter.class);
|
||||
|
||||
/** Rendition Service */
|
||||
private RenditionService renditionService;
|
||||
|
||||
/** Thumbnail Service */
|
||||
private ThumbnailService thumbnailService;
|
||||
|
||||
@@ -52,6 +63,16 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
|
||||
public static final String PARAM_CONTENT_PROPERTY = "content-property";
|
||||
public static final String PARAM_THUMBNAIL_NODE = "thumbnail-node";
|
||||
|
||||
/**
|
||||
* Injects the rendition service.
|
||||
*
|
||||
* @param renditionService the rendition service.
|
||||
*/
|
||||
public void setRenditionService(RenditionService renditionService)
|
||||
{
|
||||
this.renditionService = renditionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thumbnail service
|
||||
*
|
||||
@@ -86,17 +107,17 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
|
||||
}
|
||||
|
||||
if (this.nodeService.exists(thumbnailNodeRef) == true &&
|
||||
ContentModel.TYPE_THUMBNAIL.equals(this.nodeService.getType(thumbnailNodeRef)) == true)
|
||||
renditionService.isRendition(thumbnailNodeRef))
|
||||
{
|
||||
// Get the thumbnail Name
|
||||
String thumbnailName = (String)this.nodeService.getProperty(thumbnailNodeRef, ContentModel.PROP_THUMBNAIL_NAME);
|
||||
ChildAssociationRef parent = renditionService.getSourceNode(thumbnailNodeRef);
|
||||
String thumbnailName = parent.getQName().getLocalName();
|
||||
|
||||
// Get the details of the thumbnail
|
||||
ThumbnailRegistry registry = this.thumbnailService.getThumbnailRegistry();
|
||||
ThumbnailDefinition details = registry.getThumbnailDefinition(thumbnailName);
|
||||
if (details == null)
|
||||
{
|
||||
// Throw exception
|
||||
throw new AlfrescoRuntimeException("The thumbnail name '" + thumbnailName + "' is not registered");
|
||||
}
|
||||
|
||||
@@ -121,5 +142,4 @@ public class UpdateThumbnailActionExecuter extends ActionExecuterAbstractBase
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_CONTENT_PROPERTY, DataTypeDefinition.QNAME, false, getParamDisplayLabel(PARAM_CONTENT_PROPERTY)));
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_THUMBNAIL_NODE, DataTypeDefinition.QNAME, false, getParamDisplayLabel(PARAM_THUMBNAIL_NODE)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -18,20 +18,31 @@
|
||||
*/
|
||||
package org.alfresco.repo.thumbnail.script;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.repo.jscript.ScriptNode;
|
||||
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* @author Roy Wetherall
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class ScriptThumbnail extends ScriptNode
|
||||
{
|
||||
private static final long serialVersionUID = 7854749986083635678L;
|
||||
|
||||
/** Logger */
|
||||
private static Log logger = LogFactory.getLog(ScriptThumbnail.class);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -49,7 +60,25 @@ public class ScriptThumbnail extends ScriptNode
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
String name = (String)services.getNodeService().getProperty(nodeRef, ContentModel.PROP_THUMBNAIL_NAME);
|
||||
List<ChildAssociationRef> parentRefs = services.getNodeService().getParentAssocs(nodeRef, RenditionModel.ASSOC_RENDITION, RegexQNamePattern.MATCH_ALL);
|
||||
// There should in fact only ever be one parent association of type rendition on any rendition node.
|
||||
if (parentRefs.size() != 1)
|
||||
{
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Node ")
|
||||
.append(nodeRef)
|
||||
.append(" has ")
|
||||
.append(parentRefs.size())
|
||||
.append(" rendition parents. Unable to update.");
|
||||
if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn(msg.toString());
|
||||
}
|
||||
throw new AlfrescoRuntimeException(msg.toString());
|
||||
}
|
||||
|
||||
String name = parentRefs.get(0).getQName().getLocalName();
|
||||
|
||||
ThumbnailDefinition def = services.getThumbnailService().getThumbnailRegistry().getThumbnailDefinition(name);
|
||||
services.getThumbnailService().updateThumbnail(this.nodeRef, def.getTransformationOptions());
|
||||
}
|
||||
|
100
source/java/org/alfresco/service/cmr/action/ActionList.java
Normal file
100
source/java/org/alfresco/service/cmr/action/ActionList.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.service.cmr.action;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface ActionList<A extends Action> extends Serializable
|
||||
{
|
||||
/**
|
||||
* Indicates whether there are any actions
|
||||
*
|
||||
* @return true if there are actions, false otherwise
|
||||
*/
|
||||
boolean hasActions();
|
||||
|
||||
/**
|
||||
* Add an action to the end of the list
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
void addAction(A action);
|
||||
|
||||
/**
|
||||
* Add an action to the list at the index specified
|
||||
*
|
||||
* @param index the index
|
||||
* @param action the action
|
||||
*/
|
||||
void addAction(int index, A action);
|
||||
|
||||
/**
|
||||
* Replace the action at the specfied index with the passed action.
|
||||
*
|
||||
* @param index the index
|
||||
* @param action the action
|
||||
*/
|
||||
void setAction(int index, A action);
|
||||
|
||||
/**
|
||||
* Gets the index of an action
|
||||
*
|
||||
* @param action the action
|
||||
* @return the index
|
||||
*/
|
||||
int indexOfAction(A action);
|
||||
|
||||
/**
|
||||
* Get list containing the actions in their current order
|
||||
*
|
||||
* @return the list of actions
|
||||
*/
|
||||
List<A> getActions();
|
||||
|
||||
/**
|
||||
* Get an action at a given index
|
||||
*
|
||||
* @param index the index
|
||||
* @return the action
|
||||
*/
|
||||
A getAction(int index);
|
||||
|
||||
/**
|
||||
* Remove an action from the list
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
void removeAction(A action);
|
||||
|
||||
/**
|
||||
* Remove all actions from the list
|
||||
*/
|
||||
void removeAllActions();
|
||||
}
|
@@ -16,79 +16,15 @@
|
||||
* 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.service.cmr.action;
|
||||
|
||||
import java.util.List;
|
||||
package org.alfresco.service.cmr.action;
|
||||
|
||||
/**
|
||||
* Composite action
|
||||
*
|
||||
* @author Roy Wetherall
|
||||
*/
|
||||
public interface CompositeAction extends Action
|
||||
public interface CompositeAction extends Action, ActionList<Action>
|
||||
{
|
||||
/**
|
||||
* Indicates whether there are any actions
|
||||
*
|
||||
* @return true if there are actions, false otherwise
|
||||
*/
|
||||
boolean hasActions();
|
||||
|
||||
/**
|
||||
* Add an action to the end of the list
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
void addAction(Action action);
|
||||
|
||||
/**
|
||||
* Add an action to the list at the index specified
|
||||
*
|
||||
* @param index the index
|
||||
* @param action the action
|
||||
*/
|
||||
void addAction(int index, Action action);
|
||||
|
||||
/**
|
||||
* Replace the action at the specfied index with the passed action.
|
||||
*
|
||||
* @param index the index
|
||||
* @param action the action
|
||||
*/
|
||||
void setAction(int index, Action action);
|
||||
|
||||
/**
|
||||
* Gets the index of an action
|
||||
*
|
||||
* @param action the action
|
||||
* @return the index
|
||||
*/
|
||||
int indexOfAction(Action action);
|
||||
|
||||
/**
|
||||
* Get list containing the actions in their current order
|
||||
*
|
||||
* @return the list of actions
|
||||
*/
|
||||
List<Action> getActions();
|
||||
|
||||
/**
|
||||
* Get an action at a given index
|
||||
*
|
||||
* @param index the index
|
||||
* @return the action
|
||||
*/
|
||||
Action getAction(int index);
|
||||
|
||||
/**
|
||||
* Remove an action from the list
|
||||
*
|
||||
* @param action the action
|
||||
*/
|
||||
void removeAction(Action action);
|
||||
|
||||
/**
|
||||
* Remove all actions from the list
|
||||
*/
|
||||
void removeAllActions();
|
||||
}
|
||||
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.action.ActionList;
|
||||
|
||||
/**
|
||||
* This is a special {@link RenditionDefinition} which allows sequential
|
||||
* execution of a list of other {@link RenditionDefinition}s. For example, it
|
||||
* might be used to transform a PDF file to a JPEG imaged and then resize that
|
||||
* image. This would be achieved by creating a
|
||||
* {@link CompositeRenditionDefinition} that has two sub-definitions, one to
|
||||
* reformat the PDF to a JPEG image and the second to resize the JPEG image.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface CompositeRenditionDefinition extends RenditionDefinition, ActionList<RenditionDefinition>
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* This interface defines a strategy object used for finding a {@link NodeRef}.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface NodeLocator
|
||||
{
|
||||
/**
|
||||
* Finds a {@link NodeRef} given a starting {@link NodeRef} and a
|
||||
* {@link Map} of parameters.
|
||||
*
|
||||
* @param sourceNode the starting point for locating a new node.
|
||||
* @param params a {@link Map} of parameters.
|
||||
* @return the {@link NodeRef}.
|
||||
*/
|
||||
NodeRef getNode(NodeRef sourceNode, Map<String, Serializable> params);
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
|
||||
/**
|
||||
* This interface defines a callback object which can be used to handle the ultimate
|
||||
* result of asynchronous renditions.
|
||||
*
|
||||
* @author Neil McErlean
|
||||
* @see RenditionService#render(org.alfresco.service.cmr.repository.NodeRef, RenditionDefinition, RenderCallback)
|
||||
*/
|
||||
public interface RenderCallback
|
||||
{
|
||||
/**
|
||||
* This callback method will be called upon successful completion of an asynchronous
|
||||
* rendition.
|
||||
* @param primaryParentOfNewRendition a ChildAssociationRef linking the new rendition
|
||||
* object to its primary parent.
|
||||
*/
|
||||
void handleSuccessfulRendition(ChildAssociationRef primaryParentOfNewRendition);
|
||||
|
||||
/**
|
||||
* This callback method will be called upon unsuccessful completion of an
|
||||
* asynchronous rendition.
|
||||
* @param t the Throwable giving the cause of the rendition failure.
|
||||
*/
|
||||
void handleFailedRendition(Throwable t);
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||
|
||||
/**
|
||||
* This class describes a rendering engine and defines what parameters can/must
|
||||
* be specified for that rendering engine.
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface RenderingEngineDefinition extends ActionDefinition
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* This class is used to fully specify a type of rendition. It specifies which
|
||||
* rendering engine will be used as well as the parameters that will be given to
|
||||
* that engine.
|
||||
* <P/>
|
||||
* Every RenditionDefinition has a <code>renditionName</code> attribute which
|
||||
* uniquely identifies it.
|
||||
*
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public interface RenditionDefinition extends Action, Serializable
|
||||
{
|
||||
/**
|
||||
* @return the name which uniquely identifies this rendering action.
|
||||
*/
|
||||
public QName getRenditionName();
|
||||
|
||||
/**
|
||||
* Returns the node to which the rendition is linked when it is first
|
||||
* created. Typically this location is only temporary temporary as the
|
||||
* rendition will be moved to a different location by the
|
||||
* {@link RenditionService} shortly after its creation.
|
||||
*
|
||||
* @return the renditionParent
|
||||
*/
|
||||
public NodeRef getRenditionParent();
|
||||
|
||||
/**
|
||||
* Sets the node to which the rendition is linked when it is first created.
|
||||
* Typically this location is only temporary temporary as the rendition will
|
||||
* be moved to a different location by the {@link RenditionService} shortly
|
||||
* after its creation.
|
||||
*
|
||||
* @param renditionParent the renditionParent to set
|
||||
*/
|
||||
public void setRenditionParent(NodeRef renditionParent);
|
||||
|
||||
/**
|
||||
* Returns the association type used to link the rendition to its parent
|
||||
* node after it has been newly created. Typically this association is only
|
||||
* temporary as the rendition will be moved to a different location by the
|
||||
* {@link RenditionService} shortly after its creation.
|
||||
*
|
||||
* @return the renditionAssociationType
|
||||
*/
|
||||
public QName getRenditionAssociationType();
|
||||
|
||||
/**
|
||||
* Sets the association type used to link the rendition to its parent node
|
||||
* after it has been newly created. Typically this association is only
|
||||
* temporary as the rendition will be moved to a different location by the
|
||||
* {@link RenditionService} shortly after its creation.
|
||||
*
|
||||
* @param renditionAssociationType the renditionAssociationType to set
|
||||
*/
|
||||
public void setRenditionAssociationType(QName renditionAssociationType);
|
||||
|
||||
/**
|
||||
* This method sets a callback object for use in asynchronous renditions. It is
|
||||
* this object that will be notified of the successful or unsuccessful completion
|
||||
* of these renditions.
|
||||
*
|
||||
* @param callback a callback object, which may be null.
|
||||
*/
|
||||
public void setCallback(RenderCallback callback);
|
||||
|
||||
/**
|
||||
* This method gets the registered callback object for use with asynchronous
|
||||
* renditions.
|
||||
*
|
||||
* @return the callback object
|
||||
*/
|
||||
public RenderCallback getCallback();
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.rendition.RenditionDefinitionPersister;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public interface RenditionService extends RenditionDefinitionPersister
|
||||
{
|
||||
public static final String PARAM_DESTINATION_NODE = "rendition-destination-node";
|
||||
public static final String PARAM_DESTINATION_PATH_TEMPLATE = "destination-path-template";
|
||||
public static final String PARAM_RENDITION_NODETYPE = "rendition-nodetype";
|
||||
public static final String PARAM_ORPHAN_EXISTING_RENDITION = "orphan-existing-rendition";
|
||||
|
||||
/**
|
||||
* Returns the {@link RenderingEngineDefinition} associated with the
|
||||
* specified rendering engine name.
|
||||
*
|
||||
* @param name The rendering engine name.
|
||||
* @return The {@link RenderingEngineDefinition} or null.
|
||||
*/
|
||||
RenderingEngineDefinition getRenderingEngineDefinition(String name);
|
||||
|
||||
/**
|
||||
* @return A {@link List} of all available {@link RenderingEngineDefinition}
|
||||
* s.
|
||||
*/
|
||||
List<RenderingEngineDefinition> getRenderingEngineDefinitions();
|
||||
|
||||
/**
|
||||
* Creates a new {@link RenditionDefinition} and sets the rendition name and
|
||||
* the rendering engine name to the specified values.
|
||||
*
|
||||
* @param renditionName A unique identifier used to specify the created
|
||||
* {@link RenditionDefinition}.
|
||||
* @param renderingEngineName The name of the rendering engine associated
|
||||
* with this {@link RenditionDefinition}.
|
||||
* @return the created {@link RenditionDefinition}.
|
||||
*/
|
||||
RenditionDefinition createRenditionDefinition(QName renditionName, String renderingEngineName);
|
||||
|
||||
/**
|
||||
* Creates a new {@link CompositeRenditionDefinition} and sets the rendition
|
||||
* name and the rendering engine name to the specified values.
|
||||
*
|
||||
* @param renditionName A unique identifier used to specify the created
|
||||
* {@link RenditionDefinition}.
|
||||
* @return the created {@link CompositeRenditionDefinition}.
|
||||
*/
|
||||
CompositeRenditionDefinition createCompositeRenditionDefinition(QName renditionName);
|
||||
|
||||
/**
|
||||
* This method gets all the renditions of the specified node.
|
||||
*
|
||||
* @return a list of ChildAssociationRefs which link the source node to the
|
||||
* renditions.
|
||||
*/
|
||||
List<ChildAssociationRef> getRenditions(NodeRef node);
|
||||
|
||||
/**
|
||||
* This method gets all the renditions of the specified node filtered by
|
||||
* MIME-type prefix. Renditions whose MIME-type string startsWith the prefix
|
||||
* will be returned.
|
||||
*
|
||||
* @param node the source node for the renditions
|
||||
* @param mimeTypePrefix a prefix to check against the rendition MIME-types.
|
||||
* This must not be null and must not be an empty String
|
||||
* @return a list of ChildAssociationRefs which link the source node to the
|
||||
* filtered renditions.
|
||||
*/
|
||||
List<ChildAssociationRef> getRenditions(NodeRef node, String mimeTypePrefix);
|
||||
|
||||
/**
|
||||
* This method gets the rendition of the specified node identified by
|
||||
* the provided rendition name.
|
||||
*
|
||||
* @param node the source node for the renditions
|
||||
* @param renditionName the renditionName used to identify a rendition.
|
||||
* @return the ChildAssociationRef which links the source node to the
|
||||
* rendition or <code>null</code> if there is no such rendition.
|
||||
*/
|
||||
ChildAssociationRef getRenditionByName(NodeRef node, QName renditionName);
|
||||
|
||||
/**
|
||||
* This method returns <code>true</code> if the specified NodeRef is a valid
|
||||
* rendition node, else <code>false</code>. A nodeRef is a rendition node
|
||||
* if it has the rn:rendition aspect (or sub-aspect) applied.
|
||||
*
|
||||
* @param node
|
||||
* @return <code>true</code> if a rendition, else <code>false</code>
|
||||
*/
|
||||
boolean isRendition(NodeRef node);
|
||||
|
||||
/**
|
||||
* This method gets the source node for the specified rendition node. There
|
||||
* should only be one source node for any given rendition node.
|
||||
*
|
||||
* @param renditionNode the nodeRef holding the rendition.
|
||||
* @return the ChildAssociationRef whose parentNodeRef is the source node, or
|
||||
* <code>null</code> if there is no source node.
|
||||
*
|
||||
* @see RenditionService#isRendition(NodeRef)
|
||||
*/
|
||||
ChildAssociationRef getSourceNode(NodeRef renditionNode);
|
||||
|
||||
//TODO The result should be the link to the primary parent.
|
||||
/**
|
||||
* This method synchronously renders content as specified by the given
|
||||
* {@link RenditionDefinition}. The content to be rendered is provided by
|
||||
* the specified source node.
|
||||
*
|
||||
* @param sourceNode the node from which the content is retrieved.
|
||||
* @param renditionDefinition this fully specifies the rendition which is to
|
||||
* be performed.
|
||||
* @return a child association reference which is the link from the source
|
||||
* node to the newly rendered content.
|
||||
* @throws RenditionServiceException if there is a problem in rendering the
|
||||
* given sourceNode
|
||||
*/
|
||||
ChildAssociationRef render(NodeRef sourceNode, RenditionDefinition renditionDefinition);
|
||||
|
||||
/**
|
||||
* This method asynchronously renders content as specified by the given
|
||||
* {@link RenditionDefinition}. The content to be rendered is provided by
|
||||
* the specified source node.
|
||||
*
|
||||
* @param sourceNode the node from which the content is retrieved.
|
||||
* @param renditionDefinition this fully specifies the rendition which is to
|
||||
* be performed.
|
||||
* @param callback a callback object to handle the ultimate result of the rendition.
|
||||
*/
|
||||
void render(NodeRef sourceNode, RenditionDefinition renditionDefinition,
|
||||
RenderCallback callback);
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 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.service.cmr.rendition;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* Rendition Service Exception Class
|
||||
*
|
||||
* @author Neil McErlean
|
||||
*/
|
||||
public class RenditionServiceException extends AlfrescoRuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -6947067735970465937L;
|
||||
|
||||
/**
|
||||
* Constructs a Rendition Service Exception with the specified message.
|
||||
*
|
||||
* @param message the message string
|
||||
*/
|
||||
public RenditionServiceException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Rendition Service Exception with the specified message and source exception.
|
||||
*
|
||||
* @param message the message string
|
||||
* @param source the source exception
|
||||
*/
|
||||
public RenditionServiceException(String message, Throwable source)
|
||||
{
|
||||
super(message, source);
|
||||
}
|
||||
}
|
@@ -88,6 +88,9 @@ public interface NamespaceService extends NamespacePrefixResolver
|
||||
/** Alfresco Forums Prefix */
|
||||
static final String FORUMS_MODEL_PREFIX = "fm";
|
||||
|
||||
/** Rendition Model URI */
|
||||
static final String RENDITION_MODEL_1_0_URI = "http://www.alfresco.org/model/rendition/1.0";
|
||||
|
||||
/** Alfresco View Namespace URI */
|
||||
static final String REPOSITORY_VIEW_1_0_URI = "http://www.alfresco.org/view/repository/1.0";
|
||||
|
||||
|
66
source/java/org/alfresco/util/FreeMarkerUtil.java
Normal file
66
source/java/org/alfresco/util/FreeMarkerUtil.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.LinkedList;
|
||||
import javax.xml.XMLConstants;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* FreeMarker utility functions.
|
||||
*
|
||||
* @author Ariel Backenroth
|
||||
*/
|
||||
public class FreeMarkerUtil
|
||||
{
|
||||
public static String buildNamespaceDeclaration(final Document xml)
|
||||
{
|
||||
final Element docEl = xml.getDocumentElement();
|
||||
final NamedNodeMap attributes = docEl.getAttributes();
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < attributes.getLength(); i++)
|
||||
{
|
||||
final Node a = attributes.item(i);
|
||||
if (a.getNodeName().startsWith(XMLConstants.XMLNS_ATTRIBUTE))
|
||||
{
|
||||
final String prefix = a.getNodeName().substring((XMLConstants.XMLNS_ATTRIBUTE + ":").length());
|
||||
final String uri = a.getNodeValue();
|
||||
if (result.length() != 0)
|
||||
{
|
||||
result.append(",\n");
|
||||
}
|
||||
result.append("\"").append(prefix).append("\":\"").append(uri).append("\"");
|
||||
}
|
||||
}
|
||||
return "<#ftl ns_prefixes={\n" + result.toString() + "}>\n";
|
||||
}
|
||||
}
|
281
source/java/org/alfresco/util/XMLUtil.java
Normal file
281
source/java/org/alfresco/util/XMLUtil.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2008 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing" */
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.io.*;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.avm.AVMService;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* XML utility functions.
|
||||
*
|
||||
* @author Ariel Backenroth
|
||||
*/
|
||||
public class XMLUtil
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(XMLUtil.class);
|
||||
|
||||
/** utility function for creating a document */
|
||||
public static Document newDocument()
|
||||
{
|
||||
return XMLUtil.getDocumentBuilder().newDocument();
|
||||
}
|
||||
|
||||
/** utility function for serializing a node */
|
||||
public static void print(final Node n, final Writer output)
|
||||
{
|
||||
XMLUtil.print(n, output, true);
|
||||
}
|
||||
|
||||
/** utility function for serializing a node */
|
||||
public static void print(final Node n, final Writer output, final boolean indent)
|
||||
{
|
||||
try
|
||||
{
|
||||
final TransformerFactory tf = TransformerFactory.newInstance();
|
||||
final Transformer t = tf.newTransformer();
|
||||
t.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no");
|
||||
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||
t.setOutputProperty(OutputKeys.METHOD, "xml");
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
LOGGER.debug("writing out a document for " +
|
||||
(n instanceof Document
|
||||
? ((Document)n).getDocumentElement()
|
||||
: n).getNodeName() +
|
||||
" to " + (output instanceof StringWriter
|
||||
? "string"
|
||||
: output));
|
||||
}
|
||||
t.transform(new DOMSource(n), new StreamResult(output));
|
||||
}
|
||||
catch (TransformerException te)
|
||||
{
|
||||
te.printStackTrace();
|
||||
assert false : te.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/** utility function for serializing a node */
|
||||
public static void print(final Node n, final File output)
|
||||
throws IOException
|
||||
{
|
||||
XMLUtil.print(n, new FileWriter(output));
|
||||
}
|
||||
|
||||
/** utility function for serializing a node */
|
||||
public static String toString(final Node n)
|
||||
{
|
||||
return XMLUtil.toString(n, true);
|
||||
}
|
||||
|
||||
/** utility function for serializing a node */
|
||||
public static String toString(final Node n, final boolean indent)
|
||||
{
|
||||
final StringWriter result = new StringWriter();
|
||||
XMLUtil.print(n, result, indent);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/** utility function for parsing xml */
|
||||
public static Document parse(final String source)
|
||||
throws SAXException,
|
||||
IOException
|
||||
{
|
||||
return XMLUtil.parse(new ByteArrayInputStream(source.getBytes("UTF-8")));
|
||||
}
|
||||
|
||||
/** utility function for parsing xml */
|
||||
public static Document parse(final NodeRef nodeRef,
|
||||
final ContentService contentService)
|
||||
throws SAXException,
|
||||
IOException
|
||||
{
|
||||
final ContentReader contentReader =
|
||||
contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
|
||||
final InputStream in = contentReader.getContentInputStream();
|
||||
return XMLUtil.parse(in);
|
||||
}
|
||||
|
||||
/** utility function for parsing xml */
|
||||
public static Document parse(final int version,
|
||||
final String path,
|
||||
final AVMService avmService)
|
||||
throws SAXException,
|
||||
IOException
|
||||
{
|
||||
return XMLUtil.parse(avmService.getFileInputStream(version, path));
|
||||
}
|
||||
|
||||
/** utility function for parsing xml */
|
||||
public static Document parse(final File source)
|
||||
throws SAXException,
|
||||
IOException
|
||||
{
|
||||
return XMLUtil.parse(new FileInputStream(source));
|
||||
}
|
||||
|
||||
/** utility function for parsing xml */
|
||||
public static Document parse(final InputStream source)
|
||||
throws SAXException,
|
||||
IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
final DocumentBuilder db = XMLUtil.getDocumentBuilder();
|
||||
return db.parse(source);
|
||||
}
|
||||
finally
|
||||
{
|
||||
source.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** provides a document builder that is namespace aware but not validating by default */
|
||||
public static DocumentBuilder getDocumentBuilder()
|
||||
{
|
||||
return XMLUtil.getDocumentBuilder(true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* FOR DIAGNOSTIC PURPOSES ONLY - incomplete<br/>
|
||||
* Builds a path to the node relative to the to node provided.
|
||||
* @param from the node from which to build the xpath
|
||||
* @param to an ancestor of <tt>from</tt> which will be the root of the path
|
||||
* @return an xpath to <tt>to</tt> rooted at <tt>from</tt>.
|
||||
*/
|
||||
public static String buildXPath(final Node from, final Element to)
|
||||
{
|
||||
String result = "";
|
||||
Node tmp = from;
|
||||
do
|
||||
{
|
||||
if (tmp instanceof Attr)
|
||||
{
|
||||
assert result.length() == 0;
|
||||
result = "@" + tmp.getNodeName();
|
||||
}
|
||||
else if (tmp instanceof Element)
|
||||
{
|
||||
Node tmp2 = tmp;
|
||||
int position = 1;
|
||||
while (tmp2.getPreviousSibling() != null)
|
||||
{
|
||||
if (tmp2.getNodeName().equals(tmp.getNodeName()))
|
||||
{
|
||||
position++;
|
||||
}
|
||||
tmp2 = tmp2.getPreviousSibling();
|
||||
}
|
||||
String part = tmp.getNodeName() + "[" + position + "]";
|
||||
result = "/" + part + result;
|
||||
}
|
||||
else if (tmp instanceof Text)
|
||||
{
|
||||
assert result.length() == 0;
|
||||
result = "/text()";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
throw new IllegalArgumentException("unsupported node type " + tmp);
|
||||
}
|
||||
}
|
||||
tmp = tmp.getParentNode();
|
||||
}
|
||||
while (tmp != to.getParentNode() && tmp != null);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static DocumentBuilder getDocumentBuilder(final boolean namespaceAware,
|
||||
final boolean validating)
|
||||
{
|
||||
try
|
||||
{
|
||||
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware(namespaceAware);
|
||||
dbf.setValidating(validating);
|
||||
return dbf.newDocumentBuilder();
|
||||
}
|
||||
catch (ParserConfigurationException pce)
|
||||
{
|
||||
LOGGER.error(pce);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a NodeList of multiple nodelists
|
||||
*/
|
||||
public static NodeList combine(final NodeList... nls)
|
||||
{
|
||||
|
||||
return new NodeList()
|
||||
{
|
||||
public Node item(final int index)
|
||||
{
|
||||
int offset = 0;
|
||||
for (int i = 0; i < nls.length; i++)
|
||||
{
|
||||
if (index - offset < nls[i].getLength())
|
||||
{
|
||||
return nls[i].item(index - offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += nls[i].getLength();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < nls.length; i++)
|
||||
{
|
||||
result += nls[i].getLength();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.util.json;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public abstract class AbstractJsonSerializerBean<T, S> implements JsonSerializer<T, S>
|
||||
{
|
||||
private Class<? extends T> classToSerialize;
|
||||
private AlfrescoJsonSerializer jsonSerializer;
|
||||
|
||||
/**
|
||||
* @param classToSerialize the classToSerialize to set
|
||||
*/
|
||||
public void setClassToSerialize(Class<? extends T> classToSerialize)
|
||||
{
|
||||
this.classToSerialize = classToSerialize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jsonSerializer the jsonSerializer to set
|
||||
*/
|
||||
public void setJsonSerializer(AlfrescoJsonSerializer jsonSerializer)
|
||||
{
|
||||
this.jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
jsonSerializer.register(classToSerialize, this);
|
||||
}
|
||||
|
||||
}
|
117
source/java/org/alfresco/util/json/AlfrescoJsonSerializer.java
Normal file
117
source/java/org/alfresco/util/json/AlfrescoJsonSerializer.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2005-20010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.util.json;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.chemistry.tck.atompub.utils.ISO8601DateFormat;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class AlfrescoJsonSerializer
|
||||
{
|
||||
private final NamespaceService namespaceService;
|
||||
private final Map<Class<?>, JsonSerializer<?, ?>> serializers = new HashMap<Class<?>, JsonSerializer<?, ?>>();
|
||||
|
||||
public AlfrescoJsonSerializer(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
public void register(Class<?> clazz, JsonSerializer<?, ?> serializer)
|
||||
{
|
||||
serializers.put(clazz, serializer);
|
||||
}
|
||||
|
||||
public Object getJsonValue(Object value) throws JSONException
|
||||
{
|
||||
if (value instanceof Date) { return getJsonDate((Date) value); }
|
||||
if (value instanceof QName) { return getJsonQName((QName) value); }
|
||||
if (value instanceof NodeRef)
|
||||
{
|
||||
return value.toString();
|
||||
}
|
||||
else if (value instanceof Collection<?>)
|
||||
{
|
||||
return getJsonArray((Collection<?>) value);
|
||||
}
|
||||
else if (value instanceof Map<?, ?>) { return getJsonObject((Map<?, ?>) value); }
|
||||
return value;
|
||||
}
|
||||
|
||||
private JSONObject getJsonObject(Map<?, ?> map) throws JSONException
|
||||
{
|
||||
JSONObject object = new JSONObject();
|
||||
for (Entry<?, ?> entry : map.entrySet())
|
||||
{
|
||||
String key = getJsonKey(entry.getKey());
|
||||
Object value = getJsonValue(entry.getValue());
|
||||
object.put(key, value);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
private String getJsonKey(Object key)
|
||||
{
|
||||
if (key instanceof QName) { return getJsonQName((QName) key); }
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
private String getJsonQName(QName name)
|
||||
{
|
||||
String nameString = name.toPrefixString(namespaceService);
|
||||
return nameString.replaceFirst(":", "_");
|
||||
}
|
||||
|
||||
private JSONObject getJsonDate(Date date) throws JSONException
|
||||
{
|
||||
JSONObject isoDate = new JSONObject();
|
||||
isoDate.put("iso8601", ISO8601DateFormat.format(date));
|
||||
return isoDate;
|
||||
}
|
||||
|
||||
private JSONArray getJsonArray(Collection<?> values) throws JSONException
|
||||
{
|
||||
JSONArray array = new JSONArray();
|
||||
for (Object val : values)
|
||||
{
|
||||
array.put(getJsonValue(val));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.util.json;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public class DefaultJsonSerializer implements JsonSerializer<Object, Object>
|
||||
{
|
||||
|
||||
/*
|
||||
* @see org.alfresco.util.json.JsonSerializer#deserialize(java.lang.Object)
|
||||
*/
|
||||
public Object deserialize(Object object)
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.alfresco.util.json.JsonSerializer#serialize(java.lang.Object)
|
||||
*/
|
||||
public Object serialize(Object object)
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
40
source/java/org/alfresco/util/json/JsonSerializer.java
Normal file
40
source/java/org/alfresco/util/json/JsonSerializer.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have recieved a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
|
||||
package org.alfresco.util.json;
|
||||
|
||||
/**
|
||||
* An interface for converting objects of a specified type (T) into a serialized
|
||||
* Json format (of type S).
|
||||
*
|
||||
* @author Nick Smith
|
||||
*/
|
||||
public interface JsonSerializer<T, S>
|
||||
{
|
||||
|
||||
S serialize(T object);
|
||||
|
||||
T deserialize(S object);
|
||||
}
|
BIN
source/test-resources/images/gray21.512.png
Normal file
BIN
source/test-resources/images/gray21.512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
source/test-resources/images/gray21.512.tiff
Normal file
BIN
source/test-resources/images/gray21.512.tiff
Normal file
Binary file not shown.
Reference in New Issue
Block a user