Publishing:

- Add latest gdata libs (1.45.0) with source code
 - cleaned the publishing context files out of the top-level application context
 - removed the notion of "content root" from publishing channels
 - added YouTube publishing channel with actions to publish and unpublish
 - added dummy channel types to ease UI development

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28575 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Brian Remmington
2011-06-24 14:40:10 +00:00
parent 6b987ab475
commit a6a4054f1e
26 changed files with 1356 additions and 106 deletions

View File

@@ -21,5 +21,8 @@
<import resource="classpath:alfresco/opencmis-context.xml" /> <import resource="classpath:alfresco/opencmis-context.xml" />
<import resource="classpath:alfresco/period-type-context.xml" /> <import resource="classpath:alfresco/period-type-context.xml" />
<import resource="classpath*:alfresco/node-locator-context.xml" /> <import resource="classpath*:alfresco/node-locator-context.xml" />
<import resource="classpath*:alfresco/transfer-service-context.xml"/>
<import resource="classpath*:alfresco/web-publishing-context.xml" />
<import resource="classpath*:alfresco/social-publishing-context.xml" />
<import resource="classpath*:alfresco/domain/*-context.xml" /> <import resource="classpath*:alfresco/domain/*-context.xml" />
</beans> </beans>

View File

@@ -16,10 +16,6 @@
--> -->
<import resource="classpath:alfresco/application-context-highlevel.xml" /> <import resource="classpath:alfresco/application-context-highlevel.xml" />
<import resource="classpath*:alfresco/transfer-service-context.xml"/>
<import resource="classpath*:alfresco/web-publishing-context.xml" />
<!-- <import resource="classpath*:alfresco/social-publishing-context.xml" /> -->
<!-- <!--
Import activation extensions for Multi-Tenancy. Import activation extensions for Multi-Tenancy.
--> -->

View File

@@ -240,13 +240,6 @@
</types> </types>
<aspects> <aspects>
<aspect name="pub:ContentRoot">
<title>Content Root Aspect</title>
<description>Applied to a node that represents the root of a delivery channel's content
hierarchy</description>
</aspect>
<aspect name="pub:channelInfo"> <aspect name="pub:channelInfo">
<title>Channel Info</title> <title>Channel Info</title>
<description>Applied to a node that exists within a Delivery Channel</description> <description>Applied to a node that exists within a Delivery Channel</description>

View File

@@ -0,0 +1,64 @@
<model name="youtube:publishingmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<description>Alfresco YouTube Publishing Content Model</description>
<author>Alfresco</author>
<published>2011-06-15</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" />
<import uri="http://www.alfresco.org/model/publishing/1.0" prefix="pub" />
</imports>
<namespaces>
<namespace uri="http://www.alfresco.org/model/publishing/youtube/1.0" prefix="youtube" />
</namespaces>
<types>
<type name="youtube:DeliveryChannel">
<title>YouTube Delivery Channel</title>
<description>Node type used to represent YouTube delivery channels</description>
<parent>pub:DeliveryChannel</parent>
<mandatory-aspects>
<aspect>youtube:DeliveryChannelAspect</aspect>
</mandatory-aspects>
</type>
</types>
<aspects>
<aspect name="youtube:DeliveryChannelAspect">
<title>YouTube Delivery Channel</title>
<description>Applied to a node that represents a YouTube delivery channel</description>
<properties>
<property name="youtube:username">
<title>YouTube User Name</title>
<type>d:text</type>
<multiple>false</multiple>
</property>
<property name="youtube:password">
<title>YouTube Password</title>
<type>d:text</type>
<multiple>false</multiple>
</property>
</properties>
</aspect>
<aspect name="youtube:AssetAspect">
<title>YouTube Asset</title>
<description>Applied to a node that has been published to YouTube</description>
<properties>
<property name="youtube:assetId">
<title>YouTube Video Id</title>
<type>d:text</type>
</property>
<property name="youtube:playerUrl">
<title>YouTube Player URL</title>
<type>d:text</type>
</property>
</properties>
</aspect>
</aspects>
</model>

View File

