mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Merge DM-DM_deployment to HEAD
17716 : Copied alfresco/HEAD to alfresco/BRANCHES/DEV/BRIAN/DM-DM_deployment. 17721 : Moved alfresco/BRANCHES/DEV/BRIAN/DM-DM_deployment to alfresco/BRANCHES/DEV/DM-DM_deployment. 17809 : Bare Bones of TransferService. 17813 : more bones 17824 : bootstrap of the transfer spaces 17826 : Added username, path, and a getter for the password. 17832 : createTransferTarget, getTransferTargets() working. 17836 : transfer target - duplicate name detection - delete transfer target by name - get transfer target by name - TransferException added along with transfer-service.properties 17840 : transfer target - enable / disable - update properties 17851 : Added the notion of a transmitter for the transfer service, and an HttpClient implementation of it. 17852 : Added the web script needed for the receiving end of a transfer, along with a command processor for clients to check availability of the service and credentials. 17856 : Added a Mockito-based test for HttpClientTransmitterImpl 17857 : Corrected javadoc for test class 17858 : Added test for overriding SSL socket factory 17859 : Wired up the transfer service to the transfer transmitter. 17896 : Rework to spring for app:transferDefinitions it's now app:transfer_definitio - Add throws clauses to TransferService - Bare bones of interface for begin and sendManifest 17944 : Work in progress on manifest file 17947 : added parent and child associations to the snapshot. 17956 : Now has the parent path implemented and introduces the TransferManifestNodeFactory. 17965 : Added content, MLText and collections. 17978 : addition of source and target peer associations. 17982 : Fixing parentNode information. 18008 : XML Manifest Reader checkpoint. (Still incomplete but lots working) 18040 : ParentPath is transmitted, fixes for source and target assocs. 18048 : SAIL-30: Initial commit of functionality for begin, sendManifest, and sendContent parts of the transfer process 18049 : Fix for parse of Locale type. 18054 : Added TransferManifestNodeHelper and more tests 18066 : Work in progress check in - Implemented the content chunker - sketched out more interfaces on TransferTransmitter. - Please note that the chunker is not yet connected to the manifest file, that will come next. r18069 : Wired up manifest reader to content chunker. r18089 : Fiest cut of callback interface for review. r18091 : added hashCode implementation which was missing from ContentData r18095 : Start of the server-side commit. Note that this is an interim commit - not tested. r18096 : Initial entry of a ContentData implementation of HttpClient's "Part" r18155 : Work in progress check in. TransferEvent - incomplete HttpClientTransmitter - first cut complete (not tested) Server side - first cut complete (not tested) 18156 : TransferMessage missing from last check in. 18166 : check in command processors 18167 : Work primarily on the transfer commit operation 18170 : corrected spring errors. 18176 : Further testing and fixing of transfer commit 18206 : Work in progress. 18236 : Work in progress - generally adding debug logging and sorting out exception handlers. 18240 : Fix to call "end" correctly after exception is thrown with "commit" 18242 : Aligning the manifest part names. 18243 : PostSnapshot calls the correct method on the receiver service. 18267 : First node has transferred. 18274 : Fixing abort to call end, debug statements, formatting code brackest 18275 : First code to handle updates. Also improved error messages passed back to client 18289 : Checked in work in progress. Content upload not working. 18290 : Update to ensure file type. 18300 : Added more log output and some of the error messages. 18301 : Work in progress 18302 : Added log output 18307 : Added a noddy transfer action 18315 : Sprint 2 complete - transfer and update one node. 18354 : Now the manifest file has deleted nodes. - Adding copyright headers 18384 : Plumbing for unit tests on one box. 18416 : First end to end unit test working. (one node create and update) 18421 : Added path based update test and many send test. 18458 : Added the functionality to transfer deleted and restored nodes. 18481 : Implementation of transferAsync 18491 : SAIL-32, SAIL-35 - Added node crawler for DM-DM Transfer F6 and F9. 18620 : Basic transfer report implementation git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18858 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
-->
|
||||
<import resource="classpath:alfresco/application-context-highlevel.xml" />
|
||||
|
||||
<import resource="classpath*:alfresco/transfer-service-context.xml"/>
|
||||
|
||||
<!--
|
||||
Import activation extensions for Multi-Tenancy.
|
||||
|
75
config/alfresco/bootstrap/transferSpaces.xml
Normal file
75
config/alfresco/bootstrap/transferSpaces.xml
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<view:view
|
||||
xmlns:view="http://www.alfresco.org/view/repository/1.0"
|
||||
xmlns:cm="http://www.alfresco.org/model/content/1.0"
|
||||
xmlns:app="http://www.alfresco.org/model/application/1.0"
|
||||
xmlns:trx="http://www.alfresco.org/model/transfer/1.0">
|
||||
|
||||
<cm:folder view:childName="${spaces.transfers.childname}">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Folder used by the Transfer subsystem.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Transfers</cm:title>
|
||||
<cm:name>Transfers</cm:name>
|
||||
</view:properties>
|
||||
<cm:contains>
|
||||
<cm:folder view:childName="${spaces.transfer_groups.childname}">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Folder containing groups of transfer targets.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Transfer Target Groups</cm:title>
|
||||
<cm:name>Transfer Target Groups</cm:name>
|
||||
</view:properties>
|
||||
<cm:contains>
|
||||
<trx:transferGroup view:childName="cm:default">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Default Group.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Default Group</cm:title>
|
||||
<cm:name>Default Group</cm:name>
|
||||
</view:properties>
|
||||
</trx:transferGroup>
|
||||
</cm:contains>
|
||||
</cm:folder>
|
||||
<cm:folder view:childName="${spaces.inbound_transfer_records.childname}">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Folder containing records of inbound transfers.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Inbound Transfer Records</cm:title>
|
||||
<cm:name>Inbound Transfer Records</cm:name>
|
||||
</view:properties>
|
||||
</cm:folder>
|
||||
<cm:folder view:childName="${spaces.outbound_transfer_records.childname}">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Folder containing records of outbound transfers.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Outbound Transfer Records</cm:title>
|
||||
<cm:name>Outbound Transfer Records</cm:name>
|
||||
</view:properties>
|
||||
</cm:folder>
|
||||
<cm:folder view:childName="${spaces.transfer_temp.childname}">
|
||||
<view:aspects>
|
||||
</view:aspects>
|
||||
<view:properties>
|
||||
<cm:description>Folder to store temporary nodes during transfer.</cm:description>
|
||||
<app:icon>space-icon-default</app:icon>
|
||||
<cm:title>Temp</cm:title>
|
||||
<cm:name>Temp</cm:name>
|
||||
</view:properties>
|
||||
</cm:folder>
|
||||
</cm:contains>
|
||||
|
||||
|
||||
</cm:folder>
|
||||
</view:view>
|
@@ -1072,6 +1072,7 @@
|
||||
<value>alfresco/model/wcmModel.xml</value>
|
||||
<value>alfresco/model/forumModel.xml</value>
|
||||
<value>alfresco/model/imapModel.xml</value>
|
||||
<value>alfresco/model/transferModel.xml</value>
|
||||
|
||||
<!-- Content models -->
|
||||
<value>alfresco/model/applicationModel.xml</value>
|
||||
|
@@ -348,6 +348,11 @@
|
||||
<prop key="spaces.templates.email.invite1.childname">${spaces.templates.email.invite1.childname}</prop>
|
||||
<prop key="spaces.templates.email.notify.childname">${spaces.templates.email.notify.childname}</prop>
|
||||
<prop key="spaces.imapConfig.childname">${spaces.imapConfig.childname}</prop>
|
||||
<prop key="spaces.transfers.childname">${spaces.transfers.childname}</prop>
|
||||
<prop key="spaces.transfer_groups.childname">${spaces.transfer_groups.childname}</prop>
|
||||
<prop key="spaces.transfer_temp.childname">${spaces.transfer_temp.childname}</prop>
|
||||
<prop key="spaces.inbound_transfer_records.childname">${spaces.inbound_transfer_records.childname}</prop>
|
||||
<prop key="spaces.outbound_transfer_records.childname">${spaces.outbound_transfer_records.childname}</prop>
|
||||
<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>
|
||||
@@ -553,7 +558,13 @@
|
||||
<prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
|
||||
<prop key="location">alfresco/bootstrap/imapSpaces.xml</prop>
|
||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||
</props>
|
||||
</props>
|
||||
|
||||
<props>
|
||||
<prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
|
||||
<prop key="location">alfresco/bootstrap/transferSpaces.xml</prop>
|
||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||
</props>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
@@ -288,4 +288,7 @@ patch.personUsagePatch.result1=Added 'cm:sizeCurrent' property to {0} people tha
|
||||
patch.personUsagePatch.result2=No people were missing the 'cm:sizeCurrent' property.
|
||||
|
||||
patch.redeployNominatedInvitationProcessWithPropsForShare.description=Redeploy nominated invitation workflow
|
||||
patch.redeployNominatedInvitationProcessWithPropsForShare.result=Nominated invitation workflow redeployed
|
||||
patch.redeployNominatedInvitationProcessWithPropsForShare.result=Nominated invitation workflow redeployed
|
||||
|
||||
patch.transferDefinitions.description=Add transfer definitions folder to data dictionary.
|
||||
patch.transferDefinitions.result=Transfer definitions folder added to data dictionary.
|
||||
|
22
config/alfresco/messages/transfer-service.properties
Normal file
22
config/alfresco/messages/transfer-service.properties
Normal file
@@ -0,0 +1,22 @@
|
||||
# Transfer service externalised display strings
|
||||
|
||||
transfer_service.unable_to_find_transfer_home=Unable to find transfer home: {0}
|
||||
transfer_service.unable_to_find_transfer_group=Unable to find transfer group with name, {0}
|
||||
transfer_service.unable_to_find_transfer_target=Unable to find transfer target with name, {0}
|
||||
transfer_service.target_exists=Unable to create a new transfer target with the name, {0}, since there is already a target with that name.
|
||||
transfer_service.comms.unsupported_protocol=Unsupported protocol: {0}
|
||||
transfer_service.comms.unsuccessful_response=Received unsuccessful response code from target server: {0}, {1}
|
||||
transfer_service.comms.http_request_failed=Failed to execute HTTP request {0} to target: {1} status: {2}
|
||||
transfer_service.no_nodes=No nodes to transfer
|
||||
|
||||
transfer_service.receiver.failed_to_create_staging_folder=Unable to create staging directory for transfer {0}
|
||||
transfer_service.receiver.lock_folder_not_found=Unable to locate specified lock folder: {0}
|
||||
transfer_service.receiver.temp_folder_not_found=Unable to locate specified temporary folder for transfer {0}: {1}
|
||||
transfer_service.receiver.lock_unavailable=Transfer lock has been claimed for another inbound transfer. Unable to start new transfer.
|
||||
transfer_service.receiver.record_folder_not_found=Failed to find folder specified to hold inbound transfer records: {0}
|
||||
transfer_service.receiver.not_lock_owner=Failed attempt to carry out transfer operation. Lock not held by specified transfer: {0}
|
||||
transfer_service.receiver.error_ending_transfer=
|
||||
transfer_service.receiver.error_staging_snapshot=
|
||||
transfer_service.receiver.error_staging_content=
|
||||
transfer_service.receiver.no_snapshot_received=
|
||||
transfer_service.receiver.error_committing_transfer=
|
134
config/alfresco/model/transferModel.xml
Normal file
134
config/alfresco/model/transferModel.xml
Normal file
@@ -0,0 +1,134 @@
|
||||
<model name="trx:applicationmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
|
||||
|
||||
<description>Alfresco Transfer Application Model</description>
|
||||
<author>Alfresco</author>
|
||||
<published>2009-12-16</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/system/1.0" prefix="sys"/>
|
||||
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
|
||||
</imports>
|
||||
|
||||
<namespaces>
|
||||
<namespace uri="http://www.alfresco.org/model/transfer/1.0" prefix="trx"/>
|
||||
</namespaces>
|
||||
|
||||
<constraints>
|
||||
<constraint name="trx:protocols" type="LIST">
|
||||
<parameter name="allowedValues">
|
||||
<list>
|
||||
<value>http</value>
|
||||
<value>https</value>
|
||||
</list>
|
||||
</parameter>
|
||||
</constraint>
|
||||
</constraints>
|
||||
|
||||
<types>
|
||||
|
||||
<type name="trx:transferGroup">
|
||||
<title>Transfer Group</title>
|
||||
<description>The definition of a transfer group</description>
|
||||
<parent>cm:folder</parent>
|
||||
<properties>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
|
||||
<type name="trx:transferTarget">
|
||||
<title>Transfer Target</title>
|
||||
<description>The definition of a transfer target</description>
|
||||
<parent>cm:folder</parent>
|
||||
<properties>
|
||||
|
||||
<property name="trx:endpointhost">
|
||||
<title>Endpoint Host</title>
|
||||
<type>d:text</type>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
<index enabled="true">
|
||||
<atomic>true</atomic>
|
||||
<stored>false</stored>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
<property name="trx:endpointport">
|
||||
<title>Endpoint Port</title>
|
||||
<type>d:int</type>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
</property>
|
||||
|
||||
<property name="trx:endpointpath">
|
||||
<title>Endpoint Path</title>
|
||||
<type>d:text</type>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
</property>
|
||||
|
||||
<property name="trx:endpointprotocol">
|
||||
<title>Endpoint Protocol</title>
|
||||
<type>d:text</type>
|
||||
<mandatory enforced="true">true</mandatory>
|
||||
<constraints>
|
||||
<constraint ref="trx:protocols" />
|
||||
</constraints>
|
||||
</property>
|
||||
|
||||
<property name="trx:username">
|
||||
<title>Username</title>
|
||||
<type>d:text</type>
|
||||
</property>
|
||||
|
||||
<!-- todo cleartext for now - needs encrypting -->
|
||||
<property name="trx:password">
|
||||
<title>Password</title>
|
||||
<type>d:any</type>
|
||||
<index enabled="false">
|
||||
<atomic>true</atomic>
|
||||
<stored>false</stored>
|
||||
<tokenised>false</tokenised>
|
||||
</index>
|
||||
</property>
|
||||
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<type name="trx:transferLock">
|
||||
<title>Transfer Lock</title>
|
||||
<description>Node type used to represent the transfer lock node</description>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
|
||||
<property name="trx:transferId">
|
||||
<title>Locked Transfer Identifier</title>
|
||||
<type>d:text</type>
|
||||
<mandatory enforced="false">true</mandatory>
|
||||
</property>
|
||||
</properties>
|
||||
</type>
|
||||
|
||||
<!-- The Transfer Report -->
|
||||
<type name="trx:transferReport">
|
||||
<title>Transfer Report</title>
|
||||
<description>Transfer Report</description>
|
||||
<parent>cm:content</parent>
|
||||
</type>
|
||||
|
||||
</types>
|
||||
|
||||
<aspects>
|
||||
<!-- Can this resorce be temporarily disabled? -->
|
||||
<aspect name="trx:enableable">
|
||||
<title>Can this resource be enabled/disabled.</title>
|
||||
<properties>
|
||||
<property name="trx:enabled">
|
||||
<title>Is this enabled.</title>
|
||||
<type>d:boolean</type>
|
||||
<mandatory>true</mandatory>
|
||||
</property>
|
||||
</properties>
|
||||
</aspect>
|
||||
</aspects>
|
||||
|
||||
</model>
|
@@ -1991,7 +1991,7 @@
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="patch.db-V3.2-ContentTables2" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||
<property name="id"><value>patch.db-V3.2-ContentTables2</value></property>
|
||||
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||
@@ -2008,16 +2008,38 @@
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="patch.db-V3.3-Remove-VersionCount" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||
<property name="id"><value>patch.db-V3.3-Remove-VersionCount</value></property>
|
||||
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>4002</value></property>
|
||||
<property name="targetSchema"><value>4003</value></property>
|
||||
<property name="scriptUrl">
|
||||
<value>classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/remove-VersionCount.sql</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="patch.db-V3.3-Remove-VersionCount" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||
<property name="id"><value>patch.db-V3.3-Remove-VersionCount</value></property>
|
||||
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>4002</value></property>
|
||||
<property name="targetSchema"><value>4003</value></property>
|
||||
<property name="scriptUrl">
|
||||
<value>classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/remove-VersionCount.sql</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>
|
||||
<property name="fixesFromSchema"><value>0</value></property>
|
||||
<property name="fixesToSchema"><value>3007</value></property>
|
||||
<property name="targetSchema"><value>3008</value></property>
|
||||
<!-- bootstrap view -->
|
||||
<property name="importerBootstrap">
|
||||
<ref bean="spacesBootstrap" />
|
||||
</property>
|
||||
|
||||
<property name="checkPath">
|
||||
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}</value>
|
||||
</property>
|
||||
<property name="bootstrapView">
|
||||
<props>
|
||||
<prop key="path">/${spaces.company_home.childname}/${spaces.dictionary.childname}</prop>
|
||||
<prop key="location">alfresco/bootstrap/transferSpaces.xml</prop>
|
||||
<prop key="messages">alfresco/messages/bootstrap-spaces</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
|
@@ -313,6 +313,11 @@ spaces.user_homes.childname=app:user_homes
|
||||
spaces.sites.childname=st:sites
|
||||
spaces.templates.email.invite.childname=cm:invite
|
||||
spaces.wcm_deployed.childname=cm:wcm_deployed
|
||||
spaces.transfers.childname=app:transfers
|
||||
spaces.transfer_groups.childname=app:transfer_groups
|
||||
spaces.transfer_temp.childname=app:temp
|
||||
spaces.inbound_transfer_records.childname=app:inbound_transfer_records
|
||||
spaces.outbound_transfer_records.childname=app:outbound_transfer_records
|
||||
|
||||
# ADM VersionStore Configuration
|
||||
version.store.deprecated.lightWeightVersionStore=workspace://lightWeightVersionStore
|
||||
@@ -447,3 +452,6 @@ deployment.service.numberOfSendingThreads=5
|
||||
deployment.service.corePoolSize=2
|
||||
deployment.service.maximumPoolSize=3
|
||||
|
||||
# Transfer Service
|
||||
transferservice.receiver.enabled=true
|
||||
transferservice.receiver.stagingDir=${java.io.tmpdir}/alfresco-transfer-staging
|
||||
|
124
config/alfresco/transfer-service-context.xml
Normal file
124
config/alfresco/transfer-service-context.xml
Normal file
@@ -0,0 +1,124 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
<beans>
|
||||
<!-- Transfer Service Configuration -->
|
||||
<bean id="transferService" class="org.alfresco.repo.transfer.TransferServiceImpl" init-method="init">
|
||||
<property name="actionService">
|
||||
<ref bean="ActionService"/>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="NodeService"/>
|
||||
</property>
|
||||
<property name="searchService">
|
||||
<ref bean="SearchService"/>
|
||||
</property>
|
||||
<property name="transactionService">
|
||||
<ref bean="TransactionService"/>
|
||||
</property>
|
||||
<property name="transferSpaceQuery">
|
||||
<value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.transfer_groups.childname}</value>
|
||||
</property>
|
||||
<property name="defaultTransferGroup">
|
||||
<value>Default Group</value>
|
||||
</property>
|
||||
<property name="transmitter" ref="transferTransmitter" />
|
||||
|
||||
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
|
||||
|
||||
<property name="transferReporter" ref="transferReporter" />
|
||||
|
||||
</bean>
|
||||
|
||||
<bean id="transferTransmitter" class="org.alfresco.repo.transfer.HttpClientTransmitterImpl" init-method="init" >
|
||||
<property name="contentService" ref="ContentService" />
|
||||
</bean>
|
||||
|
||||
<bean id="transferReporter" class="org.alfresco.repo.transfer.report.TransferReporterImpl" init-method="init" >
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
<bean id="transferManifestNodeFactory" class="org.alfresco.repo.transfer.manifest.TransferManifestNodeFactoryImpl" init-method="init" >
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="transferReceiver" class="org.alfresco.repo.transfer.RepoTransferReceiverImpl" init-method="init">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="searchService" ref="SearchService" />
|
||||
<property name="transactionService" ref="TransactionService" />
|
||||
<property name="transferLockFolderPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}</value></property>
|
||||
<property name="transferTempFolderPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.transfer_temp.childname}</value></property>
|
||||
<property name="inboundTransferRecordsPath"><value>/${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.transfers.childname}/${spaces.inbound_transfer_records.childname}</value></property>
|
||||
<property name="rootStagingDirectory"><value>${transferservice.receiver.stagingDir}</value></property>
|
||||
<property name="manifestProcessorFactory" ref="transferManifestProcessorFactory" />
|
||||
<property name="behaviourFilter" ref="policyBehaviourFilter" />
|
||||
</bean>
|
||||
|
||||
<bean id="transferManifestProcessorFactory" class="org.alfresco.repo.transfer.DefaultManifestProcessorFactoryImpl">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="nodeResolverFactory" ref="transferNodeResolverFactory" />
|
||||
</bean>
|
||||
|
||||
<bean id="transferNodeResolverFactory" class="org.alfresco.repo.transfer.DefaultCorrespondingNodeResolverFactory">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
<!-- I18N -->
|
||||
<bean id="transferServiceResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
|
||||
<property name="resourceBundles">
|
||||
<list>
|
||||
<value>alfresco.messages.transfer-service</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="TransferService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
|
||||
|
||||
<bean id="TransferService_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>
|
||||
|
||||
<!-- Transfer service bean -->
|
||||
<bean id="TransferService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.service.cmr.transfer.TransferService</value>
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="transferService"/>
|
||||
</property>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref local="TransferService_transaction"/>
|
||||
<idref bean="AuditMethodInterceptor"/>
|
||||
<idref bean="exceptionTranslator"/>
|
||||
<idref local="TransferService_security"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Action for transfer async -->
|
||||
<bean id="transfer-async" class="org.alfresco.repo.transfer.TransferAsyncAction" parent="action-executer">
|
||||
|
||||
<!-- Run transferAsyncAction on the deployment queue -->
|
||||
<property name="queueName">
|
||||
<value>deployment</value>
|
||||
</property>
|
||||
<property name="transferService">
|
||||
<ref bean="TransferService"/>
|
||||
</property>
|
||||
<property name="publicAction">
|
||||
<value>false</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
|
||||
</beans>
|
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.repository.Path.Element;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class BasicCorrespondingNodeResolverImpl implements CorrespondingNodeResolver
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(BasicCorrespondingNodeResolverImpl.class);
|
||||
|
||||
private static final String MSG_SPECIFIED_STORE_DOES_NOT_EXIST = "transfer_service.receiver.specified_store_nonexistent";
|
||||
private NodeService nodeService;
|
||||
|
||||
public ResolvedParentChildPair resolveCorrespondingNode(NodeRef sourceNodeRef, ChildAssociationRef primaryAssoc,
|
||||
Path parentPath)
|
||||
{
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Attempting to resolve corresponding node for noderef " + sourceNodeRef);
|
||||
log.debug("Supplied parent path: " + parentPath);
|
||||
log.debug("Supplied parent assoc: " + primaryAssoc.toString());
|
||||
}
|
||||
ResolvedParentChildPair result = new ResolvedParentChildPair(null, null);
|
||||
|
||||
// Does a node with the same NodeRef already exist in this repo?
|
||||
if (nodeService.exists(sourceNodeRef))
|
||||
{
|
||||
result.resolvedChild = sourceNodeRef;
|
||||
}
|
||||
|
||||
// Find where this node should live
|
||||
NodeRef parentNodeRef = primaryAssoc.getParentRef();
|
||||
if (!nodeService.exists(parentNodeRef.getStoreRef()))
|
||||
{
|
||||
throw new TransferProcessingException(MSG_SPECIFIED_STORE_DOES_NOT_EXIST);
|
||||
}
|
||||
if (!nodeService.exists(parentNodeRef))
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Unable to find node's parent by node ref: " + parentNodeRef);
|
||||
}
|
||||
parentNodeRef = resolveParentPath(primaryAssoc.getParentRef().getStoreRef(), parentPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Node's parent has been resolved by noderef: " + parentNodeRef);
|
||||
}
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Parent noderef resolved to node: " + parentNodeRef);
|
||||
}
|
||||
result.resolvedParent = parentNodeRef;
|
||||
if ((parentNodeRef != null) && (result.resolvedChild == null))
|
||||
{
|
||||
//We've managed to find the approprate parent node, but not the child.
|
||||
//See if we can find the child by looking at the parent's child associations
|
||||
List<ChildAssociationRef> children = nodeService.getChildAssocs(parentNodeRef, RegexQNamePattern.MATCH_ALL,
|
||||
primaryAssoc.getQName());
|
||||
if (!children.isEmpty())
|
||||
{
|
||||
result.resolvedChild = children.get(0).getChildRef();
|
||||
}
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Resolved child node to: " + result.resolvedChild);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parentPath
|
||||
*/
|
||||
private NodeRef resolveParentPath(StoreRef store, Path parentPath)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Trying to resolve parent path " + parentPath);
|
||||
}
|
||||
NodeRef node = nodeService.getRootNode(store);
|
||||
int index = 1;
|
||||
while (index < parentPath.size())
|
||||
{
|
||||
Element element = parentPath.get(index++);
|
||||
QName name = QName.createQName(element.getElementString());
|
||||
List<ChildAssociationRef> children = nodeService.getChildAssocs(node, RegexQNamePattern.MATCH_ALL, name);
|
||||
|
||||
if (children.isEmpty())
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Failed to resolve path element " + element.getElementString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Resolved path element " + element.getElementString());
|
||||
}
|
||||
node = children.get(0).getChildRef();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class CachingCorrespondingNodeResolverImpl implements CorrespondingNodeResolver
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(CachingCorrespondingNodeResolverImpl.class);
|
||||
|
||||
private Map<NodeRef, ResolvedParentChildPair> cache = new HashMap<NodeRef, ResolvedParentChildPair>(359);
|
||||
private CorrespondingNodeResolver delegateResolver;
|
||||
|
||||
public CachingCorrespondingNodeResolverImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param delegateResolver
|
||||
*/
|
||||
public CachingCorrespondingNodeResolverImpl(CorrespondingNodeResolver delegateResolver)
|
||||
{
|
||||
super();
|
||||
this.delegateResolver = delegateResolver;
|
||||
}
|
||||
|
||||
public ResolvedParentChildPair resolveCorrespondingNode(NodeRef sourceNodeRef, ChildAssociationRef primaryAssoc,
|
||||
Path parentPath)
|
||||
{
|
||||
|
||||
ResolvedParentChildPair result = cache.get(sourceNodeRef);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Found fully-resolved entry in cache for node " + sourceNodeRef);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
result = delegateResolver.resolveCorrespondingNode(sourceNodeRef, primaryAssoc, parentPath);
|
||||
|
||||
//If we have fully resolved the parent and child nodes then stick it in the cache...
|
||||
if (result.resolvedChild != null && result.resolvedParent != null)
|
||||
{
|
||||
cache.put(sourceNodeRef, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param delegateResolver the delegateResolver to set
|
||||
*/
|
||||
public void setDelegateResolver(CorrespondingNodeResolver delegateResolver)
|
||||
{
|
||||
this.delegateResolver = delegateResolver;
|
||||
}
|
||||
}
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
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.transfer.NodeFinder;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class ChildAssociatedNodeFinder implements NodeFinder
|
||||
{
|
||||
private Set<QName> suppliedAssociationTypes = new HashSet<QName>();
|
||||
private boolean exclude = false;
|
||||
private boolean initialised = false;
|
||||
private List<QName> childAssociationTypes = new ArrayList<QName>();
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
public ChildAssociatedNodeFinder()
|
||||
{
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(Set<QName> associationTypeNames)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(QName... associationTypeNames)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(Set<QName> associationTypeNames, boolean exclude)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(ServiceRegistry serviceRegistry, Set<QName> associationTypeNames)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(ServiceRegistry serviceRegistry, QName... associationTypeNames)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public ChildAssociatedNodeFinder(ServiceRegistry serviceRegistry, Set<QName> associationTypeNames, boolean exclude)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
public void setAssociationTypes(QName... associationTypes)
|
||||
{
|
||||
setAssociationTypes(Arrays.asList(associationTypes));
|
||||
}
|
||||
|
||||
public void setAssociationTypes(Collection<QName> associationTypes)
|
||||
{
|
||||
this.suppliedAssociationTypes = new HashSet<QName>(associationTypes);
|
||||
initialised = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exclude
|
||||
* the exclude to set
|
||||
*/
|
||||
public void setExclude(boolean exclude)
|
||||
{
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.NodeFinder#findFrom(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.service.ServiceRegistry)
|
||||
*/
|
||||
public Set<NodeRef> findFrom(NodeRef thisNode)
|
||||
{
|
||||
if (!initialised)
|
||||
{
|
||||
init();
|
||||
}
|
||||
if (exclude)
|
||||
{
|
||||
return processExcludedSet(thisNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return processIncludedSet(thisNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thisNode
|
||||
* @param serviceRegistry
|
||||
* @return
|
||||
*/
|
||||
private Set<NodeRef> processExcludedSet(NodeRef thisNode)
|
||||
{
|
||||
Set<NodeRef> results = new HashSet<NodeRef>(89);
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
|
||||
// Find all the child nodes (filtering as necessary).
|
||||
List<ChildAssociationRef> children = nodeService.getChildAssocs(thisNode);
|
||||
boolean filterChildren = !childAssociationTypes.isEmpty();
|
||||
for (ChildAssociationRef child : children)
|
||||
{
|
||||
if (!filterChildren || !childAssociationTypes.contains(child.getTypeQName()))
|
||||
{
|
||||
results.add(child.getChildRef());
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private Set<NodeRef> processIncludedSet(NodeRef startingNode)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
Set<NodeRef> foundNodes = new HashSet<NodeRef>(89);
|
||||
for (QName assocType : childAssociationTypes)
|
||||
{
|
||||
List<ChildAssociationRef> children = nodeService.getChildAssocs(startingNode, assocType,
|
||||
RegexQNamePattern.MATCH_ALL);
|
||||
for (ChildAssociationRef child : children)
|
||||
{
|
||||
foundNodes.add(child.getChildRef());
|
||||
}
|
||||
}
|
||||
return foundNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry
|
||||
* the serviceRegistry to set
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
ParameterCheck.mandatory("serviceRegistry", serviceRegistry);
|
||||
// Quickly scan the supplied association types and remove any that either
|
||||
// do not exist or are not child association types.
|
||||
DictionaryService dictionaryService = serviceRegistry.getDictionaryService();
|
||||
childAssociationTypes.clear();
|
||||
for (QName associationType : suppliedAssociationTypes)
|
||||
{
|
||||
AssociationDefinition assocDef = dictionaryService.getAssociation(associationType);
|
||||
if (assocDef != null && assocDef.isChild())
|
||||
{
|
||||
childAssociationTypes.add(associationType);
|
||||
}
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface ContentChunkProcessor
|
||||
{
|
||||
/**
|
||||
* process this chunk of content data
|
||||
* @param data
|
||||
*/
|
||||
public void processChunk(Set<ContentData> data) throws TransferException;
|
||||
|
||||
}
|
65
source/java/org/alfresco/repo/transfer/ContentChunker.java
Normal file
65
source/java/org/alfresco/repo/transfer/ContentChunker.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
|
||||
/**
|
||||
* The Content Chunker Splits Content into "Chunks" of a given size
|
||||
*
|
||||
* @author Mark
|
||||
*/
|
||||
public interface ContentChunker
|
||||
{
|
||||
/**
|
||||
* add content data to the chunker
|
||||
*/
|
||||
public void addContent(ContentData data) throws TransferException;
|
||||
|
||||
/**
|
||||
* flush any remaining content data
|
||||
*/
|
||||
public void flush() throws TransferException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chunkSize
|
||||
*/
|
||||
public void setChunkSize(long chunkSize);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getChunkSize();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param handler
|
||||
*/
|
||||
public void setHandler(ContentChunkProcessor handler);
|
||||
|
||||
}
|
123
source/java/org/alfresco/repo/transfer/ContentChunkerImpl.java
Normal file
123
source/java/org/alfresco/repo/transfer/ContentChunkerImpl.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.site.SiteServiceImpl;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* The Content Chunker Splits Content into "Chunks" of a given size.
|
||||
*
|
||||
* @author Mark
|
||||
*/
|
||||
public class ContentChunkerImpl implements ContentChunker
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(ContentChunkerImpl.class);
|
||||
|
||||
/**
|
||||
* The chunk size.
|
||||
*/
|
||||
private long chunkSize = 1000000;
|
||||
|
||||
/**
|
||||
* The handler to recieve the "chunks"
|
||||
*/
|
||||
private ContentChunkProcessor handler;
|
||||
|
||||
/**
|
||||
* The internal buffer
|
||||
*/
|
||||
private Set<ContentData> buffer = new HashSet<ContentData>();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void addContent(ContentData data) throws TransferException
|
||||
{
|
||||
logger.debug("add content size:" + data.getSize());
|
||||
buffer.add(data);
|
||||
|
||||
/**
|
||||
* work out whether the buffer has filled up and needs to be flushed
|
||||
*/
|
||||
Iterator iter = buffer.iterator();
|
||||
long totalContentSize = 0;
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
ContentData x = (ContentData)iter.next();
|
||||
totalContentSize += x.getSize();
|
||||
}
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("elements " + buffer.size() + ", totalContentSize:" + totalContentSize);
|
||||
}
|
||||
if(totalContentSize >= chunkSize)
|
||||
{
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void flush() throws TransferException
|
||||
{
|
||||
logger.debug("flush number of contents:" + buffer.size());
|
||||
if(buffer.size() > 0)
|
||||
{
|
||||
handler.processChunk(buffer);
|
||||
}
|
||||
buffer.clear();
|
||||
logger.debug("buffer empty");
|
||||
}
|
||||
|
||||
public void setChunkSize(long chunkSize)
|
||||
{
|
||||
this.chunkSize = chunkSize;
|
||||
}
|
||||
|
||||
public long getChunkSize()
|
||||
{
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
public void setHandler(ContentChunkProcessor handler)
|
||||
{
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public ContentChunkProcessor getHandler()
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Unit test of the Content Chunker
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class ContentChunkerImplTest extends TestCase
|
||||
{
|
||||
public void testContentChunkerImpl() throws Exception
|
||||
{
|
||||
ContentChunker chunker = new ContentChunkerImpl();
|
||||
|
||||
final Set<ContentData>processedContent = new HashSet<ContentData>();
|
||||
|
||||
chunker.setHandler(
|
||||
new ContentChunkProcessor(){
|
||||
public void processChunk(Set<ContentData> data)
|
||||
{
|
||||
processedContent.addAll(data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Set a chunk size of 10 bytes
|
||||
*/
|
||||
chunker.setChunkSize(10);
|
||||
|
||||
/**
|
||||
* add one contet of size 20, should flush immediatly
|
||||
*/
|
||||
chunker.addContent(new ContentData(null, null, 20, null));
|
||||
assertTrue("size 20 not written immediatley", processedContent.size() == 1);
|
||||
|
||||
/**
|
||||
* add one content of size 1 - should remain buffered in chunker
|
||||
*/
|
||||
processedContent.clear();
|
||||
chunker.addContent(new ContentData(null, null, 1, null));
|
||||
assertTrue("size 1 not buffered", processedContent.size() == 0);
|
||||
|
||||
/**
|
||||
* flush should write it out
|
||||
*/
|
||||
chunker.flush();
|
||||
assertTrue("size 1 not flushed", processedContent.size() == 1);
|
||||
|
||||
/**
|
||||
* Now test the boundary condition over the threashold
|
||||
*/
|
||||
processedContent.clear();
|
||||
for(int i = 0; i < 11 ; i++)
|
||||
{
|
||||
chunker.addContent(new ContentData(null, null, 1, null));
|
||||
}
|
||||
assertEquals("size 10 not buffered", processedContent.size(), 10);
|
||||
|
||||
/**
|
||||
* flush should write it out
|
||||
*/
|
||||
chunker.flush();
|
||||
assertTrue("size 1 not flushed", processedContent.size() == 11);
|
||||
|
||||
|
||||
/**
|
||||
* Now Just whack some load through
|
||||
*/
|
||||
processedContent.clear();
|
||||
for(int i = 0; i < 100 ; i++)
|
||||
{
|
||||
chunker.addContent(new ContentData(null, null, 3, null));
|
||||
}
|
||||
chunker.flush();
|
||||
assertEquals("size 100 not written", processedContent.size(), 100);
|
||||
|
||||
}
|
||||
}
|
204
source/java/org/alfresco/repo/transfer/ContentClassFilter.java
Normal file
204
source/java/org/alfresco/repo/transfer/ContentClassFilter.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.transfer.NodeFilter;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class ContentClassFilter implements NodeFilter
|
||||
{
|
||||
private Set<QName> contentClasses = new HashSet<QName>();
|
||||
private Set<QName> aspects = new HashSet<QName>();
|
||||
private Set<QName> types = new HashSet<QName>();
|
||||
private boolean initialised = false;
|
||||
private boolean exclude = false;
|
||||
private boolean directOnly = false;
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
public ContentClassFilter()
|
||||
{
|
||||
}
|
||||
|
||||
public ContentClassFilter(QName... contentClasses)
|
||||
{
|
||||
setContentClasses(contentClasses);
|
||||
}
|
||||
|
||||
public ContentClassFilter(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this();
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public ContentClassFilter(ServiceRegistry serviceRegistry, QName... contentClasses)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setContentClasses(contentClasses);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.NodeFilter#accept(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.service.ServiceRegistry)
|
||||
*/
|
||||
public boolean accept(NodeRef thisNode)
|
||||
{
|
||||
if (!initialised)
|
||||
{
|
||||
init();
|
||||
}
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
|
||||
Set<QName> nodesAspects = nodeService.getAspects(thisNode);
|
||||
QName type = nodeService.getType(thisNode);
|
||||
|
||||
boolean typeIsInSet = types.contains(type);
|
||||
boolean aspectIsInSet = false;
|
||||
for (QName aspect : nodesAspects)
|
||||
{
|
||||
if (aspects.contains(aspect))
|
||||
{
|
||||
aspectIsInSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (!exclude && (typeIsInSet || aspectIsInSet)) || (exclude && (!typeIsInSet && !aspectIsInSet));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry
|
||||
* the serviceRegistry to set
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
ParameterCheck.mandatory("serviceRegistry", serviceRegistry);
|
||||
DictionaryService dictionaryService = serviceRegistry.getDictionaryService();
|
||||
aspects.clear();
|
||||
types.clear();
|
||||
for (QName contentClass : contentClasses)
|
||||
{
|
||||
ClassDefinition classDef = dictionaryService.getClass(contentClass);
|
||||
if (classDef == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (classDef.isAspect())
|
||||
{
|
||||
aspects.add(contentClass);
|
||||
if (!directOnly)
|
||||
{
|
||||
aspects.addAll(dictionaryService.getSubAspects(contentClass, true));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
types.add(contentClass);
|
||||
if (!directOnly)
|
||||
{
|
||||
types.addAll(dictionaryService.getSubTypes(contentClass, true));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the classes of content (types and aspects) to filter by.
|
||||
*
|
||||
* @param contentClasses
|
||||
* the contentClasses to set
|
||||
*/
|
||||
public void setContentClasses(Collection<QName> contentClasses)
|
||||
{
|
||||
this.contentClasses = new HashSet<QName>(contentClasses);
|
||||
initialised = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the classes of content (types and aspects) to filter by.
|
||||
*
|
||||
* @param contentClasses
|
||||
* the contentClasses to set
|
||||
*/
|
||||
public void setContentClasses(QName... contentClasses)
|
||||
{
|
||||
this.contentClasses = new HashSet<QName>(Arrays.asList(contentClasses));
|
||||
initialised = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the filter should exclude the specified classes of content.
|
||||
*
|
||||
* @param exclude
|
||||
* If true then this filter will not accept content that is of any of the filtered classes of content. If
|
||||
* false then this filter will only accept content that has one or more of the filtered classes of
|
||||
* content. Defaults to false.
|
||||
*/
|
||||
public void setExclude(boolean exclude)
|
||||
{
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the filter should only test against the content classes that have been supplied, or if it should
|
||||
* also test against all subclasses of those classes. For example, if "directOnly" is true and "cm:content" is in
|
||||
* the set of content classes then a node of type "cm:thumnail" will not be filtered.
|
||||
*
|
||||
* @param directOnly
|
||||
* If true then the filter only filters specifically the specified content classes. Defaults to false.
|
||||
*/
|
||||
public void setDirectOnly(boolean directOnly)
|
||||
{
|
||||
this.directOnly = directOnly;
|
||||
initialised = false;
|
||||
}
|
||||
|
||||
}
|
132
source/java/org/alfresco/repo/transfer/ContentDataPart.java
Normal file
132
source/java/org/alfresco/repo/transfer/ContentDataPart.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.apache.commons.httpclient.methods.multipart.PartBase;
|
||||
import org.apache.commons.httpclient.util.EncodingUtil;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class ContentDataPart extends PartBase
|
||||
{
|
||||
/** Attachment's file name */
|
||||
protected static final String FILE_NAME = "; filename=";
|
||||
|
||||
/** Attachment's file name as a byte array */
|
||||
private static final byte[] FILE_NAME_BYTES =
|
||||
EncodingUtil.getAsciiBytes(FILE_NAME);
|
||||
|
||||
private ContentService contentService;
|
||||
private ContentData data;
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* ContentDataPart
|
||||
* @param contentService
|
||||
* @param partName
|
||||
* @param data
|
||||
*/
|
||||
public ContentDataPart(ContentService contentService, String partName, ContentData data) {
|
||||
super(partName, data.getMimetype(), data.getEncoding(), null);
|
||||
this.contentService = contentService;
|
||||
this.data = data;
|
||||
this.filename = partName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the disposition header to the output stream
|
||||
* @param out The output stream
|
||||
* @throws IOException If an IO problem occurs
|
||||
* @see Part#sendDispositionHeader(OutputStream)
|
||||
*/
|
||||
protected void sendDispositionHeader(OutputStream out)
|
||||
throws IOException {
|
||||
super.sendDispositionHeader(out);
|
||||
if (filename != null) {
|
||||
out.write(FILE_NAME_BYTES);
|
||||
out.write(QUOTE_BYTES);
|
||||
out.write(EncodingUtil.getAsciiBytes(filename));
|
||||
out.write(QUOTE_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.methods.multipart.Part#lengthOfData()
|
||||
*/
|
||||
@Override
|
||||
protected long lengthOfData() throws IOException
|
||||
{
|
||||
return data.getSize();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.methods.multipart.Part#sendData(java.io.OutputStream)
|
||||
*/
|
||||
@Override
|
||||
protected void sendData(OutputStream out) throws IOException
|
||||
{
|
||||
|
||||
// Get the content from the content URL and write it to out
|
||||
|
||||
// Can't use the following code since it closes 'out', which needs to remain open.
|
||||
// AbstractContentReader.
|
||||
// contentService.getRawReader(data.getContentUrl()).getContent(out);
|
||||
|
||||
InputStream is = contentService.getRawReader(data.getContentUrl()).getContentInputStream();
|
||||
|
||||
// ReadableByteChannel rbc = Channels.newChannel(is);
|
||||
// WritableByteChannel wbc = Channels.newChannel(out);
|
||||
|
||||
try
|
||||
{
|
||||
byte[] tmp = new byte[4096];
|
||||
int len;
|
||||
while ((len = is.read(tmp)) >= 0)
|
||||
{
|
||||
out.write(tmp, 0, len);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// we're done with the input stream, close it
|
||||
is.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface CorrespondingNodeResolver
|
||||
{
|
||||
ResolvedParentChildPair resolveCorrespondingNode(NodeRef sourceNodeRef, ChildAssociationRef primaryAssoc,
|
||||
Path parentPath);
|
||||
|
||||
static class ResolvedParentChildPair {
|
||||
public NodeRef resolvedParent;
|
||||
public NodeRef resolvedChild;
|
||||
|
||||
public ResolvedParentChildPair(NodeRef parent, NodeRef child) {
|
||||
this.resolvedParent = parent;
|
||||
this.resolvedChild = child;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface CorrespondingNodeResolverFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
CorrespondingNodeResolver getResolver();
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class DefaultCorrespondingNodeResolverFactory implements CorrespondingNodeResolverFactory
|
||||
{
|
||||
private NodeService nodeService;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transfer.CorrespondingNodeResolverFactory#getResolver()
|
||||
*/
|
||||
public CorrespondingNodeResolver getResolver()
|
||||
{
|
||||
BasicCorrespondingNodeResolverImpl basicResolver = new BasicCorrespondingNodeResolverImpl();
|
||||
basicResolver.setNodeService(nodeService);
|
||||
CachingCorrespondingNodeResolverImpl cachingResolver = new CachingCorrespondingNodeResolverImpl(basicResolver);
|
||||
return cachingResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class DefaultManifestProcessorFactoryImpl implements ManifestProcessorFactory
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
private CorrespondingNodeResolverFactory nodeResolverFactory;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.ManifestProcessorFactory#getPrimaryCommitProcessor()
|
||||
*/
|
||||
public List<TransferManifestProcessor> getCommitProcessors(TransferReceiver receiver, String transferId)
|
||||
{
|
||||
List<TransferManifestProcessor> processors = new ArrayList<TransferManifestProcessor>();
|
||||
CorrespondingNodeResolver nodeResolver = nodeResolverFactory.getResolver();
|
||||
|
||||
RepoPrimaryManifestProcessorImpl primaryProcessor = new RepoPrimaryManifestProcessorImpl(receiver, transferId);
|
||||
primaryProcessor.setContentService(contentService);
|
||||
primaryProcessor.setNodeResolver(nodeResolver);
|
||||
primaryProcessor.setNodeService(nodeService);
|
||||
processors.add(primaryProcessor);
|
||||
|
||||
RepoSecondaryManifestProcessorImpl secondaryProcessor = new RepoSecondaryManifestProcessorImpl(transferId);
|
||||
secondaryProcessor.setNodeResolver(nodeResolver);
|
||||
secondaryProcessor.setNodeService(nodeService);
|
||||
processors.add(secondaryProcessor);
|
||||
|
||||
return processors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentService the contentService to set
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeResolverFactory the nodeResolverFactory to set
|
||||
*/
|
||||
public void setNodeResolverFactory(CorrespondingNodeResolverFactory nodeResolverFactory)
|
||||
{
|
||||
this.nodeResolverFactory = nodeResolverFactory;
|
||||
}
|
||||
|
||||
}
|
35
source/java/org/alfresco/repo/transfer/DeltaList.java
Normal file
35
source/java/org/alfresco/repo/transfer/DeltaList.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
/**
|
||||
* Details back from the manifest to say which nodes the remote server already has.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class DeltaList
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
import org.apache.commons.httpclient.HostConfiguration;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpMethod;
|
||||
import org.apache.commons.httpclient.HttpState;
|
||||
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
|
||||
import org.apache.commons.httpclient.NameValuePair;
|
||||
import org.apache.commons.httpclient.UsernamePasswordCredentials;
|
||||
import org.apache.commons.httpclient.auth.AuthScope;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.methods.multipart.FilePart;
|
||||
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
|
||||
import org.apache.commons.httpclient.methods.multipart.Part;
|
||||
import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
|
||||
import org.apache.commons.httpclient.protocol.Protocol;
|
||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
|
||||
import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* HTTP implementation of TransferTransmitter.
|
||||
*
|
||||
* Sends data via HTTP to the server.
|
||||
*
|
||||
* @author brian
|
||||
*/
|
||||
public class HttpClientTransmitterImpl implements TransferTransmitter
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(HttpClientTransmitterImpl.class);
|
||||
|
||||
private static final String MSG_UNSUPPORTED_PROTOCOL = "transfer_service.comms.unsupported_protocol";
|
||||
private static final String MSG_UNSUCCESSFUL_RESPONSE = "transfer_service.comms.unsuccessful_response";
|
||||
private static final String MSG_HTTP_REQUEST_FAILED = "transfer_service.comms.http_request_failed";
|
||||
|
||||
private static final int DEFAULT_HTTP_PORT = 80;
|
||||
private static final int DEFAULT_HTTPS_PORT = 443;
|
||||
private static final String HTTP_SCHEME_NAME = "http"; // lowercase is important
|
||||
private static final String HTTPS_SCHEME_NAME = "https"; // lowercase is important
|
||||
|
||||
private HttpClient httpClient = null;
|
||||
private Protocol httpProtocol = new Protocol(HTTP_SCHEME_NAME, new DefaultProtocolSocketFactory(), DEFAULT_HTTP_PORT);
|
||||
private Protocol httpsProtocol = new Protocol(HTTPS_SCHEME_NAME, (ProtocolSocketFactory) new SSLProtocolSocketFactory(), DEFAULT_HTTPS_PORT);
|
||||
private Map<String,Protocol> protocolMap = null;
|
||||
|
||||
private ContentService contentService;
|
||||
|
||||
public HttpClientTransmitterImpl()
|
||||
{
|
||||
protocolMap = new TreeMap<String,Protocol>();
|
||||
protocolMap.put(HTTP_SCHEME_NAME, httpProtocol);
|
||||
protocolMap.put(HTTPS_SCHEME_NAME, httpsProtocol);
|
||||
|
||||
httpClient = new HttpClient();
|
||||
httpClient.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* By default this class uses the standard SSLProtocolSocketFactory, but this method allows this to be overridden.
|
||||
* Useful if, for example, one wishes to permit support of self-signed certificates on the target.
|
||||
* @param socketFactory
|
||||
*/
|
||||
public void setHttpsSocketFactory(ProtocolSocketFactory socketFactory)
|
||||
{
|
||||
protocolMap.put(HTTPS_SCHEME_NAME, new Protocol(HTTPS_SCHEME_NAME, socketFactory, DEFAULT_HTTPS_PORT));
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, this class uses a plain HttpClient instance with the only non-default
|
||||
* option being the multi-threaded connection manager.
|
||||
* Use this method to replace this with your own HttpClient instance configured how you wish
|
||||
* @param httpClient
|
||||
*/
|
||||
public void setHttpClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transfer.Transmitter#verifyTarget(org.alfresco.service.cmr.transfer.TransferTarget)
|
||||
*/
|
||||
public void verifyTarget(TransferTarget target) throws TransferException
|
||||
{
|
||||
HttpMethod verifyRequest = new PostMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
verifyRequest.setPath(target.getEndpointPath() + "/test");
|
||||
try
|
||||
{
|
||||
int response = httpClient.executeMethod(hostConfig, verifyRequest, httpState);
|
||||
checkResponseStatus("verifyTarget", response, verifyRequest);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"verifyTraget", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
verifyRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param response
|
||||
*/
|
||||
private void checkResponseStatus(String methodName, int response, HttpMethod method)
|
||||
{
|
||||
if (response != 200)
|
||||
{
|
||||
String errorId = null;
|
||||
String[] errorParams = null;
|
||||
try {
|
||||
log.error("Received \"unsuccessful\" response code from target server: " + response);
|
||||
String errorPayload = method.getResponseBodyAsString();
|
||||
JSONObject errorObj = new JSONObject(errorPayload);
|
||||
errorId = errorObj.getString("errorId");
|
||||
JSONArray errorParamArray = errorObj.getJSONArray("errorParams");
|
||||
int length = errorParamArray.length();
|
||||
errorParams = new String[length];
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
errorParams[i] = errorParamArray.getString(i);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new TransferException(MSG_UNSUCCESSFUL_RESPONSE, new Object[] {methodName, response});
|
||||
}
|
||||
throw new TransferException(errorId, errorParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTPState for a transfer target
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
private HttpState getHttpState(TransferTarget target)
|
||||
{
|
||||
HttpState httpState = new HttpState();
|
||||
httpState.setCredentials(new AuthScope(target.getEndpointHost(), target.getEndpointPort(),
|
||||
AuthScope.ANY_REALM),
|
||||
new UsernamePasswordCredentials(target.getUsername(), new String(target.getUsername())));
|
||||
return httpState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
private HostConfiguration getHostConfig(TransferTarget target)
|
||||
{
|
||||
String requiredProtocol = target.getEndpointProtocol();
|
||||
if (requiredProtocol == null)
|
||||
{
|
||||
throw new TransferException(MSG_UNSUPPORTED_PROTOCOL, new Object[] {target.getEndpointProtocol()});
|
||||
}
|
||||
|
||||
Protocol protocol = protocolMap.get(requiredProtocol.toLowerCase().trim());
|
||||
if (protocol == null) {
|
||||
log.error("Unsupported protocol: " + target.getEndpointProtocol());
|
||||
throw new TransferException(MSG_UNSUPPORTED_PROTOCOL, new Object[] {target.getEndpointProtocol()});
|
||||
}
|
||||
|
||||
HostConfiguration hostConfig = new HostConfiguration();
|
||||
hostConfig.setHost(target.getEndpointHost(), target.getEndpointPort(), protocol);
|
||||
return hostConfig;
|
||||
}
|
||||
|
||||
public Transfer begin(TransferTarget target) throws TransferException
|
||||
{
|
||||
HttpMethod beginRequest = new PostMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
beginRequest.setPath(target.getEndpointPath() + "/begin");
|
||||
try
|
||||
{
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, beginRequest, httpState);
|
||||
checkResponseStatus("begin", responseStatus, beginRequest);
|
||||
//If we get here then we've received a 200 response
|
||||
//We're expecting the transfer id encoded in a JSON object...
|
||||
JSONObject response = new JSONObject(beginRequest.getResponseBodyAsString());
|
||||
String transferId = response.getString("transferId");
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("begin transfer transferId:" + transferId +", target:" + target);
|
||||
}
|
||||
Transfer transfer = new Transfer();
|
||||
transfer.setTransferId(transferId);
|
||||
transfer.setTransferTarget(target);
|
||||
return transfer;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[] {"begin", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
beginRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public DeltaList sendManifest(Transfer transfer, File manifest) throws TransferException
|
||||
{
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
PostMethod postSnapshotRequest = new PostMethod();
|
||||
MultipartRequestEntity requestEntity;
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("does manifest exist? " + manifest.exists());
|
||||
log.debug("sendManifest file : " + manifest.getAbsoluteFile());
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
try
|
||||
{
|
||||
postSnapshotRequest.setPath(target.getEndpointPath() + "/post-snapshot");
|
||||
|
||||
//Put the transferId on the query string
|
||||
postSnapshotRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
|
||||
//TODO encapsulate the name of the manifest part
|
||||
//And add the manifest file as a "part"
|
||||
Part file = new FilePart(TransferCommons.PART_NAME_MANIFEST, manifest);
|
||||
requestEntity = new MultipartRequestEntity(new Part[] {file}, postSnapshotRequest.getParams());
|
||||
postSnapshotRequest.setRequestEntity(requestEntity);
|
||||
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, postSnapshotRequest, httpState);
|
||||
checkResponseStatus("sendManifest", responseStatus, postSnapshotRequest);
|
||||
return null;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"sendManifest", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
postSnapshotRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void abort(Transfer transfer) throws TransferException
|
||||
{
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
HttpMethod abortRequest = new PostMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
abortRequest.setPath(target.getEndpointPath() + "/abort");
|
||||
//Put the transferId on the query string
|
||||
abortRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
|
||||
try
|
||||
{
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, abortRequest, httpState);
|
||||
checkResponseStatus("abort", responseStatus, abortRequest);
|
||||
//If we get here then we've received a 200 response
|
||||
//We're expecting the transfer id encoded in a JSON object...
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"abort", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
abortRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void commit(Transfer transfer) throws TransferException
|
||||
{
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
HttpMethod commitRequest = new PostMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
commitRequest.setPath(target.getEndpointPath() + "/commit");
|
||||
//Put the transferId on the query string
|
||||
commitRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
try
|
||||
{
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, commitRequest, httpState);
|
||||
checkResponseStatus("commit", responseStatus, commitRequest);
|
||||
//If we get here then we've received a 200 response
|
||||
//We're expecting the transfer id encoded in a JSON object...
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.error(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"commit", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
commitRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void prepare(Transfer transfer) throws TransferException
|
||||
{
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
HttpMethod prepareRequest = new PostMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
prepareRequest.setPath(target.getEndpointPath() + "/prepare");
|
||||
//Put the transferId on the query string
|
||||
prepareRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
try
|
||||
{
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, prepareRequest, httpState);
|
||||
checkResponseStatus("prepare", responseStatus, prepareRequest);
|
||||
//If we get here then we've received a 200 response
|
||||
//We're expecting the transfer id encoded in a JSON object...
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"prepare", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
prepareRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void sendContent(Transfer transfer, Set<ContentData> data) throws TransferException
|
||||
{
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("send content to transfer:" + transfer);
|
||||
}
|
||||
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
PostMethod postContentRequest = new PostMethod();
|
||||
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
try
|
||||
{
|
||||
postContentRequest.setPath(target.getEndpointPath() + "/post-content");
|
||||
//Put the transferId on the query string
|
||||
postContentRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
|
||||
//Put the transferId on the query string
|
||||
postContentRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
|
||||
Part[] parts = new Part[data.size()];
|
||||
|
||||
int index = 0;
|
||||
for(ContentData content : data)
|
||||
{
|
||||
// TODO Encapsulate the URL to FileName algorithm
|
||||
String contentUrl = content.getContentUrl();
|
||||
String fileName = TransferCommons.URLToPartName(contentUrl);
|
||||
log.debug("content partName: " + fileName);
|
||||
|
||||
parts[index++] = new ContentDataPart(getContentService(), fileName, content);
|
||||
}
|
||||
|
||||
MultipartRequestEntity requestEntity = new MultipartRequestEntity(parts, postContentRequest.getParams());
|
||||
postContentRequest.setRequestEntity(requestEntity);
|
||||
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, postContentRequest, httpState);
|
||||
checkResponseStatus("sendContent", responseStatus, postContentRequest);
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("sent content");
|
||||
}
|
||||
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"sendContent", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
postContentRequest.releaseConnection();
|
||||
}
|
||||
} // end of sendContent
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Set<TransferMessage> getMessages(Transfer transfer)
|
||||
{
|
||||
// TODO How to signal last message ? return null rather than empty
|
||||
Set<TransferMessage> messages = new HashSet<TransferMessage>();
|
||||
|
||||
TransferTarget target = transfer.getTransferTarget();
|
||||
HttpMethod messagesRequest = new GetMethod();
|
||||
try
|
||||
{
|
||||
HostConfiguration hostConfig = getHostConfig(target);
|
||||
HttpState httpState = getHttpState(target);
|
||||
|
||||
messagesRequest.setPath(target.getEndpointPath() + "/messages");
|
||||
//Put the transferId on the query string
|
||||
messagesRequest.setQueryString(
|
||||
new NameValuePair[] {new NameValuePair("transferId", transfer.getTransferId())});
|
||||
|
||||
try
|
||||
{
|
||||
int responseStatus = httpClient.executeMethod(hostConfig, messagesRequest, httpState);
|
||||
checkResponseStatus("getMessages", responseStatus, messagesRequest);
|
||||
//If we get here then we've received a 200 response
|
||||
//We're expecting the transfer id encoded in a JSON object...
|
||||
|
||||
JSONObject lookupResult = new JSONObject(messagesRequest.getResponseBodyAsString());
|
||||
JSONArray data = lookupResult.getJSONArray("data");
|
||||
|
||||
for(int i = 0; i < data.length(); i++)
|
||||
{
|
||||
JSONObject obj = data.getJSONObject(i);
|
||||
String message = obj.getString("message");
|
||||
//TODO Need some sort of TransferMessage impl
|
||||
// messages.add(new TransferMessageImpl());
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String error = "Failed to execute HTTP request to target";
|
||||
log.debug(error, e);
|
||||
throw new TransferException(MSG_HTTP_REQUEST_FAILED, new Object[]{"getMessages", target.toString(), e.toString()}, e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
messagesRequest.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public ContentService getContentService()
|
||||
{
|
||||
return contentService;
|
||||
}
|
||||
|
||||
|
||||
} // end of class
|
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.apache.commons.httpclient.ConnectTimeoutException;
|
||||
import org.apache.commons.httpclient.HostConfiguration;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpMethod;
|
||||
import org.apache.commons.httpclient.HttpState;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.params.HttpConnectionParams;
|
||||
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/**
|
||||
* Unit test for HttpClientTransmitterImpl
|
||||
*
|
||||
* @author Brian Remmington
|
||||
*/
|
||||
public class HttpClientTransmitterImplTest extends TestCase
|
||||
{
|
||||
|
||||
|
||||
private static final String TARGET_HOST = "my.testhost.com";
|
||||
private static final String HTTP_PROTOCOL = "HTTP";
|
||||
private static final String HTTPS_PROTOCOL = "HTTPS";
|
||||
private static final String TRANSFER_SERVICE_PATH = "/api/transfer";
|
||||
private static final int HTTP_PORT = 80;
|
||||
private static final int HTTPS_PORT = 443;
|
||||
private static final String TARGET_USERNAME = "transferuser";
|
||||
private static final char[] TARGET_PASSWORD = "password".toCharArray();
|
||||
|
||||
private HttpClientTransmitterImpl transmitter;
|
||||
private HttpClient mockedHttpClient;
|
||||
private TransferTargetImpl target;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see junit.framework.TestCase#setUp()
|
||||
*/
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
|
||||
this.transmitter = new HttpClientTransmitterImpl();
|
||||
this.mockedHttpClient = mock(HttpClient.class);
|
||||
transmitter.setHttpClient(mockedHttpClient);
|
||||
|
||||
this.target = new TransferTargetImpl();
|
||||
target.setEndpointHost(TARGET_HOST);
|
||||
target.setEndpointProtocol(HTTP_PROTOCOL);
|
||||
target.setEndpointPath(TRANSFER_SERVICE_PATH);
|
||||
target.setEndpointPort(HTTP_PORT);
|
||||
target.setUsername(TARGET_USERNAME);
|
||||
target.setPassword(TARGET_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create target.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testSuccessfulVerifyTargetOverHttp() throws Exception
|
||||
{
|
||||
//Stub HttpClient so that executeMethod returns a 200 response
|
||||
when(mockedHttpClient.executeMethod(any(HostConfiguration.class), any(HttpMethod.class),
|
||||
any(HttpState.class))).thenReturn(200);
|
||||
|
||||
//Call verifyTarget
|
||||
transmitter.verifyTarget(target);
|
||||
|
||||
ArgumentCaptor<HostConfiguration> hostConfig = ArgumentCaptor.forClass(HostConfiguration.class);
|
||||
ArgumentCaptor<HttpMethod> httpMethod = ArgumentCaptor.forClass(HttpMethod.class);
|
||||
ArgumentCaptor<HttpState> httpState = ArgumentCaptor.forClass(HttpState.class);
|
||||
|
||||
verify(mockedHttpClient).executeMethod(hostConfig.capture(), httpMethod.capture(), httpState.capture());
|
||||
|
||||
assertTrue("post method", httpMethod.getValue() instanceof PostMethod);
|
||||
assertEquals("host name", TARGET_HOST, hostConfig.getValue().getHost());
|
||||
assertEquals("port", HTTP_PORT, hostConfig.getValue().getPort());
|
||||
assertEquals("protocol", HTTP_PROTOCOL.toLowerCase(),
|
||||
hostConfig.getValue().getProtocol().getScheme().toLowerCase());
|
||||
assertEquals("path", TRANSFER_SERVICE_PATH + "/test", httpMethod.getValue().getPath());
|
||||
}
|
||||
|
||||
public void testSuccessfulVerifyTargetOverHttps() throws Exception
|
||||
{
|
||||
|
||||
//Stub HttpClient so that executeMethod returns a 200 response
|
||||
when(mockedHttpClient.executeMethod(any(HostConfiguration.class), any(HttpMethod.class),
|
||||
any(HttpState.class))).thenReturn(200);
|
||||
|
||||
target.setEndpointProtocol(HTTPS_PROTOCOL);
|
||||
target.setEndpointPort(HTTPS_PORT);
|
||||
|
||||
//Call verifyTarget
|
||||
transmitter.verifyTarget(target);
|
||||
|
||||
ArgumentCaptor<HostConfiguration> hostConfig = ArgumentCaptor.forClass(HostConfiguration.class);
|
||||
ArgumentCaptor<HttpMethod> httpMethod = ArgumentCaptor.forClass(HttpMethod.class);
|
||||
ArgumentCaptor<HttpState> httpState = ArgumentCaptor.forClass(HttpState.class);
|
||||
|
||||
verify(mockedHttpClient).executeMethod(hostConfig.capture(), httpMethod.capture(), httpState.capture());
|
||||
|
||||
assertEquals("port", HTTPS_PORT, hostConfig.getValue().getPort());
|
||||
assertTrue("socket factory",
|
||||
hostConfig.getValue().getProtocol().getSocketFactory() instanceof SecureProtocolSocketFactory);
|
||||
assertEquals("protocol", HTTPS_PROTOCOL.toLowerCase(),
|
||||
hostConfig.getValue().getProtocol().getScheme().toLowerCase());
|
||||
}
|
||||
|
||||
public void testHttpsVerifyTargetWithCustomSocketFactory() throws Exception
|
||||
{
|
||||
//Override the default SSL socket factory with our own custom one...
|
||||
CustomSocketFactory socketFactory = new CustomSocketFactory();
|
||||
transmitter.setHttpsSocketFactory(socketFactory);
|
||||
|
||||
target.setEndpointProtocol(HTTPS_PROTOCOL);
|
||||
target.setEndpointPort(HTTPS_PORT);
|
||||
|
||||
//Stub HttpClient so that executeMethod returns a 200 response
|
||||
when(mockedHttpClient.executeMethod(any(HostConfiguration.class), any(HttpMethod.class),
|
||||
any(HttpState.class))).thenReturn(200);
|
||||
|
||||
//Call verifyTarget
|
||||
transmitter.verifyTarget(target);
|
||||
|
||||
ArgumentCaptor<HostConfiguration> hostConfig = ArgumentCaptor.forClass(HostConfiguration.class);
|
||||
ArgumentCaptor<HttpMethod> httpMethod = ArgumentCaptor.forClass(HttpMethod.class);
|
||||
ArgumentCaptor<HttpState> httpState = ArgumentCaptor.forClass(HttpState.class);
|
||||
|
||||
verify(mockedHttpClient).executeMethod(hostConfig.capture(), httpMethod.capture(), httpState.capture());
|
||||
|
||||
assertEquals("port", HTTPS_PORT, hostConfig.getValue().getPort());
|
||||
//test that the socket factory passed to HttpClient is our custom one (intentional use of '==')
|
||||
assertTrue("socket factory", hostConfig.getValue().getProtocol().getSocketFactory() == socketFactory);
|
||||
assertEquals("protocol", HTTPS_PROTOCOL.toLowerCase(),
|
||||
hostConfig.getValue().getProtocol().getScheme().toLowerCase());
|
||||
}
|
||||
|
||||
|
||||
public void testVerifyTargetWithInvalidProtocol() throws Exception
|
||||
{
|
||||
target.setEndpointProtocol("invalidprotocol");
|
||||
try
|
||||
{
|
||||
transmitter.verifyTarget(target);
|
||||
fail("invalid protocol");
|
||||
}
|
||||
catch(TransferException ex)
|
||||
{
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnauthorisedVerifyTarget() throws Exception
|
||||
{
|
||||
//Stub HttpClient so that executeMethod returns a 401 response
|
||||
when(mockedHttpClient.executeMethod(any(HostConfiguration.class), any(HttpMethod.class),
|
||||
any(HttpState.class))).thenReturn(401);
|
||||
|
||||
try
|
||||
{
|
||||
transmitter.verifyTarget(target);
|
||||
}
|
||||
catch (TransferException ex)
|
||||
{
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomSocketFactory implements SecureProtocolSocketFactory
|
||||
{
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean)
|
||||
*/
|
||||
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
|
||||
UnknownHostException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String, int)
|
||||
*/
|
||||
public Socket createSocket(String host, int port) throws IOException, UnknownHostException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
|
||||
*/
|
||||
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException,
|
||||
UnknownHostException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int, org.apache.commons.httpclient.params.HttpConnectionParams)
|
||||
*/
|
||||
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort,
|
||||
HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface ManifestProcessorFactory
|
||||
{
|
||||
List<TransferManifestProcessor> getCommitProcessors(TransferReceiver receiver, String transferId);
|
||||
}
|
200
source/java/org/alfresco/repo/transfer/NodeCrawlerTest.java
Normal file
200
source/java/org/alfresco/repo/transfer/NodeCrawlerTest.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.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.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;
|
||||
|
||||
/**
|
||||
* Unit test for RepoTransferReceiverImpl
|
||||
*
|
||||
* @author Brian Remmington
|
||||
*/
|
||||
public class NodeCrawlerTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private NodeRef companyHome;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the required services
|
||||
this.nodeService = (NodeService) this.getApplicationContext().getBean("NodeService");
|
||||
this.serviceRegistry = (ServiceRegistry) this.getApplicationContext().getBean("ServiceRegistry");
|
||||
ResultSet rs = serviceRegistry.getSearchService().query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_XPATH, "/app:company_home");
|
||||
if (rs.length() == 0)
|
||||
{
|
||||
fail("Could not find company home");
|
||||
}
|
||||
companyHome = rs.getNodeRef(0);
|
||||
}
|
||||
|
||||
public void testContentClassFilter() throws Exception
|
||||
{
|
||||
NodeRef node1 = makeNode(companyHome, ContentModel.TYPE_BASE);
|
||||
NodeRef node2 = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
NodeRef node3 = makeNode(companyHome, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node4 = makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
NodeRef node5 = makeNode(companyHome, ContentModel.TYPE_THUMBNAIL);
|
||||
|
||||
nodeService.addAspect(node4, ContentModel.ASPECT_REFERENCEABLE, null);
|
||||
|
||||
ContentClassFilter contentFilter = new ContentClassFilter(serviceRegistry);
|
||||
contentFilter.setContentClasses(ContentModel.TYPE_BASE);
|
||||
|
||||
assertTrue(contentFilter.accept(node1));
|
||||
assertTrue(contentFilter.accept(node2));
|
||||
assertTrue(contentFilter.accept(node3));
|
||||
|
||||
contentFilter.setDirectOnly(true);
|
||||
assertTrue(contentFilter.accept(node1));
|
||||
assertFalse(contentFilter.accept(node2));
|
||||
assertFalse(contentFilter.accept(node3));
|
||||
|
||||
contentFilter.setContentClasses(ContentModel.TYPE_BASE, ContentModel.ASPECT_REFERENCEABLE);
|
||||
assertTrue(contentFilter.accept(node4));
|
||||
|
||||
contentFilter.setExclude(true);
|
||||
contentFilter.setDirectOnly(false);
|
||||
contentFilter.setContentClasses(ContentModel.TYPE_CONTENT);
|
||||
assertTrue(contentFilter.accept(node1));
|
||||
assertFalse(contentFilter.accept(node2));
|
||||
assertTrue(contentFilter.accept(node3));
|
||||
assertFalse(contentFilter.accept(node5));
|
||||
|
||||
contentFilter.setDirectOnly(true);
|
||||
assertTrue(contentFilter.accept(node1));
|
||||
assertFalse(contentFilter.accept(node2));
|
||||
assertTrue(contentFilter.accept(node3));
|
||||
assertTrue(contentFilter.accept(node5));
|
||||
|
||||
}
|
||||
|
||||
public void testChildAssociationFinder()
|
||||
{
|
||||
makeNode(companyHome, ContentModel.TYPE_BASE);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
makeNode(companyHome, ContentModel.TYPE_CONTENT);
|
||||
NodeRef node8 = makeNode(companyHome, ContentModel.TYPE_FOLDER);
|
||||
makeNode(node8, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node10 = makeNode(node8, ContentModel.TYPE_FOLDER);
|
||||
makeNode(node10, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node12 = makeNode(node10, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node13 = makeNode(node12, ContentModel.TYPE_FOLDER);
|
||||
makeNode(node13, ContentModel.TYPE_CONTENT);
|
||||
NodeRef node15 = makeNode(node13, ContentModel.TYPE_THUMBNAIL);
|
||||
|
||||
nodeService.addAspect(node8, ContentModel.ASPECT_THUMBNAILED, null);
|
||||
nodeService.addChild(node8, node15, ContentModel.ASSOC_THUMBNAILS, QName.createQName(
|
||||
NamespaceService.APP_MODEL_1_0_URI, "temp"));
|
||||
|
||||
ChildAssociatedNodeFinder nodeFinder = new ChildAssociatedNodeFinder(serviceRegistry);
|
||||
nodeFinder.setAssociationTypes(ContentModel.ASSOC_CONTAINS);
|
||||
|
||||
Set<NodeRef> results = nodeFinder.findFrom(node8);
|
||||
assertEquals(2, results.size());
|
||||
|
||||
nodeFinder.setAssociationTypes(ContentModel.ASSOC_THUMBNAILS);
|
||||
results = nodeFinder.findFrom(node8);
|
||||
assertEquals(1, results.size());
|
||||
assertEquals(node15, new ArrayList<NodeRef>(results).get(0));
|
||||
}
|
||||
|
||||
public void testCrawler()
|
||||
{
|
||||
NodeRef node8 = makeNode(companyHome, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node9 = makeNode(node8, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node10 = makeNode(node8, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node11 = makeNode(node10, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node12 = makeNode(node10, ContentModel.TYPE_FOLDER);
|
||||
NodeRef node13 = makeNode(node12, ContentModel.TYPE_FOLDER);
|
||||
|
||||
makeNode(node10, ContentModel.TYPE_BASE);
|
||||
makeNode(node13, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node10, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node11, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node8, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node8, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node9, ContentModel.TYPE_CONTENT);
|
||||
makeNode(node13, ContentModel.TYPE_CONTENT);
|
||||
NodeRef node15 = makeNode(node13, ContentModel.TYPE_THUMBNAIL);
|
||||
|
||||
nodeService.addAspect(node8, ContentModel.ASPECT_THUMBNAILED, null);
|
||||
nodeService.addChild(node8, node15, ContentModel.ASSOC_THUMBNAILS, QName.createQName(
|
||||
NamespaceService.APP_MODEL_1_0_URI, "temp"));
|
||||
|
||||
StandardNodeCrawlerImpl crawler = new StandardNodeCrawlerImpl(serviceRegistry);
|
||||
crawler.setNodeFinders(new ChildAssociatedNodeFinder(ContentModel.ASSOC_CONTAINS));
|
||||
|
||||
Set<NodeRef> crawledNodes = crawler.crawl(node8);
|
||||
assertEquals(15, crawledNodes.size());
|
||||
|
||||
crawler.setNodeFilters(new ContentClassFilter(ContentModel.TYPE_FOLDER));
|
||||
crawledNodes = crawler.crawl(node8);
|
||||
assertEquals(6, crawledNodes.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param companyHome2
|
||||
* @param nodeType
|
||||
* @return
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
61
source/java/org/alfresco/repo/transfer/PathHelper.java
Normal file
61
source/java/org/alfresco/repo/transfer/PathHelper.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package org.alfresco.repo.transfer;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.util.ISO9075;
|
||||
|
||||
public class PathHelper
|
||||
{
|
||||
/**
|
||||
* Converts a String representation of a path to a Path
|
||||
*
|
||||
* e.g "/{http://www.alfresco.org/model/application/1.0}company_home/{http://www.alfresco.org/model/application/1.0}dictionary/{http://www.alfresco.org/model/application/1.0}transfers/{http://www.alfresco.org/model/content/1.0}default/{http://www.alfresco.org/model/transfer/1.0}snapshotMe";
|
||||
* @param value the string representation of the path.
|
||||
* @return Path
|
||||
*/
|
||||
public static Path stringToPath(String value)
|
||||
{
|
||||
Path path = new Path();
|
||||
|
||||
// pattern for QName e.g. /{stuff}stuff
|
||||
|
||||
Pattern pattern = Pattern.compile("/\\{[a-zA-Z:./0-9]*\\}[A-Z0-9a-z_ ]*");
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
|
||||
// This is the root node
|
||||
path.append(new SimplePathElement("/"));
|
||||
|
||||
while ( matcher.find() )
|
||||
{
|
||||
String group = matcher.group();
|
||||
final String val = ISO9075.decode(group.substring(1));
|
||||
path.append(new SimplePathElement(val));
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
private static class SimplePathElement extends Path.Element {
|
||||
private static final long serialVersionUID = -5243552616345217924L;
|
||||
private String elementString;
|
||||
|
||||
public SimplePathElement(String elementString)
|
||||
{
|
||||
this.elementString = elementString;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.repository.Path.Element#getElementString()
|
||||
*/
|
||||
@Override
|
||||
public String getElementString()
|
||||
{
|
||||
return elementString;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.transfer.NodeFinder;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class PeerAssociatedNodeFinder implements NodeFinder
|
||||
{
|
||||
private Set<QName> suppliedAssociationTypes = new HashSet<QName>();
|
||||
private boolean exclude = false;
|
||||
private boolean initialised = false;
|
||||
private List<QName> peerAssociationTypes = new ArrayList<QName>();
|
||||
private ServiceRegistry serviceRegistry;
|
||||
|
||||
public PeerAssociatedNodeFinder()
|
||||
{
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(Collection<QName> associationTypeNames)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(QName... associationTypeNames)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(Collection<QName> associationTypeNames, boolean exclude)
|
||||
{
|
||||
setAssociationTypes(associationTypeNames);
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(ServiceRegistry serviceRegistry, Collection<QName> associationTypeNames)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(ServiceRegistry serviceRegistry, QName... associationTypeNames)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setAssociationTypes(associationTypeNames);
|
||||
}
|
||||
|
||||
public PeerAssociatedNodeFinder(ServiceRegistry serviceRegistry, Collection<QName> associationTypeNames, boolean exclude)
|
||||
{
|
||||
this(serviceRegistry);
|
||||
setAssociationTypes(associationTypeNames);
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exclude
|
||||
* Set to true to exclude the specified association types, and false to include only the specified
|
||||
* association types.
|
||||
*/
|
||||
public void setExclude(boolean exclude)
|
||||
{
|
||||
this.exclude = exclude;
|
||||
}
|
||||
|
||||
public void setAssociationTypes(QName... associationTypes)
|
||||
{
|
||||
setAssociationTypes(Arrays.asList(associationTypes));
|
||||
}
|
||||
|
||||
public void setAssociationTypes(Collection<QName> associationTypes)
|
||||
{
|
||||
suppliedAssociationTypes = new HashSet<QName>(associationTypes);
|
||||
initialised = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.NodeFinder#findFrom(org.alfresco.service.cmr.repository.NodeRef,
|
||||
* org.alfresco.service.ServiceRegistry)
|
||||
*/
|
||||
public Set<NodeRef> findFrom(NodeRef thisNode)
|
||||
{
|
||||
if (!initialised)
|
||||
{
|
||||
init();
|
||||
}
|
||||
if (exclude)
|
||||
{
|
||||
return processExcludedSet(thisNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return processIncludedSet(thisNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thisNode
|
||||
* @param serviceRegistry
|
||||
* @return
|
||||
*/
|
||||
private Set<NodeRef> processExcludedSet(NodeRef thisNode)
|
||||
{
|
||||
Set<NodeRef> results = new HashSet<NodeRef>(89);
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
|
||||
// Find any peer nodes (filtering as necessary)
|
||||
List<AssociationRef> targets = nodeService.getTargetAssocs(thisNode, RegexQNamePattern.MATCH_ALL);
|
||||
boolean filterPeers = !peerAssociationTypes.isEmpty();
|
||||
for (AssociationRef target : targets)
|
||||
{
|
||||
if (!filterPeers || !peerAssociationTypes.contains(target.getTypeQName()))
|
||||
{
|
||||
results.add(target.getTargetRef());
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private Set<NodeRef> processIncludedSet(NodeRef startingNode)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.getNodeService();
|
||||
Set<NodeRef> foundNodes = new HashSet<NodeRef>(89);
|
||||
for (QName assocType : peerAssociationTypes)
|
||||
{
|
||||
List<AssociationRef> targets = nodeService.getTargetAssocs(startingNode, assocType);
|
||||
for (AssociationRef target : targets)
|
||||
{
|
||||
foundNodes.add(target.getTargetRef());
|
||||
}
|
||||
}
|
||||
return foundNodes;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
ParameterCheck.mandatory("serviceRegistry", serviceRegistry);
|
||||
DictionaryService dictionaryService = serviceRegistry.getDictionaryService();
|
||||
peerAssociationTypes.clear();
|
||||
for (QName associationType : suppliedAssociationTypes)
|
||||
{
|
||||
AssociationDefinition assocDef = dictionaryService.getAssociation(associationType);
|
||||
if (assocDef != null && !assocDef.isChild())
|
||||
{
|
||||
peerAssociationTypes.add(associationType);
|
||||
}
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry
|
||||
* the serviceRegistry to set
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,612 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transfer.CorrespondingNodeResolver.ResolvedParentChildPair;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
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.StoreRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class RepoPrimaryManifestProcessorImpl implements TransferManifestProcessor
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(RepoPrimaryManifestProcessorImpl.class);
|
||||
|
||||
private static final String MSG_NO_PRIMARY_PARENT_SUPPLIED = "transfer_service.receiver.no_primary_parent_supplied";
|
||||
private static final String MSG_ORPHANS_EXIST = "transfer_service.receiver.orphans_exist";
|
||||
private static final String MSG_REFERENCED_CONTENT_FILE_MISSING = "transfer_service.receiver.content_file_missing";
|
||||
|
||||
protected static final Set<QName> DEFAULT_LOCAL_PROPERTIES = new HashSet<QName>();
|
||||
|
||||
static
|
||||
{
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_STORE_IDENTIFIER);
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_STORE_NAME);
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_STORE_PROTOCOL);
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_NODE_DBID);
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_NODE_REF);
|
||||
DEFAULT_LOCAL_PROPERTIES.add(ContentModel.PROP_NODE_UUID);
|
||||
}
|
||||
|
||||
private TransferReceiver receiver;
|
||||
private String transferId;
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
private CorrespondingNodeResolver nodeResolver;
|
||||
|
||||
private Map<NodeRef, List<ChildAssociationRef>> orphans = new HashMap<NodeRef, List<ChildAssociationRef>>(89);
|
||||
|
||||
/**
|
||||
* @param transferId
|
||||
*/
|
||||
public RepoPrimaryManifestProcessorImpl(TransferReceiver receiver, String transferId)
|
||||
{
|
||||
this.receiver = receiver;
|
||||
this.transferId = transferId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#endTransferManifest()
|
||||
*/
|
||||
public void endTransferManifest()
|
||||
{
|
||||
if (!orphans.isEmpty())
|
||||
{
|
||||
error(MSG_ORPHANS_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestDeletedNode node)
|
||||
{
|
||||
// This is a deleted node. First we need to check whether it has already been deleted in this repo
|
||||
// too by looking in the local archive store. If we find it then we need not do anything.
|
||||
// If we can't find it in our archive store then we'll see if we can find a corresponding node in the
|
||||
// store in which its old parent lives.
|
||||
// If we can find a corresponding node then we'll delete it.
|
||||
// If we can't find a corresponding node then we'll do nothing.
|
||||
|
||||
if (!nodeService.exists(node.getNodeRef()))
|
||||
{
|
||||
// It's not in our archive store. Check to see if we can find it in its original store...
|
||||
ChildAssociationRef origPrimaryParent = node.getPrimaryParentAssoc();
|
||||
NodeRef origNodeRef = new NodeRef(origPrimaryParent.getParentRef().getStoreRef(), node.getNodeRef().getId());
|
||||
|
||||
CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode(
|
||||
origNodeRef, origPrimaryParent, node.getParentPath());
|
||||
|
||||
// Does a corresponding node exist in this repo?
|
||||
if (resolvedNodes.resolvedChild != null)
|
||||
{
|
||||
// Yes, it does. Delete it.
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Incoming deleted noderef " + node.getNodeRef() +
|
||||
" has been resolved to existing local noderef " + resolvedNodes.resolvedChild +
|
||||
" - deleting");
|
||||
}
|
||||
nodeService.deleteNode(resolvedNodes.resolvedChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Incoming deleted noderef has no corresponding local noderef: " + node.getNodeRef() +
|
||||
" - ignoring");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifestNode(org.alfresco.repo.transfer
|
||||
* .manifest.TransferManifestNode)
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestNormalNode node)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Processing node with incoming noderef of " + node.getNodeRef());
|
||||
}
|
||||
ChildAssociationRef primaryParentAssoc = getPrimaryParent(node);
|
||||
if (primaryParentAssoc == null)
|
||||
{
|
||||
error(node, MSG_NO_PRIMARY_PARENT_SUPPLIED);
|
||||
}
|
||||
|
||||
CorrespondingNodeResolver.ResolvedParentChildPair resolvedNodes = nodeResolver.resolveCorrespondingNode(
|
||||
node.getNodeRef(), primaryParentAssoc, node.getParentPath());
|
||||
|
||||
// Does a corresponding node exist in this repo?
|
||||
if (resolvedNodes.resolvedChild != null)
|
||||
{
|
||||
// Yes, it does. Update it.
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Incoming noderef " + node.getNodeRef() +
|
||||
" has been resolved to existing local noderef " + resolvedNodes.resolvedChild);
|
||||
}
|
||||
update(node, resolvedNodes, primaryParentAssoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No, there is no corresponding node. Worth just quickly checking the archive store...
|
||||
NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, node.getNodeRef().getId());
|
||||
if (nodeService.exists(archiveNodeRef))
|
||||
{
|
||||
// We have found a node in the archive store that has the same UUID as the one that we've
|
||||
// been sent. We'll restore that archived node to a temporary location and then try
|
||||
// processing this node again
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("Located an archived node with UUID matching transferred node: " + archiveNodeRef);
|
||||
log.info("Attempting to restore " + archiveNodeRef);
|
||||
}
|
||||
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
|
||||
NodeRef restoredNodeRef = nodeService.restoreNode(archiveNodeRef, tempLocation.getParentRef(),
|
||||
tempLocation.getTypeQName(), tempLocation.getQName());
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("Successfully restored node as " + restoredNodeRef + " - retrying transferred node");
|
||||
}
|
||||
processTransferManifestNode(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Incoming noderef has no corresponding local noderef: " + node.getNodeRef());
|
||||
}
|
||||
create(node, resolvedNodes, primaryParentAssoc);
|
||||
}
|
||||
|
||||
}
|
||||
catch (TransferProcessingException ex)
|
||||
{
|
||||
log.error("transfer processing exception" + ex.toString(), ex);
|
||||
//TODO MER BUGBUG - What to do here? probably can't just swallow it
|
||||
// does this mean that the manifest is stuffed?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the node ref, this method constructs the appropriate ChildAssociationRef that would place this node in the
|
||||
* transfer's temporary folder. Useful when handling orphans.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
*/
|
||||
private ChildAssociationRef getTemporaryLocation(NodeRef nodeRef)
|
||||
{
|
||||
NodeRef parentNodeRef = receiver.getTempFolder(transferId);
|
||||
QName parentAssocType = ContentModel.ASSOC_CONTAINS;
|
||||
QName parentAssocName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, nodeRef.getId());
|
||||
return new ChildAssociationRef(parentAssocType, parentNodeRef, parentAssocName, nodeRef, true, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node
|
||||
* @param resolvedNodes
|
||||
* @param primaryParentAssoc
|
||||
*/
|
||||
private void create(TransferManifestNormalNode node, ResolvedParentChildPair resolvedNodes,
|
||||
ChildAssociationRef primaryParentAssoc)
|
||||
{
|
||||
log.info("Creating new node with noderef " + node.getNodeRef());
|
||||
QName parentAssocType = primaryParentAssoc.getTypeQName();
|
||||
QName parentAssocName = primaryParentAssoc.getQName();
|
||||
NodeRef parentNodeRef = resolvedNodes.resolvedParent;
|
||||
if (parentNodeRef == null)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Unable to resolve parent for inbound noderef " + node.getNodeRef() +
|
||||
".\n Supplied parent noderef is " + primaryParentAssoc.getParentRef() +
|
||||
".\n Supplied parent path is " + node.getParentPath().toString());
|
||||
}
|
||||
// We can't find the node's parent.
|
||||
// We'll store the node in a temporary location and record it for later processing
|
||||
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
|
||||
parentNodeRef = tempLocation.getParentRef();
|
||||
parentAssocType = tempLocation.getTypeQName();
|
||||
parentAssocName = tempLocation.getQName();
|
||||
log.info("Recording orphaned transfer node: " + node.getNodeRef());
|
||||
storeOrphanNode(primaryParentAssoc);
|
||||
}
|
||||
// We now know that this is a new node, and we have found the appropriate parent node in the
|
||||
// local repository.
|
||||
log.info("Resolved parent node to " + parentNodeRef);
|
||||
|
||||
// We need to process content properties separately.
|
||||
// First, create a shallow copy of the supplied property map...
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>(node.getProperties());
|
||||
|
||||
// Split out the content properties and sanitise the others
|
||||
Map<QName, Serializable> contentProps = processProperties(null, props, true);
|
||||
|
||||
// Create the corresponding node...
|
||||
ChildAssociationRef newNode = nodeService.createNode(parentNodeRef, parentAssocType, parentAssocName,
|
||||
node.getType(), props);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Created new node (" + newNode.getChildRef() + ") parented by node " + newNode.getParentRef());
|
||||
}
|
||||
|
||||
// Deal with the content properties
|
||||
writeContent(newNode.getChildRef(), contentProps);
|
||||
|
||||
// Apply any aspects that are needed but haven't automatically been applied
|
||||
Set<QName> aspects = new HashSet<QName>(node.getAspects());
|
||||
aspects.removeAll(nodeService.getAspects(newNode.getChildRef()));
|
||||
for (QName aspect : aspects)
|
||||
{
|
||||
nodeService.addAspect(newNode.getChildRef(), aspect, null);
|
||||
}
|
||||
|
||||
// Is the node that we've just added the parent of any orphans that we've found earlier?
|
||||
List<ChildAssociationRef> orphansToClaim = orphans.get(newNode.getChildRef());
|
||||
if (orphansToClaim != null)
|
||||
{
|
||||
// Yes, it is...
|
||||
for (ChildAssociationRef orphan : orphansToClaim)
|
||||
{
|
||||
nodeService.moveNode(orphan.getChildRef(), orphan.getParentRef(), orphan.getTypeQName(),
|
||||
orphan.getQName());
|
||||
}
|
||||
// We can now remove the record of these orphans, as their parent has been found
|
||||
orphans.remove(newNode.getChildRef());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node
|
||||
* @param resolvedNodes
|
||||
* @param primaryParentAssoc
|
||||
*/
|
||||
private void update(TransferManifestNormalNode node, ResolvedParentChildPair resolvedNodes,
|
||||
ChildAssociationRef primaryParentAssoc)
|
||||
{
|
||||
NodeRef nodeToUpdate = resolvedNodes.resolvedChild;
|
||||
|
||||
QName parentAssocType = primaryParentAssoc.getTypeQName();
|
||||
QName parentAssocName = primaryParentAssoc.getQName();
|
||||
NodeRef parentNodeRef = resolvedNodes.resolvedParent;
|
||||
if (parentNodeRef == null)
|
||||
{
|
||||
// We can't find the node's parent.
|
||||
// We'll store the node in a temporary location and record it for later processing
|
||||
ChildAssociationRef tempLocation = getTemporaryLocation(node.getNodeRef());
|
||||
parentNodeRef = tempLocation.getParentRef();
|
||||
parentAssocType = tempLocation.getTypeQName();
|
||||
parentAssocName = tempLocation.getQName();
|
||||
storeOrphanNode(primaryParentAssoc);
|
||||
}
|
||||
// First of all, do we need to move the node? If any aspect of the primary parent association has changed
|
||||
// then the answer is "yes"
|
||||
ChildAssociationRef currentParent = nodeService.getPrimaryParent(nodeToUpdate);
|
||||
if (!currentParent.getParentRef().equals(parentNodeRef) ||
|
||||
!currentParent.getTypeQName().equals(parentAssocType) ||
|
||||
!currentParent.getQName().equals(parentAssocName))
|
||||
{
|
||||
// Yes, we need to move the node
|
||||
nodeService.moveNode(nodeToUpdate, parentNodeRef, parentAssocType, parentAssocName);
|
||||
}
|
||||
|
||||
log.info("Resolved parent node to " + parentNodeRef);
|
||||
|
||||
if (updateNeeded(node, nodeToUpdate))
|
||||
{
|
||||
|
||||
// We need to process content properties separately.
|
||||
// First, create a shallow copy of the supplied property map...
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>(node.getProperties());
|
||||
|
||||
// Split out the content properties and sanitise the others
|
||||
Map<QName, Serializable> contentProps = processProperties(nodeToUpdate, props, false);
|
||||
|
||||
// Update the non-content properties
|
||||
nodeService.setProperties(nodeToUpdate, props);
|
||||
|
||||
// Deal with the content properties
|
||||
writeContent(nodeToUpdate, contentProps);
|
||||
|
||||
// Blend the aspects together
|
||||
Set<QName> suppliedAspects = new HashSet<QName>(node.getAspects());
|
||||
Set<QName> existingAspects = nodeService.getAspects(nodeToUpdate);
|
||||
Set<QName> aspectsToRemove = new HashSet<QName>(existingAspects);
|
||||
|
||||
aspectsToRemove.removeAll(suppliedAspects);
|
||||
suppliedAspects.removeAll(existingAspects);
|
||||
|
||||
// Now aspectsToRemove contains the set of aspects to remove
|
||||
// and suppliedAspects contains the set of aspects to add
|
||||
for (QName aspect : suppliedAspects)
|
||||
{
|
||||
nodeService.addAspect(nodeToUpdate, aspect, null);
|
||||
}
|
||||
|
||||
for (QName aspect : aspectsToRemove)
|
||||
{
|
||||
nodeService.removeAspect(nodeToUpdate, aspect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes all the received properties and separates them into two parts. The content properties are
|
||||
* removed from the non-content properties such that the non-content properties remain in the "props" map and the
|
||||
* content properties are returned from this method Subsequently, any properties that are to be retained from the
|
||||
* local repository are copied over into the "props" map. The result of all this is that, upon return, "props"
|
||||
* contains all the non-content properties that are to be written to the local repo, and "contentProps" contains all
|
||||
* the content properties that are to be written to the local repo.
|
||||
*
|
||||
* @param nodeToUpdate
|
||||
* The noderef of the existing node in the local repo that is to be updated with these properties. May be
|
||||
* null, indicating that these properties are destined for a brand new local node.
|
||||
* @param props
|
||||
* @return A map containing the content properties from the supplied "props" map
|
||||
*/
|
||||
private Map<QName, Serializable> processProperties(NodeRef nodeToUpdate, Map<QName, Serializable> props,
|
||||
boolean isNew)
|
||||
{
|
||||
Map<QName, Serializable> contentProps = new HashMap<QName, Serializable>();
|
||||
// ...and copy any supplied content properties into this new map...
|
||||
for (Map.Entry<QName, Serializable> propEntry : props.entrySet())
|
||||
{
|
||||
if (ContentData.class.isAssignableFrom(propEntry.getValue().getClass()))
|
||||
{
|
||||
contentProps.put(propEntry.getKey(), propEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can remove the content properties from amongst the other kinds of properties
|
||||
// (no removeAll on a Map...)
|
||||
for (QName contentPropertyName : contentProps.keySet())
|
||||
{
|
||||
props.remove(contentPropertyName);
|
||||
}
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
// Finally, overlay the repo-specific properties from the existing node (if there is one)
|
||||
Map<QName, Serializable> existingProps = (nodeToUpdate == null) ? new HashMap<QName, Serializable>()
|
||||
: nodeService.getProperties(nodeToUpdate);
|
||||
|
||||
for (QName localProperty : getLocalProperties())
|
||||
{
|
||||
Serializable existingValue = existingProps.get(localProperty);
|
||||
if (existingValue != null)
|
||||
{
|
||||
props.put(localProperty, existingValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
props.remove(localProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
return contentProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @param nodeToUpdate
|
||||
* @param contentProps
|
||||
*/
|
||||
private void writeContent(NodeRef nodeToUpdate, Map<QName, Serializable> contentProps)
|
||||
{
|
||||
File stagingDir = receiver.getStagingFolder(transferId);
|
||||
for (Map.Entry<QName, Serializable> contentEntry : contentProps.entrySet())
|
||||
{
|
||||
ContentData contentData = (ContentData) contentEntry.getValue();
|
||||
String contentUrl = contentData.getContentUrl();
|
||||
String fileName = contentUrl.substring(contentUrl.lastIndexOf('/') + 1);
|
||||
File stagedFile = new File(stagingDir, fileName);
|
||||
if (!stagedFile.exists())
|
||||
{
|
||||
error(MSG_REFERENCED_CONTENT_FILE_MISSING);
|
||||
}
|
||||
ContentWriter writer = contentService.getWriter(nodeToUpdate, contentEntry.getKey(), true);
|
||||
writer.setEncoding(contentData.getEncoding());
|
||||
writer.setMimetype(contentData.getMimetype());
|
||||
writer.setLocale(contentData.getLocale());
|
||||
writer.putContent(stagedFile);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean updateNeeded(TransferManifestNode node, NodeRef nodeToUpdate)
|
||||
{
|
||||
return true;
|
||||
// TODO MER - Temp commenting out.
|
||||
// //Assumption: if the modified and modifier properties haven't changed, and the cm:content property
|
||||
// //(if it exists) hasn't changed size then we can assume that properties don't need to be updated...
|
||||
// Map<QName, Serializable> suppliedProps = node.getProperties();
|
||||
// Date suppliedModifiedDate = (Date)suppliedProps.get(ContentModel.PROP_MODIFIED);
|
||||
// String suppliedModifier = (String)suppliedProps.get(ContentModel.PROP_MODIFIER);
|
||||
// ContentData suppliedContent = (ContentData)suppliedProps.get(ContentModel.PROP_CONTENT);
|
||||
//
|
||||
// Map<QName, Serializable> existingProps = nodeService.getProperties(nodeToUpdate);
|
||||
// Date existingModifiedDate = (Date)existingProps.get(ContentModel.PROP_MODIFIED);
|
||||
// String existingModifier = (String)existingProps.get(ContentModel.PROP_MODIFIER);
|
||||
// ContentData existingContent = (ContentData)existingProps.get(ContentModel.PROP_CONTENT);
|
||||
//
|
||||
// boolean updateNeeded = false;
|
||||
// updateNeeded |= ((suppliedModifiedDate != null && !suppliedModifiedDate.equals(existingModifiedDate)) ||
|
||||
// (existingModifiedDate != null && !existingModifiedDate.equals(suppliedModifiedDate)));
|
||||
// updateNeeded |= ((suppliedContent != null && existingContent == null) ||
|
||||
// (suppliedContent == null && existingContent != null) ||
|
||||
// (suppliedContent != null && existingContent != null && suppliedContent.getSize() !=
|
||||
// existingContent.getSize()));
|
||||
// updateNeeded |= ((suppliedModifier != null && !suppliedModifier.equals(existingModifier)) ||
|
||||
// (existingModifier != null && !existingModifier.equals(suppliedModifier)));
|
||||
// return updateNeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected Set<QName> getLocalProperties()
|
||||
{
|
||||
return DEFAULT_LOCAL_PROPERTIES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param primaryParentAssoc
|
||||
*/
|
||||
private void storeOrphanNode(ChildAssociationRef primaryParentAssoc)
|
||||
{
|
||||
List<ChildAssociationRef> orphansOfParent = orphans.get(primaryParentAssoc.getParentRef());
|
||||
if (orphansOfParent == null)
|
||||
{
|
||||
orphansOfParent = new ArrayList<ChildAssociationRef>();
|
||||
orphans.put(primaryParentAssoc.getParentRef(), orphansOfParent);
|
||||
}
|
||||
orphansOfParent.add(primaryParentAssoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @param msgId
|
||||
*/
|
||||
private void error(TransferManifestNode node, String msgId)
|
||||
{
|
||||
TransferProcessingException ex = new TransferProcessingException(msgId);
|
||||
log.error(ex.getMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
*/
|
||||
private void error(String msgId)
|
||||
{
|
||||
TransferProcessingException ex = new TransferProcessingException(msgId);
|
||||
log.error(ex.getMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
private ChildAssociationRef getPrimaryParent(TransferManifestNormalNode node)
|
||||
{
|
||||
List<ChildAssociationRef> parents = node.getParentAssocs();
|
||||
for (ChildAssociationRef parent : parents)
|
||||
{
|
||||
if (parent.isPrimary())
|
||||
return parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifiestHeader(org.alfresco.repo
|
||||
* .transfer.manifest.TransferManifestHeader)
|
||||
*/
|
||||
public void processTransferManifiestHeader(TransferManifestHeader header)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#startTransferManifest()
|
||||
*/
|
||||
public void startTransferManifest()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
* the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentService
|
||||
* the contentService to set
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeResolver
|
||||
* the nodeResolver to set
|
||||
*/
|
||||
public void setNodeResolver(CorrespondingNodeResolver nodeResolver)
|
||||
{
|
||||
this.nodeResolver = nodeResolver;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeHelper;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
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.RegexQNamePattern;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class RepoSecondaryManifestProcessorImpl implements TransferManifestProcessor
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private CorrespondingNodeResolver nodeResolver;
|
||||
private String transferId;
|
||||
|
||||
/**
|
||||
* @param transferId
|
||||
*/
|
||||
public RepoSecondaryManifestProcessorImpl(String transferId)
|
||||
{
|
||||
this.transferId = transferId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#endTransferManifest()
|
||||
*/
|
||||
public void endTransferManifest()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestDeletedNode node)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifestNode(org.alfresco.repo.transfer
|
||||
* .manifest.TransferManifestNode)
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestNormalNode node)
|
||||
{
|
||||
NodeRef correspondingNodeRef = nodeResolver.resolveCorrespondingNode(node.getNodeRef(),
|
||||
TransferManifestNodeHelper.getPrimaryParentAssoc(node), node.getParentPath()).resolvedChild;
|
||||
|
||||
if (correspondingNodeRef == null)
|
||||
{
|
||||
correspondingNodeRef = node.getNodeRef();
|
||||
}
|
||||
|
||||
|
||||
//Process parent assocs...
|
||||
List<ChildAssociationRef> requiredAssocs = node.getParentAssocs();
|
||||
List<ChildAssociationRef> currentAssocs = nodeService.getParentAssocs(correspondingNodeRef);
|
||||
processParentChildAssociations(requiredAssocs, currentAssocs, correspondingNodeRef, false);
|
||||
|
||||
//Process child assocs...
|
||||
requiredAssocs = node.getChildAssocs();
|
||||
currentAssocs = nodeService.getChildAssocs(correspondingNodeRef);
|
||||
processParentChildAssociations(requiredAssocs, currentAssocs, correspondingNodeRef, true);
|
||||
|
||||
|
||||
//Process "target" peer associations (associations *from* this node)
|
||||
List<AssociationRef> requiredPeerAssocs = node.getTargetAssocs();
|
||||
List<AssociationRef> currentPeerAssocs = nodeService.getTargetAssocs(correspondingNodeRef, RegexQNamePattern.MATCH_ALL);
|
||||
processPeerAssociations(requiredPeerAssocs, currentPeerAssocs, correspondingNodeRef, true);
|
||||
|
||||
//Process "source" peer associations (associations *to* this node)
|
||||
requiredPeerAssocs = node.getSourceAssocs();
|
||||
currentPeerAssocs = nodeService.getSourceAssocs(correspondingNodeRef, RegexQNamePattern.MATCH_ALL);
|
||||
processPeerAssociations(requiredPeerAssocs, currentPeerAssocs, correspondingNodeRef, true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param requiredAssocs
|
||||
* @param currentAssocs
|
||||
* @param correspondingNodeRef
|
||||
* @param isSource
|
||||
*/
|
||||
private void processPeerAssociations(List<AssociationRef> requiredAssocs,
|
||||
List<AssociationRef> currentAssocs, NodeRef nodeRef, boolean isSource)
|
||||
{
|
||||
if (requiredAssocs == null) {
|
||||
requiredAssocs = new ArrayList<AssociationRef>();
|
||||
}
|
||||
if (currentAssocs == null) {
|
||||
currentAssocs = new ArrayList<AssociationRef>();
|
||||
}
|
||||
|
||||
List<AssociationRef> assocsToAdd = new ArrayList<AssociationRef>();
|
||||
List<AssociationRef> assocsToRemove = new ArrayList<AssociationRef>();
|
||||
|
||||
Map<NodeRef, AssociationRef> currentAssocMap = new HashMap<NodeRef, AssociationRef>();
|
||||
|
||||
for (AssociationRef currentAssoc : currentAssocs) {
|
||||
NodeRef otherNode = isSource ? currentAssoc.getTargetRef() : currentAssoc.getSourceRef();
|
||||
currentAssocMap.put(otherNode, currentAssoc);
|
||||
}
|
||||
|
||||
for (AssociationRef requiredAssoc : requiredAssocs)
|
||||
{
|
||||
NodeRef otherNode = isSource ? requiredAssoc.getTargetRef() : requiredAssoc.getSourceRef();
|
||||
AssociationRef existingAssociation = currentAssocMap.remove(otherNode);
|
||||
if (existingAssociation != null) {
|
||||
//We already have an association with the required node.
|
||||
//Check whether it is correct
|
||||
if (!existingAssociation.getTypeQName().equals(requiredAssoc.getTypeQName())) {
|
||||
//No, the existing one doesn't match the required one
|
||||
assocsToRemove.add(existingAssociation);
|
||||
assocsToAdd.add(requiredAssoc);
|
||||
}
|
||||
} else {
|
||||
//We don't have an existing association with this required node
|
||||
//Check that the required node exists in this repo, and record it for adding
|
||||
//if it does
|
||||
if (nodeService.exists(otherNode)) {
|
||||
assocsToAdd.add(requiredAssoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Once we get here, any entries remaining in currentParentMap are associations that need to be deleted.
|
||||
assocsToRemove.addAll(currentAssocMap.values());
|
||||
//Deal with associations to be removed
|
||||
for (AssociationRef assocToRemove : assocsToRemove) {
|
||||
nodeService.removeAssociation(assocToRemove.getSourceRef(), assocToRemove.getTargetRef(), assocToRemove.getTypeQName());
|
||||
}
|
||||
//Deal with associations to be added
|
||||
for (AssociationRef assocToAdd : assocsToAdd) {
|
||||
NodeRef source = isSource ? nodeRef : assocToAdd.getSourceRef();
|
||||
NodeRef target = isSource ? assocToAdd.getTargetRef() : nodeRef;
|
||||
nodeService.createAssociation(source, target, assocToAdd.getTypeQName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processParentChildAssociations(List<ChildAssociationRef> requiredAssocs,
|
||||
List<ChildAssociationRef> currentAssocs, NodeRef nodeRef, boolean isParent) {
|
||||
|
||||
if (requiredAssocs == null) {
|
||||
requiredAssocs = new ArrayList<ChildAssociationRef>();
|
||||
}
|
||||
if (currentAssocs == null) {
|
||||
currentAssocs = new ArrayList<ChildAssociationRef>();
|
||||
}
|
||||
|
||||
List<ChildAssociationRef> assocsToAdd = new ArrayList<ChildAssociationRef>();
|
||||
List<ChildAssociationRef> assocsToRemove = new ArrayList<ChildAssociationRef>();
|
||||
|
||||
Map<NodeRef, ChildAssociationRef> currentAssocMap = new HashMap<NodeRef, ChildAssociationRef>();
|
||||
|
||||
for (ChildAssociationRef currentAssoc : currentAssocs) {
|
||||
if (!currentAssoc.isPrimary()) {
|
||||
NodeRef key = isParent ? currentAssoc.getChildRef() : currentAssoc.getParentRef();
|
||||
currentAssocMap.put(key, currentAssoc);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChildAssociationRef requiredAssoc : requiredAssocs)
|
||||
{
|
||||
// We skip the primary parent, since this has already been handled
|
||||
if (!requiredAssoc.isPrimary())
|
||||
{
|
||||
NodeRef otherNode = isParent ? requiredAssoc.getChildRef() : requiredAssoc.getParentRef();
|
||||
ChildAssociationRef existingAssociation = currentAssocMap.remove(otherNode);
|
||||
if (existingAssociation != null) {
|
||||
//We already have an association with the required parent.
|
||||
//Check whether it is correct
|
||||
if (!existingAssociation.getQName().equals(requiredAssoc.getQName()) ||
|
||||
!existingAssociation.getTypeQName().equals(requiredAssoc.getTypeQName())) {
|
||||
//No, the existing one doesn't match the required one
|
||||
assocsToRemove.add(existingAssociation);
|
||||
assocsToAdd.add(requiredAssoc);
|
||||
}
|
||||
} else {
|
||||
//We don't have an existing association with this required parent
|
||||
//Check that the requiredParent exists in this repo, and record it for adding
|
||||
//if it does
|
||||
if (nodeService.exists(otherNode)) {
|
||||
assocsToAdd.add(requiredAssoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Once we get here, any entries remaining in currentParentMap are associations that need to be deleted.
|
||||
assocsToRemove.addAll(currentAssocMap.values());
|
||||
//Deal with associations to be removed
|
||||
for (ChildAssociationRef assocToRemove : assocsToRemove) {
|
||||
nodeService.removeChildAssociation(assocToRemove);
|
||||
}
|
||||
//Deal with associations to be added
|
||||
for (ChildAssociationRef assocToAdd : assocsToAdd) {
|
||||
NodeRef parent = isParent ? nodeRef : assocToAdd.getParentRef();
|
||||
NodeRef child = isParent ? assocToAdd.getChildRef() : nodeRef;
|
||||
nodeService.addChild(parent, child,
|
||||
assocToAdd.getTypeQName(), assocToAdd.getQName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.repo.transfer.manifest.TransferManifestProcessor#processTransferManifiestHeader(org.alfresco.repo
|
||||
* .transfer.manifest.TransferManifestHeader)
|
||||
*/
|
||||
public void processTransferManifiestHeader(TransferManifestHeader header)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestProcessor#startTransferManifest()
|
||||
*/
|
||||
public void startTransferManifest()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
* the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeResolver
|
||||
* the nodeResolver to set
|
||||
*/
|
||||
public void setNodeResolver(CorrespondingNodeResolver nodeResolver)
|
||||
{
|
||||
this.nodeResolver = nodeResolver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.repo.transfer.manifest.XMLTransferManifestReader;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
||||
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.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class RepoTransferReceiverImpl implements TransferReceiver
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(RepoTransferReceiverImpl.class);
|
||||
|
||||
private static final String MSG_FAILED_TO_CREATE_STAGING_FOLDER = "transfer_service.receiver.failed_to_create_staging_folder";
|
||||
private static final String MSG_TRANSFER_LOCK_FOLDER_NOT_FOUND = "transfer_service.receiver.lock_folder_not_found";
|
||||
private static final String MSG_TRANSFER_TEMP_FOLDER_NOT_FOUND = "transfer_service.receiver.temp_folder_not_found";
|
||||
private static final String MSG_TRANSFER_LOCK_UNAVAILABLE = "transfer_service.receiver.lock_unavailable";
|
||||
private static final String MSG_INBOUND_TRANSFER_FOLDER_NOT_FOUND = "transfer_service.receiver.record_folder_not_found";
|
||||
private static final String MSG_NOT_LOCK_OWNER = "transfer_service.receiver.not_lock_owner";
|
||||
private static final String MSG_ERROR_WHILE_ENDING_TRANSFER = "transfer_service.receiver.error_ending_transfer";
|
||||
private static final String MSG_ERROR_WHILE_STAGING_SNAPSHOT = "transfer_service.receiver.error_staging_snapshot";
|
||||
private static final String MSG_ERROR_WHILE_STAGING_CONTENT = "transfer_service.receiver.error_staging_content";
|
||||
private static final String MSG_NO_SNAPSHOT_RECEIVED = "transfer_service.receiver.no_snapshot_received";
|
||||
private static final String MSG_ERROR_WHILE_COMMITTING_TRANSFER = "transfer_service.receiver.error_committing_transfer";
|
||||
|
||||
private static final String LOCK_FILE_NAME = ".lock";
|
||||
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, LOCK_FILE_NAME);
|
||||
private static final String SNAPSHOT_FILE_NAME = "snapshot.xml";
|
||||
|
||||
private NodeService nodeService;
|
||||
private SearchService searchService;
|
||||
private TransactionService transactionService;
|
||||
private String transferLockFolderPath;
|
||||
private String inboundTransferRecordsPath;
|
||||
private String rootStagingDirectory;
|
||||
private String transferTempFolderPath;
|
||||
private ManifestProcessorFactory manifestProcessorFactory;
|
||||
private BehaviourFilter behaviourFilter;
|
||||
|
||||
|
||||
private NodeRef transferLockFolder;
|
||||
private NodeRef transferTempFolder;
|
||||
private NodeRef inboundTransferRecordsFolder;
|
||||
|
||||
public void init()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "nodeService", nodeService);
|
||||
PropertyCheck.mandatory(this, "searchService", searchService);
|
||||
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
||||
PropertyCheck.mandatory(this, "transferLockFolderPath", transferLockFolderPath);
|
||||
PropertyCheck.mandatory(this, "inboundTransferRecordsPath", inboundTransferRecordsPath);
|
||||
PropertyCheck.mandatory(this, "rootStagingDirectory", rootStagingDirectory);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.repo.web.scripts.transfer.TransferReceiver#getStagingFolder(org.alfresco.service.cmr.repository.
|
||||
* NodeRef)
|
||||
*/
|
||||
public File getStagingFolder(String transferId)
|
||||
{
|
||||
if (transferId == null)
|
||||
{
|
||||
throw new IllegalArgumentException("transferId = " + transferId);
|
||||
}
|
||||
NodeRef transferNodeRef = new NodeRef(transferId);
|
||||
File tempFolder;
|
||||
String tempFolderPath = rootStagingDirectory + "/" + transferNodeRef.getId();
|
||||
tempFolder = new File(tempFolderPath);
|
||||
if (!tempFolder.exists())
|
||||
{
|
||||
if (!tempFolder.mkdirs())
|
||||
{
|
||||
tempFolder = null;
|
||||
throw new TransferException(MSG_FAILED_TO_CREATE_STAGING_FOLDER, new Object[] {transferId});
|
||||
}
|
||||
}
|
||||
return tempFolder;
|
||||
|
||||
}
|
||||
|
||||
private NodeRef getLockFolder()
|
||||
{
|
||||
// Have we already resolved the node that is the parent of the lock node?
|
||||
// If not then do so.
|
||||
if (transferLockFolder == null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (transferLockFolder == null)
|
||||
{
|
||||
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, "PATH:\"" + transferLockFolderPath + "\"");
|
||||
if (rs.length() > 0)
|
||||
{
|
||||
transferLockFolder = rs.getNodeRef(0);
|
||||
} else
|
||||
{
|
||||
throw new TransferException(MSG_TRANSFER_LOCK_FOLDER_NOT_FOUND, new Object[] {transferLockFolderPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return transferLockFolder;
|
||||
|
||||
}
|
||||
|
||||
public NodeRef getTempFolder(String transferId)
|
||||
{
|
||||
// Have we already resolved the node that is the temp folder?
|
||||
// If not then do so.
|
||||
if (transferTempFolder == null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (transferTempFolder == null)
|
||||
{
|
||||
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, "PATH:\"" + transferTempFolderPath + "\"");
|
||||
if (rs.length() > 0)
|
||||
{
|
||||
transferTempFolder = rs.getNodeRef(0);
|
||||
} else
|
||||
{
|
||||
throw new TransferException(MSG_TRANSFER_TEMP_FOLDER_NOT_FOUND, new Object[] {transferId, transferTempFolderPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeRef transferNodeRef = new NodeRef(transferId);
|
||||
String tempTransferFolderName = transferNodeRef.getId();
|
||||
NodeRef tempFolderNode = null;
|
||||
QName folderName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, tempTransferFolderName);
|
||||
|
||||
// Do we already have a temp folder for this transfer?
|
||||
List<ChildAssociationRef> tempChildren = nodeService.getChildAssocs(transferTempFolder,
|
||||
RegexQNamePattern.MATCH_ALL, folderName);
|
||||
if (tempChildren.isEmpty())
|
||||
{
|
||||
// No, we don't have a temp folder for this transfer yet. Create it...
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, tempTransferFolderName);
|
||||
tempFolderNode = nodeService.createNode(transferTempFolder, ContentModel.ASSOC_CONTAINS, folderName,
|
||||
ContentModel.TYPE_FOLDER, props).getChildRef();
|
||||
} else
|
||||
{
|
||||
// Yes, we do have a temp folder for this transfer already. Return it.
|
||||
tempFolderNode = tempChildren.get(0).getChildRef();
|
||||
}
|
||||
return tempFolderNode;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.web.scripts.transfer.TransferReceiver#start()
|
||||
*/
|
||||
public String start()
|
||||
{
|
||||
log.debug("start");
|
||||
final NodeRef relatedTransferRecord = createTransferRecord();
|
||||
final NodeRef lockFolder = getLockFolder();
|
||||
|
||||
RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
|
||||
try
|
||||
{
|
||||
txHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, LOCK_FILE_NAME);
|
||||
props.put(TransferModel.PROP_TRANSFER_ID, relatedTransferRecord.toString());
|
||||
|
||||
log.error("Creating transfer lock associated with this transfer record: " + relatedTransferRecord);
|
||||
ChildAssociationRef assoc = nodeService.createNode(lockFolder, ContentModel.ASSOC_CONTAINS,
|
||||
LOCK_QNAME, TransferModel.TYPE_TRANSFER_LOCK, props);
|
||||
log.error("Transfer lock created as node " + assoc.getChildRef());
|
||||
return assoc.getChildRef();
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
catch (DuplicateChildNodeNameException ex)
|
||||
{
|
||||
log.debug("lock is already taken");
|
||||
// lock is already taken.
|
||||
throw new TransferException(MSG_TRANSFER_LOCK_UNAVAILABLE);
|
||||
}
|
||||
String transferId = relatedTransferRecord.toString();
|
||||
getStagingFolder(transferId);
|
||||
return transferId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private NodeRef createTransferRecord()
|
||||
{
|
||||
log.debug("->createTransferRecord");
|
||||
if (inboundTransferRecordsFolder == null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (inboundTransferRecordsFolder == null)
|
||||
{
|
||||
log.debug("Trying to find transfer records folder: " + inboundTransferRecordsPath);
|
||||
ResultSet rs = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, "PATH:\"" + inboundTransferRecordsPath + "\"");
|
||||
if (rs.length() > 0)
|
||||
{
|
||||
inboundTransferRecordsFolder = rs.getNodeRef(0);
|
||||
log.debug("Found inbound transfer records folder: " + inboundTransferRecordsFolder);
|
||||
} else
|
||||
{
|
||||
throw new TransferException(MSG_INBOUND_TRANSFER_FOLDER_NOT_FOUND, new Object[] {inboundTransferRecordsPath});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssSSSZ");
|
||||
String timeNow = format.format(new Date());
|
||||
QName recordName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, timeNow);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NAME, timeNow);
|
||||
|
||||
log.debug("Creating transfer record with name: " + timeNow);
|
||||
ChildAssociationRef assoc = nodeService.createNode(inboundTransferRecordsFolder, ContentModel.ASSOC_CONTAINS,
|
||||
recordName, ContentModel.TYPE_CONTENT, props);
|
||||
log.debug("<-createTransferRecord: " + assoc.getChildRef());
|
||||
return assoc.getChildRef();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.web.scripts.transfer.TransferReceiver#end(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
public void end(final String transferId)
|
||||
{
|
||||
log.debug("end transferId:" + transferId);
|
||||
if (transferId == null)
|
||||
{
|
||||
throw new IllegalArgumentException("transferId = " + transferId);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// We remove the lock node in a separate transaction, since it was created in a separate transaction
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Find the lock node
|
||||
NodeRef lockId = getLockNode();
|
||||
if (lockId != null)
|
||||
{
|
||||
if (!testLockedTransfer(lockId, transferId))
|
||||
{
|
||||
throw new TransferException(MSG_NOT_LOCK_OWNER, new Object[] {transferId});
|
||||
}
|
||||
// Delete the lock node.
|
||||
log.debug("delete lock node :" + lockId);
|
||||
nodeService.deleteNode(lockId);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
log.debug("delete staging folder " + transferId);
|
||||
// Delete the staging folder.
|
||||
File stagingFolder = getStagingFolder(transferId);
|
||||
deleteFile(stagingFolder);
|
||||
log.debug("Staging folder deleted");
|
||||
}
|
||||
catch (TransferException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TransferException(MSG_ERROR_WHILE_ENDING_TRANSFER, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void abort(String transferId) throws TransferException
|
||||
{
|
||||
//TODO Think about the relationship between abort and end.
|
||||
end(transferId);
|
||||
}
|
||||
|
||||
public void prepare(String transferId) throws TransferException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stagingFolder
|
||||
*/
|
||||
private void deleteFile(File file)
|
||||
{
|
||||
if (!file.isDirectory()) file.delete();
|
||||
File[] fileList = file.listFiles();
|
||||
if (fileList != null) {
|
||||
for (File currentFile : fileList) {
|
||||
deleteFile(currentFile);
|
||||
}
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
|
||||
private NodeRef getLockNode()
|
||||
{
|
||||
final NodeRef lockFolder = getLockFolder();
|
||||
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(lockFolder, ContentModel.ASSOC_CONTAINS,
|
||||
LOCK_QNAME);
|
||||
NodeRef lockId = assocs.size() == 0 ? null : assocs.get(0).getChildRef();
|
||||
return lockId;
|
||||
}
|
||||
|
||||
private boolean testLockedTransfer(NodeRef lockId, String transferId)
|
||||
{
|
||||
if (lockId == null)
|
||||
{
|
||||
throw new IllegalArgumentException("lockId = null");
|
||||
}
|
||||
if (transferId == null)
|
||||
{
|
||||
throw new IllegalArgumentException("transferId = null");
|
||||
}
|
||||
String currentTransferId = (String) nodeService.getProperty(lockId, TransferModel.PROP_TRANSFER_ID);
|
||||
// Check that the lock is held for the specified transfer (error if not)
|
||||
return (transferId.equals(currentTransferId));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.TransferReceiver#nudgeLock(java.lang.String)
|
||||
*/
|
||||
public void nudgeLock(final String transferId) throws TransferException
|
||||
{
|
||||
if (transferId == null)
|
||||
throw new IllegalArgumentException("transferId = null");
|
||||
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
// Find the lock node
|
||||
NodeRef lockId = getLockNode();
|
||||
// Check that the specified transfer is the one that owns the lock
|
||||
if (!testLockedTransfer(lockId, transferId))
|
||||
{
|
||||
throw new TransferException(MSG_NOT_LOCK_OWNER);
|
||||
}
|
||||
// Just write the lock file name again (no change, but forces the modified time to be updated)
|
||||
nodeService.setProperty(lockId, ContentModel.PROP_NAME, LOCK_FILE_NAME);
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.TransferReceiver#saveSnapshot(java.io.InputStream)
|
||||
*/
|
||||
public void saveSnapshot(String transferId, InputStream openStream) throws TransferException
|
||||
{
|
||||
log.debug("save snapshot transferId=" + transferId);
|
||||
// Check that this transfer owns the lock and give it a nudge to stop it expiring
|
||||
nudgeLock(transferId);
|
||||
File snapshotFile = new File(getStagingFolder(transferId), SNAPSHOT_FILE_NAME);
|
||||
try
|
||||
{
|
||||
if (snapshotFile.createNewFile())
|
||||
{
|
||||
FileCopyUtils.copy(openStream, new FileOutputStream(snapshotFile));
|
||||
}
|
||||
log.debug("saved snapshot for transferId=" + transferId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TransferException(MSG_ERROR_WHILE_STAGING_SNAPSHOT, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.transfer.TransferReceiver#saveContent(java.lang.String, java.lang.String,
|
||||
* java.io.InputStream)
|
||||
*/
|
||||
public void saveContent(String transferId, String contentFileId, InputStream contentStream)
|
||||
throws TransferException
|
||||
{
|
||||
nudgeLock(transferId);
|
||||
File stagedFile = new File(getStagingFolder(transferId), contentFileId);
|
||||
try
|
||||
{
|
||||
if (stagedFile.createNewFile())
|
||||
{
|
||||
FileCopyUtils.copy(contentStream, new BufferedOutputStream(new FileOutputStream(stagedFile)));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new TransferException(MSG_ERROR_WHILE_STAGING_CONTENT, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void commit(String transferId) throws TransferException
|
||||
{
|
||||
log.debug("commit transferId=" + transferId);
|
||||
try
|
||||
{
|
||||
nudgeLock(transferId);
|
||||
List<TransferManifestProcessor> commitProcessors = manifestProcessorFactory.getCommitProcessors(this, transferId);
|
||||
|
||||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = saxParserFactory.newSAXParser();
|
||||
File snapshotFile = getSnapshotFile(transferId);
|
||||
|
||||
if (snapshotFile.exists())
|
||||
{
|
||||
log.debug("processing manifest file:" + snapshotFile.getAbsolutePath());
|
||||
//We parse the file as many times as we have processors
|
||||
for (TransferManifestProcessor processor : commitProcessors)
|
||||
{
|
||||
XMLTransferManifestReader reader = new XMLTransferManifestReader(processor);
|
||||
behaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
parser.parse(snapshotFile, reader);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
nudgeLock(transferId);
|
||||
parser.reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug("no snapshot received");
|
||||
throw new TransferException(MSG_NO_SNAPSHOT_RECEIVED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Successfully transfred
|
||||
*/
|
||||
log.debug("commit success transferId=" + transferId);
|
||||
|
||||
}
|
||||
catch (TransferException ex)
|
||||
{
|
||||
log.debug("unable to commit", ex);
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.debug("unable to commit", ex);
|
||||
throw new TransferException(MSG_ERROR_WHILE_COMMITTING_TRANSFER, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
/**
|
||||
* Clean up at the end of the transfer
|
||||
*/
|
||||
try
|
||||
{
|
||||
log.debug("calling end");
|
||||
end(transferId);
|
||||
log.debug("called end");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.error("Failed to clean up transfer. Lock may still be in place: " + transferId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getSnapshotFile(String transferId)
|
||||
{
|
||||
return new File(getStagingFolder(transferId), SNAPSHOT_FILE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchService
|
||||
* the searchService to set
|
||||
*/
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionService
|
||||
* the transactionService to set
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transferLockFolderPath
|
||||
* the transferLockFolderPath to set
|
||||
*/
|
||||
public void setTransferLockFolderPath(String transferLockFolderPath)
|
||||
{
|
||||
this.transferLockFolderPath = transferLockFolderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transferTempFolderPath the transferTempFolderPath to set
|
||||
*/
|
||||
public void setTransferTempFolderPath(String transferTempFolderPath)
|
||||
{
|
||||
this.transferTempFolderPath = transferTempFolderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rootStagingDirectory
|
||||
* the rootTransferFolder to set
|
||||
*/
|
||||
public void setRootStagingDirectory(String rootStagingDirectory)
|
||||
{
|
||||
this.rootStagingDirectory = rootStagingDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inboundTransferRecordsPath
|
||||
* the inboundTransferRecordsPath to set
|
||||
*/
|
||||
public void setInboundTransferRecordsPath(String inboundTransferRecordsPath)
|
||||
{
|
||||
this.inboundTransferRecordsPath = inboundTransferRecordsPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
* the nodeService to set
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param manifestProcessorFactory the manifestProcessorFactory to set
|
||||
*/
|
||||
public void setManifestProcessorFactory(ManifestProcessorFactory manifestProcessorFactory)
|
||||
{
|
||||
this.manifestProcessorFactory = manifestProcessorFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param behaviourFilter the behaviourFilter to set
|
||||
*/
|
||||
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||
{
|
||||
this.behaviourFilter = behaviourFilter;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
|
||||
import org.alfresco.repo.transfer.manifest.XMLTransferManifestWriter;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
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.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.tools.ant.filters.StringInputStream;
|
||||
|
||||
/**
|
||||
* Unit test for RepoTransferReceiverImpl
|
||||
*
|
||||
* @author Brian Remmington
|
||||
*/
|
||||
public class RepoTransferReceiverImplTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
private static int fileCount = 0;
|
||||
private static final Log log = LogFactory.getLog(RepoTransferReceiverImplTest.class);
|
||||
|
||||
private RepoTransferReceiverImpl receiver;
|
||||
private String dummyContent;
|
||||
private byte[] dummyContentBytes;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
System.out.println("java.io.tmpdir == " + System.getProperty("java.io.tmpdir"));
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the required services
|
||||
this.receiver = (RepoTransferReceiverImpl) this.getApplicationContext().getBean("transferReceiver");
|
||||
this.dummyContent = "This is some dummy content.";
|
||||
this.dummyContentBytes = dummyContent.getBytes("UTF-8");
|
||||
}
|
||||
|
||||
public void testStartAndEnd() throws Exception
|
||||
{
|
||||
String transferId = receiver.start();
|
||||
System.out.println("TransferId == " + transferId);
|
||||
|
||||
File stagingFolder = receiver.getStagingFolder(transferId);
|
||||
assertTrue(receiver.getStagingFolder(transferId).exists());
|
||||
|
||||
try
|
||||
{
|
||||
receiver.start();
|
||||
fail("Successfully started twice!");
|
||||
} catch (TransferException ex)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
try
|
||||
{
|
||||
receiver.end(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, GUID.generate()).toString());
|
||||
fail("Successfully ended with transfer id that doesn't own lock.");
|
||||
} catch (TransferException ex)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
receiver.end(transferId);
|
||||
assertFalse(stagingFolder.exists());
|
||||
|
||||
receiver.end(receiver.start());
|
||||
}
|
||||
|
||||
public void testSaveContent() throws Exception
|
||||
{
|
||||
String transferId = receiver.start();
|
||||
try
|
||||
{
|
||||
String contentId = "mytestcontent";
|
||||
receiver.saveContent(transferId, contentId, new ByteArrayInputStream(dummyContentBytes));
|
||||
File contentFile = new File(receiver.getStagingFolder(transferId), contentId);
|
||||
assertTrue(contentFile.exists());
|
||||
assertEquals(dummyContentBytes.length, contentFile.length());
|
||||
} finally
|
||||
{
|
||||
receiver.end(transferId);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSaveSnapshot() throws Exception
|
||||
{
|
||||
String transferId = receiver.start();
|
||||
File snapshotFile = null;
|
||||
try
|
||||
{
|
||||
TransferManifestNode node = createContentNode(transferId);
|
||||
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
|
||||
nodes.add(node);
|
||||
String snapshot = createSnapshot(nodes);
|
||||
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
|
||||
File stagingFolder = receiver.getStagingFolder(transferId);
|
||||
snapshotFile = new File(stagingFolder, "snapshot.xml");
|
||||
assertTrue(snapshotFile.exists());
|
||||
assertEquals(snapshot.getBytes("UTF-8").length, snapshotFile.length());
|
||||
} finally
|
||||
{
|
||||
receiver.end(transferId);
|
||||
if (snapshotFile != null) {
|
||||
assertFalse(snapshotFile.exists());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testBasicCommit() throws Exception {
|
||||
String transferId = receiver.start();
|
||||
try
|
||||
{
|
||||
TransferManifestNode node = createContentNode(transferId);
|
||||
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
|
||||
nodes.add(node);
|
||||
String snapshot = createSnapshot(nodes);
|
||||
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
|
||||
receiver.commit(transferId);
|
||||
|
||||
assertTrue(nodeService.exists(node.getNodeRef()));
|
||||
nodeService.deleteNode(node.getNodeRef());
|
||||
} catch (Exception ex)
|
||||
{
|
||||
receiver.end(transferId);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testMoreComplexCommit() throws Exception {
|
||||
String transferId = receiver.start();
|
||||
try
|
||||
{
|
||||
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
|
||||
TransferManifestNormalNode node1 = createContentNode(transferId);
|
||||
nodes.add(node1);
|
||||
TransferManifestNormalNode node2 = createContentNode(transferId);
|
||||
nodes.add(node2);
|
||||
TransferManifestNode node3 = createContentNode(transferId);
|
||||
nodes.add(node3);
|
||||
TransferManifestNode node4 = createContentNode(transferId);
|
||||
nodes.add(node4);
|
||||
TransferManifestNode node5 = createContentNode(transferId);
|
||||
nodes.add(node5);
|
||||
TransferManifestNode node6 = createContentNode(transferId);
|
||||
nodes.add(node6);
|
||||
TransferManifestNode node7 = createContentNode(transferId);
|
||||
nodes.add(node7);
|
||||
TransferManifestNode node8 = createFolderNode(transferId);
|
||||
nodes.add(node8);
|
||||
TransferManifestNode node9 = createFolderNode(transferId);
|
||||
nodes.add(node9);
|
||||
TransferManifestNode node10 = createFolderNode(transferId);
|
||||
nodes.add(node10);
|
||||
TransferManifestNormalNode node11 = createFolderNode(transferId);
|
||||
nodes.add(node11);
|
||||
TransferManifestNode node12 = createFolderNode(transferId);
|
||||
nodes.add(node12);
|
||||
|
||||
associatePeers(node1, node2);
|
||||
moveNode(node2, node11);
|
||||
|
||||
String snapshot = createSnapshot(nodes);
|
||||
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
|
||||
for (TransferManifestNode node : nodes) {
|
||||
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
|
||||
}
|
||||
receiver.commit(transferId);
|
||||
|
||||
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
|
||||
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
|
||||
for (TransferManifestNode node : nodes) {
|
||||
assertTrue(nodeService.exists(node.getNodeRef()));
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
receiver.end(transferId);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testNodeDeleteAndRestore() throws Exception {
|
||||
String transferId = receiver.start();
|
||||
try
|
||||
{
|
||||
List<TransferManifestNode> nodes = new ArrayList<TransferManifestNode>();
|
||||
TransferManifestNormalNode node1 = createContentNode(transferId);
|
||||
nodes.add(node1);
|
||||
TransferManifestNormalNode node2 = createContentNode(transferId);
|
||||
nodes.add(node2);
|
||||
TransferManifestNode node3 = createContentNode(transferId);
|
||||
nodes.add(node3);
|
||||
TransferManifestNode node4 = createContentNode(transferId);
|
||||
nodes.add(node4);
|
||||
TransferManifestNode node5 = createContentNode(transferId);
|
||||
nodes.add(node5);
|
||||
TransferManifestNode node6 = createContentNode(transferId);
|
||||
nodes.add(node6);
|
||||
TransferManifestNode node7 = createContentNode(transferId);
|
||||
nodes.add(node7);
|
||||
TransferManifestNode node8 = createFolderNode(transferId);
|
||||
nodes.add(node8);
|
||||
TransferManifestNode node9 = createFolderNode(transferId);
|
||||
nodes.add(node9);
|
||||
TransferManifestNode node10 = createFolderNode(transferId);
|
||||
nodes.add(node10);
|
||||
TransferManifestNormalNode node11 = createFolderNode(transferId);
|
||||
nodes.add(node11);
|
||||
TransferManifestNode node12 = createFolderNode(transferId);
|
||||
nodes.add(node12);
|
||||
|
||||
associatePeers(node1, node2);
|
||||
moveNode(node2, node11);
|
||||
|
||||
String snapshot = createSnapshot(nodes);
|
||||
log.debug(snapshot);
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
|
||||
for (TransferManifestNode node : nodes) {
|
||||
receiver.saveContent(transferId, node.getUuid(), new ByteArrayInputStream(dummyContentBytes));
|
||||
}
|
||||
receiver.commit(transferId);
|
||||
|
||||
assertTrue(nodeService.getAspects(node1.getNodeRef()).contains(ContentModel.ASPECT_ATTACHABLE));
|
||||
assertFalse(nodeService.getSourceAssocs(node2.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS).isEmpty());
|
||||
for (TransferManifestNode node : nodes) {
|
||||
assertTrue(nodeService.exists(node.getNodeRef()));
|
||||
}
|
||||
|
||||
//Now delete nodes 8, 2, and 11 (2 and 11 are parent/child)
|
||||
TransferManifestDeletedNode deletedNode8 = createDeletedNode(node8);
|
||||
TransferManifestDeletedNode deletedNode2 = createDeletedNode(node2);
|
||||
TransferManifestDeletedNode deletedNode11 = createDeletedNode(node11);
|
||||
transferId = receiver.start();
|
||||
snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] {deletedNode8, deletedNode2, deletedNode11}));
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
receiver.commit(transferId);
|
||||
assertTrue(nodeService.exists(deletedNode8.getNodeRef()));
|
||||
assertTrue(nodeService.hasAspect(deletedNode8.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
|
||||
assertTrue(nodeService.exists(deletedNode2.getNodeRef()));
|
||||
assertTrue(nodeService.hasAspect(deletedNode2.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
|
||||
assertTrue(nodeService.exists(deletedNode11.getNodeRef()));
|
||||
assertTrue(nodeService.hasAspect(deletedNode11.getNodeRef(), ContentModel.ASPECT_ARCHIVED));
|
||||
|
||||
//try to restore node 2. Expect an "orphan" failure, since its parent (node11) is deleted
|
||||
transferId = receiver.start();
|
||||
snapshot = createSnapshot(Arrays.asList(new TransferManifestNode[] {node2}));
|
||||
log.debug(snapshot);
|
||||
receiver.saveSnapshot(transferId, new StringInputStream(snapshot, "UTF-8"));
|
||||
receiver.saveContent(transferId, node2.getUuid(), new ByteArrayInputStream(dummyContentBytes));
|
||||
try
|
||||
{
|
||||
receiver.commit(transferId);
|
||||
fail("Expected an exception!");
|
||||
}
|
||||
catch (TransferException ex)
|
||||
{
|
||||
assertTrue(ex.getMsgId(), ex.getMsgId().contains("orphan"));
|
||||
}
|
||||
|
||||
} catch (Exception ex)
|
||||
{
|
||||
receiver.end(transferId);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeToDelete
|
||||
* @return
|
||||
*/
|
||||
private TransferManifestDeletedNode createDeletedNode(TransferManifestNode nodeToDelete)
|
||||
{
|
||||
TransferManifestDeletedNode deletedNode = new TransferManifestDeletedNode();
|
||||
deletedNode.setNodeRef(new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, nodeToDelete.getNodeRef().getId()));
|
||||
deletedNode.setParentPath(nodeToDelete.getParentPath());
|
||||
deletedNode.setPrimaryParentAssoc(nodeToDelete.getPrimaryParentAssoc());
|
||||
deletedNode.setUuid(nodeToDelete.getUuid());
|
||||
return deletedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param childNode
|
||||
* @param newParent
|
||||
*/
|
||||
private void moveNode(TransferManifestNormalNode childNode, TransferManifestNormalNode newParent)
|
||||
{
|
||||
List<ChildAssociationRef> currentParents = childNode.getParentAssocs();
|
||||
List<ChildAssociationRef> newParents = new ArrayList<ChildAssociationRef>();
|
||||
|
||||
for (ChildAssociationRef parent : currentParents) {
|
||||
if (!parent.isPrimary()) {
|
||||
newParents.add(parent);
|
||||
} else {
|
||||
ChildAssociationRef newPrimaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
||||
newParent.getNodeRef(), parent.getQName(), parent.getChildRef(), true, -1);
|
||||
newParents.add(newPrimaryAssoc);
|
||||
childNode.setPrimaryParentAssoc(newPrimaryAssoc);
|
||||
Path newParentPath = new Path();
|
||||
newParentPath.append(newParent.getParentPath());
|
||||
newParentPath.append(new Path.ChildAssocElement(newParent.getPrimaryParentAssoc()));
|
||||
childNode.setParentPath(newParentPath);
|
||||
}
|
||||
}
|
||||
childNode.setParentAssocs(newParents);
|
||||
}
|
||||
|
||||
private void associatePeers(TransferManifestNormalNode source, TransferManifestNormalNode target) {
|
||||
List<AssociationRef> currentReferencedPeers = source.getTargetAssocs();
|
||||
if (currentReferencedPeers == null) {
|
||||
currentReferencedPeers = new ArrayList<AssociationRef>();
|
||||
source.setTargetAssocs(currentReferencedPeers);
|
||||
}
|
||||
|
||||
List<AssociationRef> currentRefereePeers = target.getSourceAssocs();
|
||||
if (currentRefereePeers == null) {
|
||||
currentRefereePeers = new ArrayList<AssociationRef>();
|
||||
target.setSourceAssocs(currentRefereePeers);
|
||||
}
|
||||
|
||||
Set<QName> aspects = source.getAspects();
|
||||
if (aspects == null ) {
|
||||
aspects = new HashSet<QName>();
|
||||
source.setAspects(aspects);
|
||||
}
|
||||
aspects.add(ContentModel.ASPECT_ATTACHABLE);
|
||||
|
||||
AssociationRef newAssoc = new AssociationRef(source.getNodeRef(), ContentModel.ASSOC_ATTACHMENTS, target.getNodeRef());
|
||||
currentRefereePeers.add(newAssoc);
|
||||
currentReferencedPeers.add(newAssoc);
|
||||
}
|
||||
|
||||
private String createSnapshot(List<TransferManifestNode> nodes) throws Exception {
|
||||
XMLTransferManifestWriter manifestWriter = new XMLTransferManifestWriter();
|
||||
StringWriter output = new StringWriter();
|
||||
manifestWriter.startTransferManifest(output);
|
||||
TransferManifestHeader header = new TransferManifestHeader();
|
||||
header.setCreatedDate(new Date());
|
||||
manifestWriter.writeTransferManifestHeader(header);
|
||||
for (TransferManifestNode node : nodes) {
|
||||
manifestWriter.writeTransferManifestNode(node);
|
||||
}
|
||||
manifestWriter.endTransferManifest();
|
||||
|
||||
return output.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private TransferManifestNormalNode createContentNode(String transferId) throws Exception
|
||||
{
|
||||
TransferManifestNormalNode node = new TransferManifestNormalNode();
|
||||
String uuid = GUID.generate();
|
||||
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, uuid);
|
||||
node.setNodeRef(nodeRef);
|
||||
node.setUuid(uuid);
|
||||
byte[] dummyContent = "This is some dummy content.".getBytes("UTF-8");
|
||||
|
||||
node.setType(ContentModel.TYPE_CONTENT);
|
||||
|
||||
NodeRef parentFolder = receiver.getTempFolder(transferId);
|
||||
String nodeName = transferId + ".testnode" + getNameSuffix();
|
||||
|
||||
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
|
||||
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
|
||||
parents.add(primaryAssoc);
|
||||
node.setParentAssocs(parents);
|
||||
node.setParentPath(nodeService.getPath(parentFolder));
|
||||
node.setPrimaryParentAssoc(primaryAssoc);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NODE_UUID, uuid);
|
||||
props.put(ContentModel.PROP_NAME, nodeName);
|
||||
ContentData contentData = new ContentData("/" + uuid, "text/plain", dummyContent.length, "UTF-8");
|
||||
props.put(ContentModel.PROP_CONTENT, contentData);
|
||||
node.setProperties(props);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private TransferManifestNormalNode createFolderNode(String transferId) throws Exception
|
||||
{
|
||||
TransferManifestNormalNode node = new TransferManifestNormalNode();
|
||||
String uuid = GUID.generate();
|
||||
NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, uuid);
|
||||
node.setNodeRef(nodeRef);
|
||||
node.setUuid(uuid);
|
||||
|
||||
node.setType(ContentModel.TYPE_FOLDER);
|
||||
|
||||
NodeRef parentFolder = receiver.getTempFolder(transferId);
|
||||
String nodeName = transferId + ".folder" + getNameSuffix();
|
||||
|
||||
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
|
||||
ChildAssociationRef primaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, parentFolder, QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), node.getNodeRef(), true, -1);
|
||||
parents.add(primaryAssoc);
|
||||
node.setParentAssocs(parents);
|
||||
node.setParentPath(nodeService.getPath(parentFolder));
|
||||
node.setPrimaryParentAssoc(primaryAssoc);
|
||||
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(ContentModel.PROP_NODE_UUID, uuid);
|
||||
props.put(ContentModel.PROP_NAME, nodeName);
|
||||
node.setProperties(props);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private String getNameSuffix() {
|
||||
return "" + fileCount++;
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.transfer.NodeFilter;
|
||||
import org.alfresco.service.cmr.transfer.NodeFinder;
|
||||
import org.alfresco.service.cmr.transfer.TransferService;
|
||||
|
||||
/**
|
||||
* This class can be used to build a set of node references from a given starting point. The caller can provide a list
|
||||
* of {@link NodeFinder} objects and a list of {@link NodeFilter} objects. Starting with the nodes supplied by the
|
||||
* caller, the crawler uses the NodeFinder objects to find other nodes. Each node that is found is then passed to the
|
||||
* NodeFilter objects to determine whether it should be included or ignored. Any included nodes are then fed back into
|
||||
* the NodeFinder objects to continue the crawl. This class was originally written to assist users of the
|
||||
* {@link TransferService} in combination with the {@link ChildAssociatedNodeFinder} and the {@link ContentClassFilter}.
|
||||
*
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class StandardNodeCrawlerImpl
|
||||
{
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private List<NodeFinder> nodeFinders = new ArrayList<NodeFinder>();
|
||||
private List<NodeFilter> nodeFilters = new ArrayList<NodeFilter>();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public StandardNodeCrawlerImpl()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serviceRegistry
|
||||
*/
|
||||
public StandardNodeCrawlerImpl(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
super();
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService
|
||||
* the nodeService to set
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public Set<NodeRef> crawl(NodeRef... nodes)
|
||||
{
|
||||
return crawl(new HashSet<NodeRef>(Arrays.asList(nodes)));
|
||||
}
|
||||
|
||||
public synchronized Set<NodeRef> crawl(Set<NodeRef> startingNodes)
|
||||
{
|
||||
init();
|
||||
Queue<NodeRef> nodesToProcess = new LinkedList<NodeRef>();
|
||||
nodesToProcess.addAll(startingNodes);
|
||||
Set<NodeRef> resultingNodeSet = new HashSet<NodeRef>(89);
|
||||
Set<NodeRef> processedNodes = new HashSet<NodeRef>(89);
|
||||
|
||||
// Do we have any more nodes to process?
|
||||
while (nodesToProcess.peek() != null)
|
||||
{
|
||||
// Yes, we do. Read the next noderef from the queue.
|
||||
NodeRef thisNode = nodesToProcess.poll();
|
||||
// Check that we haven't already processed it. Skip it if we have, process it if we haven't
|
||||
if (!processedNodes.contains(thisNode))
|
||||
{
|
||||
// Record the fact that we're processing this node
|
||||
processedNodes.add(thisNode);
|
||||
// We check this node against any filters that are in place (the nodes
|
||||
// that we were given to start with are always processed)
|
||||
if (startingNodes.contains(thisNode) || includeNode(thisNode))
|
||||
{
|
||||
resultingNodeSet.add(thisNode);
|
||||
Set<NodeRef> subsequentNodes = findSubsequentNodes(thisNode);
|
||||
for (NodeRef node : subsequentNodes)
|
||||
{
|
||||
nodesToProcess.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultingNodeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
for (NodeFinder nodeFinder : this.nodeFinders)
|
||||
{
|
||||
nodeFinder.setServiceRegistry(serviceRegistry);
|
||||
nodeFinder.init();
|
||||
}
|
||||
for (NodeFilter nodeFilter : this.nodeFilters)
|
||||
{
|
||||
nodeFilter.setServiceRegistry(serviceRegistry);
|
||||
nodeFilter.init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thisNode
|
||||
* @return
|
||||
*/
|
||||
private Set<NodeRef> findSubsequentNodes(NodeRef thisNode)
|
||||
{
|
||||
Set<NodeRef> foundNodes = new HashSet<NodeRef>(89);
|
||||
for (NodeFinder finder : nodeFinders)
|
||||
{
|
||||
foundNodes.addAll(finder.findFrom(thisNode));
|
||||
}
|
||||
return foundNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thisNode
|
||||
* @return
|
||||
*/
|
||||
private boolean includeNode(NodeRef thisNode)
|
||||
{
|
||||
boolean include = true;
|
||||
for (int i = 0; include && (i < nodeFilters.size()); ++i)
|
||||
{
|
||||
include &= nodeFilters.get(i).accept(thisNode);
|
||||
}
|
||||
return include;
|
||||
}
|
||||
|
||||
public synchronized void setNodeFinders(NodeFinder... finders)
|
||||
{
|
||||
nodeFinders = Arrays.asList(finders);
|
||||
}
|
||||
|
||||
public synchronized void setNodeFilters(NodeFilter... filters)
|
||||
{
|
||||
nodeFilters = Arrays.asList(filters);
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package org.alfresco.repo.transfer;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferCallback;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class TestTransferCallback implements TransferCallback
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Log logger = LogFactory.getLog(TestTransferCallback.class);
|
||||
|
||||
public void processEvent(TransferEvent event)
|
||||
{
|
||||
logger.debug(event.toString());
|
||||
events.add(event);
|
||||
}
|
||||
|
||||
Queue<TransferEvent> events = new ConcurrentLinkedQueue<TransferEvent>();
|
||||
|
||||
/**
|
||||
* Get the thread safe queue of events
|
||||
* @return
|
||||
*/
|
||||
public Queue<TransferEvent> getEvents()
|
||||
{
|
||||
return events;
|
||||
}
|
||||
|
||||
}
|
95
source/java/org/alfresco/repo/transfer/Transfer.java
Normal file
95
source/java/org/alfresco/repo/transfer/Transfer.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 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.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
|
||||
/**
|
||||
* Information about a transfer which is in progress.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class Transfer
|
||||
{
|
||||
private String transferId;
|
||||
private TransferTarget transferTarget;
|
||||
|
||||
public void setTransferId(String transferId)
|
||||
{
|
||||
this.transferId = transferId;
|
||||
}
|
||||
|
||||
public String getTransferId()
|
||||
{
|
||||
return transferId;
|
||||
}
|
||||
|
||||
// may also have capabilities of the remote system here (for when we are
|
||||
// transfering accross versions)
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (obj instanceof Transfer == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Transfer that = (Transfer) obj;
|
||||
return (this.transferId.equals(that.getTransferId()));
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return transferId.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target
|
||||
*/
|
||||
public void setTransferTarget(TransferTarget target)
|
||||
{
|
||||
this.transferTarget = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the transferTarget
|
||||
*/
|
||||
public TransferTarget getTransferTarget()
|
||||
{
|
||||
return transferTarget;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "TransferId" + transferId + ", target:" + transferTarget ;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
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.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferService;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class TransferActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "transfer-node";
|
||||
public static final String PARAM_TRANSFER_TARGET = "target-name";
|
||||
private TransferService transferService;
|
||||
|
||||
/**
|
||||
* @param transferService the transferService to set
|
||||
*/
|
||||
public void setTransferService(TransferService transferService)
|
||||
{
|
||||
this.transferService = transferService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
|
||||
{
|
||||
TransferDefinition td = new TransferDefinition();
|
||||
Set<NodeRef> nodes = new HashSet<NodeRef>();
|
||||
nodes.add(actionedUponNodeRef);
|
||||
td.setNodes(nodes);
|
||||
transferService.transfer("transferMe", td);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
//paramList.add(new ParameterDefinitionImpl(PARAM_TRANSFER_TARGET, DataTypeDefinition.TEXT, true, "Transfer Target Name"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 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.transfer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferCallback;
|
||||
import org.alfresco.service.cmr.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Deploys a website to a remote server.
|
||||
*
|
||||
* TODO refactor and add to WCM services (when we support WCM deployment config)
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
public class TransferAsyncAction extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String ASYNC_QUEUE_NAME = "deployment";
|
||||
|
||||
private TransferService transferService;
|
||||
|
||||
private static Log logger = LogFactory.getLog(TransferAsyncAction.class);
|
||||
|
||||
public void init()
|
||||
{
|
||||
super.name = "transfer-async";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
|
||||
{
|
||||
System.out.println("In TransferAsyncAction");
|
||||
|
||||
String targetName = (String)action.getParameterValue("targetName");
|
||||
TransferDefinition definition = (TransferDefinition)action.getParameterValue("definition");
|
||||
Set<TransferCallback> callback = (Set<TransferCallback>) action.getParameterValue("callbacks");
|
||||
|
||||
transferService.transfer(targetName, definition, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
}
|
||||
|
||||
public void setTransferService(TransferService transferService)
|
||||
{
|
||||
this.transferService = transferService;
|
||||
}
|
||||
|
||||
public TransferService getTransferService()
|
||||
{
|
||||
return transferService;
|
||||
}
|
||||
}
|
51
source/java/org/alfresco/repo/transfer/TransferCommons.java
Normal file
51
source/java/org/alfresco/repo/transfer/TransferCommons.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
/**
|
||||
* A bucket for little odds and ends for the transfer service.
|
||||
*
|
||||
* If this becomes a big class then refactor it away.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferCommons
|
||||
{
|
||||
/**
|
||||
* The Mime Part Name of the manifest file
|
||||
*/
|
||||
public final static String PART_NAME_MANIFEST = "manifest";
|
||||
|
||||
/**
|
||||
* Mapping between contentUrl and part name.
|
||||
*
|
||||
* @param URL
|
||||
* @return the part name
|
||||
*/
|
||||
public final static String URLToPartName(String contentUrl)
|
||||
{
|
||||
return contentUrl.substring(contentUrl.lastIndexOf('/')+1);
|
||||
}
|
||||
}
|
140
source/java/org/alfresco/repo/transfer/TransferEventImpl.java
Normal file
140
source/java/org/alfresco/repo/transfer/TransferEventImpl.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
|
||||
/**
|
||||
* An abstract implementation of TransferEvent.
|
||||
* Also implements RangedTransferEvent.
|
||||
* @see TransferEvent
|
||||
* @see RangedTransferEvent
|
||||
*/
|
||||
public abstract class TransferEventImpl implements TransferEvent
|
||||
{
|
||||
private String message;
|
||||
private TransferState state;
|
||||
private boolean last = false;
|
||||
private long range = 0;
|
||||
private long position = 0;
|
||||
private Date time = new Date();
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public Date getTime()
|
||||
{
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void setRange(long range)
|
||||
{
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
public void setPosition(long position)
|
||||
{
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void setTransferState(TransferState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void setTime(Date time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public TransferState getTransferState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setLast(boolean last)
|
||||
{
|
||||
this.last = last;
|
||||
}
|
||||
|
||||
public boolean isLast()
|
||||
{
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* The position in the range
|
||||
* @return
|
||||
*/
|
||||
public long getPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum range
|
||||
* @return
|
||||
*/
|
||||
public long getRange()
|
||||
{
|
||||
return range;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "TransferEventImpl : " + this.getTime() + ", " + this.getTransferState();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof TransferEventImpl)
|
||||
{
|
||||
TransferEventImpl other = (TransferEventImpl)obj;
|
||||
if(other.getTransferState().equals(this.getTransferState()) &&
|
||||
other.getPosition() == this.getPosition() &&
|
||||
other.getTime().equals(this.getTime()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
// discard any high bits
|
||||
return (int)this.getTime().getTime();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.transfer.TransferCallback;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventCommittingStatus;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventEndState;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventEnterState;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventError;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventSendingContent;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventSendingManifest;
|
||||
import org.alfresco.service.cmr.transfer.TransferEventSuccess;
|
||||
|
||||
/**
|
||||
* Class to bring together all the transfer event stuff.
|
||||
*
|
||||
* One processor instance for each transfer.
|
||||
*
|
||||
* Observer
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
|
||||
|
||||
public class TransferEventProcessor
|
||||
{
|
||||
public Set<TransferCallback> observers = new HashSet<TransferCallback>();
|
||||
|
||||
LinkedBlockingQueue<TransferEvent> queue = new LinkedBlockingQueue<TransferEvent>();
|
||||
|
||||
|
||||
|
||||
public void addObserver(TransferCallback observer)
|
||||
{
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
public void deleteObserver(TransferCallback observer)
|
||||
{
|
||||
observers.remove(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public TransferEventProcessor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
setState(TransferEvent.TransferState.START);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
public void success()
|
||||
{
|
||||
setState(TransferEvent.TransferState.SUCCESS);
|
||||
|
||||
/**
|
||||
* Write the success event
|
||||
*/
|
||||
TransferEventSuccess event = new TransferEventSuccess();
|
||||
event.setTransferState(TransferEvent.TransferState.SUCCESS);
|
||||
event.setLast(true);
|
||||
queue.add(event);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
public void error(Exception exception)
|
||||
{
|
||||
setState(TransferEvent.TransferState.ERROR);
|
||||
|
||||
/**
|
||||
* Write the error event
|
||||
*/
|
||||
TransferEventError event = new TransferEventError();
|
||||
event.setTransferState(TransferEvent.TransferState.ERROR);
|
||||
event.setLast(true);
|
||||
event.setException(exception);
|
||||
queue.add(event);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param range
|
||||
* @param position
|
||||
*/
|
||||
public void sendContent(ContentData data, long range, long position)
|
||||
{
|
||||
setState(TransferEvent.TransferState.SENDING_CONTENT);
|
||||
|
||||
TransferEventSendingContent event = new TransferEventSendingContent();
|
||||
event.setTransferState(TransferEvent.TransferState.SENDING_CONTENT);
|
||||
event.setRange(range);
|
||||
event.setPosition(position);
|
||||
event.setSize(data.getSize());
|
||||
event.setMessage("sending content " + position + " of " + range + ", size: " + event.getSize());
|
||||
queue.add(event);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param range
|
||||
* @param position
|
||||
*/
|
||||
public void sendManifest(long range, long position)
|
||||
{
|
||||
setState(TransferEvent.TransferState.SENDING_MANIFEST);
|
||||
|
||||
TransferEventSendingManifest event = new TransferEventSendingManifest();
|
||||
event.setTransferState(TransferEvent.TransferState.SENDING_MANIFEST);
|
||||
event.setRange(range);
|
||||
event.setPosition(position);
|
||||
event.setMessage("sending manifest");
|
||||
queue.add(event);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
public void prepare()
|
||||
{
|
||||
setState(TransferEvent.TransferState.PREPARING);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param range
|
||||
* @param position
|
||||
*/
|
||||
public void committing(long range, long position)
|
||||
{
|
||||
setState(TransferEvent.TransferState.COMMITTING);
|
||||
|
||||
TransferEventCommittingStatus event = new TransferEventCommittingStatus();
|
||||
event.setTransferState(TransferEvent.TransferState.COMMITTING);
|
||||
event.setRange(range);
|
||||
event.setPosition(position);
|
||||
event.setMessage("committing " + position + " of " + range);
|
||||
queue.add(event);
|
||||
notifyObservers();
|
||||
|
||||
}
|
||||
|
||||
public void abort()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private TransferEvent.TransferState currentState;
|
||||
|
||||
private void setState(TransferEvent.TransferState state)
|
||||
{
|
||||
if(currentState != state)
|
||||
{
|
||||
if(currentState != null)
|
||||
{
|
||||
TransferEventImpl event = new TransferEventEndState();
|
||||
event.setMessage("End State: " + currentState);
|
||||
event.setTransferState(state);
|
||||
queue.add(event);
|
||||
}
|
||||
{
|
||||
TransferEventImpl event = new TransferEventEnterState();
|
||||
event.setMessage("Enter State: " + state);
|
||||
event.setTransferState(state);
|
||||
queue.add(event);
|
||||
}
|
||||
currentState = state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void notifyObservers()
|
||||
{
|
||||
TransferEvent event = (TransferEvent)queue.poll();
|
||||
while(event != null)
|
||||
{
|
||||
// call the observers
|
||||
for(TransferCallback callback : observers)
|
||||
{
|
||||
callback.processEvent(event);
|
||||
}
|
||||
event = (TransferEvent)queue.poll();
|
||||
}
|
||||
}
|
||||
}
|
31
source/java/org/alfresco/repo/transfer/TransferMessage.java
Normal file
31
source/java/org/alfresco/repo/transfer/TransferMessage.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
public interface TransferMessage
|
||||
{
|
||||
String getMessage();
|
||||
|
||||
}
|
70
source/java/org/alfresco/repo/transfer/TransferModel.java
Normal file
70
source/java/org/alfresco/repo/transfer/TransferModel.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 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.transfer;
|
||||
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Transfer Model Constants
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferModel
|
||||
{
|
||||
static final String TRANSFER_MODEL_1_0_URI = "http://www.alfresco.org/model/transfer/1.0";
|
||||
|
||||
static final QName ASPECT_ENABLEABLE = QName.createQName(TRANSFER_MODEL_1_0_URI, "enableable");
|
||||
// static final QName ASSOC_IMAP_ATTACHMENTS_FOLDER = QName.createQName(IMAP_MODEL_1_0_URI, "attachmentsFolder");
|
||||
|
||||
/*
|
||||
* Type : Transfer Group
|
||||
*/
|
||||
static final QName TYPE_TRANSFER_GROUP = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferGroup");
|
||||
|
||||
/*
|
||||
* Type : Transfer Target
|
||||
*/
|
||||
static final QName TYPE_TRANSFER_TARGET = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferTarget");
|
||||
static final QName PROP_ENDPOINT_PROTOCOL = QName.createQName(TRANSFER_MODEL_1_0_URI, "endpointprotocol");
|
||||
static final QName PROP_ENDPOINT_HOST = QName.createQName(TRANSFER_MODEL_1_0_URI, "endpointhost");
|
||||
static final QName PROP_ENDPOINT_PORT = QName.createQName(TRANSFER_MODEL_1_0_URI, "endpointport");
|
||||
static final QName PROP_ENDPOINT_PATH = QName.createQName(TRANSFER_MODEL_1_0_URI, "endpointpath");
|
||||
static final QName PROP_USERNAME = QName.createQName(TRANSFER_MODEL_1_0_URI, "username");
|
||||
static final QName PROP_PASSWORD = QName.createQName(TRANSFER_MODEL_1_0_URI, "password");
|
||||
|
||||
static final QName PROP_ENABLED = QName.createQName(TRANSFER_MODEL_1_0_URI, "enabled");
|
||||
|
||||
/*
|
||||
* Type : Transfer Lock
|
||||
*/
|
||||
static final QName TYPE_TRANSFER_LOCK = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferLock");
|
||||
static final QName PROP_TRANSFER_ID = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferId");
|
||||
|
||||
/*
|
||||
* Type : Transfer report
|
||||
*/
|
||||
static final QName TYPE_TRANSFER_REPORT = QName.createQName(TRANSFER_MODEL_1_0_URI, "transferReport");
|
||||
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public class TransferProcessingException extends TransferException
|
||||
{
|
||||
private boolean fatal = false;
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
* @param cause
|
||||
*/
|
||||
public TransferProcessingException(String msgId, Object[] msgParams, Throwable cause)
|
||||
{
|
||||
super(msgId, msgParams, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param msgParams
|
||||
*/
|
||||
public TransferProcessingException(String msgId, Object[] msgParams)
|
||||
{
|
||||
super(msgId, msgParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
* @param cause
|
||||
*/
|
||||
public TransferProcessingException(String msgId, Throwable cause)
|
||||
{
|
||||
super(msgId, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msgId
|
||||
*/
|
||||
public TransferProcessingException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fatal
|
||||
*/
|
||||
public boolean isFatal()
|
||||
{
|
||||
return fatal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fatal the fatal to set
|
||||
*/
|
||||
public void setFatal(boolean fatal)
|
||||
{
|
||||
this.fatal = fatal;
|
||||
}
|
||||
|
||||
}
|
889
source/java/org/alfresco/repo/transfer/TransferServiceImpl.java
Normal file
889
source/java/org/alfresco/repo/transfer/TransferServiceImpl.java
Normal file
@@ -0,0 +1,889 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.transfer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.NotSupportedException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.UserTransaction;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.jlan.smb.dcerpc.UUID;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transfer.manifest.TestTransferManifestProcessor;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactory;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactoryImpl;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeHelper;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestProcessor;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestWriter;
|
||||
import org.alfresco.repo.transfer.manifest.XMLTransferManifestReader;
|
||||
import org.alfresco.repo.transfer.manifest.XMLTransferManifestWriter;
|
||||
import org.alfresco.repo.transfer.report.TransferReporter;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
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.repository.NodeService;
|
||||
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.cmr.transfer.TransferCallback;
|
||||
import org.alfresco.service.cmr.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferService;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
|
||||
public class TransferServiceImpl implements TransferService
|
||||
{
|
||||
private static final String MSG_NO_HOME = "transfer_service.unable_to_find_transfer_home";
|
||||
private static final String MSG_NO_GROUP = "transfer_service.unable_to_find_transfer_group";
|
||||
private static final String MSG_NO_TARGET = "transfer_service.unable_to_find_transfer_target";
|
||||
private static final String MSG_TARGET_EXISTS = "transfer_service.target_exists";
|
||||
private static final String MSG_NO_NODES = "transfer_service.no_nodes";
|
||||
|
||||
private static Log logger = LogFactory.getLog(TransferServiceImpl.class);
|
||||
|
||||
public void init()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "nodeService", nodeService);
|
||||
PropertyCheck.mandatory(this, "searchService", getSearchService());
|
||||
PropertyCheck.mandatory(this, "transferSpaceQuery", transferSpaceQuery);
|
||||
PropertyCheck.mandatory(this, "defaultTransferGroup", defaultTransferGroup);
|
||||
PropertyCheck.mandatory(this, "transmitter", transmitter);
|
||||
PropertyCheck.mandatory(this, "namespaceResolver", transmitter);
|
||||
PropertyCheck.mandatory(this, "actionService", actionService);
|
||||
PropertyCheck.mandatory(this, "transactionService", transactionService);
|
||||
}
|
||||
|
||||
private String transferSpaceQuery;
|
||||
private String defaultTransferGroup;
|
||||
private NodeService nodeService;
|
||||
private SearchService searchService;
|
||||
private TransferTransmitter transmitter;
|
||||
private TransactionService transactionService;
|
||||
private ActionService actionService;
|
||||
private TransferManifestNodeFactory transferManifestNodeFactory;
|
||||
private TransferReporter transferReporter;
|
||||
|
||||
/**
|
||||
* create transfer target
|
||||
*/
|
||||
public TransferTarget createTransferTarget(String name, String title, String description, String endpointProtocol, String endpointHost, int endpointPort, String endpointPath, String username, char[] password)
|
||||
{
|
||||
/**
|
||||
* Check whether name is already used
|
||||
*/
|
||||
NodeRef dummy = lookupTransferTarget(name);
|
||||
if(dummy != null)
|
||||
{
|
||||
throw new TransferException(MSG_TARGET_EXISTS, new Object[]{name} );
|
||||
}
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
|
||||
// type properties
|
||||
properties.put(TransferModel.PROP_ENDPOINT_HOST, endpointHost);
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PORT, endpointPort);
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PROTOCOL, endpointProtocol);
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PATH, endpointPath);
|
||||
properties.put(TransferModel.PROP_USERNAME, username);
|
||||
properties.put(TransferModel.PROP_PASSWORD, encrypt(password));
|
||||
|
||||
// titled aspect
|
||||
properties.put(ContentModel.PROP_TITLE, title);
|
||||
properties.put(ContentModel.PROP_NAME, name);
|
||||
properties.put(ContentModel.PROP_DESCRIPTION, description);
|
||||
|
||||
// enableable aspect
|
||||
properties.put(TransferModel.PROP_ENABLED, Boolean.TRUE);
|
||||
|
||||
NodeRef home = getTransferHome();
|
||||
|
||||
/**
|
||||
* Work out which group the transfer target is for, in this case the default group.
|
||||
*/
|
||||
NodeRef defaultGroup = nodeService.getChildByName(home, ContentModel.ASSOC_CONTAINS, defaultTransferGroup);
|
||||
|
||||
/**
|
||||
* Go ahead and create the new node
|
||||
*/
|
||||
ChildAssociationRef ref = nodeService.createNode(defaultGroup, ContentModel.ASSOC_CONTAINS, QName.createQName(TransferModel.TRANSFER_MODEL_1_0_URI, name), TransferModel.TYPE_TRANSFER_TARGET, properties);
|
||||
|
||||
/**
|
||||
* Now create a new TransferTarget object to return to the caller.
|
||||
*/
|
||||
TransferTargetImpl newTarget = new TransferTargetImpl();
|
||||
mapTransferTarget(ref.getChildRef(), newTarget);
|
||||
|
||||
return newTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all transfer targets
|
||||
*/
|
||||
public Set<TransferTarget> getTransferTargets()
|
||||
{
|
||||
NodeRef home = getTransferHome();
|
||||
|
||||
Set<TransferTarget> ret = new HashSet<TransferTarget>();
|
||||
|
||||
// get all groups
|
||||
List<ChildAssociationRef> groups = nodeService.getChildAssocs(home);
|
||||
|
||||
// for each group
|
||||
for(ChildAssociationRef group : groups)
|
||||
{
|
||||
NodeRef groupNode = group.getChildRef();
|
||||
List<ChildAssociationRef>children = nodeService.getChildAssocs(groupNode, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
|
||||
|
||||
for(ChildAssociationRef child : children)
|
||||
{
|
||||
if(nodeService.getType(child.getChildRef()).equals(TransferModel.TYPE_TRANSFER_TARGET))
|
||||
{
|
||||
TransferTargetImpl newTarget = new TransferTargetImpl();
|
||||
mapTransferTarget(child.getChildRef(), newTarget);
|
||||
ret.add(newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all transfer targets in the specified group
|
||||
*/
|
||||
public Set<TransferTarget> getTransferTargets(String groupName)
|
||||
{
|
||||
NodeRef home = getTransferHome();
|
||||
|
||||
Set<TransferTarget> ret = new HashSet<TransferTarget>();
|
||||
|
||||
// get group with assoc groupName
|
||||
NodeRef groupNode = nodeService.getChildByName(home, ContentModel.ASSOC_CONTAINS, groupName);
|
||||
|
||||
if(groupNode == null)
|
||||
{
|
||||
// No transfer group.
|
||||
throw new TransferException(MSG_NO_GROUP, new Object[]{groupName});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children of groupNode
|
||||
*/
|
||||
List<ChildAssociationRef>children = nodeService.getChildAssocs(groupNode, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
|
||||
|
||||
for(ChildAssociationRef child : children)
|
||||
{
|
||||
if(nodeService.getType(child.getChildRef()).equals(TransferModel.TYPE_TRANSFER_TARGET))
|
||||
{
|
||||
TransferTargetImpl newTarget = new TransferTargetImpl();
|
||||
mapTransferTarget(child.getChildRef(), newTarget);
|
||||
ret.add(newTarget);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void deleteTransferTarget(String name)
|
||||
{
|
||||
NodeRef nodeRef = lookupTransferTarget(name);
|
||||
|
||||
if(nodeRef == null)
|
||||
{
|
||||
// target does not exist
|
||||
throw new TransferException(MSG_NO_TARGET, new Object[]{name} );
|
||||
}
|
||||
nodeService.deleteNode(nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/Disables the named transfer target
|
||||
*/
|
||||
public void enableTransferTarget(String name, boolean enable)
|
||||
{
|
||||
NodeRef nodeRef = lookupTransferTarget(name);
|
||||
nodeService.setProperty(nodeRef, TransferModel.PROP_ENABLED, new Boolean(enable));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public TransferTarget getTransferTarget(String name)
|
||||
{
|
||||
NodeRef nodeRef = lookupTransferTarget(name);
|
||||
|
||||
if(nodeRef == null)
|
||||
{
|
||||
// target does not exist
|
||||
throw new TransferException(MSG_NO_TARGET, new Object[]{name} );
|
||||
}
|
||||
TransferTargetImpl newTarget = new TransferTargetImpl();
|
||||
mapTransferTarget(nodeRef, newTarget);
|
||||
|
||||
return newTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public TransferTarget updateTransferTarget(TransferTarget update)
|
||||
{
|
||||
NodeRef nodeRef = lookupTransferTarget(update.getName());
|
||||
if(nodeRef == null)
|
||||
{
|
||||
// target does not exist
|
||||
throw new TransferException(MSG_NO_TARGET, new Object[]{update.getName()} );
|
||||
}
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
properties.put(TransferModel.PROP_ENDPOINT_HOST, update.getEndpointHost());
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PORT, update.getEndpointPort());
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PROTOCOL, update.getEndpointProtocol());
|
||||
properties.put(TransferModel.PROP_ENDPOINT_PATH, update.getEndpointPath());
|
||||
properties.put(TransferModel.PROP_USERNAME, update.getUsername());
|
||||
properties.put(TransferModel.PROP_PASSWORD, encrypt(update.getPassword()));
|
||||
|
||||
// titled aspect
|
||||
properties.put(ContentModel.PROP_TITLE, update.getTitle());
|
||||
properties.put(ContentModel.PROP_NAME, update.getName());
|
||||
properties.put(ContentModel.PROP_DESCRIPTION, update.getDescription());
|
||||
|
||||
properties.put(TransferModel.PROP_ENABLED, new Boolean(update.isEnabled()));
|
||||
nodeService.setProperties(nodeRef, properties);
|
||||
|
||||
TransferTargetImpl newTarget = new TransferTargetImpl();
|
||||
mapTransferTarget(nodeRef, newTarget);
|
||||
return newTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public NodeRef transfer(String targetName, TransferDefinition definition)
|
||||
{
|
||||
final TransferEventProcessor eventProcessor = new TransferEventProcessor();
|
||||
return transferImpl(targetName, definition, eventProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer async.
|
||||
*
|
||||
* @param targetName
|
||||
* @param definition
|
||||
* @param callbacks
|
||||
*/
|
||||
public void transferAsync(String targetName, TransferDefinition definition, Set<TransferCallback> callbacks)
|
||||
{
|
||||
/**
|
||||
* Event processor for this transfer instance
|
||||
*/
|
||||
final TransferEventProcessor eventProcessor = new TransferEventProcessor();
|
||||
if(callbacks != null)
|
||||
{
|
||||
eventProcessor.observers.addAll(callbacks);
|
||||
}
|
||||
|
||||
Map<String, Serializable> params = new HashMap<String, Serializable>();
|
||||
params.put("targetName", targetName);
|
||||
params.put("definition", definition);
|
||||
params.put("callbacks", (Serializable)callbacks);
|
||||
|
||||
Action transferAction = getActionService().createAction("transfer-async", params);
|
||||
|
||||
/**
|
||||
* Execute transfer async in its own transaction.
|
||||
* The action service only runs actions in the post commit which is why there's
|
||||
* a separate transaction here.
|
||||
*/
|
||||
boolean success = false;
|
||||
UserTransaction trx = transactionService.getNonPropagatingUserTransaction();
|
||||
try
|
||||
{
|
||||
trx.begin();
|
||||
logger.debug("calling action service to execute action");
|
||||
getActionService().executeAction(transferAction, null, false, true);
|
||||
trx.commit();
|
||||
logger.debug("committed successfully");
|
||||
success = true;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
logger.error("unexpected exception", error);
|
||||
throw new AlfrescoRuntimeException("unable to transfer async", error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(!success)
|
||||
{
|
||||
try
|
||||
{
|
||||
logger.debug("rolling back after error");
|
||||
trx.rollback();
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
logger.error("unexpected exception during rollback", error);
|
||||
// There's nothing much we can do here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer Synchronous
|
||||
* @param targetName
|
||||
* @param definition
|
||||
* @param callbacks
|
||||
*/
|
||||
public NodeRef transfer(String targetName, TransferDefinition definition, Set<TransferCallback> callbacks)
|
||||
{
|
||||
/**
|
||||
* Event processor for this transfer instance
|
||||
*/
|
||||
final TransferEventProcessor eventProcessor = new TransferEventProcessor();
|
||||
if(callbacks != null)
|
||||
{
|
||||
eventProcessor.observers.addAll(callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Now go ahead and do the transfer
|
||||
*/
|
||||
return transferImpl(targetName, definition, eventProcessor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transfer Implementation
|
||||
* @param targetName name of transfer target
|
||||
* @param definition thranser definition
|
||||
* @param eventProcessor
|
||||
*/
|
||||
private NodeRef transferImpl(String targetName, final TransferDefinition definition, final TransferEventProcessor eventProcessor)
|
||||
{
|
||||
NodeRef reportNode = null;
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("transfer started to :" + targetName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire in the transferReport
|
||||
*/
|
||||
final List<TransferEvent> transferReport = new LinkedList<TransferEvent>();
|
||||
TransferCallback reportCallback = new TransferCallback()
|
||||
{
|
||||
private static final long serialVersionUID = 4072579605731036522L;
|
||||
|
||||
public void processEvent(TransferEvent event)
|
||||
{
|
||||
transferReport.add(event);
|
||||
}
|
||||
};
|
||||
eventProcessor.addObserver(reportCallback);
|
||||
|
||||
File snapshotFile = null;
|
||||
TransferTarget target = null;
|
||||
try
|
||||
{
|
||||
target = getTransferTarget(targetName);
|
||||
|
||||
// which nodes to write to the snapshot
|
||||
Set<NodeRef>nodes = definition.getNodes();
|
||||
|
||||
if(nodes == null || nodes.size() == 0)
|
||||
{
|
||||
logger.debug("no nodes to transfer");
|
||||
throw new TransferException(MSG_NO_NODES);
|
||||
}
|
||||
|
||||
/**
|
||||
* create snapshot
|
||||
*/
|
||||
String prefix = "TRX-SNAP";
|
||||
String suffix = ".xml";
|
||||
|
||||
long numberOfNodes = 0;
|
||||
|
||||
logger.debug("create snapshot");
|
||||
|
||||
// where to put snapshot ?
|
||||
snapshotFile = TempFileProvider.createTempFile(prefix, suffix);
|
||||
|
||||
FileWriter snapshotWriter = new FileWriter(snapshotFile);
|
||||
|
||||
// Write the manifest file
|
||||
TransferManifestWriter formatter = new XMLTransferManifestWriter();
|
||||
TransferManifestHeader header = new TransferManifestHeader();
|
||||
header.setCreatedDate(new Date());
|
||||
formatter.startTransferManifest(snapshotWriter);
|
||||
formatter.writeTransferManifestHeader(header);
|
||||
for(NodeRef nodeRef : nodes)
|
||||
{
|
||||
TransferManifestNode node = transferManifestNodeFactory.createTransferManifestNode(nodeRef);
|
||||
formatter.writeTransferManifestNode(node);
|
||||
numberOfNodes++;
|
||||
}
|
||||
formatter.endTransferManifest();
|
||||
snapshotWriter.close();
|
||||
|
||||
logger.debug("snapshot file written to local filesystem");
|
||||
// If we are debugging then write the file to stdout.
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
outputFile(snapshotFile);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
error.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin
|
||||
*/
|
||||
eventProcessor.start();
|
||||
final Transfer transfer = transmitter.begin(target);
|
||||
if(transfer != null)
|
||||
{
|
||||
logger.debug("transfer begin");
|
||||
|
||||
boolean prepared = false;
|
||||
try
|
||||
{
|
||||
/**
|
||||
* send Manifest
|
||||
*/
|
||||
eventProcessor.sendManifest(1,1);
|
||||
DeltaList deltas = transmitter.sendManifest(transfer, snapshotFile);
|
||||
|
||||
logger.debug("manifest sent");
|
||||
|
||||
/**
|
||||
* Parse the manifest file and transfer chunks over
|
||||
*/
|
||||
|
||||
// create a chunker and wire it up to the transmitter
|
||||
final ContentChunker chunker = new ContentChunkerImpl();
|
||||
final Long fRange = Long.valueOf(numberOfNodes);
|
||||
chunker.setHandler(
|
||||
new ContentChunkProcessor(){
|
||||
private long counter = 0;
|
||||
public void processChunk(Set<ContentData> data)
|
||||
{
|
||||
logger.debug("send chunk to transmitter");
|
||||
for(ContentData file : data)
|
||||
{
|
||||
counter++;
|
||||
eventProcessor.sendContent(file, fRange, counter);
|
||||
}
|
||||
transmitter.sendContent(transfer, data);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// create a manifest processor and wire it up to the chunker
|
||||
TransferManifestProcessor processor = new TransferManifestProcessor()
|
||||
{
|
||||
public void processTransferManifestNode(TransferManifestNormalNode node)
|
||||
{
|
||||
Set<ContentData> data = TransferManifestNodeHelper.getContentData(node);
|
||||
for(ContentData d : data)
|
||||
{
|
||||
logger.debug("add content to chunker");
|
||||
chunker.addContent(d);
|
||||
}
|
||||
}
|
||||
|
||||
public void processTransferManifiestHeader(TransferManifestHeader header){/* NO-OP */ }
|
||||
public void startTransferManifest(){ /* NO-OP */ }
|
||||
public void endTransferManifest(){ /* NO-OP */ }
|
||||
public void processTransferManifestNode(TransferManifestDeletedNode node)
|
||||
{ /* NO-OP */
|
||||
}
|
||||
};
|
||||
|
||||
// wire up the manifest parser to a manifest processor
|
||||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
SAXParser parser;
|
||||
parser = saxParserFactory.newSAXParser();
|
||||
XMLTransferManifestReader reader = new XMLTransferManifestReader(processor);
|
||||
|
||||
// start the magic
|
||||
parser.parse(snapshotFile, reader);
|
||||
|
||||
chunker.flush();
|
||||
|
||||
logger.debug("content sending finished");
|
||||
|
||||
/**
|
||||
* prepare
|
||||
*/
|
||||
eventProcessor.prepare();
|
||||
transmitter.prepare(transfer);
|
||||
logger.debug("prepared");
|
||||
|
||||
/**
|
||||
* committing
|
||||
*/
|
||||
eventProcessor.committing(100, 0);
|
||||
transmitter.commit(transfer);
|
||||
|
||||
/**
|
||||
* need to poll for status
|
||||
*/
|
||||
// transmitter.getCommitStatus(transfer);
|
||||
|
||||
eventProcessor.committing(100, 50);
|
||||
eventProcessor.committing(100, 100);
|
||||
|
||||
/**
|
||||
* committed
|
||||
*/
|
||||
//eventProcessor.serverMessage("Committed");
|
||||
|
||||
eventProcessor.success();
|
||||
|
||||
prepared = true;
|
||||
|
||||
logger.debug("committed");
|
||||
|
||||
// Write the Successful transfer report if we get here
|
||||
// in its own transaction so it cannot be rolled back
|
||||
final TransferTarget fTarget = target;
|
||||
reportNode = transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
logger.debug("transfer report starting");
|
||||
NodeRef reportNode = transferReporter.createTransferReport(transfer, fTarget, definition, transferReport);
|
||||
logger.debug("transfer report done");
|
||||
return reportNode;
|
||||
}
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(!prepared)
|
||||
{
|
||||
logger.debug("abort incomplete transfer");
|
||||
transmitter.abort(transfer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TransferException t)
|
||||
{
|
||||
eventProcessor.error(t);
|
||||
|
||||
/**
|
||||
* Write the transfer report. This is an error report so needs to be out
|
||||
*/
|
||||
if(target != null && reportNode!= null)
|
||||
{
|
||||
// reportNode = transferReporter.createTransferReport(target, definition, transferReport);
|
||||
}
|
||||
throw t;
|
||||
}
|
||||
catch (Exception t)
|
||||
{
|
||||
// Wrap any other exception as a transfer exception
|
||||
logger.debug("unable to transfer", t);
|
||||
eventProcessor.error(t);
|
||||
|
||||
/**
|
||||
* Write the transfer report. This is an error report so needs to be out
|
||||
*/
|
||||
if(target != null && reportNode!= null)
|
||||
{
|
||||
// reportNode = transferReporter.createTransferReport(target, definition, transferReport);
|
||||
}
|
||||
throw new TransferException("unable to transfer:" + t.toString(), t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
/**
|
||||
* clean up
|
||||
*/
|
||||
if(snapshotFile != null)
|
||||
{
|
||||
snapshotFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
return reportNode;
|
||||
} // end of transferImpl
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public SearchService getSearchService()
|
||||
{
|
||||
return searchService;
|
||||
}
|
||||
|
||||
public void setTransferSpaceQuery(String transferSpaceQuery)
|
||||
{
|
||||
this.transferSpaceQuery = transferSpaceQuery;
|
||||
}
|
||||
|
||||
public String getTransferSpaceQuery()
|
||||
{
|
||||
return transferSpaceQuery;
|
||||
}
|
||||
|
||||
public void setDefaultTransferGroup(String defaultGroup)
|
||||
{
|
||||
this.defaultTransferGroup = defaultGroup;
|
||||
}
|
||||
|
||||
public String getDefaultTransferGroup()
|
||||
{
|
||||
return defaultTransferGroup;
|
||||
}
|
||||
|
||||
public TransferTransmitter getTransmitter()
|
||||
{
|
||||
return transmitter;
|
||||
}
|
||||
|
||||
public void setTransmitter(TransferTransmitter transmitter)
|
||||
{
|
||||
this.transmitter = transmitter;
|
||||
}
|
||||
|
||||
private NodeRef transferHome;
|
||||
protected NodeRef getTransferHome()
|
||||
{
|
||||
if(transferHome == null)
|
||||
{
|
||||
String query = transferSpaceQuery;
|
||||
|
||||
ResultSet result = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_XPATH, query);
|
||||
|
||||
if(result.length() == 0)
|
||||
{
|
||||
// No transfer home.
|
||||
throw new TransferException(MSG_NO_HOME, new Object[]{query});
|
||||
}
|
||||
if (result.getNodeRefs().size() != 0)
|
||||
{
|
||||
transferHome = result.getNodeRef(0);
|
||||
}
|
||||
}
|
||||
return transferHome;
|
||||
}
|
||||
|
||||
private char[] encrypt(char[] text)
|
||||
{
|
||||
// placeholder dummy implementation - add an 'E' to the start
|
||||
// String dummy = new String("E" + text);
|
||||
// String dummy = new String(text);
|
||||
// return dummy.toCharArray();
|
||||
return text;
|
||||
}
|
||||
|
||||
private char[] decrypt(char[] text)
|
||||
{
|
||||
// placeholder dummy implementation - strips off leading 'E'
|
||||
// String dummy = new String(text);
|
||||
return text;
|
||||
//return dummy.substring(1).toCharArray();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private NodeRef lookupTransferTarget(String name)
|
||||
{
|
||||
String query = "+TYPE:\"trx:transferTarget\" +@cm\\:name:\"" +name + "\"";
|
||||
|
||||
ResultSet result = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
|
||||
SearchService.LANGUAGE_LUCENE, query);
|
||||
|
||||
if(result.length() == 1)
|
||||
{
|
||||
return result.getNodeRef(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void mapTransferTarget(NodeRef nodeRef, TransferTargetImpl def)
|
||||
{
|
||||
def.setNodeRef(nodeRef);
|
||||
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
||||
def.setEndpointPath((String)properties.get(TransferModel.PROP_ENDPOINT_PATH));
|
||||
def.setEndpointProtocol((String)properties.get(TransferModel.PROP_ENDPOINT_PROTOCOL));
|
||||
def.setEndpointHost((String)properties.get(TransferModel.PROP_ENDPOINT_HOST));
|
||||
def.setEndpointPort((Integer)properties.get(TransferModel.PROP_ENDPOINT_PORT));
|
||||
Serializable passwordVal = properties.get(TransferModel.PROP_PASSWORD);
|
||||
|
||||
if(passwordVal.getClass().isArray())
|
||||
{
|
||||
def.setPassword(decrypt((char[])passwordVal));
|
||||
}
|
||||
if(passwordVal instanceof String)
|
||||
{
|
||||
String password = (String)passwordVal;
|
||||
def.setPassword(decrypt(password.toCharArray()));
|
||||
}
|
||||
|
||||
|
||||
def.setUsername((String)properties.get(TransferModel.PROP_USERNAME));
|
||||
def.setName((String)properties.get(ContentModel.PROP_NAME));
|
||||
def.setTitle((String)properties.get(ContentModel.PROP_TITLE));
|
||||
def.setDescription((String)properties.get(ContentModel.PROP_DESCRIPTION));
|
||||
|
||||
if(nodeService.hasAspect(nodeRef, TransferModel.ASPECT_ENABLEABLE))
|
||||
{
|
||||
def.setEnabled((Boolean)properties.get(TransferModel.PROP_ENABLED));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.service.cmr.transfer.TransferService#verify(org.alfresco.service.cmr.transfer.TransferTarget)
|
||||
*/
|
||||
public void verify(TransferTarget target) throws TransferException
|
||||
{
|
||||
transmitter.verifyTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to dump the contents of a file to the console
|
||||
* @param file
|
||||
*/
|
||||
private static void outputFile(File file) throws Exception
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String s = reader.readLine();
|
||||
while(s != null)
|
||||
{
|
||||
System.out.println(s);
|
||||
s = reader.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTransferManifestNodeFactory(TransferManifestNodeFactory transferManifestNodeFactory)
|
||||
{
|
||||
this.transferManifestNodeFactory = transferManifestNodeFactory;
|
||||
}
|
||||
|
||||
public TransferManifestNodeFactory getTransferManifestNodeFactory()
|
||||
{
|
||||
return transferManifestNodeFactory;
|
||||
}
|
||||
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
public ActionService getActionService()
|
||||
{
|
||||
return actionService;
|
||||
}
|
||||
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
public TransactionService getTransactionService()
|
||||
{
|
||||
return transactionService;
|
||||
}
|
||||
|
||||
public void setTransferReporter(TransferReporter transferReporter)
|
||||
{
|
||||
this.transferReporter = transferReporter;
|
||||
}
|
||||
|
||||
public TransferReporter getTransferReporter()
|
||||
{
|
||||
return transferReporter;
|
||||
}
|
||||
}
|
1265
source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java
Normal file
1265
source/java/org/alfresco/repo/transfer/TransferServiceImplTest.java
Normal file
File diff suppressed because it is too large
Load Diff
174
source/java/org/alfresco/repo/transfer/TransferTargetImpl.java
Normal file
174
source/java/org/alfresco/repo/transfer/TransferTargetImpl.java
Normal file
@@ -0,0 +1,174 @@
|
||||
package org.alfresco.repo.transfer;
|
||||
/*
|
||||
* Copyright (C) 2009-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"
|
||||
*/
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
|
||||
/**
|
||||
* Data Transfer Object for a TransferTarget. The definition of the connection to a remote system.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferTargetImpl implements TransferTarget
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private String name;
|
||||
private String title;
|
||||
private String description;
|
||||
private String endpointProtocol;
|
||||
private String endpointHost;
|
||||
private int endpointPort;
|
||||
private String endpointPath;
|
||||
private String username;
|
||||
private char[] password;
|
||||
private boolean enabled;
|
||||
|
||||
public void setNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
public void setTitle(String title)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
public void setDescription(String description)
|
||||
{
|
||||
this.description = description;
|
||||
}
|
||||
public String getDescription()
|
||||
{
|
||||
return description;
|
||||
}
|
||||
public void setEndpointProtocol(String endpointProtocol)
|
||||
{
|
||||
this.endpointProtocol = endpointProtocol;
|
||||
}
|
||||
public String getEndpointProtocol()
|
||||
{
|
||||
return endpointProtocol;
|
||||
}
|
||||
public void setEndpointHost(String endpointHost)
|
||||
{
|
||||
this.endpointHost = endpointHost;
|
||||
}
|
||||
public String getEndpointHost()
|
||||
{
|
||||
return endpointHost;
|
||||
}
|
||||
public void setPassword(char[] password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
public char[] getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
}
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
public void setEndpointPath(String endpointPath)
|
||||
{
|
||||
this.endpointPath = endpointPath;
|
||||
}
|
||||
public String getEndpointPath()
|
||||
{
|
||||
return endpointPath;
|
||||
}
|
||||
public void setEndpointPort(int endpointPort)
|
||||
{
|
||||
this.endpointPort = endpointPort;
|
||||
}
|
||||
public int getEndpointPort()
|
||||
{
|
||||
return endpointPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getNodeRef()
|
||||
* @see NodeRef#equals(Object)
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (obj instanceof TransferTargetImpl == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
TransferTargetImpl that = (TransferTargetImpl) obj;
|
||||
return (this.getNodeRef().equals(that.getNodeRef()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getNodeRef()
|
||||
* @see NodeRef#hashCode()
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return getNodeRef().hashCode();
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "TransferTarget: " + name + ",host:" + endpointHost + ",port:" + endpointPort;
|
||||
}
|
||||
}
|
102
source/java/org/alfresco/repo/transfer/TransferTransmitter.java
Normal file
102
source/java/org/alfresco/repo/transfer/TransferTransmitter.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface TransferTransmitter
|
||||
{
|
||||
/**
|
||||
* Verify that the target is available
|
||||
* @param target
|
||||
* @throws TransferException
|
||||
*/
|
||||
void verifyTarget(TransferTarget target) throws TransferException;
|
||||
|
||||
/**
|
||||
* Begin a transfer, the transfer object returned will be used by subsequent
|
||||
* calls to the transfer service.
|
||||
*
|
||||
* @param target definition of where to transfer to.
|
||||
* @return the transfer object or null if the target cannot be locked.
|
||||
* @throws TransferException
|
||||
*/
|
||||
Transfer begin(TransferTarget target) throws TransferException;
|
||||
|
||||
/**
|
||||
* @param manifest, the transfer manifest file
|
||||
* @param transfer the transfer object returned by an earlier call to begin
|
||||
* @return the delta list.
|
||||
* @throws TransferException
|
||||
*/
|
||||
DeltaList sendManifest(Transfer transfer, File manifest) throws TransferException;
|
||||
|
||||
/**
|
||||
* Send the content of the specified urls
|
||||
*
|
||||
* @param transfer the transfer object returned by an earlier call to begin
|
||||
* @param data the content to send
|
||||
* @throws TransferException
|
||||
*/
|
||||
void sendContent(Transfer transfer, Set<ContentData> data);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param transfer the transfer object returned by an earlier call to begin
|
||||
* @throws TransferException
|
||||
*/
|
||||
void prepare(Transfer transfer) throws TransferException;
|
||||
|
||||
/**
|
||||
* @param transfer the transfer object returned by an earlier call to begin
|
||||
* @throws TransferException
|
||||
*/
|
||||
void commit(Transfer transfer) throws TransferException;
|
||||
|
||||
/**
|
||||
* Abort the transfer
|
||||
* @param transfer the transfer object returned by an earlier call to begin
|
||||
* @throws TransferException
|
||||
*/
|
||||
void abort(Transfer transfer) throws TransferException;
|
||||
|
||||
/**
|
||||
* Get Async Messages for a transfer.
|
||||
* Server Side Messages.
|
||||
* @return messages
|
||||
*/
|
||||
Set<TransferMessage> getMessages(Transfer transfer);
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
|
||||
/**
|
||||
* This class delegates transfer service to the transfer receiver without
|
||||
* using any networking.
|
||||
*
|
||||
* It is used for unit testing the transfer service without requiring two instance
|
||||
* of the repository to be running.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class UnitTestInProcessTransmitterImpl implements TransferTransmitter
|
||||
{
|
||||
private TransferReceiver receiver;
|
||||
|
||||
private ContentService contentService;
|
||||
|
||||
public UnitTestInProcessTransmitterImpl(TransferReceiver receiver, ContentService contentService)
|
||||
{
|
||||
this.receiver = receiver;
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public Transfer begin(TransferTarget target) throws TransferException
|
||||
{
|
||||
Transfer transfer = new Transfer();
|
||||
String transferId = receiver.start();
|
||||
transfer.setTransferId(transferId);
|
||||
transfer.setTransferTarget(target);
|
||||
return transfer;
|
||||
}
|
||||
|
||||
public void abort(Transfer transfer) throws TransferException
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
receiver.abort(transferId);
|
||||
}
|
||||
|
||||
public void commit(Transfer transfer) throws TransferException
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
receiver.commit(transferId);
|
||||
}
|
||||
|
||||
public Set<TransferMessage> getMessages(Transfer transfer)
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void prepare(Transfer transfer) throws TransferException
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
receiver.prepare(transferId);
|
||||
}
|
||||
|
||||
public void sendContent(Transfer transfer, Set<ContentData> data)
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
|
||||
for(ContentData content : data)
|
||||
{
|
||||
String contentUrl = content.getContentUrl();
|
||||
String fileName = TransferCommons.URLToPartName(contentUrl);
|
||||
|
||||
InputStream contentStream = getContentService().getRawReader(contentUrl).getContentInputStream();
|
||||
receiver.saveContent(transferId, fileName, contentStream);
|
||||
}
|
||||
}
|
||||
|
||||
public DeltaList sendManifest(Transfer transfer, File manifest) throws TransferException
|
||||
{
|
||||
try
|
||||
{
|
||||
String transferId = transfer.getTransferId();
|
||||
FileInputStream fs = new FileInputStream(manifest);
|
||||
receiver.saveSnapshot(transferId, fs);
|
||||
}
|
||||
catch (FileNotFoundException error)
|
||||
{
|
||||
throw new TransferException("test error", error);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public void verifyTarget(TransferTarget target) throws TransferException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void setReceiver(TransferReceiver receiver)
|
||||
{
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
public TransferReceiver getReceiver()
|
||||
{
|
||||
return receiver;
|
||||
}
|
||||
|
||||
private void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
private ContentService getContentService()
|
||||
{
|
||||
return contentService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer;
|
||||
|
||||
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.repo.transfer.manifest.TransferManifestNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactory;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNormalNode;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
|
||||
/**
|
||||
* This is a test class to enable unit testing on a single machine. Since the single machine will already have the
|
||||
* target node.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class UnitTestTransferManifestNodeFactory implements TransferManifestNodeFactory
|
||||
{
|
||||
/**
|
||||
* Map of source to target noderef.
|
||||
*/
|
||||
Map<NodeRef, NodeRef> refMap = new HashMap<NodeRef, NodeRef>();
|
||||
|
||||
/**
|
||||
* List of paths
|
||||
*
|
||||
* <From Path, To Path>
|
||||
*/
|
||||
private List<Pair<Path, Path>> pathMap = new ArrayList<Pair<Path, Path>>();
|
||||
|
||||
/**
|
||||
* The node factory that does the work for real.
|
||||
*/
|
||||
TransferManifestNodeFactory realFactory;
|
||||
|
||||
/**
|
||||
* Create a new UnitTestTransferManifestNodeFactory
|
||||
*
|
||||
* @param realFactory
|
||||
*/
|
||||
UnitTestTransferManifestNodeFactory(TransferManifestNodeFactory realFactory)
|
||||
{
|
||||
this.realFactory = realFactory;
|
||||
}
|
||||
|
||||
public TransferManifestNode createTransferManifestNode(NodeRef nodeRef)
|
||||
{
|
||||
TransferManifestNode newNode = realFactory.createTransferManifestNode(nodeRef);
|
||||
|
||||
NodeRef origNodeRef = newNode.getNodeRef();
|
||||
|
||||
/**
|
||||
* Fiddle with the node ref to prevent a clash with the source
|
||||
*/
|
||||
NodeRef mappedNodeRef = mapNodeRef(origNodeRef);
|
||||
newNode.setNodeRef(mappedNodeRef);
|
||||
|
||||
/**
|
||||
* Fiddle with the parent node ref and parent path.
|
||||
*/
|
||||
ChildAssociationRef primaryParentAssoc = newNode.getPrimaryParentAssoc();
|
||||
NodeRef mappedParentNodeRef = mapNodeRef(primaryParentAssoc.getParentRef());
|
||||
Path parentPath = newNode.getParentPath();
|
||||
newNode.setParentPath(getMappedPath(parentPath));
|
||||
newNode.setPrimaryParentAssoc(new ChildAssociationRef(primaryParentAssoc.getTypeQName(), mappedParentNodeRef,
|
||||
primaryParentAssoc.getQName(), mappedNodeRef, primaryParentAssoc.isPrimary(),
|
||||
primaryParentAssoc.getNthSibling()));
|
||||
|
||||
/**
|
||||
* Fiddle with the parent assocs
|
||||
*/
|
||||
if (newNode instanceof TransferManifestNormalNode)
|
||||
{
|
||||
TransferManifestNormalNode normalNode = (TransferManifestNormalNode) newNode;
|
||||
List<ChildAssociationRef> mappedParentAssocs = new ArrayList<ChildAssociationRef>();
|
||||
List<ChildAssociationRef> assocs = normalNode.getParentAssocs();
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
ChildAssociationRef replace = new ChildAssociationRef(assoc.getTypeQName(), mappedParentNodeRef,
|
||||
assoc.getQName(), mappedNodeRef, assoc.isPrimary(), assoc.getNthSibling());
|
||||
mappedParentAssocs.add(replace);
|
||||
}
|
||||
normalNode.setParentAssocs(mappedParentAssocs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fiddle with the UUID property
|
||||
*/
|
||||
if (newNode instanceof TransferManifestNormalNode)
|
||||
{
|
||||
TransferManifestNormalNode normalNode = (TransferManifestNormalNode) newNode;
|
||||
Map<QName, Serializable> props = normalNode.getProperties();
|
||||
|
||||
if (props.containsKey(ContentModel.PROP_NODE_UUID))
|
||||
{
|
||||
props.put(ContentModel.PROP_NODE_UUID, mappedNodeRef.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapped node ref
|
||||
*
|
||||
* @param node
|
||||
* @return the mapped node ref or null;
|
||||
*/
|
||||
public NodeRef getMappedNodeRef(NodeRef node)
|
||||
{
|
||||
return refMap.get(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mapped path
|
||||
*/
|
||||
public Path getMappedPath(Path from)
|
||||
{
|
||||
Path to = new Path();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
Path source = new Path();
|
||||
for (int i = 0; i < from.size(); i++)
|
||||
{
|
||||
// Source steps through each element of from.
|
||||
source.append(from.get(i));
|
||||
boolean replacePath = false;
|
||||
for (Pair<Path, Path> xx : getPathMap())
|
||||
{
|
||||
// Can't use direct equals because of mismatched node refs (which we don't care about)
|
||||
if (xx.getFirst().toString().equals(source.toString()))
|
||||
{
|
||||
to = xx.getSecond().subPath(xx.getSecond().size() - 1);
|
||||
replacePath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!replacePath)
|
||||
{
|
||||
to.append(from.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
private NodeRef mapNodeRef(NodeRef in)
|
||||
{
|
||||
NodeRef mappedNodeRef = refMap.get(in);
|
||||
if (mappedNodeRef == null)
|
||||
{
|
||||
/**
|
||||
* Map the node ref by replacing the 36th digit with a Z. The existing UUID could have 0-9 1-F in the 36th
|
||||
* digit
|
||||
*/
|
||||
String nodeRef = in.getId();
|
||||
if (nodeRef.length() == 36)
|
||||
{
|
||||
nodeRef = in.getId().substring(0, 35) + "Z";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeRef = in.getId() + "Z";
|
||||
}
|
||||
|
||||
mappedNodeRef = new NodeRef(in.getStoreRef(), nodeRef);
|
||||
refMap.put(in, mappedNodeRef);
|
||||
}
|
||||
return mappedNodeRef;
|
||||
}
|
||||
|
||||
public void setPathMap(List<Pair<Path, Path>> pathMap)
|
||||
{
|
||||
this.pathMap = pathMap;
|
||||
}
|
||||
|
||||
public List<Pair<Path, Path>> getPathMap()
|
||||
{
|
||||
return pathMap;
|
||||
}
|
||||
}
|
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.transfer.manifest;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNode;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestNodeFactoryImpl;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestWriter;
|
||||
import org.alfresco.repo.transfer.manifest.XMLTransferManifestWriter;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferService;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.BaseAlfrescoSpringTest;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
|
||||
/**
|
||||
* Integration test for Transfer Manifest
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class ManifestIntegrationTest extends BaseAlfrescoSpringTest
|
||||
{
|
||||
private TransferService transferService;
|
||||
private ContentService contentService;
|
||||
private SearchService searchService;
|
||||
|
||||
/**
|
||||
* Called during the transaction setup
|
||||
*/
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
|
||||
// Get the required services
|
||||
this.transferService = (TransferService)this.applicationContext.getBean("TransferService");
|
||||
this.contentService = (ContentService)this.applicationContext.getBean("ContentService");
|
||||
this.searchService = (SearchService)this.applicationContext.getBean("SearchService");
|
||||
}
|
||||
|
||||
public void testSnapshot() throws Exception
|
||||
{
|
||||
// Snapshot a transfer node
|
||||
String CONTENT_STRING = "hello world";
|
||||
Locale CONTENT_LOCALE = Locale.TAIWAN;
|
||||
String CONTENT_TITLE = "the title";
|
||||
String CONTENT_NAME = "&the name <\\*"; // nasty name for XML
|
||||
String CONTENT_ASSOC_NAME = "&hell+-1we";
|
||||
|
||||
String snapshotMe = "snapshotMe";
|
||||
String title = "title";
|
||||
String description = "description";
|
||||
String endpointProtocol = "http";
|
||||
String endpointHost = "localhost";
|
||||
int endpointPort = 8080;
|
||||
String endpointPath = "rhubarb";
|
||||
String username = "admin";
|
||||
char[] password = "password".toCharArray();
|
||||
|
||||
Map<NodeRef, TransferManifestNode> sentNodes = new HashMap<NodeRef, TransferManifestNode>();
|
||||
|
||||
TransferManifestNodeFactoryImpl nodeFactory = new TransferManifestNodeFactoryImpl();
|
||||
nodeFactory.setNodeService(nodeService);
|
||||
|
||||
/**
|
||||
* Create our transfer target
|
||||
*/
|
||||
TransferTarget target = transferService.createTransferTarget(snapshotMe, title, description, endpointProtocol, endpointHost, endpointPort, endpointPath, username, password);
|
||||
|
||||
File snapshotFile = null;
|
||||
|
||||
try
|
||||
{
|
||||
/**
|
||||
* Create a test node that we will read and write
|
||||
*/
|
||||
ChildAssociationRef child = nodeService.createNode(target.getNodeRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(CONTENT_ASSOC_NAME), ContentModel.TYPE_CONTENT);
|
||||
|
||||
NodeRef childNodeRef = child.getChildRef();
|
||||
ContentWriter writer = contentService.getWriter(childNodeRef, ContentModel.PROP_CONTENT, true);
|
||||
writer.setLocale(CONTENT_LOCALE);
|
||||
writer.putContent(CONTENT_STRING);
|
||||
|
||||
nodeService.setProperty(childNodeRef, ContentModel.PROP_TITLE, CONTENT_TITLE);
|
||||
|
||||
nodeService.setProperty(childNodeRef, ContentModel.PROP_NAME, CONTENT_NAME);
|
||||
|
||||
snapshotFile = TempFileProvider.createTempFile("xxx", ".xml");
|
||||
FileWriter snapshotWriter = new FileWriter(snapshotFile);
|
||||
|
||||
Set<NodeRef> nodes = new HashSet<NodeRef>();
|
||||
|
||||
nodes.add(nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE));
|
||||
nodes.add(target.getNodeRef());
|
||||
nodes.add(childNodeRef);
|
||||
|
||||
TransferManifestWriter formatter = new XMLTransferManifestWriter();
|
||||
TransferManifestHeader header = new TransferManifestHeader();
|
||||
header.setCreatedDate(new Date());
|
||||
formatter.startTransferManifest(snapshotWriter);
|
||||
formatter.writeTransferManifestHeader(header);
|
||||
for(NodeRef nodeRef : nodes)
|
||||
{
|
||||
TransferManifestNode node = nodeFactory.createTransferManifestNode(nodeRef);
|
||||
formatter.writeTransferManifestNode(node);
|
||||
sentNodes.put(nodeRef, node);
|
||||
}
|
||||
formatter.endTransferManifest();
|
||||
snapshotWriter.close();
|
||||
|
||||
// Show the snapshot file (For dev purposes)
|
||||
outputFile(snapshotFile);
|
||||
|
||||
/**
|
||||
* Now read the snapshot file
|
||||
*/
|
||||
TestTransferManifestProcessor processor = new TestTransferManifestProcessor();
|
||||
XMLTransferManifestReader reader = new XMLTransferManifestReader(processor);
|
||||
|
||||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = saxParserFactory.newSAXParser();
|
||||
parser.parse(snapshotFile, reader);
|
||||
|
||||
/**
|
||||
* Now validate that we read back what we write out
|
||||
*/
|
||||
assertEquals("did not get back the same number of nodes", nodes.size(), processor.getNodes().size());
|
||||
assertNotNull("header is null", processor.getHeader());
|
||||
|
||||
for(NodeRef nodeId : nodes)
|
||||
{
|
||||
System.out.println("Processing node:" + nodeId);
|
||||
TransferManifestNormalNode readNode = (TransferManifestNormalNode)processor.getNodes().get(nodeId);
|
||||
TransferManifestNormalNode writeNode = (TransferManifestNormalNode)sentNodes.get(nodeId);
|
||||
assertNotNull("readNode is null", readNode);
|
||||
assertNotNull("writeNode is null", writeNode);
|
||||
|
||||
assertEquals("type is different", writeNode.getType(), readNode.getType());
|
||||
assertEquals("nodeRef is different", writeNode.getNodeRef(), readNode.getNodeRef());
|
||||
assertEquals("parent node ref is different", writeNode.getPrimaryParentAssoc(), readNode.getPrimaryParentAssoc());
|
||||
if(writeNode.getParentPath() != null)
|
||||
{
|
||||
assertEquals("parent path is different", writeNode.getParentPath().toString(), readNode.getParentPath().toString());
|
||||
}
|
||||
|
||||
assertEquals("aspects array different size", writeNode.getAspects().size(), readNode.getAspects().size());
|
||||
for(QName aspect : writeNode.getAspects())
|
||||
{
|
||||
assertTrue("missing aspect", readNode.getAspects().contains(aspect));
|
||||
}
|
||||
|
||||
assertEquals("properties array different size", writeNode.getProperties().size(), readNode.getProperties().size());
|
||||
for(QName prop : writeNode.getProperties().keySet())
|
||||
{
|
||||
assertTrue("missing property", readNode.getProperties().containsKey(prop));
|
||||
}
|
||||
|
||||
assertEquals("child assocs different", writeNode.getChildAssocs().size(), readNode.getChildAssocs().size());
|
||||
assertEquals("parent assocs different", writeNode.getParentAssocs().size(), readNode.getParentAssocs().size());
|
||||
assertEquals("source assocs different", writeNode.getSourceAssocs().size(), readNode.getSourceAssocs().size());
|
||||
assertEquals("target assocs different", writeNode.getTargetAssocs().size(), readNode.getTargetAssocs().size());
|
||||
|
||||
if(readNode.getNodeRef().equals(childNodeRef))
|
||||
{
|
||||
/**
|
||||
* Check the child node since we created it at the start of this test this test
|
||||
*/
|
||||
ContentData data = (ContentData)readNode.getProperties().get(ContentModel.PROP_CONTENT);
|
||||
assertEquals("content data wrong size", data.getSize(), CONTENT_STRING.length());
|
||||
assertEquals("content locale wrong", data.getLocale(), CONTENT_LOCALE);
|
||||
|
||||
String childTitle = (String)readNode.getProperties().get(ContentModel.PROP_TITLE);
|
||||
assertEquals("content title wrong", childTitle, CONTENT_TITLE);
|
||||
|
||||
String childName = (String)readNode.getProperties().get(ContentModel.PROP_NAME);
|
||||
assertEquals("content name wrong", childName, CONTENT_NAME);
|
||||
|
||||
/**
|
||||
* Check the parent associations, there should be only one primary
|
||||
*/
|
||||
assertTrue("one parent assoc", readNode.getParentAssocs().size() == 1);
|
||||
assertTrue("isPrimary", readNode.getParentAssocs().get(0).isPrimary());
|
||||
assertEquals("parent q name", readNode.getParentAssocs().get(0).getQName(), QName.createQName(CONTENT_ASSOC_NAME));
|
||||
assertEquals("parent type q name", readNode.getParentAssocs().get(0).getTypeQName(), ContentModel.ASSOC_CONTAINS);
|
||||
assertEquals("child node ref", readNode.getParentAssocs().get(0).getChildRef(), childNodeRef);
|
||||
assertEquals("parent node ref", readNode.getParentAssocs().get(0).getParentRef(), readNode.getPrimaryParentAssoc());
|
||||
assertTrue("zero child assoc", readNode.getChildAssocs().size() == 0);
|
||||
|
||||
/**
|
||||
* Test Node Helper
|
||||
*/
|
||||
assertEquals(readNode.getParentAssocs().get(0), TransferManifestNodeHelper.getPrimaryParentAssoc(readNode));
|
||||
|
||||
Set<ContentData> content = TransferManifestNodeHelper.getContentData(readNode);
|
||||
assertEquals("content not found", content.size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(snapshotFile != null)
|
||||
{
|
||||
snapshotFile.delete();
|
||||
}
|
||||
transferService.deleteTransferTarget(snapshotMe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to dump the contents of a file to the console
|
||||
* @param file
|
||||
*/
|
||||
private static void outputFile(File file) throws Exception
|
||||
{
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String s = reader.readLine();
|
||||
while(s != null)
|
||||
{
|
||||
System.out.println(s);
|
||||
s = reader.readLine();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferModel;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* The transfer model - extended for XML Manifest Model
|
||||
*/
|
||||
public interface ManifestModel extends TransferModel
|
||||
{
|
||||
static final String LOCALNAME_TRANSFER_MAINIFEST = "transferManifest";
|
||||
static final String LOCALNAME_TRANSFER_HEADER = "transferManifestHeader";
|
||||
static final String LOCALNAME_HEADER_CREATED_DATE = "createdDate";
|
||||
static final String LOCALNAME_ELEMENT_NODES = "nodes";
|
||||
static final String LOCALNAME_ELEMENT_NODE = "node";
|
||||
static final String LOCALNAME_ELEMENT_DELETED_NODE = "deletedNode";
|
||||
static final String LOCALNAME_ELEMENT_ASPECTS = "aspects";
|
||||
static final String LOCALNAME_ELEMENT_ASPECT = "aspect";
|
||||
static final String LOCALNAME_ELEMENT_PROPERTIES = "properties";
|
||||
static final String LOCALNAME_ELEMENT_PROPERTY = "property";
|
||||
static final String LOCALNAME_ELEMENT_PARENT_ASSOCS = "parentAssocs";
|
||||
static final String LOCALNAME_ELEMENT_CHILD_ASSOCS = "childAssocs";
|
||||
static final String LOCALNAME_ELEMENT_CHILD_ASSOC = "childAssoc";
|
||||
static final String LOCALNAME_ELEMENT_PARENT_ASSOC = "parentAssoc";
|
||||
static final String LOCALNAME_ELEMENT_TARGET_ASSOCS = "targetAssocs";
|
||||
static final String LOCALNAME_ELEMENT_SOURCE_ASSOCS = "sourceAssocs";
|
||||
static final String LOCALNAME_ELEMENT_ASSOC = "assoc";
|
||||
static final String LOCALNAME_ELEMENT_PRIMARY_PARENT = "primaryParent";
|
||||
static final String LOCALNAME_ELEMENT_PRIMARY_PATH = "primaryPath";
|
||||
static final String LOCALNAME_ELEMENT_VALUES = "values";
|
||||
static final String LOCALNAME_ELEMENT_VALUE = "value";
|
||||
static final String LOCALNAME_ELEMENT_MLVALUE = "mlvalue";
|
||||
static final String LOCALNAME_ELEMENT_CONTENT_HEADER = "content";
|
||||
|
||||
// Manifest file prefix
|
||||
static final String MANIFEST_PREFIX = "xfer";
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Test implementation of TransferManifestProcessor.
|
||||
*
|
||||
* Simply gives access to the data through header and nodes properties.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TestTransferManifestProcessor implements TransferManifestProcessor
|
||||
{
|
||||
private TransferManifestHeader header;
|
||||
private Map<NodeRef, TransferManifestNode> nodes = new HashMap<NodeRef, TransferManifestNode>();
|
||||
|
||||
public void endTransferManifest()
|
||||
{
|
||||
}
|
||||
|
||||
public void processTransferManifestNode(TransferManifestNormalNode node)
|
||||
{
|
||||
nodes.put(node.getNodeRef(), node);
|
||||
}
|
||||
|
||||
public void processTransferManifestNode(TransferManifestDeletedNode node)
|
||||
{
|
||||
nodes.put(node.getNodeRef(), node);
|
||||
}
|
||||
|
||||
public void processTransferManifiestHeader(TransferManifestHeader header)
|
||||
{
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public void startTransferManifest()
|
||||
{
|
||||
}
|
||||
|
||||
void setHeader(TransferManifestHeader header)
|
||||
{
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
TransferManifestHeader getHeader()
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
void setNodes( Map<NodeRef, TransferManifestNode> nodes)
|
||||
{
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
Map<NodeRef, TransferManifestNode> getNodes()
|
||||
{
|
||||
return nodes;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package org.alfresco.repo.transfer.manifest;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
|
||||
/**
|
||||
* A record of a deleted node in the transfer manifest
|
||||
*
|
||||
* The path and node ref refers to the state prior to the node's deletion.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferManifestDeletedNode implements TransferManifestNode
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private ChildAssociationRef primaryParentAssoc;
|
||||
private String uuid;
|
||||
private Path parentPath;
|
||||
|
||||
public void setNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid)
|
||||
{
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getUuid()
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setParentPath(Path parentPath)
|
||||
{
|
||||
this.parentPath = parentPath;
|
||||
}
|
||||
|
||||
public Path getParentPath()
|
||||
{
|
||||
return parentPath;
|
||||
}
|
||||
|
||||
public void setPrimaryParentAssoc(ChildAssociationRef parentAssoc)
|
||||
{
|
||||
this.primaryParentAssoc = parentAssoc;
|
||||
}
|
||||
|
||||
public ChildAssociationRef getPrimaryParentAssoc()
|
||||
{
|
||||
return primaryParentAssoc;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Data value object
|
||||
*
|
||||
* Part of the transfer manifest
|
||||
*/
|
||||
|
||||
public class TransferManifestHeader
|
||||
{
|
||||
private Date createdDate;
|
||||
|
||||
public void setCreatedDate(Date createDate)
|
||||
{
|
||||
this.createdDate = createDate;
|
||||
}
|
||||
|
||||
public Date getCreatedDate()
|
||||
{
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
|
||||
/**
|
||||
* Data value object - part of the transfer manifest
|
||||
*
|
||||
* Represents a single node in the transfer manifest
|
||||
*
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestDeletedNode
|
||||
* @see org.alfresco.repo.transfer.manifest.TransferManifestNormalNode
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferManifestNode
|
||||
{
|
||||
public NodeRef getNodeRef();
|
||||
public void setNodeRef(NodeRef nodeRef);
|
||||
|
||||
public void setUuid(String uuid);
|
||||
public String getUuid();
|
||||
|
||||
public void setParentPath(Path parentPath);
|
||||
public Path getParentPath();
|
||||
|
||||
public void setPrimaryParentAssoc(ChildAssociationRef primaryParent);
|
||||
public ChildAssociationRef getPrimaryParentAssoc();
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
public interface TransferManifestNodeFactory
|
||||
{
|
||||
TransferManifestNode createTransferManifestNode(NodeRef nodeRef);
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
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.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
|
||||
public class TransferManifestNodeFactoryImpl implements TransferManifestNodeFactory
|
||||
{
|
||||
private NodeService nodeService;
|
||||
|
||||
public void init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TransferManifestNode createTransferManifestNode(NodeRef nodeRef)
|
||||
{
|
||||
NodeRef.Status status = nodeService.getNodeStatus(nodeRef);
|
||||
|
||||
if(status == null)
|
||||
{
|
||||
throw new TransferException("Unable to get node status for node : " + nodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out whether this is a deleted node or not
|
||||
*/
|
||||
if(nodeRef.getStoreRef().equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE) || status.isDeleted())
|
||||
{
|
||||
if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_ARCHIVED))
|
||||
{
|
||||
// Yes we have an archived aspect
|
||||
ChildAssociationRef car = (ChildAssociationRef)nodeService.getProperty(nodeRef,
|
||||
ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC);
|
||||
|
||||
TransferManifestDeletedNode node = new TransferManifestDeletedNode();
|
||||
NodeRef parentNodeRef = car.getParentRef();
|
||||
node.setNodeRef(car.getChildRef());
|
||||
node.setPrimaryParentAssoc(car);
|
||||
|
||||
if(nodeService.exists(parentNodeRef))
|
||||
{
|
||||
// The parent node still exists so it still has a path.
|
||||
Path parentPath = nodeService.getPath(parentNodeRef);
|
||||
node.setParentPath(parentPath);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// No we don't have an archived aspect - maybe we are not yet committed
|
||||
TransferManifestDeletedNode node = new TransferManifestDeletedNode();
|
||||
node.setNodeRef(nodeRef);
|
||||
ChildAssociationRef parentAssocRef = nodeService.getPrimaryParent(nodeRef);
|
||||
if(parentAssocRef != null && parentAssocRef.getParentRef() != null)
|
||||
{
|
||||
NodeRef parentNodeRef = parentAssocRef.getParentRef();
|
||||
node.setPrimaryParentAssoc(parentAssocRef);
|
||||
Path parentPath = nodeService.getPath(parentNodeRef);
|
||||
node.setParentPath(parentPath);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a "normal" node
|
||||
|
||||
TransferManifestNormalNode node = new TransferManifestNormalNode();
|
||||
node.setNodeRef(nodeRef);
|
||||
node.setProperties(nodeService.getProperties(nodeRef));
|
||||
node.setAspects(nodeService.getAspects(nodeRef));
|
||||
node.setType(nodeService.getType(nodeRef));
|
||||
ChildAssociationRef parentAssocRef = nodeService.getPrimaryParent(nodeRef);
|
||||
if(parentAssocRef != null && parentAssocRef.getParentRef() != null)
|
||||
{
|
||||
NodeRef parentNodeRef = parentAssocRef.getParentRef();
|
||||
node.setPrimaryParentAssoc(parentAssocRef);
|
||||
Path parentPath = nodeService.getPath(parentNodeRef);
|
||||
node.setParentPath(parentPath);
|
||||
}
|
||||
node.setChildAssocs(nodeService.getChildAssocs(nodeRef));
|
||||
node.setParentAssocs(nodeService.getParentAssocs(nodeRef));
|
||||
node.setTargetAssocs(nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL ));
|
||||
node.setSourceAssocs(nodeService.getSourceAssocs(nodeRef, RegexQNamePattern.MATCH_ALL));
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Decorator to extend capabilities of TransferManifestNode
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferManifestNodeHelper
|
||||
{
|
||||
/**
|
||||
* Gets the primary parent association
|
||||
* @param node the node to process
|
||||
* @return the primary parent association or null if this is a root node
|
||||
*/
|
||||
public static ChildAssociationRef getPrimaryParentAssoc(TransferManifestNormalNode node)
|
||||
{
|
||||
List<ChildAssociationRef> assocs = node.getParentAssocs();
|
||||
|
||||
for(ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
if(assoc.isPrimary())
|
||||
{
|
||||
return assoc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content properties for a node
|
||||
* @param node the node to process
|
||||
* @return
|
||||
*/
|
||||
public static Set<ContentData> getContentData(TransferManifestNormalNode node)
|
||||
{
|
||||
Set<ContentData> content = new HashSet<ContentData>();
|
||||
|
||||
for(Serializable value : node.getProperties().values())
|
||||
{
|
||||
if(value instanceof ContentData)
|
||||
{
|
||||
content.add((ContentData)value);
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Data value object - part of the transfer manifest
|
||||
*
|
||||
* Represents a single node and either a create or an update.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferManifestNormalNode implements TransferManifestNode
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private ChildAssociationRef primaryParentAssoc;
|
||||
private String uuid;
|
||||
private QName type;
|
||||
private Map<QName,Serializable> properties;
|
||||
private Set<QName> aspects;
|
||||
private List<ChildAssociationRef> childAssocs;
|
||||
private List<ChildAssociationRef> parentAssocs;
|
||||
private List<AssociationRef> sourceAssocs;
|
||||
private List<AssociationRef> targetAssocs;
|
||||
private Path parentPath;
|
||||
|
||||
public void setNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid)
|
||||
{
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getUuid()
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all properties for the node
|
||||
*
|
||||
* @return the properties
|
||||
*/
|
||||
public Map<QName,Serializable> getProperties()
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
//
|
||||
// /**
|
||||
// * Gets the property data type
|
||||
// *
|
||||
// * @param propertyName name of property
|
||||
// * @return data type of named property
|
||||
// */
|
||||
// public DataTypeDefinition getPropertyDataType(QName propertyName);
|
||||
//
|
||||
// /**
|
||||
// * @return the aspects of this node
|
||||
// */
|
||||
// public Set<QName> getNodeAspects();
|
||||
//
|
||||
// /**
|
||||
// * @return true => the node inherits permissions from its parent
|
||||
// */
|
||||
// public boolean getInheritPermissions();
|
||||
//
|
||||
// /**
|
||||
// * @return the permissions applied to this node
|
||||
// */
|
||||
// public List<AccessPermission> getAccessControlEntries();
|
||||
|
||||
public void setProperties(Map<QName,Serializable> properties)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void setAspects(Set<QName> aspects)
|
||||
{
|
||||
this.aspects = aspects;
|
||||
}
|
||||
|
||||
public Set<QName> getAspects()
|
||||
{
|
||||
return aspects;
|
||||
}
|
||||
|
||||
public void setType(QName type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public QName getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setChildAssocs(List<ChildAssociationRef> childAssocs)
|
||||
{
|
||||
this.childAssocs = childAssocs;
|
||||
}
|
||||
|
||||
public List<ChildAssociationRef> getChildAssocs()
|
||||
{
|
||||
return childAssocs;
|
||||
}
|
||||
|
||||
public void setParentAssocs(List<ChildAssociationRef> parentAssocs)
|
||||
{
|
||||
this.parentAssocs = parentAssocs;
|
||||
}
|
||||
|
||||
public List<ChildAssociationRef> getParentAssocs()
|
||||
{
|
||||
return parentAssocs;
|
||||
}
|
||||
|
||||
public void setParentPath(Path parentPath)
|
||||
{
|
||||
this.parentPath = parentPath;
|
||||
}
|
||||
|
||||
public Path getParentPath()
|
||||
{
|
||||
return parentPath;
|
||||
}
|
||||
|
||||
public void setSourceAssocs(List<AssociationRef> sourceAssocs)
|
||||
{
|
||||
this.sourceAssocs = sourceAssocs;
|
||||
}
|
||||
|
||||
public List<AssociationRef> getSourceAssocs()
|
||||
{
|
||||
return sourceAssocs;
|
||||
}
|
||||
|
||||
public void setTargetAssocs(List<AssociationRef> targetAssocs)
|
||||
{
|
||||
this.targetAssocs = targetAssocs;
|
||||
}
|
||||
|
||||
public List<AssociationRef> getTargetAssocs()
|
||||
{
|
||||
return targetAssocs;
|
||||
}
|
||||
|
||||
public void setPrimaryParentAssoc(ChildAssociationRef primaryParentAssoc)
|
||||
{
|
||||
this.primaryParentAssoc = primaryParentAssoc;
|
||||
}
|
||||
|
||||
public ChildAssociationRef getPrimaryParentAssoc()
|
||||
{
|
||||
return primaryParentAssoc;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
/**
|
||||
* Manifest Processor
|
||||
*
|
||||
* Interface called when parsing the transfer manifest file
|
||||
*
|
||||
* When Parsing the manifest file, the startTransferManifest will be called first, then
|
||||
* processHeader, then mulpiple calls of processTransferManifestNode, one for each node,
|
||||
* then endTransferManifest
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferManifestProcessor
|
||||
{
|
||||
/**
|
||||
* Signals the start of a transfer manifest
|
||||
*/
|
||||
public void startTransferManifest();
|
||||
|
||||
/**
|
||||
* Gives the header to be proceessed
|
||||
* @param header, the header
|
||||
*/
|
||||
public void processTransferManifiestHeader(TransferManifestHeader header);
|
||||
|
||||
/**
|
||||
* Gives a manifest node to be processed
|
||||
* @param node, the node
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestNormalNode node);
|
||||
|
||||
/**
|
||||
* Gives a deleted manifest node to be processed
|
||||
* @param node, the node
|
||||
*/
|
||||
public void processTransferManifestNode(TransferManifestDeletedNode node);
|
||||
|
||||
/**
|
||||
* Signals the end of a transfer manifest
|
||||
*/
|
||||
public void endTransferManifest();
|
||||
|
||||
}
|
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TransferManifestTest extends TestCase
|
||||
{
|
||||
public void testCreateAndReadSnapshot() throws Exception
|
||||
{
|
||||
/**
|
||||
* create snapshot
|
||||
*/
|
||||
String prefix = "TRX-SNAP";
|
||||
String suffix = ".xml";
|
||||
|
||||
// where to put snapshot ?
|
||||
File snapshotFile = TempFileProvider.createTempFile(prefix, suffix);
|
||||
FileWriter snapshotWriter = new FileWriter(snapshotFile);
|
||||
|
||||
// Write the manifest file
|
||||
TransferManifestWriter formatter = new XMLTransferManifestWriter();
|
||||
TransferManifestHeader header = new TransferManifestHeader();
|
||||
header.setCreatedDate(new Date());
|
||||
formatter.startTransferManifest(snapshotWriter);
|
||||
formatter.writeTransferManifestHeader(header);
|
||||
|
||||
// node to transmit
|
||||
TransferManifestNormalNode node = new TransferManifestNormalNode();
|
||||
node.setNodeRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "123"));
|
||||
node.setParentPath(new Path());
|
||||
Set<QName> aspects = new HashSet<QName>();
|
||||
aspects.add(QName.createQName("{gsxhjsx}", "cm:wobble"));
|
||||
aspects.add(QName.createQName("{gsxhjsx}", "cm:wibble"));
|
||||
node.setAspects(aspects);
|
||||
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
properties.put(QName.createQName("{gsxhjsx}", "cm:name"), "brian.jpg");
|
||||
properties.put(QName.createQName("{gsxhjsx}", "cm:created"), new java.util.Date());
|
||||
properties.put(QName.createQName("{gsxhjsx}", "trx:enabled"), Boolean.FALSE);
|
||||
MLText mltext = new MLText();
|
||||
mltext.addValue(Locale.FRENCH, "Bonjour");
|
||||
mltext.addValue(Locale.ENGLISH, "Hello");
|
||||
mltext.addValue(Locale.ITALY, "Buongiorno");
|
||||
properties.put(QName.createQName("{gsxhjsx}", "cm:title"), mltext);
|
||||
String password = "helloWorld";
|
||||
properties.put(QName.createQName("{gsxhjsx}", "trx:password"), password.toCharArray());
|
||||
|
||||
|
||||
List<ChildAssociationRef> parents = new ArrayList<ChildAssociationRef>();
|
||||
ChildAssociationRef primaryParent = new ChildAssociationRef(QName.createQName("{gsxhjsx}", "cm:contains"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P1"),
|
||||
QName.createQName("{gsxhjsx}", "app:smashing"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "123"),
|
||||
true,
|
||||
-1);
|
||||
parents.add(primaryParent);
|
||||
parents.add(new ChildAssociationRef(QName.createQName("{gsxhjsx}", "app:wibble"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P1"),
|
||||
QName.createQName("{gsxhjsx}", "app:jskjsdc"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "123"),
|
||||
false,
|
||||
-1));
|
||||
node.setParentAssocs(parents);
|
||||
node.setPrimaryParentAssoc(primaryParent);
|
||||
|
||||
List<ChildAssociationRef> children = new ArrayList<ChildAssociationRef>();
|
||||
children.add(new ChildAssociationRef(QName.createQName("{gsxhjsx}", "cm:contains"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P1"),
|
||||
QName.createQName("{gsxhjsx}", "app:super"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P5"),
|
||||
true,
|
||||
-1));
|
||||
|
||||
node.setChildAssocs(children);
|
||||
|
||||
Set<String>values=new HashSet<String>();
|
||||
values.add("red");
|
||||
values.add("blue");
|
||||
values.add("green");
|
||||
properties.put(QName.createQName("{gsxhjsx}", "xyz:colours"), (Serializable)values);
|
||||
|
||||
ContentData contentHeader = new ContentData("http://wibble", "mimeType", 123, "utf-8", Locale.ENGLISH);
|
||||
properties.put(QName.createQName("{gsxhjsx}", "cm:content"), (Serializable)contentHeader);
|
||||
|
||||
node.setProperties(properties);
|
||||
|
||||
node.setType(QName.createQName("{gsxhjsx}", "trx:nsbbmbs"));
|
||||
|
||||
List<AssociationRef> targetAssocs = new ArrayList<AssociationRef>();
|
||||
List<AssociationRef> sourceAssocs = new ArrayList<AssociationRef>();
|
||||
|
||||
targetAssocs.add(new AssociationRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "SA"),
|
||||
QName.createQName("{gsxhjsx}", "app:super"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "TA")));
|
||||
|
||||
|
||||
|
||||
sourceAssocs.add(new AssociationRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "HH"),
|
||||
QName.createQName("{gsxhjsx}", "app:super"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "JJ")));
|
||||
|
||||
node.setSourceAssocs(sourceAssocs);
|
||||
node.setTargetAssocs(targetAssocs);
|
||||
|
||||
formatter.writeTransferManifestNode(node);
|
||||
|
||||
/**
|
||||
* Write a second node
|
||||
*/
|
||||
|
||||
TransferManifestNormalNode node2 = new TransferManifestNormalNode();
|
||||
node2.setNodeRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "456"));
|
||||
node2.setType(QName.createQName("{gsxhjsx}", "trx:dummy"));
|
||||
formatter.writeTransferManifestNode(node2);
|
||||
|
||||
|
||||
/**
|
||||
* Write a deleted node
|
||||
*/
|
||||
TransferManifestDeletedNode node3 = new TransferManifestDeletedNode();
|
||||
node3.setNodeRef(new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, "567"));
|
||||
|
||||
ChildAssociationRef origPrimaryParent = new ChildAssociationRef(QName.createQName("{gsxhjsx}", "cm:contains"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "P1"),
|
||||
QName.createQName("{gsxhjsx}", "app:whopper"),
|
||||
new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "567"),
|
||||
true,
|
||||
-1);
|
||||
|
||||
node3.setPrimaryParentAssoc(origPrimaryParent);
|
||||
node3.setParentPath(new Path());
|
||||
|
||||
formatter.writeTransferManifestNode(node3);
|
||||
|
||||
|
||||
formatter.endTransferManifest();
|
||||
snapshotWriter.close();
|
||||
|
||||
//
|
||||
BufferedReader reader = new BufferedReader(new FileReader(snapshotFile));
|
||||
String s = reader.readLine();
|
||||
while(s != null)
|
||||
{
|
||||
System.out.println(s);
|
||||
s = reader.readLine();
|
||||
}
|
||||
|
||||
// Now try to parse the snapshot file we have just created
|
||||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
SAXParser parser = saxParserFactory.newSAXParser();
|
||||
|
||||
TransferManifestProcessor tp = new TestTransferManifestProcessor();
|
||||
|
||||
XMLTransferManifestReader xmlReader = new XMLTransferManifestReader(tp);
|
||||
parser.parse(snapshotFile, xmlReader );
|
||||
|
||||
|
||||
|
||||
snapshotFile.delete();
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Transfer Manifest Writer
|
||||
*
|
||||
* This class formats the transfer manifest and prints it to the specified writer
|
||||
*
|
||||
* It is a statefull object and writes one manifest at a time.
|
||||
*
|
||||
* Call start once, then write the header, then one or more nodes, then end.
|
||||
*
|
||||
*/
|
||||
public interface TransferManifestWriter
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param writer
|
||||
* @throws SAXException
|
||||
*/
|
||||
void startTransferManifest(Writer writer) throws SAXException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param header
|
||||
* @throws SAXException
|
||||
*/
|
||||
void writeTransferManifestHeader(TransferManifestHeader header) throws SAXException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node
|
||||
* @throws SAXException
|
||||
*/
|
||||
void writeTransferManifestNode(TransferManifestNode node) throws SAXException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws SAXException
|
||||
*/
|
||||
void endTransferManifest() throws SAXException;
|
||||
}
|
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.i18n.I18NUtil;
|
||||
import org.alfresco.repo.transfer.PathHelper;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.NamespaceException;
|
||||
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.alfresco.util.ISO9075;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* SAX XML Content Handler to read a transfer manifest XML Stream and
|
||||
* delegate processing to the specified TransferManifestProcessor
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class XMLTransferManifestReader extends DefaultHandler implements ContentHandler, NamespacePrefixResolver
|
||||
{
|
||||
private TransferManifestProcessor processor;
|
||||
|
||||
/**
|
||||
* These are the namespaces used within the document - there may be a different mapping to
|
||||
* the namespaces of the Data Dictionary.
|
||||
*/
|
||||
// Map<String, String> documentNamespaces = new HashMap<String, String>();
|
||||
|
||||
final String TRANSFER_URI = ManifestModel.TRANSFER_MODEL_1_0_URI;
|
||||
final String XMLNS_URI = "http://www.w3.org/XML/1998/namespace";
|
||||
LinkedList<HashMap<String, String>> namespaces = new LinkedList<HashMap<String, String>>();
|
||||
|
||||
public XMLTransferManifestReader(TransferManifestProcessor snapshotProcessor)
|
||||
{
|
||||
this.processor = snapshotProcessor;
|
||||
|
||||
// prefix to uri map
|
||||
HashMap<String, String> namespace = new HashMap<String, String>();
|
||||
namespace.put("xmlns", XMLNS_URI);
|
||||
namespaces.add(namespace);
|
||||
}
|
||||
|
||||
public void startDocument() throws SAXException
|
||||
{
|
||||
processor.startTransferManifest();
|
||||
}
|
||||
|
||||
public void endDocument() throws SAXException
|
||||
{
|
||||
processor.endTransferManifest();
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int start, int length) throws SAXException
|
||||
{
|
||||
if(buffer != null)
|
||||
{
|
||||
buffer.append(ch, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Current State of the parser
|
||||
*/
|
||||
private StringBuffer buffer;
|
||||
private Map<String, Object>props = new HashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* Start Element
|
||||
*/
|
||||
public void startElement(String uri, String localName, String prefixName, Attributes atts)
|
||||
throws SAXException
|
||||
{
|
||||
QName elementQName = QName.resolveToQName(this, prefixName);
|
||||
|
||||
HashMap<String, String> namespace = new HashMap<String, String>();
|
||||
namespaces.addFirst(namespace);
|
||||
|
||||
/**
|
||||
* Look for any namespace attributes
|
||||
*/
|
||||
for(int i = 0; i < atts.getLength(); i++)
|
||||
{
|
||||
QName attributeQName = QName.resolveToQName(this, atts.getQName(i));
|
||||
if(attributeQName.getNamespaceURI().equals(XMLNS_URI))
|
||||
{
|
||||
namespace.put(attributeQName.getLocalName(), atts.getValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
if(elementQName == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(elementQName.getNamespaceURI().equals(TRANSFER_URI));
|
||||
{
|
||||
// This is one of the transfer manifest elements
|
||||
String elementName = elementQName.getLocalName();
|
||||
|
||||
// Simple and stupid parser for now
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_MAINIFEST))
|
||||
{
|
||||
// Good we got this
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
|
||||
{
|
||||
TransferManifestHeader header = new TransferManifestHeader();
|
||||
props.put("header", header);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
|
||||
{
|
||||
TransferManifestDeletedNode node = new TransferManifestDeletedNode();
|
||||
NodeRef nodeRef = new NodeRef(atts.getValue("", "nodeRef"));
|
||||
node.setNodeRef(nodeRef);
|
||||
props.put("node", node);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
|
||||
{
|
||||
TransferManifestNormalNode node = new TransferManifestNormalNode();
|
||||
NodeRef nodeRef = new NodeRef(atts.getValue("", "nodeRef"));
|
||||
QName type = QName.createQName(atts.getValue("", "nodeType"));
|
||||
node.setNodeRef(nodeRef);
|
||||
node.setType(type);
|
||||
props.put("node", node);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
node.setAspects(new HashSet<QName>());
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
HashMap<QName, Serializable>properties = new HashMap<QName, Serializable>();
|
||||
node.setProperties(properties);
|
||||
props.put("properties", properties);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
|
||||
{
|
||||
QName name = QName.createQName(atts.getValue("", "name"));
|
||||
props.put("name", name);
|
||||
props.remove("values");
|
||||
props.remove("mltext");
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
node.setChildAssocs(new ArrayList<ChildAssociationRef>());
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
NodeRef to = new NodeRef(atts.getValue("", "to"));
|
||||
QName type = QName.createQName(atts.getValue("", "type"));
|
||||
Boolean isPrimary = Boolean.parseBoolean(atts.getValue("", "isPrimary"));
|
||||
|
||||
props.put("to", to);
|
||||
props.put("type", type);
|
||||
props.put("isPrimary", isPrimary);
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
NodeRef from = new NodeRef(atts.getValue("", "from"));
|
||||
QName type = QName.createQName(atts.getValue("", "type"));
|
||||
Boolean isPrimary = Boolean.parseBoolean(atts.getValue("", "isPrimary"));
|
||||
props.put("from", from);
|
||||
props.put("type", type);
|
||||
props.put("isPrimary", isPrimary);
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
|
||||
node.setTargetAssocs(assocs);
|
||||
props.put("assocs", assocs);
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
List<AssociationRef> assocs = new ArrayList<AssociationRef>();
|
||||
node.setSourceAssocs(assocs);
|
||||
props.put("assocs", assocs);
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
|
||||
{
|
||||
NodeRef source = new NodeRef(atts.getValue("", "source"));
|
||||
NodeRef target = new NodeRef(atts.getValue("", "target"));
|
||||
QName type = QName.createQName(atts.getValue("", "type"));
|
||||
props.put("source", source);
|
||||
props.put("target", target);
|
||||
props.put("type", type);
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
|
||||
{
|
||||
Collection<Serializable> values = new ArrayList<Serializable>();
|
||||
props.put("values", values);
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE))
|
||||
{
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
|
||||
{
|
||||
MLText mltext = (MLText)props.get("mlvalues");
|
||||
if(mltext == null)
|
||||
{
|
||||
mltext = new MLText();
|
||||
props.put("mlvalues", mltext);
|
||||
}
|
||||
String strLocale = (String)atts.getValue("", "locale");
|
||||
Locale locale = I18NUtil.parseLocale(strLocale);
|
||||
props.put("locale", locale);
|
||||
buffer = new StringBuffer();
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
|
||||
{
|
||||
String contentURL = (String)atts.getValue("", "contentURL");
|
||||
String mimetype = (String)atts.getValue("", "mimetype");
|
||||
String strLocale = (String)atts.getValue("", "locale");
|
||||
Locale locale = I18NUtil.parseLocale(strLocale);
|
||||
String encoding = (String)atts.getValue("", "encoding");
|
||||
String sizeStr = (String)atts.getValue("", "size");
|
||||
Long size = Long.valueOf(sizeStr);
|
||||
ContentData contentHeader = new ContentData(contentURL, mimetype, size.longValue(), encoding, locale);
|
||||
props.put("contentHeader", contentHeader);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // startElement
|
||||
|
||||
/**
|
||||
* End Element
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void endElement(String uri, String localName, String prefixName) throws SAXException
|
||||
{
|
||||
namespaces.removeFirst();
|
||||
|
||||
QName elementQName = QName.resolveToQName(this, prefixName);
|
||||
|
||||
if(elementQName == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(elementQName.getNamespaceURI().equals(TRANSFER_URI));
|
||||
{
|
||||
// This is one of the transfer manifest elements
|
||||
String elementName = elementQName.getLocalName();
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_MAINIFEST))
|
||||
{
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_TRANSFER_HEADER))
|
||||
{
|
||||
TransferManifestHeader header = (TransferManifestHeader)props.get("header");
|
||||
// User to process the header
|
||||
processor.processTransferManifiestHeader(header);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_NODE))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
processor.processTransferManifestNode(node);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE))
|
||||
{
|
||||
TransferManifestDeletedNode node = (TransferManifestDeletedNode)props.get("node");
|
||||
processor.processTransferManifestNode(node);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECTS))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASPECT))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
node.getAspects().add(QName.createQName(buffer.toString()));
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTIES))
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PROPERTY))
|
||||
{
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
QName name = (QName)props.get("name");
|
||||
Serializable value = (Serializable)props.get("value");
|
||||
node.getProperties().put(name, value);
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_HEADER_CREATED_DATE))
|
||||
{
|
||||
TransferManifestHeader header = (TransferManifestHeader)props.get("header");
|
||||
header.setCreatedDate(ISO8601DateFormat.parse(buffer.toString()));
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS))
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC))
|
||||
{
|
||||
String value = buffer.toString();
|
||||
QName name = QName.createQName(value);
|
||||
NodeRef to = (NodeRef)props.get("to");
|
||||
QName type = (QName) props.get("type");
|
||||
Boolean isPrimary = (Boolean)props.get("isPrimary");
|
||||
TransferManifestNormalNode node = (TransferManifestNormalNode)props.get("node");
|
||||
|
||||
ChildAssociationRef childAssociationRef = new ChildAssociationRef(type, node.getNodeRef(), name, to, isPrimary, -1);
|
||||
node.getChildAssocs().add(childAssociationRef);
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC))
|
||||
{
|
||||
String value = buffer.toString();
|
||||
QName name = QName.createQName(value);
|
||||
NodeRef from = (NodeRef)props.get("from");
|
||||
QName type = (QName) props.get("type");
|
||||
Boolean isPrimary = (Boolean)props.get("isPrimary");
|
||||
TransferManifestNode node = (TransferManifestNode)props.get("node");
|
||||
|
||||
ChildAssociationRef childAssociationRef = new ChildAssociationRef(type, from, name, node.getNodeRef(), isPrimary, -1);
|
||||
|
||||
if (TransferManifestNormalNode.class.isAssignableFrom(node.getClass()))
|
||||
{
|
||||
TransferManifestNormalNode normalNode = (TransferManifestNormalNode)node;
|
||||
List<ChildAssociationRef> parents = normalNode.getParentAssocs();
|
||||
if (parents == null)
|
||||
{
|
||||
parents = new ArrayList<ChildAssociationRef>();
|
||||
normalNode.setParentAssocs(parents);
|
||||
}
|
||||
parents.add(childAssociationRef);
|
||||
}
|
||||
if (isPrimary)
|
||||
{
|
||||
node.setPrimaryParentAssoc(childAssociationRef);
|
||||
}
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS))
|
||||
{
|
||||
//TransferManifestNode node = (TransferManifestNode)props.get("node");
|
||||
//node.getTargetAssocs().add((AssociationRef)props.get("assoc"));
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS))
|
||||
{
|
||||
//TransferManifestNode node = (TransferManifestNode)props.get("node");
|
||||
//node.getSourceAssocs().add((AssociationRef)props.get("assoc"));
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_ASSOC))
|
||||
{
|
||||
NodeRef source = (NodeRef)props.get("source");
|
||||
NodeRef target = (NodeRef)props.get("target");
|
||||
QName type = (QName) props.get("type");
|
||||
List<AssociationRef> assocs = (List<AssociationRef>)props.get("assocs");
|
||||
AssociationRef assoc = new AssociationRef(source, type, target);
|
||||
assocs.add(assoc);
|
||||
props.put("assoc", new AssociationRef(source, type, target));
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH))
|
||||
{
|
||||
TransferManifestNode node = (TransferManifestNode)props.get("node");
|
||||
String value = buffer.toString();
|
||||
Path path = PathHelper.stringToPath(value);
|
||||
node.setParentPath(path);
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUES))
|
||||
{
|
||||
props.put("value", props.get("values"));
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_VALUE))
|
||||
{
|
||||
Collection<Serializable> values = (Collection<Serializable>)props.get("values");
|
||||
String value = buffer.toString();
|
||||
|
||||
if(values != null)
|
||||
{
|
||||
values.add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
props.put("value", value);
|
||||
}
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_MLVALUE))
|
||||
{
|
||||
MLText mltext = (MLText)props.get("mlvalues");
|
||||
Locale locale = (Locale)props.get("locale");
|
||||
String value = buffer.toString();
|
||||
mltext.addValue(locale, value);
|
||||
props.put("value", mltext);
|
||||
|
||||
}
|
||||
if(elementName.equals(ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER))
|
||||
{
|
||||
TransferManifestNode node = (TransferManifestNode)props.get("node");
|
||||
ContentData data = (ContentData)props.get("contentHeader");
|
||||
props.put("value", data);
|
||||
}
|
||||
}
|
||||
} // end element
|
||||
|
||||
|
||||
|
||||
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
public void processingInstruction(String target, String data) throws SAXException
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
public void setDocumentLocator(Locator locator)
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
public void skippedEntity(String name) throws SAXException
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
public void startPrefixMapping(String prefix, String uri) throws SAXException
|
||||
{
|
||||
HashMap<String, String> namespace = namespaces.get(0);
|
||||
// prefix is key, URI is value
|
||||
namespace.put(prefix, uri);
|
||||
}
|
||||
|
||||
public void endPrefixMapping(String prefix) throws SAXException
|
||||
{
|
||||
HashMap<String, String> namespace = namespaces.get(0);
|
||||
// prefix is key, URI is value
|
||||
namespace.remove(prefix);
|
||||
}
|
||||
|
||||
// Namespace Prefix Resolver implementation below
|
||||
|
||||
/**
|
||||
* lookup the prefix for a URI e.g. TRANSFER_URI for xfer
|
||||
*/
|
||||
public String getNamespaceURI(String prefix) throws NamespaceException
|
||||
{
|
||||
for(HashMap<String, String> namespace : namespaces)
|
||||
{
|
||||
String uri = namespace.get(prefix);
|
||||
if(uri != null)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri
|
||||
* @return the prefix
|
||||
*/
|
||||
public Collection<String> getPrefixes(String namespaceURI) throws NamespaceException
|
||||
{
|
||||
Collection<String> prefixes = new HashSet<String>();
|
||||
|
||||
for(HashMap<String, String> namespace : namespaces)
|
||||
{
|
||||
for(Entry<String, String> entry : namespace.entrySet())
|
||||
{
|
||||
if (namespaceURI.equals(entry.getValue()))
|
||||
{
|
||||
prefixes.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
public Collection<String> getPrefixes()
|
||||
{
|
||||
Collection<String> prefixes = new HashSet<String>();
|
||||
|
||||
for(HashMap<String, String> namespace : namespaces)
|
||||
{
|
||||
prefixes.addAll(namespace.keySet());
|
||||
}
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
public Collection<String> getURIs()
|
||||
{
|
||||
Collection<String> uris = new HashSet<String>();
|
||||
|
||||
for(HashMap<String, String> namespace : namespaces)
|
||||
{
|
||||
uris.addAll(namespace.values());
|
||||
}
|
||||
|
||||
return uris;
|
||||
}
|
||||
}
|
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.manifest;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferModel;
|
||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
/**
|
||||
* XMLTransferManifestWriter
|
||||
*
|
||||
* Writes the transfer manifest out to XML format.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class XMLTransferManifestWriter implements TransferManifestWriter
|
||||
{
|
||||
public XMLTransferManifestWriter()
|
||||
{
|
||||
}
|
||||
|
||||
private XMLWriter writer;
|
||||
|
||||
final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl();
|
||||
|
||||
final String PREFIX = ManifestModel.MANIFEST_PREFIX;
|
||||
|
||||
/**
|
||||
* Start the transfer manifest
|
||||
*/
|
||||
public void startTransferManifest(Writer writer) throws SAXException
|
||||
{
|
||||
OutputFormat format = OutputFormat.createPrettyPrint();
|
||||
format.setNewLineAfterDeclaration(false);
|
||||
format.setIndentSize(3);
|
||||
format.setEncoding("UTF-8");
|
||||
|
||||
this.writer = new XMLWriter(writer, format);
|
||||
this.writer.startDocument();
|
||||
|
||||
this.writer.startPrefixMapping(PREFIX, TransferModel.TRANSFER_MODEL_1_0_URI);
|
||||
this.writer.startPrefixMapping("cm", NamespaceService.CONTENT_MODEL_1_0_URI);
|
||||
|
||||
// Start Transfer Manifest // uri, name, prefix
|
||||
this.writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_TRANSFER_MAINIFEST, PREFIX + ":" + ManifestModel.LOCALNAME_TRANSFER_MAINIFEST, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transfer manifest
|
||||
*/
|
||||
public void endTransferManifest() throws SAXException
|
||||
{
|
||||
// End Transfer Manifest
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_TRANSFER_MAINIFEST, PREFIX + ":" + ManifestModel.LOCALNAME_TRANSFER_MAINIFEST);
|
||||
writer.endPrefixMapping(PREFIX);
|
||||
|
||||
writer.endDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the transfer manifest header
|
||||
*/
|
||||
public void writeTransferManifestHeader(TransferManifestHeader header) throws SAXException
|
||||
{
|
||||
if(header.getCreatedDate() != null)
|
||||
{
|
||||
// Start Header
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_TRANSFER_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_TRANSFER_HEADER, EMPTY_ATTRIBUTES);
|
||||
|
||||
// Created Date
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_HEADER_CREATED_DATE, PREFIX + ":" + ManifestModel.LOCALNAME_HEADER_CREATED_DATE, EMPTY_ATTRIBUTES);
|
||||
writeDate(header.getCreatedDate());
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_HEADER_CREATED_DATE, PREFIX + ":" + ManifestModel.LOCALNAME_HEADER_CREATED_DATE);
|
||||
|
||||
// End Header
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_TRANSFER_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_TRANSFER_HEADER);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a deleted node to the manifest file
|
||||
*
|
||||
* @param node
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void writeTransferManifestNode(TransferManifestDeletedNode node) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute("uri", "nodeRef", "nodeRef", "String", node.getNodeRef().toString());
|
||||
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_NODE, PREFIX + ":" +ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE, attributes);
|
||||
|
||||
if(node.getPrimaryParentAssoc() != null)
|
||||
{
|
||||
writePrimaryParent(node.getPrimaryParentAssoc(), node.getParentPath());
|
||||
}
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_NODE, PREFIX + ":" +ManifestModel.LOCALNAME_ELEMENT_DELETED_NODE);
|
||||
|
||||
}
|
||||
|
||||
public void writeTransferManifestNode(TransferManifestNode node) throws SAXException
|
||||
{
|
||||
if(node instanceof TransferManifestDeletedNode)
|
||||
{
|
||||
TransferManifestDeletedNode node2 = (TransferManifestDeletedNode)node;
|
||||
writeTransferManifestNode(node2);
|
||||
}
|
||||
else if(node instanceof TransferManifestNormalNode)
|
||||
{
|
||||
TransferManifestNormalNode node2 = (TransferManifestNormalNode)node;
|
||||
writeTransferManifestNode(node2);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Unexpected type" + node.getClass().getName());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a normal transfer manifest node
|
||||
* @param nodeRef
|
||||
* @throws SAXException
|
||||
*/
|
||||
public void writeTransferManifestNode(TransferManifestNormalNode node) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute("uri", "nodeRef", "nodeRef", "String", node.getNodeRef().toString());
|
||||
attributes.addAttribute("uri", "nodeType", "nodeType", "String", formatQName(node.getType()));
|
||||
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_NODE, PREFIX + ":" +ManifestModel.LOCALNAME_ELEMENT_NODE, attributes);
|
||||
|
||||
if(node.getPrimaryParentAssoc() != null)
|
||||
{
|
||||
writePrimaryParent(node.getPrimaryParentAssoc(), node.getParentPath());
|
||||
}
|
||||
|
||||
writeAspects(node.getAspects());
|
||||
|
||||
writeProperties(node.getProperties());
|
||||
|
||||
writeParentAssocs(node.getParentAssocs());
|
||||
|
||||
writeChildAssocs(node.getChildAssocs());
|
||||
|
||||
writeTargetAssocs(node.getTargetAssocs());
|
||||
|
||||
writeSourceAssocs(node.getSourceAssocs());
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_NODE, PREFIX + ":" +ManifestModel.LOCALNAME_ELEMENT_NODE);
|
||||
}
|
||||
|
||||
private void writeProperties(Map<QName, Serializable> properties) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PROPERTIES, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PROPERTIES, EMPTY_ATTRIBUTES);
|
||||
if(properties != null )
|
||||
{
|
||||
for(Entry<QName, Serializable> entry : properties.entrySet())
|
||||
{
|
||||
writeProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PROPERTIES, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PROPERTIES);
|
||||
}
|
||||
|
||||
private void writeProperty(QName name, Serializable value) throws SAXException
|
||||
{
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "name", "name", "String", formatQName(name));
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PROPERTY, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PROPERTY, attributes);
|
||||
}
|
||||
|
||||
// TODO - Char [] does not seem to be processed correctly
|
||||
if(value.getClass().isArray())
|
||||
{
|
||||
writeValue(value.toString());
|
||||
}
|
||||
// Collection
|
||||
else if(value instanceof ContentData)
|
||||
{
|
||||
ContentData data = (ContentData)value;
|
||||
AttributesImpl dataAttributes = new AttributesImpl();
|
||||
dataAttributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "contentURL","contentURL", "String", data.getContentUrl());
|
||||
dataAttributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "mimetype", "mimetype", "String", data.getMimetype());
|
||||
dataAttributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "size", "size", "String", Long.toString(data.getSize()));
|
||||
dataAttributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "encoding", "encoding", "String", data.getEncoding());
|
||||
dataAttributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "locale", "locale", "String", data.getLocale().toString());
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, dataAttributes);
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CONTENT_HEADER);
|
||||
}
|
||||
// Collection
|
||||
else if(value instanceof Collection)
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUES, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUES, EMPTY_ATTRIBUTES);
|
||||
int index = 0;
|
||||
for (Object valueInCollection : (Collection)value)
|
||||
{
|
||||
writeValue((Serializable)valueInCollection);
|
||||
index++;
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUES, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUES);
|
||||
}
|
||||
else if(value instanceof MLText)
|
||||
{
|
||||
MLText mltext = (MLText)value;
|
||||
for(Entry<Locale, String> entry : mltext.entrySet())
|
||||
{
|
||||
writeMLValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeValue(value);
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PROPERTY, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PROPERTY);
|
||||
}
|
||||
|
||||
private void writeValue(Serializable value) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE, EMPTY_ATTRIBUTES);
|
||||
String strValue = (String)DefaultTypeConverter.INSTANCE.convert(String.class, value);
|
||||
|
||||
writer.characters(strValue.toCharArray(), 0, strValue.length());
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_VALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_VALUE);
|
||||
}
|
||||
|
||||
private void writeMLValue(Locale locale, Serializable value) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "locale", "locale", "String", locale.toString());
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_MLVALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_MLVALUE, attributes);
|
||||
String strValue = (String)DefaultTypeConverter.INSTANCE.convert(String.class, value);
|
||||
writer.characters(strValue.toCharArray(), 0, strValue.length());
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_MLVALUE, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_MLVALUE);
|
||||
}
|
||||
|
||||
private void writeAspects(Set<QName> aspects) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASPECTS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASPECTS, EMPTY_ATTRIBUTES);
|
||||
|
||||
if(aspects != null)
|
||||
{
|
||||
for(QName aspect : aspects)
|
||||
{
|
||||
writeAspect(aspect);
|
||||
}
|
||||
}
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASPECTS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASPECTS);
|
||||
}
|
||||
|
||||
private void writeAspect(QName aspect) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASPECT, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASPECT, EMPTY_ATTRIBUTES);
|
||||
String name=formatQName(aspect);
|
||||
writer.characters(name.toCharArray(), 0, name.length());
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASPECT, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASPECT);
|
||||
}
|
||||
|
||||
private void writeDate(Date date) throws SAXException
|
||||
{
|
||||
String dates = ISO8601DateFormat.format(date);
|
||||
writer.characters(dates.toCharArray(), 0, dates.length());
|
||||
|
||||
}
|
||||
|
||||
private String formatQName(QName qname)
|
||||
{
|
||||
return qname.toString();
|
||||
}
|
||||
|
||||
private void writePrimaryParent(ChildAssociationRef parentAssoc, Path parentPath) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT, EMPTY_ATTRIBUTES);
|
||||
|
||||
writeParentAssoc(parentAssoc);
|
||||
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH, EMPTY_ATTRIBUTES);
|
||||
if(parentPath != null)
|
||||
{
|
||||
String path = parentPath.toString();
|
||||
writer.characters(path.toCharArray(), 0, path.length());
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PATH);
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PRIMARY_PARENT);
|
||||
}
|
||||
|
||||
private void writeParentAssocs(List<ChildAssociationRef> refs) throws SAXException
|
||||
{
|
||||
if(refs != null)
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS, EMPTY_ATTRIBUTES);
|
||||
|
||||
for(ChildAssociationRef assoc : refs)
|
||||
{
|
||||
writeParentAssoc(assoc);
|
||||
}
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOCS);
|
||||
}
|
||||
}
|
||||
private void writeChildAssocs(List<ChildAssociationRef> refs) throws SAXException
|
||||
{
|
||||
if(refs != null)
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS, EMPTY_ATTRIBUTES);
|
||||
|
||||
for(ChildAssociationRef assoc : refs)
|
||||
{
|
||||
writeChildAssoc(assoc);
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOCS);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeParentAssoc(ChildAssociationRef assoc) throws SAXException
|
||||
{
|
||||
if(assoc != null)
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "from", "from", "String", assoc.getParentRef().toString());
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "type", "String", formatQName(assoc.getTypeQName()));
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "isPrimary", "Boolean", assoc.isPrimary()?"true":"false");
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, attributes);
|
||||
String name= formatQName(assoc.getQName());
|
||||
writer.characters(name.toCharArray(), 0, name.length());
|
||||
assoc.isPrimary();
|
||||
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_PARENT_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeChildAssoc(ChildAssociationRef assoc) throws SAXException
|
||||
{
|
||||
if(assoc != null)
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "to", "to", "String", assoc.getChildRef().toString());
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "type", "String", formatQName(assoc.getTypeQName()));
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "isPrimary", "Boolean", assoc.isPrimary()?"true":"false");
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC, attributes);
|
||||
String name= formatQName(assoc.getQName());
|
||||
writer.characters(name.toCharArray(), 0, name.length());
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_CHILD_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTargetAssocs(List<AssociationRef> refs) throws SAXException
|
||||
{
|
||||
if(refs != null)
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS, EMPTY_ATTRIBUTES);
|
||||
|
||||
for(AssociationRef assoc : refs)
|
||||
{
|
||||
writeAssoc(assoc);
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_TARGET_ASSOCS);
|
||||
}
|
||||
}
|
||||
private void writeSourceAssocs(List<AssociationRef> refs) throws SAXException
|
||||
{
|
||||
if(refs != null)
|
||||
{
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS, EMPTY_ATTRIBUTES);
|
||||
|
||||
for(AssociationRef assoc : refs)
|
||||
{
|
||||
writeAssoc(assoc);
|
||||
}
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_SOURCE_ASSOCS);
|
||||
}
|
||||
}
|
||||
private void writeAssoc(AssociationRef ref) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "source", "source", "String", ref.getSourceRef().toString());
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "target", "target", "String", ref.getTargetRef().toString());
|
||||
attributes.addAttribute(TransferModel.TRANSFER_MODEL_1_0_URI, "type", "type", "String", formatQName(ref.getTypeQName()));
|
||||
|
||||
writer.startElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASSOC, attributes);
|
||||
writer.endElement(TransferModel.TRANSFER_MODEL_1_0_URI, ManifestModel.LOCALNAME_ELEMENT_ASSOC, PREFIX + ":" + ManifestModel.LOCALNAME_ELEMENT_ASSOC);
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.alfresco.org/model/transferReport/1.0" xmlns:report="http://www.alfresco.org/model/transferReport/1.0" elementFormDefault="qualified">
|
||||
|
||||
<!-- XML Schema for the client side transferReport -->
|
||||
<complexType name="transferReport">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
This is the transfer report root tag
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<sequence>
|
||||
<element name="target" type="report:target" maxOccurs="1" minOccurs="1"></element>
|
||||
<element name="definition" type="report:definition" maxOccurs="1" minOccurs="1"></element>
|
||||
<element name="events" type="report:events"></element>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="target">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The destination of the transfer
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<attribute name="name" type="string"></attribute>
|
||||
<attribute name="endpointPort" type="int"></attribute>
|
||||
<attribute name="endpointHost" type="string"></attribute>
|
||||
</complexType>
|
||||
|
||||
<complexType name="definition">
|
||||
</complexType>
|
||||
|
||||
<complexType name="events">
|
||||
<sequence maxOccurs="unbounded" minOccurs="0">
|
||||
<element name="event" type="report:event"></element>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="event">
|
||||
<attribute name="date" type="dateTime"></attribute>
|
||||
<!-- message is content -->
|
||||
</complexType>
|
||||
|
||||
|
||||
</schema>
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.repo.transfer.report;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferModel;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* The transfer report model - extended for XML Manifest Model
|
||||
*/
|
||||
public interface TransferReportModel extends TransferModel
|
||||
{
|
||||
static final String LOCALNAME_TRANSFER_REPORT = "transferReport";
|
||||
static final String LOCALNAME_TRANSFER_TARGET = "target";
|
||||
static final String LOCALNAME_TRANSFER_DEFINITION = "definition";
|
||||
static final String LOCALNAME_TRANSFER_EVENTS = "events";
|
||||
static final String LOCALNAME_TRANSFER_EVENT = "event";
|
||||
static final String REPORT_PREFIX = "report";
|
||||
|
||||
static final String TRANSFER_REPORT_MODEL_1_0_URI = "http://www.alfresco.org/model/transferReport/1.0";
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 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.transfer.report;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.transfer.Transfer;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
|
||||
public interface TransferReporter
|
||||
{
|
||||
/**
|
||||
* Create a transfer report
|
||||
* @param target the target of the transfer
|
||||
* @param definition the definition of the transfer
|
||||
* @param events the transfer events generated by the transfer.
|
||||
* @return the node ref of the transfer report
|
||||
*/
|
||||
NodeRef createTransferReport(Transfer transfer,
|
||||
TransferTarget target,
|
||||
TransferDefinition definition,
|
||||
List<TransferEvent> events);
|
||||
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 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.transfer.report;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.transfer.Transfer;
|
||||
import org.alfresco.repo.transfer.TransferModel;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
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.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class TransferReporterImpl implements TransferReporter
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
|
||||
/** Default encoding **/
|
||||
private static String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
public void init()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "nodeService", nodeService);
|
||||
PropertyCheck.mandatory(this, "contentService", contentService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transfer report
|
||||
* @return NodeRef the node ref of the new transfer report
|
||||
*/
|
||||
public NodeRef createTransferReport(Transfer transfer,
|
||||
TransferTarget target,
|
||||
TransferDefinition definition,
|
||||
List<TransferEvent> events)
|
||||
{
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable> ();
|
||||
String transferId = transfer.getTransferId();
|
||||
String title = "transfer report: success :" + transferId;
|
||||
String name = transferId;
|
||||
String description = "successful transfer report";
|
||||
|
||||
properties.put(ContentModel.PROP_NAME, name);
|
||||
properties.put(ContentModel.PROP_TITLE, title);
|
||||
properties.put(ContentModel.PROP_DESCRIPTION, description);
|
||||
ChildAssociationRef ref = nodeService.createNode(target.getNodeRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), TransferModel.TYPE_TRANSFER_REPORT, properties);
|
||||
ContentWriter writer = contentService.getWriter(ref.getChildRef(), ContentModel.PROP_CONTENT, true);
|
||||
writer.setLocale(Locale.getDefault());
|
||||
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
|
||||
writer.setEncoding("UTF-8");
|
||||
|
||||
//
|
||||
XMLTransferReportWriter reportWriter = new XMLTransferReportWriter();
|
||||
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(writer.getContentOutputStream()));
|
||||
|
||||
try
|
||||
{
|
||||
reportWriter.startTransferReport("UTF-8", bufferedWriter);
|
||||
|
||||
// Header
|
||||
reportWriter.writeTarget(target);
|
||||
|
||||
reportWriter.writeDefinition(definition);
|
||||
|
||||
// Detail
|
||||
reportWriter.writeTransferEvents(events);
|
||||
|
||||
reportWriter.endTransferReport();
|
||||
|
||||
return ref.getChildRef();
|
||||
}
|
||||
|
||||
catch (SAXException se)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
bufferedWriter.close();
|
||||
}
|
||||
catch (IOException error)
|
||||
{
|
||||
error.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public ContentService getContentService()
|
||||
{
|
||||
return contentService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
package org.alfresco.repo.transfer.report;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferModel;
|
||||
import org.alfresco.repo.transfer.manifest.ManifestModel;
|
||||
import org.alfresco.repo.transfer.manifest.TransferManifestHeader;
|
||||
import org.alfresco.service.cmr.transfer.TransferDefinition;
|
||||
import org.alfresco.service.cmr.transfer.TransferEvent;
|
||||
import org.alfresco.service.cmr.transfer.TransferTarget;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
public class XMLTransferReportWriter
|
||||
{
|
||||
public XMLTransferReportWriter()
|
||||
{
|
||||
}
|
||||
|
||||
private XMLWriter writer;
|
||||
|
||||
final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl();
|
||||
|
||||
final String PREFIX = TransferReportModel.REPORT_PREFIX;
|
||||
|
||||
/**
|
||||
* Start the transfer report
|
||||
*/
|
||||
public void startTransferReport(String encoding, Writer writer) throws SAXException
|
||||
{
|
||||
OutputFormat format = OutputFormat.createPrettyPrint();
|
||||
format.setNewLineAfterDeclaration(false);
|
||||
format.setIndentSize(3);
|
||||
format.setEncoding(encoding);
|
||||
|
||||
this.writer = new XMLWriter(writer, format);
|
||||
this.writer.startDocument();
|
||||
|
||||
this.writer.startPrefixMapping(PREFIX, TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI);
|
||||
|
||||
// Start Transfer Manifest // uri, name, prefix
|
||||
this.writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_REPORT, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transfer report
|
||||
*/
|
||||
public void endTransferReport() throws SAXException
|
||||
{
|
||||
// End Transfer Manifest
|
||||
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_REPORT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_REPORT);
|
||||
writer.endPrefixMapping(PREFIX);
|
||||
writer.endDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the target to the report
|
||||
*/
|
||||
public void writeTarget(TransferTarget target) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "name", "name", "String", target.getName());
|
||||
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "endpointHost", "endpointHost", "String", target.getEndpointHost());
|
||||
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "endpointPort", "endpointPort", "int", String.valueOf(target.getEndpointPort()));
|
||||
|
||||
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_TARGET, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_TARGET, attributes);
|
||||
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_TARGET, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_TARGET);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the definition to the report
|
||||
*/
|
||||
public void writeDefinition(TransferDefinition definition) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_DEFINITION, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_DEFINITION, EMPTY_ATTRIBUTES);
|
||||
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_DEFINITION, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_DEFINITION);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the transfer manifest header
|
||||
*/
|
||||
public void writeTransferEvents(List<TransferEvent> events) throws SAXException
|
||||
{
|
||||
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_EVENTS, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_EVENTS, EMPTY_ATTRIBUTES);
|
||||
|
||||
for(TransferEvent event : events)
|
||||
{
|
||||
writeTransferEvent(event);
|
||||
}
|
||||
|
||||
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_EVENTS, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_EVENTS);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the transfer manifest header
|
||||
*/
|
||||
public void writeTransferEvent(TransferEvent event) throws SAXException
|
||||
{
|
||||
AttributesImpl attributes = new AttributesImpl();
|
||||
attributes.addAttribute(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, "date", "date", "dateTime", ISO8601DateFormat.format(event.getTime()));
|
||||
|
||||
writer.startElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_EVENT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_EVENT, attributes);
|
||||
|
||||
String message = event.getMessage();
|
||||
if(message != null)
|
||||
{
|
||||
writer.characters(message.toCharArray(), 0, message.length());
|
||||
}
|
||||
writer.endElement(TransferReportModel.TRANSFER_REPORT_MODEL_1_0_URI, TransferReportModel.LOCALNAME_TRANSFER_EVENT, PREFIX + ":" + TransferReportModel.LOCALNAME_TRANSFER_EVENT);
|
||||
}
|
||||
}
|
@@ -333,4 +333,17 @@ public class ContentData implements Serializable
|
||||
{
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return hashCode
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
if(contentUrl!= null)
|
||||
{
|
||||
return contentUrl.hashCode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,7 +41,7 @@ import org.alfresco.util.ISO9075;
|
||||
* /x/y/z
|
||||
* </pre></b>
|
||||
* In the above example, there will be <b>4</b> elements, the first being a reference
|
||||
* to the root node, followed by qname elements for <b>x</b>, <b>x</b> and <b>z</b>.
|
||||
* to the root node, followed by qname elements for <b>x</b>, <b>y</b> and <b>z</b>.
|
||||
* <p>
|
||||
* Methods and constructors are available to construct a <code>Path</code> instance
|
||||
* from a path string or by building the path incrementally, including the ability to
|
||||
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.service.cmr.transfer;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface NodeFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* Examines the supplied node and indicates whether it has been accepted by the filter.
|
||||
* @param thisNode
|
||||
* @param serviceRegistry
|
||||
* @return true if the supplied node matches the criteria specified on this filter, and false
|
||||
* otherwise.
|
||||
*/
|
||||
boolean accept(NodeRef thisNode);
|
||||
|
||||
void init();
|
||||
|
||||
void setServiceRegistry(ServiceRegistry serviceRegistry);
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.service.cmr.transfer;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface NodeFinder
|
||||
{
|
||||
|
||||
/**
|
||||
* @param thisNode
|
||||
* @param serviceRegistry
|
||||
* @return
|
||||
*/
|
||||
Set<NodeRef> findFrom(NodeRef thisNode);
|
||||
|
||||
void init();
|
||||
|
||||
void setServiceRegistry(ServiceRegistry serviceRegistry);
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
/**
|
||||
* A Ranged Transfer event is a detail record for a State that has many smaller steps. For example when sending content the first
|
||||
* event is 1 of the number of files to send. The second is 2 of the number of files to send.
|
||||
*
|
||||
* These events are intended to support "progress bar" types of interfaces.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface RangedTransferEvent extends TransferEvent
|
||||
{
|
||||
/**
|
||||
* The position in the range
|
||||
* @return
|
||||
*/
|
||||
long getPosition();
|
||||
|
||||
/**
|
||||
* The maximum range
|
||||
* @return
|
||||
*/
|
||||
long getRange();
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The transfer callback is called during a transfer, it allows the real-time feedback of
|
||||
* an in progress transfer. It can be used to populate a deployment report or to display
|
||||
* a user interface.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferCallback extends Serializable
|
||||
{
|
||||
/**
|
||||
* processEvent
|
||||
* @param event
|
||||
*/
|
||||
public void processEvent(TransferEvent event);
|
||||
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Definition of a transfer.
|
||||
*
|
||||
* Specifies which node to transfer
|
||||
*
|
||||
*/
|
||||
public class TransferDefinition implements Serializable
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -8497919749300106861L;
|
||||
|
||||
// Which nodes to deploy
|
||||
private Set<NodeRef> nodes;
|
||||
|
||||
/**
|
||||
* Set which nodes to transfer
|
||||
* @param nodes
|
||||
*/
|
||||
public void setNodes(Set<NodeRef> nodes)
|
||||
{
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get which nodes to transfer
|
||||
* @return
|
||||
*/
|
||||
public Set<NodeRef> getNodes()
|
||||
{
|
||||
return nodes;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package org.alfresco.service.cmr.transfer;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferEvent
|
||||
{
|
||||
/**
|
||||
* The transfer events will Start with a START event and finish with either SUCCESS or ERROR
|
||||
*/
|
||||
enum TransferState { START, SENDING_MANIFEST, SENDING_CONTENT, PREPARING, COMMITTING, SUCCESS, ERROR };
|
||||
|
||||
/**
|
||||
* Get the state of this transfer
|
||||
* @return the state of this transfer
|
||||
*/
|
||||
TransferState getTransferState();
|
||||
|
||||
/**
|
||||
* The time this event occured.
|
||||
* @return the date/time the event
|
||||
*/
|
||||
Date getTime();
|
||||
|
||||
/**
|
||||
* Get a human readable message for this event
|
||||
* @return
|
||||
*/
|
||||
String getMessage();
|
||||
|
||||
/**
|
||||
* Is this the last event for this transfer ?
|
||||
*/
|
||||
boolean isLast();
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
/**
|
||||
* TransferEventCommittingStatus are produced when a transfer is being committed.
|
||||
*
|
||||
* The range can be used to produce a "progress bar"
|
||||
*
|
||||
*/
|
||||
public class TransferEventCommittingStatus extends TransferEventImpl implements RangedTransferEvent
|
||||
{
|
||||
public String toString()
|
||||
{
|
||||
return "TransferEventCommittingStatus: " + super.getPosition() + " of " + super.getRange();
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
public class TransferEventEndState extends TransferEventImpl implements TransferEvent
|
||||
{
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return ("TransferEventEndState: " + super.toString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
public class TransferEventEnterState extends TransferEventImpl implements TransferEvent
|
||||
{
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return ("TransferEventEnterState: " + super.toString());
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
/**
|
||||
* Indicates the reason why a transfer failed
|
||||
*/
|
||||
public class TransferEventError extends TransferEventImpl implements TransferEvent
|
||||
{
|
||||
private Exception exception;
|
||||
|
||||
public void setException(Exception exception)
|
||||
{
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public Exception getException()
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
/**
|
||||
* Ranged Transfer event for sending content (e.g. sending content 1 of 64)
|
||||
*/
|
||||
public class TransferEventSendingContent extends TransferEventImpl implements RangedTransferEvent
|
||||
{
|
||||
private long size;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "TransferEventSendingContent: " + super.getPosition() + " of " + super.getRange();
|
||||
}
|
||||
|
||||
public void setSize(long size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public long getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class TransferEventSendingManifest extends TransferEventImpl implements RangedTransferEvent
|
||||
{
|
||||
public String toString()
|
||||
{
|
||||
return "TransferEventSendingManifest: " + super.getPosition() + " of " + super.getRange();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
public class TransferEventSentContent extends TransferEventImpl implements TransferEvent
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferEventImpl;
|
||||
|
||||
/**
|
||||
* The success event indicates a successfull transfer
|
||||
*/
|
||||
public class TransferEventSuccess extends TransferEventImpl implements TransferEvent
|
||||
{
|
||||
public String toString()
|
||||
{
|
||||
return "TransferEventSuccess";
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 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.transfer;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* Transfer service exception class
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public class TransferException extends AlfrescoRuntimeException
|
||||
{
|
||||
/**
|
||||
* Serial version UID
|
||||
*/
|
||||
private static final long serialVersionUID = 3257571685241467958L;
|
||||
|
||||
public TransferException(String msgId)
|
||||
{
|
||||
super(msgId);
|
||||
}
|
||||
|
||||
public TransferException(String msgId, Object[] msgParams)
|
||||
{
|
||||
super(msgId, msgParams);
|
||||
}
|
||||
|
||||
public TransferException(String msgId, Object[] msgParams, Throwable cause)
|
||||
{
|
||||
super(msgId, msgParams, cause);
|
||||
}
|
||||
|
||||
public TransferException(String msgId, Throwable cause)
|
||||
{
|
||||
super(msgId, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.service.cmr.transfer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* @author brian
|
||||
*
|
||||
*/
|
||||
public interface TransferReceiver
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param transferId
|
||||
* @return
|
||||
*/
|
||||
File getStagingFolder(String transferId);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param transferId
|
||||
* @return
|
||||
*/
|
||||
NodeRef getTempFolder(String transferId);
|
||||
|
||||
/**
|
||||
* Asks the receiver to setup a new transfer.
|
||||
* @return The identifier of the new transfer
|
||||
* @throws TransferException if an error occurred while setting up the transfer
|
||||
*/
|
||||
String start() throws TransferException;
|
||||
|
||||
/**
|
||||
* Asks the receiver to end (and clean up) the specified transfer
|
||||
* @param transferId The transfer to end
|
||||
* @throws TransferException If the process of ending the transfer fails
|
||||
*/
|
||||
void end(String transferId) throws TransferException;
|
||||
|
||||
/**
|
||||
* Nudge the transfer lock (to prevent it expiring) if the supplied transferId matches that referenced by the lock.
|
||||
* @param transferId
|
||||
* @throws TransferException if the lock doesn't exist or doesn't correspond to the supplied transferId.
|
||||
*/
|
||||
void nudgeLock(String transferId) throws TransferException;
|
||||
|
||||
/**
|
||||
* Store the specified snapshot file into the transfer staging area.
|
||||
* The specified transfer must currently be the holder of the transfer lock, otherwise an exception is thrown.
|
||||
* This operation does not close the supplied stream, so the caller must do it as appropriate. The caller
|
||||
* should assume that the supplied stream has been fully read when this operation returns.
|
||||
* @param transferId The identifier of the transfer with which this snapshot is associated
|
||||
* @param snapshotStream The open stream that holds the snapshot file.
|
||||
* @throws TransferException If an error occurs while saving the snapshot file.
|
||||
*/
|
||||
void saveSnapshot(String transferId, InputStream snapshotStream) throws TransferException;
|
||||
|
||||
void saveContent(String transferId, String contentId, InputStream contentStream) throws TransferException;
|
||||
|
||||
/**
|
||||
* Prepare
|
||||
* @param transferId
|
||||
* @throws TransferException
|
||||
*/
|
||||
void prepare(String transferId) throws TransferException;
|
||||
|
||||
/**
|
||||
* Abort
|
||||
* @param transferId
|
||||
* @throws TransferException
|
||||
*/
|
||||
void abort(String transferId) throws TransferException;
|
||||
|
||||
/**
|
||||
* Commit
|
||||
* @param transferId
|
||||
* @throws TransferException
|
||||
*/
|
||||
void commit(String transferId) throws TransferException;
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2009-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.transfer;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* The transfer service is responsible for transfering nodes between one instance of Alfresco and another remote instance.
|
||||
* as well as the transfer method, this interface also provides methods for managing the
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferService
|
||||
{
|
||||
|
||||
/**
|
||||
* Transfer nodes, sync. This synchronous version of the transfer method waits for the transfer to complete
|
||||
* before returning to the caller. Callbacks are called in the current thread context, so will be associated with the current
|
||||
* transaction and user.
|
||||
*
|
||||
* @param targetName the name of the target to transfer to
|
||||
* The following properties must be set, nodes
|
||||
* @param definition, the definition of the transfer. Specifies which nodes to transfer.
|
||||
* @throws TransferException
|
||||
* @return the node reference of the transfer report
|
||||
*/
|
||||
public NodeRef transfer(String targetName, TransferDefinition definition) throws TransferException;
|
||||
|
||||
/**
|
||||
* Transfer nodes sync, with callback. This synchronous version of the transfer method waits for the transfer to complete
|
||||
* before returning to the caller. Callbacks are called in the current thread context, so will be associated with the current
|
||||
* transaction and user.
|
||||
*
|
||||
* @param targetName the name of the target to transfer to
|
||||
* @param definition - the definition of the transfer. Specifies which nodes to transfer.
|
||||
* The following properties must be set, nodes
|
||||
* @param callback - a set of callback handlers that will be called as transfer proceeds. May be null.
|
||||
* @throws TransferException
|
||||
* @return the node reference of the transfer report
|
||||
*/
|
||||
public NodeRef transfer(String targetName, TransferDefinition definition, Set<TransferCallback> callback) throws TransferException;
|
||||
|
||||
/**
|
||||
* Transfer nodes async with callback. The asynchronous version of the transfer method starts a transfer and returns as
|
||||
* soon as possible.
|
||||
* The transfer callbacks will be called by a different thread to that used to call the transferAsync method so transaction
|
||||
* context will be different to the calling context.
|
||||
*
|
||||
* Please also be aware that the asychronous transfer does not have access to uncommitted
|
||||
* data in the calling transaction.
|
||||
*
|
||||
* @param targetName the name of the target to transfer to
|
||||
* @param definition - the definition of the transfer. Specifies which nodes to transfer.
|
||||
* The following properties must be set, nodes
|
||||
* @param callback - a set of callback handlers that will be called as transfer proceeds. May be null.
|
||||
* @throws TransferException
|
||||
*/
|
||||
public void transferAsync(String targetName, TransferDefinition definition, Set<TransferCallback> callback) throws TransferException;
|
||||
|
||||
/**
|
||||
* Verify a target is available and that the configured credentials correctly identify an admin user.
|
||||
* @throws TransferException
|
||||
*/
|
||||
public void verify(TransferTarget target) throws TransferException;
|
||||
|
||||
/**
|
||||
* crate a new transfer target
|
||||
* @param name, the name of this transfer target, which must be unique
|
||||
* @param title, the display name of this transfer target
|
||||
* @param description,
|
||||
* @param endpointProtocol, either http or https
|
||||
* @param endpointHost,
|
||||
* @param endpointPort,
|
||||
* @param endpointPath,
|
||||
* @param username,
|
||||
* @param password,
|
||||
*/
|
||||
public TransferTarget createTransferTarget(String name, String title, String description, String endpointProtocol, String endpointHost, int endpointPort, String endpointPath, String username, char[] password) throws TransferException;
|
||||
|
||||
/**
|
||||
* Get all the transfer targets
|
||||
*/
|
||||
public Set<TransferTarget>getTransferTargets() throws TransferException;
|
||||
|
||||
/**
|
||||
* Get All the transfer targets for a particular transfer target group.
|
||||
* @param groupName, the name of the transfer group
|
||||
*/
|
||||
public Set<TransferTarget>getTransferTargets(String groupName) throws TransferException;
|
||||
|
||||
/**
|
||||
* Get a transfer target by its name
|
||||
* @throws TransferException - target does not exist
|
||||
*/
|
||||
public TransferTarget getTransferTarget(String name) throws TransferException;
|
||||
|
||||
/**
|
||||
* Delete a transfer target. After calling this method the transfer target will no longer exist.
|
||||
* @throws TransferException - target does not exist
|
||||
* @param name, the name of this transfer target,
|
||||
*/
|
||||
public void deleteTransferTarget(String name) throws TransferException;
|
||||
|
||||
/**
|
||||
* Update TransferTarget
|
||||
* The following properties may be updated:
|
||||
* endpointHost,
|
||||
* endpointPort,
|
||||
* endpointProtocol,
|
||||
* endpointPath,
|
||||
* username,
|
||||
* password,
|
||||
* title,
|
||||
* description
|
||||
*
|
||||
* The following properties may not be updated:
|
||||
* name, must be specified.
|
||||
* nodeRef, if specified will be ignored.
|
||||
*
|
||||
* @param update
|
||||
*/
|
||||
public TransferTarget updateTransferTarget(TransferTarget update) throws TransferException;
|
||||
|
||||
/**
|
||||
* Enables/Disables the named transfer target
|
||||
* @param name the name of the transfer target
|
||||
* @param enable (or false=disable)
|
||||
*/
|
||||
public void enableTransferTarget(String name, boolean enable) throws TransferException;
|
||||
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
package org.alfresco.service.cmr.transfer;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Transfer Target.
|
||||
*
|
||||
* @author Mark Rogers
|
||||
*/
|
||||
public interface TransferTarget
|
||||
{
|
||||
/**
|
||||
* read only - get the node reference of the underlying transfer target node.
|
||||
* @return
|
||||
*/
|
||||
public NodeRef getNodeRef();
|
||||
|
||||
/**
|
||||
* Get the name of this transfer target
|
||||
* @return
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Set the name of this transfer target. Please note that you can't update the name of a
|
||||
* transfer target.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public void setName(String name);
|
||||
|
||||
/**
|
||||
* Get the description for this transfer target
|
||||
* @return
|
||||
*/
|
||||
public String getDescription();
|
||||
|
||||
/**
|
||||
* Set the decription for this transfer target
|
||||
* @param description
|
||||
*/
|
||||
public void setDescription(String description);
|
||||
|
||||
/**
|
||||
* Get the title of this transfer target
|
||||
* @return
|
||||
*/
|
||||
String getTitle();
|
||||
|
||||
/**
|
||||
* Set the title for this transfer target
|
||||
* @param title
|
||||
*/
|
||||
public void setTitle(String title);
|
||||
|
||||
/**
|
||||
* Get the endpoint host
|
||||
* @return
|
||||
*/
|
||||
public String getEndpointHost();
|
||||
|
||||
/**
|
||||
* Set the endpoint host
|
||||
* @param endpointHost
|
||||
*/
|
||||
public void setEndpointHost(String endpointHost);
|
||||
|
||||
/**
|
||||
* Get the endpoint port
|
||||
* @return
|
||||
*/
|
||||
int getEndpointPort();
|
||||
|
||||
/**
|
||||
* Set the endpoint port
|
||||
* @param endpointPort
|
||||
*/
|
||||
public void setEndpointPort(int endpointPort);
|
||||
|
||||
/**
|
||||
* HTTP OR HTTPS
|
||||
*/
|
||||
public String getEndpointProtocol();
|
||||
|
||||
/**
|
||||
* Set the endpoint protocol.
|
||||
* @param endpointProtocol
|
||||
*/
|
||||
public void setEndpointProtocol(String endpointProtocol);
|
||||
|
||||
/**
|
||||
* Set the password for this transfer target
|
||||
* @param password clear text password.
|
||||
*/
|
||||
public void setPassword(char[] password);
|
||||
|
||||
/**
|
||||
* The username used to authenticate with the transfer target
|
||||
* @return
|
||||
*/
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* The username used to authenticate with the transfer target
|
||||
* @param userName
|
||||
*/
|
||||
void setUsername(String userName);
|
||||
|
||||
/**
|
||||
* Get the cleartext password
|
||||
* @return
|
||||
*/
|
||||
char[] getPassword();
|
||||
|
||||
/**
|
||||
* The location of the transfer service on the target endpoint host
|
||||
* @return
|
||||
*/
|
||||
String getEndpointPath();
|
||||
|
||||
/**
|
||||
* The location of the transfer service on the target endpoint host
|
||||
*/
|
||||
void setEndpointPath(String path);
|
||||
|
||||
/**
|
||||
* is this transfer target enabled or disabled?
|
||||
*/
|
||||
boolean isEnabled();
|
||||
|
||||
/**
|
||||
* enable this transfer target
|
||||
*/
|
||||
void setEnabled(boolean enabled);
|
||||
}
|
@@ -58,8 +58,10 @@ public final class QName implements QNamePattern, Serializable, Cloneable, Compa
|
||||
/**
|
||||
* Create a QName
|
||||
*
|
||||
* (With no prefix)
|
||||
*
|
||||
* @param namespaceURI the qualifying namespace (maybe null or empty string)
|
||||
* @param localName the qualified name
|
||||
* @param localName the local name
|
||||
* @return the QName
|
||||
*/
|
||||
public static QName createQName(String namespaceURI, String localName)
|
||||
@@ -109,7 +111,7 @@ public final class QName implements QNamePattern, Serializable, Cloneable, Compa
|
||||
|
||||
|
||||
/**
|
||||
* Create a QName
|
||||
* Create a QName (from prefix format) <code>prefix:localName</code>
|
||||
*
|
||||
* @param qname qualified name of the following format <code>prefix:localName</code>
|
||||
* @param prefixResolver lookup to resolve mappings between prefix and namespace
|
||||
|
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package org.alfresco.util;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
@@ -191,9 +192,11 @@ public class ThreadPoolExecutorFactoryBean implements FactoryBean, InitializingB
|
||||
|
||||
if (workQueueSize < 0)
|
||||
{
|
||||
workQueueSize = Integer.MAX_VALUE;
|
||||
// Setting workQueueSize to MAX_VALUE prevents the pool growing and shrinking. See JavaDoc
|
||||
// workQueueSize = Integer.MAX_VALUE;
|
||||
workQueueSize = 1000;
|
||||
}
|
||||
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(workQueueSize);
|
||||
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(workQueueSize);
|
||||
|
||||
// construct the instance
|
||||
instance = new ThreadPoolExecutor(
|
||||
|
Reference in New Issue
Block a user