@@ -2,7 +2,7 @@
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans> <beans>
<bean id="publishingService_dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap"> <bean id="publishingService_dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
<property name="models"> <property name="models">
<list> <list>
<value>alfresco/model/publishingModel.xml</value> <value>alfresco/model/publishingModel.xml</value>
@@ -10,7 +10,7 @@
</property> </property>
</bean> </bean>
<!-- Bootstrap the publishing process definition --> <!-- Bootstrap the publishing process definition -->
<bean parent="workflowDeployer"> <bean parent="workflowDeployer">
<property name="workflowDefinitions"> <property name="workflowDefinitions">
<list> <list>
@@ -29,80 +29,80 @@
</property> </property>
</bean> </bean>
<bean id="publishingResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent"> <bean id="publishingResourceBundles" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
<property name="resourceBundles"> <property name="resourceBundles">
<list> <list>
<value>alfresco.messages.publishing-service</value> <value>alfresco.messages.publishing-service</value>
</list> </list>
</property> </property>
</bean> </bean>
<!-- Channel Service --> <!-- Channel Service -->
<bean id="channelService" class="org.alfresco.repo.publishing.ChannelServiceImpl"> <bean id="channelService" class="org.alfresco.repo.publishing.ChannelServiceImpl">
<property name="dictionaryService" ref="DictionaryService" /> <property name="dictionaryService" ref="DictionaryService" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="siteService" ref="SiteService" /> <property name="siteService" ref="SiteService" />
<property name="environmentHelper" ref="environmentHelper" /> <property name="environmentHelper" ref="environmentHelper" />
<property name="channelHelper" ref="channelHelper" /> <property name="channelHelper" ref="channelHelper" />
</bean> </bean>
<!-- Channel Type Implementations --> <!-- Channel Type Implementations -->
<bean id="baseChannelType" class="org.alfresco.repo.publishing.AbstractChannelType" abstract="true" > <bean id="baseChannelType" class="org.alfresco.repo.publishing.AbstractChannelType" abstract="true">
<property name="channelService" ref="channelService" /> <property name="channelService" ref="channelService" />
<property name="serviceRegistry" ref="ServiceRegistry" /> <property name="serviceRegistry" ref="ServiceRegistry" />
</bean> </bean>
<bean id="channelHelper" class="org.alfresco.repo.publishing.ChannelHelper"> <bean id="channelHelper" class="org.alfresco.repo.publishing.ChannelHelper">
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="dictionaryService" ref="DictionaryService" /> <property name="dictionaryService" ref="DictionaryService" />
<property name="fileFolderService" ref="FileFolderService" /> <property name="fileFolderService" ref="FileFolderService" />
</bean> </bean>
<bean id="environmentHelper" class="org.alfresco.repo.publishing.EnvironmentHelper"> <bean id="environmentHelper" class="org.alfresco.repo.publishing.EnvironmentHelper">
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="siteService" ref="SiteService" /> <property name="siteService" ref="SiteService" />
<property name="publishingEventHelper" ref="publishingEventHelper" /> <property name="publishingEventHelper" ref="publishingEventHelper" />
<property name="channelHelper" ref="channelHelper" /> <property name="channelHelper" ref="channelHelper" />
</bean> </bean>
<bean id="publishingEventHelper" class="org.alfresco.repo.publishing.PublishingEventHelper"> <bean id="publishingEventHelper" class="org.alfresco.repo.publishing.PublishingEventHelper">
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="contentService" ref="ContentService" /> <property name="contentService" ref="ContentService" />
<property name="serializer" ref="publishingPackageSerializer" /> <property name="serializer" ref="publishingPackageSerializer" />
<property name="workflowService" ref="WorkflowService" /> <property name="workflowService" ref="WorkflowService" />
<property name="workflowEngineId" value="jbpm" /> <property name="workflowEngineId" value="jbpm" />
</bean> </bean>
<!-- Check Publishing Dependencies Action --> <!-- Check Publishing Dependencies Action -->
<bean id="pub_checkPublishingDependencies" <bean id="pub_checkPublishingDependencies" class="org.alfresco.repo.publishing.CheckPublishingDependenciesAction" />
class="org.alfresco.repo.publishing.CheckPublishingDependenciesAction" />
<!-- Publish Event Action --> <!-- Publish Event Action -->
<bean id="pub_publishEvent" class="org.alfresco.repo.publishing.PublishEventAction" > <bean id="pub_publishEvent" class="org.alfresco.repo.publishing.PublishEventAction">
<property name="publishingEventProcessor" ref="publishingEventProcessor" /> <property name="publishingEventProcessor" ref="publishingEventProcessor" />
</bean> </bean>
<!-- Publishing Event Processor --> <!-- Publishing Event Processor -->
<bean id="publishingEventProcessor" class="org.alfresco.repo.publishing.PublishingEventProcessor"> <bean id="publishingEventProcessor" class="org.alfresco.repo.publishing.PublishingEventProcessor">
<property name="channelHelper" ref="channelHelper" /> <property name="channelHelper" ref="channelHelper" />
<property name="channelService" ref="channelService" /> <property name="channelService" ref="channelService" />
<property name="publishingEventHelper" ref="publishingEventHelper" /> <property name="publishingEventHelper" ref="publishingEventHelper" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="behaviourFilter" ref="policyBehaviourFilter" /> <property name="behaviourFilter" ref="policyBehaviourFilter" />
</bean> </bean>
<bean id="publishingObjectFactory" class="org.alfresco.repo.publishing.PublishingObjectFactory"> <bean id="publishingObjectFactory" class="org.alfresco.repo.publishing.PublishingObjectFactory">
<property name="environmentHelper" ref="environmentHelper" /> <property name="environmentHelper" ref="environmentHelper" />
<property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" /> <property name="transferManifestNodeFactory" ref="transferManifestNodeFactory" />
<property name="publishingEventHelper" ref="publishingEventHelper" /> <property name="publishingEventHelper" ref="publishingEventHelper" />
</bean> </bean>
<!-- Publishing Service -->
<bean id="publishingService" class="org.alfresco.repo.publishing.PublishServiceImpl">
<property name="environmentFactory" ref="publishingObjectFactory" />
<property name="publishingEventHelper" ref="publishingEventHelper" />
</bean>
<bean id="publishingPackageSerializer" class="org.alfresco.repo.publishing.StandardPublishingPackageSerializer" />
<!-- Publishing Service -->
<bean id="publishingService" class="org.alfresco.repo.publishing.PublishServiceImpl">
<property name="environmentFactory" ref="publishingObjectFactory" />
<property name="publishingEventHelper" ref="publishingEventHelper" />
</bean>
<bean id="publishingPackageSerializer" class="org.alfresco.repo.publishing.StandardPublishingPackageSerializer" />
<import resource="classpath:alfresco/youtube-publishing-context.xml" />
</beans> </beans>

View File

@@ -0,0 +1,32 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
<property name="models">
<list>
<value>alfresco/model/youtubePublishingModel.xml</value>
</list>
</property>
</bean>
<bean id="youtubePublishingHelper" class="org.alfresco.repo.publishing.youtube.YouTubePublishingHelper">
<property name="nodeService" ref="NodeService" />
</bean>
<bean id="publish_youtube" parent="action-executer" class="org.alfresco.repo.publishing.youtube.YouTubePublishAction">
<property name="nodeService" ref="NodeService" />
<property name="taggingService" ref="TaggingService" />
<property name="contentService" ref="ContentService" />
<property name="youTubeHelper" ref="youtubePublishingHelper" />
</bean>
<bean id="unpublish_youtube" parent="action-executer" class="org.alfresco.repo.publishing.youtube.YouTubeUnpublishAction">
<property name="nodeService" ref="NodeService" />
<property name="youTubeHelper" ref="youtubePublishingHelper" />
</bean>
<bean id="youtubeDeliveryChannelType" class="org.alfresco.repo.publishing.youtube.YouTubeChannelType" parent="baseChannelType" />
</beans>

Binary file not shown.

View File

@@ -29,6 +29,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.publishing.PublishingService;
import org.alfresco.service.cmr.publishing.channels.ChannelType; import org.alfresco.service.cmr.publishing.channels.ChannelType;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -54,8 +55,6 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional @Transactional
public abstract class AbstractPublishingIntegrationTest public abstract class AbstractPublishingIntegrationTest
{ {
protected static final String environmentName = "live";
protected static final String channelTypeId = "MockChannelType"; protected static final String channelTypeId = "MockChannelType";
@Resource(name="publishingObjectFactory") @Resource(name="publishingObjectFactory")
@@ -83,12 +82,12 @@ public abstract class AbstractPublishingIntegrationTest
this.siteId = GUID.generate(); this.siteId = GUID.generate();
siteService.createSite("test", siteId, siteService.createSite("test", siteId,
"Test site created by ChannelServiceImplIntegratedTest", "Site created by publishing test",
"Test site created by ChannelServiceImplIntegratedTest", "Site created by publishing test",
SiteVisibility.PUBLIC); SiteVisibility.PUBLIC);
this.docLib = siteService.createContainer(siteId, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null); this.docLib = siteService.createContainer(siteId, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null);
this.environment = (EnvironmentImpl) factory.createEnvironmentObject(siteId, environmentName); this.environment = (EnvironmentImpl) factory.createEnvironmentObject(siteId, PublishingService.LIVE_ENVIRONMENT_NAME);
this.queue = (PublishingQueueImpl) environment.getPublishingQueue(); this.queue = (PublishingQueueImpl) environment.getPublishingQueue();
} }
@@ -103,7 +102,6 @@ public abstract class AbstractPublishingIntegrationTest
ChannelType channelType = mock(ChannelType.class); ChannelType channelType = mock(ChannelType.class);
when(channelType.getId()).thenReturn(channelTypeId); when(channelType.getId()).thenReturn(channelTypeId);
when(channelType.getChannelNodeType()).thenReturn(TYPE_DELIVERY_CHANNEL); when(channelType.getChannelNodeType()).thenReturn(TYPE_DELIVERY_CHANNEL);
when(channelType.getContentRootNodeType()).thenReturn(ContentModel.TYPE_FOLDER);
return channelType; return channelType;
} }

View File

@@ -20,7 +20,6 @@
package org.alfresco.repo.publishing; package org.alfresco.repo.publishing;
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS; import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.repo.publishing.PublishingModel.ASPECT_CONTENT_ROOT;
import static org.alfresco.repo.publishing.PublishingModel.ASPECT_PUBLISHED; import static org.alfresco.repo.publishing.PublishingModel.ASPECT_PUBLISHED;
import static org.alfresco.repo.publishing.PublishingModel.ASSOC_SOURCE; import static org.alfresco.repo.publishing.PublishingModel.ASSOC_SOURCE;
import static org.alfresco.repo.publishing.PublishingModel.NAMESPACE; import static org.alfresco.repo.publishing.PublishingModel.NAMESPACE;
@@ -65,8 +64,6 @@ import org.alfresco.util.collections.Function;
*/ */
public class ChannelHelper public class ChannelHelper
{ {
private static final QName ROOT_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "root");
private NodeService nodeService; private NodeService nodeService;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private FileFolderService fileFolderService; private FileFolderService fileFolderService;
@@ -90,10 +87,6 @@ public class ChannelHelper
ChildAssociationRef channelAssoc = ChildAssociationRef channelAssoc =
nodeService.createNode(parent, ASSOC_CONTAINS, channelQName, channelNodeType, props); nodeService.createNode(parent, ASSOC_CONTAINS, channelQName, channelNodeType, props);
NodeRef channelNode = channelAssoc.getChildRef(); NodeRef channelNode = channelAssoc.getChildRef();
QName rootNodeType = channelType.getContentRootNodeType();
ChildAssociationRef rootAssoc = nodeService.createNode(channelNode, ASSOC_CONTAINS, ROOT_NAME, rootNodeType);
nodeService.addAspect(rootAssoc.getChildRef(), ASPECT_CONTENT_ROOT, null);
return channelNode; return channelNode;
} }
@@ -134,17 +127,6 @@ public class ChannelHelper
return getSingleValue(channelAssocs, true); return getSingleValue(channelAssocs, true);
} }
public NodeRef getChannelRootNode(NodeRef channel)
{
List<ChildAssociationRef> rootAssocs = nodeService.getChildAssocs(channel, ASSOC_CONTAINS, ROOT_NAME);
NodeRef root = getSingleValue(rootAssocs, true);
if(root ==null || nodeService.hasAspect(root, ASPECT_CONTENT_ROOT)==false)
{
throw new IllegalStateException("All channels must have a root folder!");
}
return root;
}
/** /**
* Given a noderef from the editorial space (e.g. the doclib), this returns the corresponding noderef in the specified channel and environment. * Given a noderef from the editorial space (e.g. the doclib), this returns the corresponding noderef in the specified channel and environment.
* @param source * @param source
@@ -169,12 +151,11 @@ public class ChannelHelper
List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(source, ASSOC_SOURCE, RegexQNamePattern.MATCH_ALL); List<ChildAssociationRef> parentAssocs = nodeService.getParentAssocs(source, ASSOC_SOURCE, RegexQNamePattern.MATCH_ALL);
if(parentAssocs != null) if(parentAssocs != null)
{ {
NodeRef root = getChannelRootNode(channel);
for (ChildAssociationRef parentAssoc : parentAssocs) for (ChildAssociationRef parentAssoc : parentAssocs)
{ {
NodeRef publishedNode = parentAssoc.getParentRef(); NodeRef publishedNode = parentAssoc.getParentRef();
NodeRef parent = nodeService.getPrimaryParent(publishedNode).getParentRef(); NodeRef parent = nodeService.getPrimaryParent(publishedNode).getParentRef();
if(root.equals(parent)) if(channel.equals(parent))
{ {
return publishedNode; return publishedNode;
} }

View File

@@ -70,7 +70,6 @@ public class ChannelServiceImplIntegratedTest extends AbstractPublishingIntegrat
super.setUp(); super.setUp();
when(mockedChannelType.getId()).thenReturn(channelTypeName); when(mockedChannelType.getId()).thenReturn(channelTypeName);
when(mockedChannelType.getChannelNodeType()).thenReturn(PublishingModel.TYPE_DELIVERY_CHANNEL); when(mockedChannelType.getChannelNodeType()).thenReturn(PublishingModel.TYPE_DELIVERY_CHANNEL);
when(mockedChannelType.getContentRootNodeType()).thenReturn(ContentModel.TYPE_FOLDER);
if (!channelTypeRegistered) if (!channelTypeRegistered)
{ {

View File

@@ -93,7 +93,6 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
@Autowired @Autowired
private PublishEventAction action; private PublishEventAction action;
private NodeRef root;
private NodeRef channel; private NodeRef channel;
private String eventId; private String eventId;
private ChannelType channelType; private ChannelType channelType;
@@ -115,7 +114,7 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel); NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel);
assertNotNull(publishedNode); assertNotNull(publishedNode);
assertTrue(nodeService.exists(publishedNode)); assertTrue(nodeService.exists(publishedNode));
assertEquals(root, nodeService.getPrimaryParent(publishedNode).getParentRef()); assertEquals(channel, nodeService.getPrimaryParent(publishedNode).getParentRef());
// Check published node type and aspects // Check published node type and aspects
assertEquals(TYPE_CONTENT, nodeService.getType(publishedNode)); assertEquals(TYPE_CONTENT, nodeService.getType(publishedNode));
@@ -410,8 +409,6 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
channelService.createChannel(siteId, channelTypeId, channelName, null); channelService.createChannel(siteId, channelTypeId, channelName, null);
this.channel = channelHelper.getChannelNodeForEnvironment(environment.getNodeRef(), channelName); this.channel = channelHelper.getChannelNodeForEnvironment(environment.getNodeRef(), channelName);
this.root = channelHelper.getChannelRootNode(channel);
assertNotNull(root);
} }
@Override @Override

View File

@@ -171,8 +171,7 @@ public class PublishingEventProcessor
ParameterCheck.mandatory("channel", channel); ParameterCheck.mandatory("channel", channel);
ParameterCheck.mandatory("snapshot", snapshot); ParameterCheck.mandatory("snapshot", snapshot);
NodeRef root = channelHelper.getChannelRootNode(channel); NodeRef publishedNode = createPublishedNode(channel, snapshot);
NodeRef publishedNode = createPublishedNode(root, snapshot);
addAspects(publishedNode, snapshot.getAspects()); addAspects(publishedNode, snapshot.getAspects());
NodeRef source = snapshot.getNodeRef(); NodeRef source = snapshot.getNodeRef();
channelHelper.createMapping(source, publishedNode); channelHelper.createMapping(source, publishedNode);

View File

@@ -112,7 +112,6 @@ public class PublishingIntegratedTest
channelTypeName = "MockedChannelType"; channelTypeName = "MockedChannelType";
when(mockedChannelType.getId()).thenReturn(channelTypeName); when(mockedChannelType.getId()).thenReturn(channelTypeName);
when(mockedChannelType.getChannelNodeType()).thenReturn(PublishingModel.TYPE_DELIVERY_CHANNEL); when(mockedChannelType.getChannelNodeType()).thenReturn(PublishingModel.TYPE_DELIVERY_CHANNEL);
when(mockedChannelType.getContentRootNodeType()).thenReturn(ContentModel.TYPE_FOLDER);
if (channelService.getChannelType(channelTypeName)== null) if (channelService.getChannelType(channelTypeName)== null)
{ {

View File

@@ -42,7 +42,6 @@ public interface PublishingModel
public static final QName TYPE_PUBLISHING_EVENT = QName.createQName(NAMESPACE, "PublishingEvent"); public static final QName TYPE_PUBLISHING_EVENT = QName.createQName(NAMESPACE, "PublishingEvent");
public static final QName TYPE_PUBLISHING_CONNECTION = QName.createQName(NAMESPACE, "Connection"); public static final QName TYPE_PUBLISHING_CONNECTION = QName.createQName(NAMESPACE, "Connection");
public static final QName ASPECT_CONTENT_ROOT = QName.createQName(NAMESPACE, "ContentRoot");
public static final QName ASPECT_CHANNEL_INFO= QName.createQName(NAMESPACE, "channelInfo"); public static final QName ASPECT_CHANNEL_INFO= QName.createQName(NAMESPACE, "channelInfo");
public static final QName ASPECT_PUBLISHED = QName.createQName(NAMESPACE, "published"); public static final QName ASPECT_PUBLISHED = QName.createQName(NAMESPACE, "published");

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of the Alfresco Web Quick Start module.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.alfresco.repo.publishing.test;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.service.cmr.publishing.channels.ChannelService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author Brian Remmington
*/
public class SiteType
{
/** Log */
private final static Log log = LogFactory.getLog(SiteType.class);
private PolicyComponent policyComponent;
private ChannelService channelService;
/**
* This is the list of collections that will be created automatically for
* any new section.
*/
/**
* Set the policy component
*
* @param policyComponent
* policy component
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
public void setChannelService(ChannelService channelService)
{
this.channelService = channelService;
}
/**
* Init method. Binds model behaviours to policies.
*/
public void init()
{
// Register the association behaviours
policyComponent.bindClassBehaviour(NodeServicePolicies.OnCreateNodePolicy.QNAME, SiteModel.TYPE_SITE,
new JavaBehaviour(this, "onCreateNode", NotificationFrequency.TRANSACTION_COMMIT));
}
/**
* On create node behaviour
*
* @param childAssocRef
* child association reference
*/
public void onCreateNode(ChildAssociationRef childAssocRef)
{
if (log.isDebugEnabled())
{
log.debug("onCreateNode " + childAssocRef);
}
String siteId = childAssocRef.getQName().getLocalName();
channelService.createChannel(siteId, "TestChannelType1", "Test Channel One", null);
channelService.createChannel(siteId, "TestChannelType2", "Test Channel Two", null);
channelService.createChannel(siteId, "TestChannelType3", "Test Channel Three", null);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.test;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.publishing.AbstractChannelType;
import org.alfresco.repo.publishing.PublishingModel;
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.namespace.QName;
public class TestChannelType1 extends AbstractChannelType
{
@Override
public boolean canPublish()
{
return true;
}
@Override
public boolean canPublishStatusUpdates()
{
return false;
}
@Override
public boolean canUnpublish()
{
return false;
}
@Override
public QName getChannelNodeType()
{
return PublishingModel.TYPE_DELIVERY_CHANNEL;
}
@Override
public String getId()
{
return "TestChannelType1";
}
@Override
public int getMaximumStatusLength()
{
return 0;
}
@Override
public NodeFilter getNodeFilter()
{
return null;
}
@Override
public NodeFinder getNodeFinder()
{
return null;
}
@Override
public String getNodeUrl(NodeRef node)
{
return node.getId();
}
@Override
public Set<QName> getSupportedContentTypes()
{
return null;
}
@Override
public Set<String> getSupportedMimetypes()
{
return null;
}
@Override
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void updateStatus(String status, Map<QName, Serializable> properties)
{
//Deliberately blank
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.test;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.publishing.AbstractChannelType;
import org.alfresco.repo.publishing.PublishingModel;
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.namespace.QName;
public class TestChannelType2 extends AbstractChannelType
{
@Override
public boolean canPublish()
{
return true;
}
@Override
public boolean canPublishStatusUpdates()
{
return true;
}
@Override
public boolean canUnpublish()
{
return false;
}
@Override
public QName getChannelNodeType()
{
return PublishingModel.TYPE_DELIVERY_CHANNEL;
}
@Override
public String getId()
{
return "TestChannelType2";
}
@Override
public int getMaximumStatusLength()
{
return 140;
}
@Override
public NodeFilter getNodeFilter()
{
return null;
}
@Override
public NodeFinder getNodeFinder()
{
return null;
}
@Override
public String getNodeUrl(NodeRef node)
{
return node.getId();
}
@Override
public Set<QName> getSupportedContentTypes()
{
return null;
}
@Override
public Set<String> getSupportedMimetypes()
{
return null;
}
@Override
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void updateStatus(String status, Map<QName, Serializable> properties)
{
//Deliberately blank
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.test;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.publishing.AbstractChannelType;
import org.alfresco.repo.publishing.PublishingModel;
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.namespace.QName;
public class TestChannelType3 extends AbstractChannelType
{
@Override
public boolean canPublish()
{
return false;
}
@Override
public boolean canPublishStatusUpdates()
{
return true;
}
@Override
public boolean canUnpublish()
{
return false;
}
@Override
public QName getChannelNodeType()
{
return PublishingModel.TYPE_DELIVERY_CHANNEL;
}
@Override
public String getId()
{
return "TestChannelType3";
}
@Override
public int getMaximumStatusLength()
{
return 200;
}
@Override
public NodeFilter getNodeFilter()
{
return null;
}
@Override
public NodeFinder getNodeFinder()
{
return null;
}
@Override
public String getNodeUrl(NodeRef node)
{
return node.getId();
}
@Override
public Set<QName> getSupportedContentTypes()
{
return null;
}
@Override
public Set<String> getSupportedMimetypes()
{
return null;
}
@Override
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
{
//Deliberately blank
}
@Override
public void updateStatus(String status, Map<QName, Serializable> properties)
{
//Deliberately blank
}
}

View File

@@ -0,0 +1,13 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean class="org.alfresco.repo.publishing.test.TestChannelType1" parent="baseChannelType" />
<bean class="org.alfresco.repo.publishing.test.TestChannelType2" parent="baseChannelType" />
<bean class="org.alfresco.repo.publishing.test.TestChannelType3" parent="baseChannelType" />
<bean class="org.alfresco.repo.publishing.test.SiteType" init-method="init">
<property name="policyComponent" ref="policyComponent" />
<property name="channelService" ref="channelService" />
</bean>
</beans>

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.publishing.AbstractChannelType;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
public class YouTubeChannelType extends AbstractChannelType
{
public final static String ID = "youtube";
private NodeService nodeService;
private ActionService actionService;
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
@Override
public boolean canPublish()
{
return true;
}
@Override
public boolean canPublishStatusUpdates()
{
return false;
}
@Override
public boolean canUnpublish()
{
return true;
}
@Override
public QName getChannelNodeType()
{
return YouTubePublishingModel.TYPE_DELIVERY_CHANNEL;
}
@Override
public String getId()
{
return ID;
}
@Override
public Set<QName> getSupportedContentTypes()
{
return Collections.emptySet();
}
@Override
public Set<String> getSupportedMimetypes()
{
return Collections.emptySet();
}
@Override
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
{
Action youtubePublishAction = actionService.createAction(YouTubePublishAction.NAME);
actionService.executeAction(youtubePublishAction, nodeToPublish);
}
@Override
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
{
Action youtubeUnpublishAction = actionService.createAction(YouTubeUnpublishAction.NAME);
actionService.executeAction(youtubeUnpublishAction, nodeToUnpublish);
}
@Override
public void updateStatus(String status, Map<QName, Serializable> properties)
{
throw new UnsupportedOperationException();
}
@Override
public String getNodeUrl(NodeRef node)
{
String url = null;
if (node != null && nodeService.exists(node) && nodeService.hasAspect(node, YouTubePublishingModel.ASPECT_ASSET))
{
url = (String)nodeService.getProperty(node, YouTubePublishingModel.PROP_PLAYER_URL);
}
return url;
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.gdata.client.media.ResumableGDataFileUploader;
import com.google.gdata.client.uploader.ProgressListener;
import com.google.gdata.client.uploader.ResumableHttpFileUploader;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.media.MediaFileSource;
import com.google.gdata.data.media.mediarss.MediaCategory;
import com.google.gdata.data.media.mediarss.MediaDescription;
import com.google.gdata.data.media.mediarss.MediaKeywords;
import com.google.gdata.data.media.mediarss.MediaTitle;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.YouTubeMediaGroup;
import com.google.gdata.data.youtube.YouTubeNamespace;
import com.google.gdata.util.ServiceException;
public class YouTubePublishAction extends ActionExecuterAbstractBase
{
private final static Log log = LogFactory.getLog(YouTubePublishAction.class);
public static final String NAME = "publish_youtube";
public static final String RESUMABLE_UPLOAD_URL = "http://uploads.gdata.youtube.com/resumable/feeds/api/users/default/uploads";
/** Time interval at which upload task will notify about the progress */
private static final int PROGRESS_UPDATE_INTERVAL = 1000;
/** Max size for each upload chunk */
private static final int DEFAULT_CHUNK_SIZE = 10000000;
private NodeService nodeService;
private ContentService contentService;
private TaggingService taggingService;
private YouTubePublishingHelper youTubeHelper;
public void setYouTubeHelper(YouTubePublishingHelper youTubeHelper)
{
this.youTubeHelper = youTubeHelper;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
YouTubeService service = youTubeHelper.getYouTubeServiceForNode(actionedUponNodeRef);
if (service != null)
{
try
{
uploadVideo(service, actionedUponNodeRef);
}
catch(Exception ex)
{
log.error("Failed to send asset to YouTube", ex);
throw new AlfrescoRuntimeException("exception.publishing.youtube.publishFailed", ex);
}
}
}
private void uploadVideo(YouTubeService service, NodeRef nodeRef) throws IOException, ServiceException,
InterruptedException
{
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
if (reader.exists())
{
File contentFile;
boolean deleteContentFileOnCompletion = false;
if (FileContentReader.class.isAssignableFrom(reader.getClass()))
{
//Grab the content straight from the content store if we can...
contentFile = ((FileContentReader)reader).getFile();
}
else
{
//...otherwise copy it to a temp file and use the copy...
File tempDir = TempFileProvider.getLongLifeTempDir("youtube");
contentFile = TempFileProvider.createTempFile("youtube", "", tempDir);
reader.getContent(contentFile);
deleteContentFileOnCompletion = true;
}
MediaFileSource ms = new MediaFileSource(contentFile, reader.getMimetype());
String videoName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
String videoTitle = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE);
if (videoTitle == null || videoTitle.length() == 0)
{
videoTitle = videoName;
}
String videoDescription = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION);
if (videoDescription == null || videoDescription.length() == 0)
{
videoDescription = videoTitle;
}
VideoEntry newEntry = new VideoEntry();
YouTubeMediaGroup mg = newEntry.getOrCreateMediaGroup();
mg.addCategory(new MediaCategory(YouTubeNamespace.CATEGORY_SCHEME, "Tech"));
mg.setTitle(new MediaTitle());
mg.getTitle().setPlainTextContent(videoTitle);
mg.setKeywords(new MediaKeywords());
List<String> tags = taggingService.getTags(nodeRef);
for (String tag : tags)
{
mg.getKeywords().addKeyword(tag);
}
mg.setDescription(new MediaDescription());
mg.getDescription().setPlainTextContent(videoDescription);
FileUploadProgressListener listener = new FileUploadProgressListener(videoName);
ResumableGDataFileUploader uploader = new ResumableGDataFileUploader.Builder(service, new URL(
RESUMABLE_UPLOAD_URL), ms, newEntry).title(videoTitle).trackProgress(listener,
PROGRESS_UPDATE_INTERVAL).chunkSize(DEFAULT_CHUNK_SIZE).build();
uploader.start();
while (!uploader.isDone())
{
Thread.sleep(PROGRESS_UPDATE_INTERVAL);
}
switch (uploader.getUploadState())
{
case COMPLETE:
VideoEntry entry = uploader.getResponse(VideoEntry.class);
String videoId = entry.getMediaGroup().getVideoId();
String contentUrl = entry.getMediaGroup().getContents().get(0).getUrl();
String playerUrl = entry.getMediaGroup().getPlayer().getUrl();
if (log.isDebugEnabled())
{
log.debug("Video content uploaded successfully: " + videoName);
log.debug("YouTube video id is " + videoId);
log.debug("YouTube content URL is " + contentUrl);
log.debug("YouTube video player URL is " + playerUrl);
}
nodeService.setProperty(nodeRef, YouTubePublishingModel.PROP_ASSET_ID, videoId);
nodeService.setProperty(nodeRef, YouTubePublishingModel.PROP_PLAYER_URL, playerUrl);
break;
case CLIENT_ERROR:
log.error("Video content failed to upload: " + videoName);
break;
default:
log.warn("Unknown upload state. Video content may not have uploaded: " + videoName + "("
+ uploader.getUploadState() + ") :" + nodeRef);
break;
}
if (deleteContentFileOnCompletion)
{
contentFile.delete();
}
}
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
}
/**
* A {@link ProgressListener} implementation to track upload progress. The
* listener can track multiple uploads at the same time.
*/
private class FileUploadProgressListener implements ProgressListener
{
String videoName;
public FileUploadProgressListener(String videoName)
{
this.videoName = videoName;
}
public synchronized void progressChanged(ResumableHttpFileUploader uploader)
{
switch (uploader.getUploadState())
{
case COMPLETE:
log.info("Upload Completed: " + videoName);
break;
case CLIENT_ERROR:
log.error("Upload Failed: " + videoName);
break;
case IN_PROGRESS:
log.info(videoName + String.format(" %3.0f", uploader.getProgress() * 100) + "%");
break;
case NOT_STARTED:
log.info("Upload Not Started: " + videoName);
break;
}
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.gdata.client.youtube.YouTubeService;
public class YouTubePublishingHelper
{
private static final Log log = LogFactory.getLog(YouTubePublishingHelper.class);
private NodeService nodeService;
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public YouTubeService getYouTubeServiceForNode(NodeRef publishNode)
{
YouTubeService service = null;
if (nodeService.exists(publishNode))
{
NodeRef parent = nodeService.getPrimaryParent(publishNode).getParentRef();
if (nodeService.hasAspect(parent, YouTubePublishingModel.ASPECT_DELIVERY_CHANNEL))
{
String youtubeUsername = (String) nodeService.getProperty(parent, YouTubePublishingModel.PROP_USERNAME);
String youtubePassword = (String) nodeService.getProperty(parent, YouTubePublishingModel.PROP_PASSWORD);
service = new YouTubeService("Alfresco Kickoff Demo",
"AI39si71pRNHkfExcTpqcZewDtI4GHWuPAXyRPL2Xq-RQUBWlE1bqn77ANXEL5lZUWFDz6ZlS_XWCw8hlr2BJY1TnC-EMs4e4g");
try
{
service.setUserCredentials(youtubeUsername, youtubePassword);
}
catch (Exception e)
{
service = null;
log.error("Failed to connect to YouTube", e);
}
}
}
return service;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import org.alfresco.service.namespace.QName;
/**
* @author Brian
*
*/
public interface YouTubePublishingModel
{
public static final String NAMESPACE = "http://www.alfresco.org/model/publishing/youtube/1.0";
public static final String PREFIX = "youtube";
public static final QName TYPE_DELIVERY_CHANNEL = QName.createQName(NAMESPACE, "DeliveryChannel");
public static final QName ASPECT_DELIVERY_CHANNEL = QName.createQName(NAMESPACE, "DeliveryChannelAspect");
public static final QName PROP_USERNAME = QName.createQName(NAMESPACE, "username");
public static final QName PROP_PASSWORD = QName.createQName(NAMESPACE, "password");
public static final QName ASPECT_ASSET = QName.createQName(NAMESPACE, "AssetAspect");
public static final QName PROP_ASSET_ID = QName.createQName(NAMESPACE, "assetId");
public static final QName PROP_PLAYER_URL = QName.createQName(NAMESPACE, "playerUrl");
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.publishing.EnvironmentImpl;
import org.alfresco.repo.publishing.PublishingQueueImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.publishing.channels.Channel;
import org.alfresco.service.cmr.publishing.channels.ChannelService;
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.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Brian
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:alfresco/application-context.xml" })
public class YouTubeTest
{
@javax.annotation.Resource(name = "ServiceRegistry")
protected ServiceRegistry serviceRegistry;
protected SiteService siteService;
protected FileFolderService fileFolderService;
protected NodeService nodeService;
protected String siteId;
protected PublishingQueueImpl queue;
protected EnvironmentImpl environment;
protected NodeRef docLib;
@javax.annotation.Resource(name = "channelService")
private ChannelService channelService;
private RetryingTransactionHelper transactionHelper;
@Before
public void setUp() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
siteService = serviceRegistry.getSiteService();
fileFolderService = serviceRegistry.getFileFolderService();
nodeService = serviceRegistry.getNodeService();
transactionHelper = serviceRegistry.getRetryingTransactionHelper();
siteId = GUID.generate();
siteService.createSite("test", siteId, "Site created by publishing test", "Site created by publishing test",
SiteVisibility.PUBLIC);
docLib = siteService.createContainer(siteId, SiteService.DOCUMENT_LIBRARY, ContentModel.TYPE_FOLDER, null);
}
@Test
public void testBlank()
{
}
//Note that this test isn't normally run, as it requires valid YouTube credentials.
//To run it, add the Test annotation and set the appropriate YouTube credentials where the
//text "YOUR_USER_NAME" and "YOUR_PASSWORD" appear.
public void testYouTubePublishAndUnpublishActions() throws Exception
{
final NodeRef vidNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
props.put(YouTubePublishingModel.PROP_USERNAME, "YOUR_USER_NAME");
props.put(YouTubePublishingModel.PROP_PASSWORD, "YOUR_PASSWORD");
Channel channel = channelService.createChannel(siteId, YouTubeChannelType.ID, "YouTubeChannel", props);
NodeRef channelNode = channel.getNodeRef();
Resource videoFile = new ClassPathResource("test/alfresco/TestVideoFile.MP4");
Map<QName, Serializable> vidProps = new HashMap<QName, Serializable>();
vidProps.put(ContentModel.PROP_NAME, "Test Video");
NodeRef vidNode = nodeService.createNode(channelNode, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testVideo"),
ContentModel.TYPE_CONTENT, vidProps).getChildRef();
ContentService contentService = serviceRegistry.getContentService();
ContentWriter writer = contentService.getWriter(vidNode, ContentModel.PROP_CONTENT, true);
writer.setMimetype("video/mpg");
writer.putContent(videoFile.getFile());
return vidNode;
}
});
transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
ActionService actionService = serviceRegistry.getActionService();
Action publishAction = actionService.createAction(YouTubePublishAction.NAME);
actionService.executeAction(publishAction, vidNode);
Map<QName, Serializable> props = nodeService.getProperties(vidNode);
Assert.assertTrue(nodeService.hasAspect(vidNode, YouTubePublishingModel.ASPECT_ASSET));
Assert.assertNotNull(props.get(YouTubePublishingModel.PROP_ASSET_ID));
Assert.assertNotNull(props.get(YouTubePublishingModel.PROP_PLAYER_URL));
System.out.println("YouTube video: " + props.get(YouTubePublishingModel.PROP_ASSET_ID));
Action unpublishAction = actionService.createAction(YouTubeUnpublishAction.NAME);
actionService.executeAction(unpublishAction, vidNode);
props = nodeService.getProperties(vidNode);
Assert.assertFalse(nodeService.hasAspect(vidNode, YouTubePublishingModel.ASPECT_ASSET));
Assert.assertNull(props.get(YouTubePublishingModel.PROP_ASSET_ID));
Assert.assertNull(props.get(YouTubePublishingModel.PROP_PLAYER_URL));
return null;
}
});
transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
nodeService.deleteNode(vidNode);
return null;
}
});
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.publishing.youtube;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
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.repository.NodeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.util.ServiceException;
public class YouTubeUnpublishAction extends ActionExecuterAbstractBase
{
private final static Log log = LogFactory.getLog(YouTubeUnpublishAction.class);
public static final String NAME = "unpublish_youtube";
private NodeService nodeService;
private YouTubePublishingHelper youTubeHelper;
public void setYouTubeHelper(YouTubePublishingHelper youTubeHelper)
{
this.youTubeHelper = youTubeHelper;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
YouTubeService service = youTubeHelper.getYouTubeServiceForNode(actionedUponNodeRef);
if (service != null)
{
try
{
removeVideo(service, actionedUponNodeRef);
}
catch(Exception ex)
{
log.error("Failed to remove asset from YouTube", ex);
throw new AlfrescoRuntimeException("exception.publishing.youtube.unpublishFailed", ex);
}
}
}
private void removeVideo(YouTubeService service, NodeRef nodeRef) throws MalformedURLException, IOException, ServiceException
{
String youtubeId = (String) nodeService.getProperty(nodeRef, YouTubePublishingModel.PROP_ASSET_ID);
if (youtubeId != null)
{
String videoEntryUrl = "https://gdata.youtube.com/feeds/api/users/default/uploads/" + youtubeId;
VideoEntry videoEntry = service.getEntry(new URL(videoEntryUrl), VideoEntry.class);
videoEntry.delete();
nodeService.removeAspect(nodeRef, YouTubePublishingModel.ASPECT_ASSET);
}
}
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
}
}

View File

@@ -36,7 +36,6 @@ public interface ChannelType
{ {
String getId(); String getId();
QName getChannelNodeType(); QName getChannelNodeType();
QName getContentRootNodeType();
NodeFinder getNodeFinder(); NodeFinder getNodeFinder();
NodeFilter getNodeFilter(); NodeFilter getNodeFilter();
void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties); void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties);