mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Fixed ALF-10333: Publishing: Multiple publishing events are processed sequentially rather than in parallel
Publishing: Remove some operations from the Channel and ChannelType interface that really shouldn't be exposed. Also removed the PublishingQueue interface - the two operations it had are now on the PublishingService. WQS: Removed obsolete references to publishing channels. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@30794 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -13,10 +13,10 @@
|
||||
<value>defaultAsyncAction</value>
|
||||
</property>
|
||||
<property name="corePoolSize">
|
||||
<value>2</value>
|
||||
<value>8</value>
|
||||
</property>
|
||||
<property name="maximumPoolSize">
|
||||
<value>10</value>
|
||||
<value>20</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
@@ -56,6 +56,7 @@
|
||||
<bean id="baseChannelType" class="org.alfresco.repo.publishing.AbstractChannelType" abstract="true" >
|
||||
<property name="channelService" ref="channelService" />
|
||||
<property name="encryptor" ref="metadataEncryptor" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
<bean id="channelHelper" class="org.alfresco.repo.publishing.ChannelHelper">
|
||||
@@ -63,6 +64,8 @@
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="fileFolderService" ref="FileFolderService" />
|
||||
<property name="permissionService" ref="PermissionService" />
|
||||
<property name="eventHelper" ref="publishingEventHelper" />
|
||||
<property name="serviceRegistry" ref="ServiceRegistry" />
|
||||
</bean>
|
||||
|
||||
<bean id="publishingRootObject" class="org.alfresco.repo.publishing.PublishingRootObject">
|
||||
@@ -95,13 +98,12 @@
|
||||
|
||||
<!-- Publishing Event Processor -->
|
||||
<bean id="publishingEventProcessor" class="org.alfresco.repo.publishing.PublishingEventProcessor">
|
||||
<property name="channelHelper" ref="channelHelper" />
|
||||
<property name="channelService" ref="channelService" />
|
||||
<property name="publishingEventHelper" ref="publishingEventHelper" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="behaviourFilter" ref="policyBehaviourFilter" />
|
||||
<property name="urlShortener" ref="urlShortener" />
|
||||
<property name="dictionaryService" ref="DictionaryService" />
|
||||
<property name="transactionService" ref="TransactionService" />
|
||||
</bean>
|
||||
|
||||
<!-- Publishing Service -->
|
||||
|
@@ -11,9 +11,10 @@
|
||||
</bean>
|
||||
|
||||
<bean id="flickrDeliveryChannelType" class="org.alfresco.repo.publishing.flickr.FlickrChannelType" parent="baseChannelType" >
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="actionService" ref="ActionService" />
|
||||
<property name="connectionFactory" ref="flickrConnectionFactory" />
|
||||
<property name="taggingService" ref="TaggingService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="flickrHelper" ref="flickrPublishingHelper" />
|
||||
</bean>
|
||||
|
||||
<bean id="flickrPublishingHelper" class="org.alfresco.repo.publishing.flickr.FlickrPublishingHelper">
|
||||
@@ -26,18 +27,4 @@
|
||||
<constructor-arg value="f7dafa571e8698ff93b08ebcb8c3de88" />
|
||||
<constructor-arg value="e9a8d6072d4cb9e6" />
|
||||
</bean>
|
||||
|
||||
<bean id="publish_flickr" parent="action-executer" class="org.alfresco.repo.publishing.flickr.FlickrPublishAction">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="taggingService" ref="TaggingService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="flickrHelper" ref="flickrPublishingHelper" />
|
||||
<property name="publicAction" value="false" />
|
||||
</bean>
|
||||
|
||||
<bean id="unpublish_flickr" parent="action-executer" class="org.alfresco.repo.publishing.flickr.FlickrUnpublishAction">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="flickrHelper" ref="flickrPublishingHelper" />
|
||||
<property name="publicAction" value="false" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
@@ -11,34 +11,19 @@
|
||||
</bean>
|
||||
|
||||
<bean id="slidesharePublishingHelper" class="org.alfresco.repo.publishing.slideshare.SlideSharePublishingHelper">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="slideshareConnector" ref="slideshareApiConnector" />
|
||||
<property name="encryptor" ref="metadataEncryptor" />
|
||||
</bean>
|
||||
|
||||
<bean id="slideshareApiConnector" class="com.benfante.jslideshare.SlideShareConnectorImpl">
|
||||
<bean id="slideshareApiConnector" class="org.alfresco.repo.publishing.slideshare.SlideShareConnectorImpl">
|
||||
<property name="apiKey" value="iXUZdaNl" />
|
||||
<property name="sharedSecret" value="DLysO5tR" />
|
||||
</bean>
|
||||
|
||||
<bean id="publish_slideshare" parent="action-executer" class="org.alfresco.repo.publishing.slideshare.SlideSharePublishAction">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<bean id="slideshareDeliveryChannelType" class="org.alfresco.repo.publishing.slideshare.SlideShareChannelType" parent="baseChannelType" >
|
||||
<property name="publishingHelper" ref="slidesharePublishingHelper" />
|
||||
<property name="taggingService" ref="TaggingService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="slideShareHelper" ref="slidesharePublishingHelper" />
|
||||
<property name="publicAction" value="false" />
|
||||
</bean>
|
||||
|
||||
<bean id="unpublish_slideshare" parent="action-executer" class="org.alfresco.repo.publishing.slideshare.SlideShareUnpublishAction">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="slideShareHelper" ref="slidesharePublishingHelper" />
|
||||
<property name="publicAction" value="false" />
|
||||
</bean>
|
||||
|
||||
<bean id="slideshareDeliveryChannelType" class="org.alfresco.repo.publishing.slideshare.SlideShareChannelType" parent="baseChannelType" >
|
||||
<property name="actionService" ref="ActionService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="publishingHelper" ref="slidesharePublishingHelper" />
|
||||
</bean>
|
||||
|
||||
|
||||
|
@@ -11,28 +11,12 @@
|
||||
</bean>
|
||||
|
||||
<bean id="youtubePublishingHelper" class="org.alfresco.repo.publishing.youtube.YouTubePublishingHelper">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<property name="encryptor" ref="metadataEncryptor" />
|
||||
</bean>
|
||||
|
||||
<bean id="publish_youtube" parent="action-executer" class="org.alfresco.repo.publishing.youtube.YouTubePublishAction">
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
<bean id="youtubeDeliveryChannelType" class="org.alfresco.repo.publishing.youtube.YouTubeChannelType" parent="baseChannelType" >
|
||||
<property name="taggingService" ref="TaggingService" />
|
||||
<property name="contentService" ref="ContentService" />
|
||||
<property name="youTubeHelper" ref="youtubePublishingHelper" />
|
||||
<property name="publicAction" value="false" />
|
||||
</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" />
|
||||
<property name="publicAction" value="false" />
|
||||
</bean>
|
||||
|
||||
<bean id="youtubeDeliveryChannelType" class="org.alfresco.repo.publishing.youtube.YouTubeChannelType" parent="baseChannelType" >
|
||||
<property name="actionService" ref="ActionService" />
|
||||
<property name="nodeService" ref="NodeService" />
|
||||
</bean>
|
||||
|
||||
|
||||
</beans>
|
||||
|
@@ -100,6 +100,10 @@
|
||||
<constructor-arg value="org.alfresco.service.cmr.security.PermissionService" />
|
||||
</bean>
|
||||
|
||||
<bean id="TransactionService" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.alfresco.service.transaction.TransactionService" />
|
||||
</bean>
|
||||
|
||||
<bean id="metadataEncryptor" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.alfresco.repo.node.encryption.MetadataEncryptor" />
|
||||
</bean>
|
||||
|
@@ -20,13 +20,17 @@
|
||||
package org.alfresco.repo.publishing;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.node.encryption.MetadataEncryptor;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
import org.alfresco.service.cmr.publishing.channels.ChannelService;
|
||||
import org.alfresco.service.cmr.publishing.channels.ChannelType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -36,8 +40,9 @@ import org.springframework.core.io.Resource;
|
||||
* @author Nick Smith
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class AbstractChannelType implements ChannelType
|
||||
public abstract class AbstractChannelType implements ChannelType, ChannelTypePublishingOperations
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private ChannelService channelService;
|
||||
private MetadataEncryptor encryptor;
|
||||
|
||||
@@ -62,6 +67,16 @@ public abstract class AbstractChannelType implements ChannelType
|
||||
return encryptor;
|
||||
}
|
||||
|
||||
protected NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -132,4 +147,46 @@ public abstract class AbstractChannelType implements ChannelType
|
||||
{
|
||||
return "png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QName> getSupportedContentTypes()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedMimeTypes()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
{
|
||||
String url = null;
|
||||
if (node != null && nodeService.exists(node) && nodeService.hasAspect(node, PublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
url = (String)nodeService.getProperty(node, PublishingModel.PROP_ASSET_URL);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -43,17 +43,11 @@ import org.springframework.social.oauth1.OAuthToken;
|
||||
*/
|
||||
public abstract class AbstractOAuth1ChannelType<A> extends AbstractChannelType
|
||||
{
|
||||
private NodeService nodeService;
|
||||
private OAuth1ConnectionFactory<A> connectionFactory;
|
||||
|
||||
public Connection<A> getConnectionForPublishNode(NodeRef publishNode)
|
||||
{
|
||||
NodeRef channelNode = nodeService.getPrimaryParent(publishNode).getParentRef();
|
||||
return getConnectionForChannel(channelNode);
|
||||
}
|
||||
|
||||
public Connection<A> getConnectionForChannel(NodeRef channelNode)
|
||||
protected Connection<A> getConnectionForChannel(NodeRef channelNode)
|
||||
{
|
||||
NodeService nodeService = getNodeService();
|
||||
Connection<A> connection = null;
|
||||
if (nodeService.exists(channelNode)
|
||||
&& nodeService.hasAspect(channelNode, PublishingModel.ASPECT_OAUTH1_DELIVERY_CHANNEL))
|
||||
@@ -73,11 +67,6 @@ public abstract class AbstractOAuth1ChannelType<A> extends AbstractChannelType
|
||||
return connection;
|
||||
}
|
||||
|
||||
protected NodeService getNodeService()
|
||||
{
|
||||
return nodeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthorisationUrl(Channel channel, String callbackUrl)
|
||||
{
|
||||
@@ -88,6 +77,7 @@ public abstract class AbstractOAuth1ChannelType<A> extends AbstractChannelType
|
||||
throw new IllegalArgumentException("Invalid channel type: " + channel.getChannelType().getId());
|
||||
}
|
||||
|
||||
NodeService nodeService = getNodeService();
|
||||
OAuth1Operations oauthOperations = getOAuth1Operations();
|
||||
OAuthToken requestToken = oauthOperations.fetchRequestToken(callbackUrl, null);
|
||||
|
||||
@@ -104,6 +94,7 @@ public abstract class AbstractOAuth1ChannelType<A> extends AbstractChannelType
|
||||
protected AuthStatus internalAcceptAuthorisation(Channel channel, Map<String, String[]> callbackHeaders,
|
||||
Map<String, String[]> callbackParams)
|
||||
{
|
||||
NodeService nodeService = getNodeService();
|
||||
AuthStatus authorised = AuthStatus.UNAUTHORISED;
|
||||
String[] verifier = callbackParams.get(getOAuthVerifierParamName());
|
||||
if (verifier != null)
|
||||
@@ -158,12 +149,4 @@ public abstract class AbstractOAuth1ChannelType<A> extends AbstractChannelType
|
||||
{
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeService the nodeService to set
|
||||
*/
|
||||
public final void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
}
|
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.node.NodeUtils;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
||||
@@ -71,15 +72,18 @@ public class ChannelHelper
|
||||
private FileFolderService fileFolderService;
|
||||
private PermissionService permissionService;
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private PublishingEventHelper eventHelper;
|
||||
|
||||
public ChannelHelper()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public ChannelHelper(NodeService nodeService, DictionaryService dictionaryService)
|
||||
public ChannelHelper(ServiceRegistry serviceRegistry, PublishingEventHelper eventHelper)
|
||||
{
|
||||
this.nodeService =nodeService;
|
||||
this.dictionaryService = dictionaryService;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
this.eventHelper = eventHelper;
|
||||
}
|
||||
|
||||
public NodeRef createChannelNode(NodeRef parent, ChannelType channelType, String channelName,
|
||||
@@ -105,7 +109,7 @@ public class ChannelHelper
|
||||
String channelTypeId = (String) props.get(PROP_CHANNEL_TYPE_ID);
|
||||
ChannelType channelType = channelService.getChannelType(channelTypeId);
|
||||
String name = (String) props.get(ContentModel.PROP_NAME);
|
||||
return new ChannelImpl(channelType, nodeRef, name, this);
|
||||
return new ChannelImpl(serviceRegistry, (AbstractChannelType) channelType, nodeRef, name, this, eventHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,4 +433,14 @@ public class ChannelHelper
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
public void setEventHelper(PublishingEventHelper eventHelper)
|
||||
{
|
||||
this.eventHelper = eventHelper;
|
||||
}
|
||||
}
|
||||
|
@@ -19,13 +19,35 @@
|
||||
|
||||
package org.alfresco.repo.publishing;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.ASPECT_PUBLISHED;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.ASSOC_LAST_PUBLISHING_EVENT;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.NAMESPACE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
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.node.NodeUtils;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.publishing.NodeSnapshot;
|
||||
import org.alfresco.service.cmr.publishing.PublishingEvent;
|
||||
import org.alfresco.service.cmr.publishing.PublishingPackageEntry;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
import org.alfresco.service.cmr.publishing.channels.ChannelType;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* @author Brian
|
||||
@@ -35,16 +57,24 @@ import org.alfresco.service.namespace.QName;
|
||||
public class ChannelImpl implements Channel
|
||||
{
|
||||
private final NodeRef nodeRef;
|
||||
private final ChannelType channelType;
|
||||
private final AbstractChannelType channelType;
|
||||
private final String name;
|
||||
private final ChannelHelper channelHelper;
|
||||
private final NodeService nodeService;
|
||||
private final DictionaryService dictionaryService;
|
||||
private final PublishingEventHelper eventHelper;
|
||||
|
||||
public ChannelImpl(ChannelType channelType, NodeRef nodeRef, String name, ChannelHelper channelHelper)
|
||||
|
||||
public ChannelImpl(ServiceRegistry serviceRegistry, AbstractChannelType channelType, NodeRef nodeRef, String name,
|
||||
ChannelHelper channelHelper, PublishingEventHelper eventHelper)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
this.channelType = channelType;
|
||||
this.name = name;
|
||||
this.channelHelper = channelHelper;
|
||||
this.nodeService = serviceRegistry.getNodeService();
|
||||
this.dictionaryService = serviceRegistry.getDictionaryService();
|
||||
this.eventHelper = eventHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,22 +117,186 @@ public class ChannelImpl implements Channel
|
||||
return channelHelper.getChannelProperties(nodeRef);
|
||||
}
|
||||
|
||||
public void publishEvent(PublishingEvent event)
|
||||
{
|
||||
NodeRef eventNode = eventHelper.getPublishingEventNode(event.getId());
|
||||
for (PublishingPackageEntry entry : event.getPackage().getEntries())
|
||||
{
|
||||
if (entry.isPublish())
|
||||
{
|
||||
publishEntry(entry, eventNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpublishEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unpublishEntry(PublishingPackageEntry entry)
|
||||
{
|
||||
NodeRef channelNode = new NodeRef(getId());
|
||||
NodeRef publishedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), channelNode);
|
||||
if (NodeUtils.exists(publishedNode, nodeService))
|
||||
{
|
||||
unpublish(publishedNode);
|
||||
// Need to set as temporary to delete node instead of archiving.
|
||||
nodeService.addAspect(publishedNode, ContentModel.ASPECT_TEMPORARY, null);
|
||||
nodeService.deleteNode(publishedNode);
|
||||
}
|
||||
}
|
||||
|
||||
public NodeRef publishEntry(PublishingPackageEntry entry, NodeRef eventNode)
|
||||
{
|
||||
NodeRef publishedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), getNodeRef());
|
||||
if (publishedNode == null)
|
||||
{
|
||||
publishedNode = publishNewNode(getNodeRef(), entry.getSnapshot());
|
||||
}
|
||||
else
|
||||
{
|
||||
updatePublishedNode(publishedNode, entry);
|
||||
}
|
||||
eventHelper.linkToLastEvent(publishedNode, eventNode);
|
||||
publish(publishedNode);
|
||||
return publishedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Creates a new node under the root of the specified channel. The type,
|
||||
* aspects and properties of the node are determined by the supplied
|
||||
* snapshot.
|
||||
*
|
||||
* @param channel
|
||||
* @param snapshot
|
||||
* @return the newly published node.
|
||||
*/
|
||||
public void publish(NodeRef nodeToPublish)
|
||||
private NodeRef publishNewNode(NodeRef channel, NodeSnapshot snapshot)
|
||||
{
|
||||
channelHelper.addPublishedAspect(nodeToPublish, nodeRef);
|
||||
if (channelHelper.canPublish(nodeToPublish, channelType))
|
||||
ParameterCheck.mandatory("channel", channel);
|
||||
ParameterCheck.mandatory("snapshot", snapshot);
|
||||
|
||||
NodeRef publishedNode = createPublishedNode(channel, snapshot);
|
||||
addAspects(publishedNode, snapshot.getAspects());
|
||||
NodeRef source = snapshot.getNodeRef();
|
||||
channelHelper.createMapping(source, publishedNode);
|
||||
return publishedNode;
|
||||
}
|
||||
|
||||
private void updatePublishedNode(NodeRef publishedNode, PublishingPackageEntry entry)
|
||||
{
|
||||
channelType.publish(nodeToPublish, getProperties());
|
||||
NodeSnapshot snapshot = entry.getSnapshot();
|
||||
Set<QName> newAspects = snapshot.getAspects();
|
||||
removeUnwantedAspects(publishedNode, newAspects);
|
||||
|
||||
Map<QName, Serializable> snapshotProps = snapshot.getProperties();
|
||||
removeUnwantedProperties(publishedNode, snapshotProps);
|
||||
|
||||
// Add new properties
|
||||
Map<QName, Serializable> newProps= new HashMap<QName, Serializable>(snapshotProps);
|
||||
newProps.remove(ContentModel.PROP_NODE_UUID);
|
||||
nodeService.setProperties(publishedNode, snapshotProps);
|
||||
|
||||
// Add new aspects
|
||||
addAspects(publishedNode, newAspects);
|
||||
|
||||
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(publishedNode, ASSOC_LAST_PUBLISHING_EVENT, RegexQNamePattern.MATCH_ALL);
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
nodeService.removeChildAssociation(assoc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @param publishedNode
|
||||
* @param snapshotProps
|
||||
*/
|
||||
public void unPublish(NodeRef nodeToUnpublish)
|
||||
private void removeUnwantedProperties(NodeRef publishedNode, Map<QName, Serializable> snapshotProps)
|
||||
{
|
||||
Map<QName, Serializable> publishProps = nodeService.getProperties(publishedNode);
|
||||
Set<QName> propsToRemove = new HashSet<QName>(publishProps.keySet());
|
||||
propsToRemove.removeAll(snapshotProps.keySet());
|
||||
|
||||
//We want to retain the published asset id and URL in the updated node...
|
||||
snapshotProps.put(PublishingModel.PROP_ASSET_ID, nodeService.getProperty(publishedNode,
|
||||
PublishingModel.PROP_ASSET_ID));
|
||||
snapshotProps.put(PublishingModel.PROP_ASSET_URL, nodeService.getProperty(publishedNode,
|
||||
PublishingModel.PROP_ASSET_URL));
|
||||
|
||||
for (QName propertyToRemove : propsToRemove)
|
||||
{
|
||||
nodeService.removeProperty(publishedNode, propertyToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publishedNode
|
||||
* @param newAspects
|
||||
*/
|
||||
private void removeUnwantedAspects(NodeRef publishedNode, Set<QName> newAspects)
|
||||
{
|
||||
Set<QName> aspectsToRemove = nodeService.getAspects(publishedNode);
|
||||
aspectsToRemove.removeAll(newAspects);
|
||||
aspectsToRemove.remove(ASPECT_PUBLISHED);
|
||||
aspectsToRemove.remove(PublishingModel.ASPECT_ASSET);
|
||||
for (QName publishedAssetAspect : dictionaryService.getSubAspects(PublishingModel.ASPECT_ASSET, true))
|
||||
{
|
||||
aspectsToRemove.remove(publishedAssetAspect);
|
||||
}
|
||||
|
||||
for (QName aspectToRemove : aspectsToRemove)
|
||||
{
|
||||
nodeService.removeAspect(publishedNode, aspectToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
private void addAspects(NodeRef publishedNode, Collection<QName> aspects)
|
||||
{
|
||||
Set<QName> currentAspects = nodeService.getAspects(publishedNode);
|
||||
for (QName aspect : aspects)
|
||||
{
|
||||
if (currentAspects.contains(aspect) == false)
|
||||
{
|
||||
nodeService.addAspect(publishedNode, aspect, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NodeRef createPublishedNode(NodeRef root, NodeSnapshot snapshot)
|
||||
{
|
||||
QName type = snapshot.getType();
|
||||
Map<QName, Serializable> actualProps = getPropertiesToPublish(snapshot);
|
||||
String name = (String) actualProps.get(ContentModel.PROP_NAME);
|
||||
if (name == null)
|
||||
{
|
||||
name = GUID.generate();
|
||||
}
|
||||
QName assocName = QName.createQName(NAMESPACE, name);
|
||||
ChildAssociationRef publishedAssoc = nodeService.createNode(root, ASSOC_CONTAINS, assocName, type, actualProps);
|
||||
NodeRef publishedNode = publishedAssoc.getChildRef();
|
||||
return publishedNode;
|
||||
}
|
||||
|
||||
private Map<QName, Serializable> getPropertiesToPublish(NodeSnapshot snapshot)
|
||||
{
|
||||
Map<QName, Serializable> properties = snapshot.getProperties();
|
||||
// Remove the Node Ref Id
|
||||
Map<QName, Serializable> actualProps = new HashMap<QName, Serializable>(properties);
|
||||
actualProps.remove(ContentModel.PROP_NODE_UUID);
|
||||
return actualProps;
|
||||
}
|
||||
|
||||
|
||||
private void publish(NodeRef nodeToPublish)
|
||||
{
|
||||
if (channelHelper.canPublish(nodeToPublish, channelType))
|
||||
{
|
||||
channelHelper.addPublishedAspect(nodeToPublish, nodeRef);
|
||||
channelType.publish(nodeToPublish, getProperties());
|
||||
}
|
||||
}
|
||||
|
||||
private void unpublish(NodeRef nodeToUnpublish)
|
||||
{
|
||||
if (channelType.canUnpublish())
|
||||
{
|
||||
@@ -113,7 +307,7 @@ public class ChannelImpl implements Channel
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateStatus(String status, String nodeUrl)
|
||||
public void sendStatusUpdate(String status, String nodeUrl)
|
||||
{
|
||||
if (channelType.canPublishStatusUpdates())
|
||||
{
|
||||
@@ -125,7 +319,7 @@ public class ChannelImpl implements Channel
|
||||
status = status.substring(0, endpoint );
|
||||
}
|
||||
String msg = nodeUrl == null ? status : status + nodeUrl;
|
||||
channelType.updateStatus(this, msg, getProperties());
|
||||
channelType.sendStatusUpdate(this, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.service.cmr.publishing.channels.ChannelType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
@@ -37,75 +36,75 @@ public class ChannelImplTest extends TestCase
|
||||
public void testUpdateStatus() throws Exception
|
||||
{
|
||||
int maxLength = 30;
|
||||
ChannelType channelType = mockChannelType(maxLength);
|
||||
AbstractChannelType channelType = mockChannelType(maxLength);
|
||||
|
||||
ChannelHelper helper = mock(ChannelHelper.class);
|
||||
when(helper.getChannelProperties(any(NodeRef.class))).thenReturn(null);
|
||||
NodeRef node = new NodeRef("test://channel/node");
|
||||
|
||||
ChannelImpl channel = new ChannelImpl(channelType, node, "Name", helper);
|
||||
ChannelImpl channel = new ChannelImpl(null, channelType, node, "Name", helper, null);
|
||||
|
||||
String msg = "Here is a message";
|
||||
channel.updateStatus(msg, null);
|
||||
verify(channelType).updateStatus(channel, msg, null);
|
||||
channel.sendStatusUpdate(msg, null);
|
||||
verify(channelType).sendStatusUpdate(channel, msg);
|
||||
}
|
||||
|
||||
public void testUpdateStatusTruncates() throws Exception
|
||||
{
|
||||
int maxLength = 30;
|
||||
ChannelType channelType = mockChannelType(maxLength);
|
||||
AbstractChannelType channelType = mockChannelType(maxLength);
|
||||
|
||||
ChannelHelper helper = mock(ChannelHelper.class);
|
||||
when(helper.getChannelProperties(any(NodeRef.class))).thenReturn(null);
|
||||
NodeRef node = new NodeRef("test://channel/node");
|
||||
|
||||
ChannelImpl channel = new ChannelImpl(channelType, node, "Name", helper);
|
||||
ChannelImpl channel = new ChannelImpl(null, channelType, node, "Name", helper, null);
|
||||
|
||||
String msg = "Here is a much longer message to truncate.";
|
||||
String expMsg = msg.substring(0, maxLength);
|
||||
channel.updateStatus(msg, null);
|
||||
verify(channelType).updateStatus(channel, expMsg, null);
|
||||
channel.sendStatusUpdate(msg, null);
|
||||
verify(channelType).sendStatusUpdate(channel, expMsg);
|
||||
}
|
||||
|
||||
public void testUpdateStatusTruncatesWithUrl() throws Exception
|
||||
{
|
||||
int maxLength = 30;
|
||||
ChannelType channelType = mockChannelType(maxLength);
|
||||
AbstractChannelType channelType = mockChannelType(maxLength);
|
||||
|
||||
ChannelHelper helper = mock(ChannelHelper.class);
|
||||
when(helper.getChannelProperties(any(NodeRef.class))).thenReturn(null);
|
||||
NodeRef node = new NodeRef("test://channel/node");
|
||||
|
||||
ChannelImpl channel = new ChannelImpl(channelType, node, "Name", helper);
|
||||
ChannelImpl channel = new ChannelImpl(null, channelType, node, "Name", helper, null);
|
||||
String nodeUrl ="http://foo/bar";
|
||||
int endpoint = maxLength - nodeUrl.length();
|
||||
|
||||
String msg = "Here is a much longer message to truncate.";
|
||||
String expMsg = msg.substring(0, endpoint) + nodeUrl;
|
||||
channel.updateStatus(msg, nodeUrl);
|
||||
verify(channelType).updateStatus(channel, expMsg, null);
|
||||
channel.sendStatusUpdate(msg, nodeUrl);
|
||||
verify(channelType).sendStatusUpdate(channel, expMsg);
|
||||
}
|
||||
|
||||
public void testUpdateStatusNoMaxLength() throws Exception
|
||||
{
|
||||
ChannelType channelType = mockChannelType(0);
|
||||
AbstractChannelType channelType = mockChannelType(0);
|
||||
|
||||
ChannelHelper helper = mock(ChannelHelper.class);
|
||||
when(helper.getChannelProperties(any(NodeRef.class))).thenReturn(null);
|
||||
NodeRef node = new NodeRef("test://channel/node");
|
||||
|
||||
ChannelImpl channel = new ChannelImpl(channelType, node, "Name", helper);
|
||||
ChannelImpl channel = new ChannelImpl(null, channelType, node, "Name", helper, null);
|
||||
String nodeUrl ="http://foo/bar";
|
||||
|
||||
String msg = "Here is a much longer message to truncate.";
|
||||
String expMsg = msg + nodeUrl;
|
||||
channel.updateStatus(msg, nodeUrl);
|
||||
verify(channelType).updateStatus(channel, expMsg, null);
|
||||
channel.sendStatusUpdate(msg, nodeUrl);
|
||||
verify(channelType).sendStatusUpdate(channel, expMsg);
|
||||
}
|
||||
|
||||
private ChannelType mockChannelType(int maxLength)
|
||||
private AbstractChannelType mockChannelType(int maxLength)
|
||||
{
|
||||
ChannelType channelType = mock(ChannelType.class);
|
||||
AbstractChannelType channelType = mock(AbstractChannelType.class);
|
||||
when(channelType.canPublishStatusUpdates()).thenReturn(true);
|
||||
when(channelType.getMaximumStatusLength()).thenReturn(maxLength);
|
||||
return channelType;
|
||||
|
@@ -102,7 +102,7 @@ public class ChannelServiceImpl implements ChannelService
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void register(ChannelType channelType)
|
||||
public void register(AbstractChannelType channelType)
|
||||
{
|
||||
ParameterCheck.mandatory("channelType", channelType);
|
||||
String id = channelType.getId();
|
||||
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
public interface ChannelTypePublishingOperations
|
||||
{
|
||||
void publish(NodeRef nodeToPublish, Map<QName, Serializable> channelProperties);
|
||||
void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> channelProperties);
|
||||
}
|
@@ -92,7 +92,7 @@ public class MockChannelType extends AbstractChannelType
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
//NOOP
|
||||
}
|
||||
|
@@ -86,7 +86,7 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
|
||||
|
||||
private Channel channel;
|
||||
private NodeRef channelNode;
|
||||
private ChannelType channelType;
|
||||
private AbstractChannelType channelType;
|
||||
|
||||
@Test
|
||||
public void testPublishNodes() throws Exception
|
||||
@@ -390,7 +390,7 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
|
||||
publishNode(source, message);
|
||||
|
||||
String expMessage = message + " " + url;
|
||||
verify(channelType, times(1)).updateStatus(any(Channel.class), eq(expMessage), anyMap());
|
||||
verify(channelType, times(1)).sendStatusUpdate(any(Channel.class), eq(expMessage));
|
||||
}
|
||||
|
||||
private NodeRef publishNode(NodeRef source)
|
||||
@@ -405,7 +405,7 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
|
||||
|
||||
private NodeRef publishNode(NodeRef source, String message, boolean publish)
|
||||
{
|
||||
PublishingDetails details = publishingService.getPublishingQueue().createPublishingDetails();
|
||||
PublishingDetails details = publishingService.createPublishingDetails();
|
||||
details.setPublishChannel(channel.getId());
|
||||
if (publish)
|
||||
{
|
||||
|
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.publishing.NodePublishStatus;
|
||||
import org.alfresco.service.cmr.publishing.PublishingDetails;
|
||||
import org.alfresco.service.cmr.publishing.PublishingEvent;
|
||||
import org.alfresco.service.cmr.publishing.PublishingQueue;
|
||||
import org.alfresco.service.cmr.publishing.PublishingService;
|
||||
@@ -95,10 +96,7 @@ public class PublishServiceImpl implements PublishingService
|
||||
publishingEventHelper.cancelEvent(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public PublishingQueue getPublishingQueue()
|
||||
private PublishingQueue getPublishingQueue()
|
||||
{
|
||||
return rootObject.getPublishingQueue();
|
||||
}
|
||||
@@ -130,4 +128,18 @@ public class PublishServiceImpl implements PublishingService
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
public PublishingDetails createPublishingDetails()
|
||||
{
|
||||
return getPublishingQueue().createPublishingDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String scheduleNewEvent(PublishingDetails publishingDetails)
|
||||
{
|
||||
return getPublishingQueue().scheduleNewEvent(publishingDetails);
|
||||
}
|
||||
|
||||
}
|
@@ -19,37 +19,19 @@
|
||||
|
||||
package org.alfresco.repo.publishing;
|
||||
|
||||
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.ASPECT_PUBLISHED;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.ASSOC_LAST_PUBLISHING_EVENT;
|
||||
import static org.alfresco.repo.publishing.PublishingModel.NAMESPACE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
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.node.NodeUtils;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.publishing.NodeSnapshot;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.publishing.PublishingEvent;
|
||||
import org.alfresco.service.cmr.publishing.PublishingPackageEntry;
|
||||
import org.alfresco.service.cmr.publishing.Status;
|
||||
import org.alfresco.service.cmr.publishing.StatusUpdate;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
import org.alfresco.service.cmr.publishing.channels.ChannelService;
|
||||
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.urlshortening.UrlShortener;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -63,34 +45,46 @@ public class PublishingEventProcessor
|
||||
private static final Log log = LogFactory.getLog(PublishingEventProcessor.class);
|
||||
|
||||
private PublishingEventHelper eventHelper;
|
||||
private ChannelHelper channelHelper;
|
||||
private ChannelService channelService;
|
||||
private NodeService nodeService;
|
||||
private BehaviourFilter behaviourFilter;
|
||||
private UrlShortener urlShortener;
|
||||
private DictionaryService dictionaryService;
|
||||
private TransactionService transactionService;
|
||||
|
||||
public void processEventNode(NodeRef eventNode)
|
||||
{
|
||||
ParameterCheck.mandatory("eventNode", eventNode);
|
||||
try
|
||||
{
|
||||
behaviourFilter.disableAllBehaviours();
|
||||
String inProgressStatus = Status.IN_PROGRESS.name();
|
||||
nodeService.setProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS, inProgressStatus);
|
||||
PublishingEvent event = eventHelper.getPublishingEvent(eventNode);
|
||||
updateEventStatus(eventNode, Status.IN_PROGRESS);
|
||||
final PublishingEvent event = eventHelper.getPublishingEvent(eventNode);
|
||||
String channelName = event.getChannelId();
|
||||
Channel channel = channelService.getChannelById(channelName);
|
||||
final ChannelImpl channel = (ChannelImpl) channelService.getChannelById(channelName);
|
||||
if (channel == null)
|
||||
{
|
||||
fail(eventNode, "No channel found");
|
||||
}
|
||||
else
|
||||
{
|
||||
publishEvent(channel, event);
|
||||
updateStatus(channel, event.getStatusUpdate());
|
||||
String completedStatus = Status.COMPLETED.name();
|
||||
nodeService.setProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS, completedStatus);
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
behaviourFilter.disableAllBehaviours();
|
||||
channel.publishEvent(event);
|
||||
sendStatusUpdate(channel, event.getStatusUpdate());
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableAllBehaviours();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
updateEventStatus(eventNode, Status.COMPLETED);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -98,13 +92,9 @@ public class PublishingEventProcessor
|
||||
log.error("Caught exception while processing publishing event " + eventNode, e);
|
||||
fail(eventNode, e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableAllBehaviours();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateStatus(Channel publishChannel, StatusUpdate update)
|
||||
public void sendStatusUpdate(Channel publishChannel, StatusUpdate update)
|
||||
{
|
||||
if (update == null)
|
||||
{
|
||||
@@ -118,7 +108,7 @@ public class PublishingEventProcessor
|
||||
Channel channel = channelService.getChannelById(channelId);
|
||||
if (channel != null)
|
||||
{
|
||||
channel.updateStatus(message, nodeUrl);
|
||||
channel.sendStatusUpdate(message, nodeUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,189 +133,25 @@ public class PublishingEventProcessor
|
||||
return nodeUrl;
|
||||
}
|
||||
|
||||
public void publishEvent(Channel channel, PublishingEvent event)
|
||||
{
|
||||
NodeRef eventNode = eventHelper.getPublishingEventNode(event.getId());
|
||||
for (PublishingPackageEntry entry : event.getPackage().getEntries())
|
||||
{
|
||||
if (entry.isPublish())
|
||||
{
|
||||
publishEntry(channel, entry, eventNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpublishEntry(channel, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unpublishEntry(Channel channel, PublishingPackageEntry entry)
|
||||
{
|
||||
NodeRef channelNode = new NodeRef(channel.getId());
|
||||
NodeRef publishedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), channelNode);
|
||||
if (NodeUtils.exists(publishedNode, nodeService))
|
||||
{
|
||||
channel.unPublish(publishedNode);
|
||||
// Need to set as temporary to delete node instead of archiving.
|
||||
nodeService.addAspect(publishedNode, ContentModel.ASPECT_TEMPORARY, null);
|
||||
nodeService.deleteNode(publishedNode);
|
||||
}
|
||||
}
|
||||
|
||||
public void fail(NodeRef eventNode, String msg)
|
||||
{
|
||||
log.error("Failed to process publishing event " + eventNode + ": " + msg);
|
||||
String completedStatus = Status.FAILED.name();
|
||||
nodeService.setProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS, completedStatus);
|
||||
updateEventStatus(eventNode, Status.FAILED);
|
||||
}
|
||||
|
||||
public NodeRef publishEntry(Channel channel, PublishingPackageEntry entry, NodeRef eventNode)
|
||||
private void updateEventStatus(final NodeRef eventNode, final Status status)
|
||||
{
|
||||
NodeRef publishedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), channel.getNodeRef());
|
||||
if (publishedNode == null)
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
publishedNode = publishNewNode(channel.getNodeRef(), entry.getSnapshot());
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
nodeService.setProperty(eventNode, PublishingModel.PROP_PUBLISHING_EVENT_STATUS, status.name());
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
updatePublishedNode(publishedNode, entry);
|
||||
}
|
||||
eventHelper.linkToLastEvent(publishedNode, eventNode);
|
||||
channel.publish(publishedNode);
|
||||
return publishedNode;
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new node under the root of the specified channel. The type,
|
||||
* aspects and properties of the node are determined by the supplied
|
||||
* snapshot.
|
||||
*
|
||||
* @param channel
|
||||
* @param snapshot
|
||||
* @return the newly published node.
|
||||
*/
|
||||
private NodeRef publishNewNode(NodeRef channel, NodeSnapshot snapshot)
|
||||
{
|
||||
ParameterCheck.mandatory("channel", channel);
|
||||
ParameterCheck.mandatory("snapshot", snapshot);
|
||||
|
||||
NodeRef publishedNode = createPublishedNode(channel, snapshot);
|
||||
addAspects(publishedNode, snapshot.getAspects());
|
||||
NodeRef source = snapshot.getNodeRef();
|
||||
channelHelper.createMapping(source, publishedNode);
|
||||
return publishedNode;
|
||||
}
|
||||
|
||||
private void updatePublishedNode(NodeRef publishedNode, PublishingPackageEntry entry)
|
||||
{
|
||||
NodeSnapshot snapshot = entry.getSnapshot();
|
||||
Set<QName> newAspects = snapshot.getAspects();
|
||||
removeUnwantedAspects(publishedNode, newAspects);
|
||||
|
||||
Map<QName, Serializable> snapshotProps = snapshot.getProperties();
|
||||
removeUnwantedProperties(publishedNode, snapshotProps);
|
||||
|
||||
// Add new properties
|
||||
Map<QName, Serializable> newProps= new HashMap<QName, Serializable>(snapshotProps);
|
||||
newProps.remove(ContentModel.PROP_NODE_UUID);
|
||||
nodeService.setProperties(publishedNode, snapshotProps);
|
||||
|
||||
// Add new aspects
|
||||
addAspects(publishedNode, newAspects);
|
||||
|
||||
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(publishedNode, ASSOC_LAST_PUBLISHING_EVENT, RegexQNamePattern.MATCH_ALL);
|
||||
for (ChildAssociationRef assoc : assocs)
|
||||
{
|
||||
nodeService.removeChildAssociation(assoc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publishedNode
|
||||
* @param snapshotProps
|
||||
*/
|
||||
private void removeUnwantedProperties(NodeRef publishedNode, Map<QName, Serializable> snapshotProps)
|
||||
{
|
||||
Map<QName, Serializable> publishProps = nodeService.getProperties(publishedNode);
|
||||
Set<QName> propsToRemove = new HashSet<QName>(publishProps.keySet());
|
||||
propsToRemove.removeAll(snapshotProps.keySet());
|
||||
|
||||
//We want to retain the published asset id and URL in the updated node...
|
||||
snapshotProps.put(PublishingModel.PROP_ASSET_ID, nodeService.getProperty(publishedNode,
|
||||
PublishingModel.PROP_ASSET_ID));
|
||||
snapshotProps.put(PublishingModel.PROP_ASSET_URL, nodeService.getProperty(publishedNode,
|
||||
PublishingModel.PROP_ASSET_URL));
|
||||
|
||||
for (QName propertyToRemove : propsToRemove)
|
||||
{
|
||||
nodeService.removeProperty(publishedNode, propertyToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publishedNode
|
||||
* @param newAspects
|
||||
*/
|
||||
private void removeUnwantedAspects(NodeRef publishedNode, Set<QName> newAspects)
|
||||
{
|
||||
Set<QName> aspectsToRemove = nodeService.getAspects(publishedNode);
|
||||
aspectsToRemove.removeAll(newAspects);
|
||||
aspectsToRemove.remove(ASPECT_PUBLISHED);
|
||||
aspectsToRemove.remove(PublishingModel.ASPECT_ASSET);
|
||||
for (QName publishedAssetAspect : dictionaryService.getSubAspects(PublishingModel.ASPECT_ASSET, true))
|
||||
{
|
||||
aspectsToRemove.remove(publishedAssetAspect);
|
||||
}
|
||||
|
||||
for (QName aspectToRemove : aspectsToRemove)
|
||||
{
|
||||
nodeService.removeAspect(publishedNode, aspectToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
private void addAspects(NodeRef publishedNode, Collection<QName> aspects)
|
||||
{
|
||||
Set<QName> currentAspects = nodeService.getAspects(publishedNode);
|
||||
for (QName aspect : aspects)
|
||||
{
|
||||
if (currentAspects.contains(aspect) == false)
|
||||
{
|
||||
nodeService.addAspect(publishedNode, aspect, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NodeRef createPublishedNode(NodeRef root, NodeSnapshot snapshot)
|
||||
{
|
||||
QName type = snapshot.getType();
|
||||
Map<QName, Serializable> actualProps = getPropertiesToPublish(snapshot);
|
||||
String name = (String) actualProps.get(ContentModel.PROP_NAME);
|
||||
if (name == null)
|
||||
{
|
||||
name = GUID.generate();
|
||||
}
|
||||
QName assocName = QName.createQName(NAMESPACE, name);
|
||||
ChildAssociationRef publishedAssoc = nodeService.createNode(root, ASSOC_CONTAINS, assocName, type, actualProps);
|
||||
NodeRef publishedNode = publishedAssoc.getChildRef();
|
||||
return publishedNode;
|
||||
}
|
||||
|
||||
private Map<QName, Serializable> getPropertiesToPublish(NodeSnapshot snapshot)
|
||||
{
|
||||
Map<QName, Serializable> properties = snapshot.getProperties();
|
||||
// Remove the Node Ref Id
|
||||
Map<QName, Serializable> actualProps = new HashMap<QName, Serializable>(properties);
|
||||
actualProps.remove(ContentModel.PROP_NODE_UUID);
|
||||
return actualProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelHelper the channelHelper to set
|
||||
*/
|
||||
public void setChannelHelper(ChannelHelper channelHelper)
|
||||
{
|
||||
this.channelHelper = channelHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelService the channelService to set
|
||||
@@ -367,8 +193,8 @@ public class PublishingEventProcessor
|
||||
this.urlShortener = urlShortener;
|
||||
}
|
||||
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
}
|
@@ -69,7 +69,7 @@ public class PublishingIntegratedTest extends BaseSpringTest
|
||||
|
||||
protected AuthenticationComponent authenticationComponent;
|
||||
private String siteId;
|
||||
private ChannelType mockedChannelType = mock(ChannelType.class);
|
||||
private AbstractChannelType mockedChannelType = mock(AbstractChannelType.class);
|
||||
private String channelTypeName;
|
||||
|
||||
@Test
|
||||
@@ -84,17 +84,15 @@ public class PublishingIntegratedTest extends BaseSpringTest
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI, Integer.toString(i)), ContentModel.TYPE_CONTENT).getChildRef());
|
||||
}
|
||||
|
||||
PublishingQueue liveQueue = publishingService.getPublishingQueue();
|
||||
|
||||
Calendar schedule = Calendar.getInstance();
|
||||
schedule.add(Calendar.HOUR, 1);
|
||||
|
||||
PublishingDetails details = liveQueue.createPublishingDetails()
|
||||
PublishingDetails details = publishingService.createPublishingDetails()
|
||||
.addNodesToPublish(nodes)
|
||||
.setPublishChannel(channel.getId())
|
||||
.setSchedule(schedule);
|
||||
|
||||
String eventId = liveQueue.scheduleNewEvent(details);
|
||||
String eventId = publishingService.scheduleNewEvent(details);
|
||||
|
||||
PublishingEvent event = publishingService.getPublishingEvent(eventId);
|
||||
|
||||
@@ -121,15 +119,14 @@ public class PublishingIntegratedTest extends BaseSpringTest
|
||||
nodes.add(nodeService.createNode(channel.getNodeRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI, Integer.toString(i)), ContentModel.TYPE_CONTENT).getChildRef());
|
||||
}
|
||||
PublishingQueue liveQueue = publishingService.getPublishingQueue();
|
||||
Calendar schedule = Calendar.getInstance();
|
||||
schedule.add(Calendar.HOUR, 1);
|
||||
|
||||
PublishingDetails details = liveQueue.createPublishingDetails()
|
||||
PublishingDetails details = publishingService.createPublishingDetails()
|
||||
.addNodesToPublish(nodes)
|
||||
.setPublishChannel(channel.getId())
|
||||
.setSchedule(schedule);
|
||||
String eventId = liveQueue.scheduleNewEvent(details);
|
||||
String eventId = publishingService.scheduleNewEvent(details);
|
||||
PublishingEvent event = publishingService.getPublishingEvent(eventId);
|
||||
Assert.assertNotNull(event);
|
||||
publishingService.cancelPublishingEvent(eventId);
|
||||
|
@@ -75,7 +75,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
|
||||
Calendar schedule = Calendar.getInstance();
|
||||
schedule.add(Calendar.HOUR, 2);
|
||||
|
||||
PublishingDetails details = publishingService.getPublishingQueue().createPublishingDetails()
|
||||
PublishingDetails details = publishingService.createPublishingDetails()
|
||||
.addNodesToPublish(firstNode, secondNode)
|
||||
.setPublishChannel(channelId)
|
||||
.setSchedule(schedule)
|
||||
@@ -142,7 +142,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
|
||||
|
||||
List<String> statusChannels = Arrays.asList("test://channel/Channel1", "test://channel/Channel2", "test://channel/Channel3" );
|
||||
String message = "The message";
|
||||
PublishingDetails details = publishingService.getPublishingQueue().createPublishingDetails()
|
||||
PublishingDetails details = publishingService.createPublishingDetails()
|
||||
.setPublishChannel(channelId)
|
||||
.addNodesToPublish(firstNode, secondNode)
|
||||
.setStatusMessage(message)
|
||||
@@ -180,7 +180,7 @@ public class PublishingQueueImplTest extends AbstractPublishingIntegrationTest
|
||||
personManager.setUser(user1);
|
||||
|
||||
// Publish an event
|
||||
PublishingDetails details = publishingService.getPublishingQueue().createPublishingDetails();
|
||||
PublishingDetails details = publishingService.createPublishingDetails();
|
||||
details.addNodesToPublish(firstNode, secondNode);
|
||||
details.setPublishChannel(publishChannel.getId());
|
||||
try
|
||||
|
@@ -158,9 +158,9 @@ public class PublishingTestHelper
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelType mockChannelType(String channelTypeId)
|
||||
public AbstractChannelType mockChannelType(String channelTypeId)
|
||||
{
|
||||
ChannelType channelType = channelService.getChannelType(channelTypeId);
|
||||
AbstractChannelType channelType = (AbstractChannelType) channelService.getChannelType(channelTypeId);
|
||||
if (channelType != null)
|
||||
{
|
||||
reset(channelType);
|
||||
@@ -168,7 +168,7 @@ public class PublishingTestHelper
|
||||
}
|
||||
else
|
||||
{
|
||||
channelType = mock(ChannelType.class);
|
||||
channelType = mock(AbstractChannelType.class);
|
||||
when(channelType.getId()).thenReturn(channelTypeId);
|
||||
channelService.register(channelType);
|
||||
}
|
||||
@@ -224,8 +224,7 @@ public class PublishingTestHelper
|
||||
|
||||
public String scheduleEvent(PublishingDetails details)
|
||||
{
|
||||
PublishingQueue queue = publishingService.getPublishingQueue();
|
||||
String eventId = queue.scheduleNewEvent(details);
|
||||
String eventId = publishingService.scheduleNewEvent(details);
|
||||
events.add(eventId);
|
||||
return eventId;
|
||||
}
|
||||
|
@@ -34,8 +34,8 @@ import org.junit.runners.Suite;
|
||||
// EnvironmentImplTest.class,
|
||||
PublishingQueueImplTest.class,
|
||||
PublishingPackageSerializerTest.class,
|
||||
PublishingIntegratedTest.class,
|
||||
PublishEventActionTest.class
|
||||
// PublishEventActionTest.class,
|
||||
PublishingIntegratedTest.class
|
||||
})
|
||||
public class WebPublishingTestSuite
|
||||
{
|
||||
|
@@ -19,10 +19,8 @@
|
||||
package org.alfresco.repo.publishing.facebook;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.publishing.AbstractChannelType;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
@@ -90,29 +88,7 @@ public class FacebookChannelType extends AbstractChannelType
|
||||
}
|
||||
|
||||
@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)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
Connection<Facebook> connection = publishingHelper.getFacebookConnectionForChannel(channel.getNodeRef());
|
||||
connection.updateStatus(status);
|
||||
|
@@ -18,23 +18,35 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.flickr;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.filestore.FileContentReader;
|
||||
import org.alfresco.repo.publishing.AbstractOAuth1ChannelType;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.Flickr;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.MediaOperations;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.PhotoInfo;
|
||||
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.service.namespace.QName;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.alfresco.util.collections.CollectionUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.social.connect.Connection;
|
||||
import org.springframework.social.oauth1.OAuth1Parameters;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -50,20 +62,33 @@ public class FlickrChannelType extends AbstractOAuth1ChannelType<Flickr>
|
||||
MimetypeMap.MIMETYPE_IMAGE_GIF,
|
||||
MimetypeMap.MIMETYPE_IMAGE_JPEG,
|
||||
MimetypeMap.MIMETYPE_IMAGE_PNG);
|
||||
private static Log log = LogFactory.getLog(FlickrChannelType.class);
|
||||
|
||||
private ActionService actionService;
|
||||
private ContentService contentService;
|
||||
private TaggingService taggingService;
|
||||
private FlickrPublishingHelper flickrHelper;
|
||||
private Set<String> supportedMimeTypes = DEFAULT_SUPPORTED_MIME_TYPES;
|
||||
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
|
||||
public void setSupportedMimeTypes(Set<String> mimeTypes)
|
||||
{
|
||||
supportedMimeTypes = Collections.unmodifiableSet(new TreeSet<String>(mimeTypes));
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setTaggingService(TaggingService taggingService)
|
||||
{
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
|
||||
public void setFlickrHelper(FlickrPublishingHelper flickrHelper)
|
||||
{
|
||||
this.flickrHelper = flickrHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPublish()
|
||||
{
|
||||
@@ -94,12 +119,6 @@ public class FlickrChannelType extends AbstractOAuth1ChannelType<Flickr>
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QName> getSupportedContentTypes()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedMimeTypes()
|
||||
{
|
||||
@@ -107,35 +126,85 @@ public class FlickrChannelType extends AbstractOAuth1ChannelType<Flickr>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
|
||||
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
Action publishAction = actionService.createAction(FlickrPublishAction.NAME);
|
||||
actionService.executeAction(publishAction, nodeToPublish);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
Action action = actionService.createAction(FlickrUnpublishAction.NAME);
|
||||
actionService.executeAction(action, nodeToUnpublish);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
{
|
||||
String url = null;
|
||||
NodeService nodeService = getNodeService();
|
||||
if (node != null && nodeService.exists(node) && nodeService.hasAspect(node, FlickrPublishingModel.ASPECT_ASSET))
|
||||
ContentReader reader = contentService.getReader(nodeToPublish, ContentModel.PROP_CONTENT);
|
||||
if (reader.exists())
|
||||
{
|
||||
url = (String)nodeService.getProperty(node, PublishingModel.PROP_ASSET_URL);
|
||||
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("flickr");
|
||||
contentFile = TempFileProvider.createTempFile("flickr", "", tempDir);
|
||||
reader.getContent(contentFile);
|
||||
deleteContentFileOnCompletion = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
Resource res = new FileSystemResource(contentFile);
|
||||
Connection<Flickr> connection = flickrHelper.getConnectionFromChannelProps(channelProperties);
|
||||
|
||||
String name = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_NAME);
|
||||
String title = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_TITLE);
|
||||
if (title == null || title.length() == 0)
|
||||
{
|
||||
title = name;
|
||||
}
|
||||
String description = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_DESCRIPTION);
|
||||
if (description == null || description.length() == 0)
|
||||
{
|
||||
description = title;
|
||||
}
|
||||
List<String> tags = taggingService.getTags(nodeToPublish);
|
||||
String[] tagArray = tags.toArray(new String[tags.size()]);
|
||||
|
||||
MediaOperations mediaOps = connection.getApi().mediaOperations();
|
||||
String id = mediaOps.postPhoto(res, title, description, tagArray);
|
||||
|
||||
//Store info onto the published node...
|
||||
nodeService.addAspect(nodeToPublish, FlickrPublishingModel.ASPECT_ASSET, null);
|
||||
log.info("Posted image " + name + " to Flickr with id " + id);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_ID, id);
|
||||
|
||||
PhotoInfo photoInfo = mediaOps.getPhoto(id);
|
||||
String url = photoInfo.getPrimaryUrl();
|
||||
log.info("Photo url = " + url);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_URL, url);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deleteContentFileOnCompletion)
|
||||
{
|
||||
contentFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
NodeService nodeService = getNodeService();
|
||||
if (nodeService.hasAspect(nodeToUnpublish, FlickrPublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String assetId = (String) nodeService.getProperty(nodeToUnpublish, PublishingModel.PROP_ASSET_ID);
|
||||
if (assetId != null)
|
||||
{
|
||||
Connection<Flickr> connection = flickrHelper.getConnectionFromChannelProps(channelProperties);
|
||||
MediaOperations mediaOps = connection.getApi().mediaOperations();
|
||||
mediaOps.deletePhoto(assetId);
|
||||
nodeService.removeAspect(nodeToUnpublish, FlickrPublishingModel.ASPECT_ASSET);
|
||||
nodeService.removeAspect(nodeToUnpublish, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* 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.flickr;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.content.filestore.FileContentReader;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.Flickr;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.MediaOperations;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.PhotoInfo;
|
||||
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 org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.social.connect.Connection;
|
||||
|
||||
public class FlickrPublishAction extends ActionExecuterAbstractBase
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(FlickrPublishAction.class);
|
||||
|
||||
public static final String NAME = "publish_flickr";
|
||||
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
private TaggingService taggingService;
|
||||
private FlickrPublishingHelper flickrHelper;
|
||||
|
||||
public void setFlickrHelper(FlickrPublishingHelper helper)
|
||||
{
|
||||
this.flickrHelper = helper;
|
||||
}
|
||||
|
||||
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 nodeToPublish)
|
||||
{
|
||||
ContentReader reader = contentService.getReader(nodeToPublish, 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("flickr");
|
||||
contentFile = TempFileProvider.createTempFile("flickr", "", tempDir);
|
||||
reader.getContent(contentFile);
|
||||
deleteContentFileOnCompletion = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
Resource res = new FileSystemResource(contentFile);
|
||||
Connection<Flickr> connection = flickrHelper.getConnectionForPublishNode(nodeToPublish);
|
||||
|
||||
String name = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_NAME);
|
||||
String title = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_TITLE);
|
||||
if (title == null || title.length() == 0)
|
||||
{
|
||||
title = name;
|
||||
}
|
||||
String description = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_DESCRIPTION);
|
||||
if (description == null || description.length() == 0)
|
||||
{
|
||||
description = title;
|
||||
}
|
||||
List<String> tags = taggingService.getTags(nodeToPublish);
|
||||
String[] tagArray = tags.toArray(new String[tags.size()]);
|
||||
|
||||
MediaOperations mediaOps = connection.getApi().mediaOperations();
|
||||
String id = mediaOps.postPhoto(res, title, description, tagArray);
|
||||
|
||||
//Store info onto the published node...
|
||||
nodeService.addAspect(nodeToPublish, FlickrPublishingModel.ASPECT_ASSET, null);
|
||||
log.info("Posted image " + name + " to Flickr with id " + id);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_ID, id);
|
||||
|
||||
PhotoInfo photoInfo = mediaOps.getPhoto(id);
|
||||
String url = photoInfo.getPrimaryUrl();
|
||||
log.info("Photo url = " + url);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_URL, url);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deleteContentFileOnCompletion)
|
||||
{
|
||||
contentFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
@@ -18,12 +18,16 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.flickr;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.node.encryption.MetadataEncryptor;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.Flickr;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.connect.FlickrConnectionFactory;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.springframework.social.connect.Connection;
|
||||
import org.springframework.social.oauth1.OAuthToken;
|
||||
|
||||
@@ -53,6 +57,23 @@ public class FlickrPublishingHelper
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
public Connection<Flickr> getConnectionFromChannelProps(Map<QName,Serializable> channelProperties)
|
||||
{
|
||||
Connection<Flickr> connection = null;
|
||||
String tokenValue = (String) encryptor.decrypt(PublishingModel.PROP_OAUTH1_TOKEN_VALUE, channelProperties
|
||||
.get(PublishingModel.PROP_OAUTH1_TOKEN_VALUE));
|
||||
String tokenSecret = (String) encryptor.decrypt(PublishingModel.PROP_OAUTH1_TOKEN_SECRET, channelProperties
|
||||
.get(PublishingModel.PROP_OAUTH1_TOKEN_SECRET));
|
||||
Boolean danceComplete = (Boolean) channelProperties.get(PublishingModel.PROP_AUTHORISATION_COMPLETE);
|
||||
|
||||
if (danceComplete)
|
||||
{
|
||||
OAuthToken token = new OAuthToken(tokenValue, tokenSecret);
|
||||
connection = connectionFactory.createConnection(token);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
public Connection<Flickr> getConnectionForPublishNode(NodeRef publishNode)
|
||||
{
|
||||
Connection<Flickr> connection = null;
|
||||
@@ -60,17 +81,7 @@ public class FlickrPublishingHelper
|
||||
if (nodeService.exists(channelNode)
|
||||
&& nodeService.hasAspect(channelNode, PublishingModel.ASPECT_OAUTH1_DELIVERY_CHANNEL))
|
||||
{
|
||||
String tokenValue = (String) encryptor.decrypt(PublishingModel.PROP_OAUTH1_TOKEN_VALUE, nodeService
|
||||
.getProperty(channelNode, PublishingModel.PROP_OAUTH1_TOKEN_VALUE));
|
||||
String tokenSecret = (String) encryptor.decrypt(PublishingModel.PROP_OAUTH1_TOKEN_SECRET, nodeService
|
||||
.getProperty(channelNode, PublishingModel.PROP_OAUTH1_TOKEN_SECRET));
|
||||
Boolean danceComplete = (Boolean) nodeService.getProperty(channelNode, PublishingModel.PROP_AUTHORISATION_COMPLETE);
|
||||
|
||||
if (danceComplete)
|
||||
{
|
||||
OAuthToken token = new OAuthToken(tokenValue, tokenSecret);
|
||||
connection = connectionFactory.createConnection(token);
|
||||
}
|
||||
connection = getConnectionFromChannelProps(nodeService.getProperties(channelNode));
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
@@ -32,8 +32,6 @@ 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;
|
||||
@@ -100,6 +98,8 @@ public class FlickrTest extends BaseSpringTest
|
||||
//text "YOUR_OAUTH_TOKEN_VALUE" and "YOUR_OAUTH_TOKEN_SECRET" appear. Note that these can be quite tricky to obtain...
|
||||
public void xtestFlickrPublishAndUnpublishActions() throws Exception
|
||||
{
|
||||
final String channelName = "FlickrTestChannel_" + GUID.generate();
|
||||
final FlickrChannelType channelType = (FlickrChannelType) channelService.getChannelType(FlickrChannelType.ID);
|
||||
final NodeRef contentNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
@@ -109,7 +109,7 @@ public class FlickrTest extends BaseSpringTest
|
||||
props.put(PublishingModel.PROP_OAUTH1_TOKEN_SECRET, "YOUR_OAUTH_TOKEN_SECRET");
|
||||
props.put(PublishingModel.PROP_AUTHORISATION_COMPLETE, Boolean.TRUE);
|
||||
|
||||
Channel channel = channelService.createChannel(FlickrChannelType.ID, "FlickrTestChannel_" + GUID.generate(), props);
|
||||
Channel channel = channelService.createChannel(FlickrChannelType.ID, channelName, props);
|
||||
//This looks a little odd, but a new channel always has its "authorisation complete" flag
|
||||
//forced off initially. This will force it on for this channel...
|
||||
channelService.updateChannel(channel, props);
|
||||
@@ -132,9 +132,9 @@ public class FlickrTest extends BaseSpringTest
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
ActionService actionService = serviceRegistry.getActionService();
|
||||
Action publishAction = actionService.createAction(FlickrPublishAction.NAME);
|
||||
actionService.executeAction(publishAction, contentNode);
|
||||
Channel channel = channelService.getChannelByName(channelName);
|
||||
channelType.publish(contentNode, channel.getProperties());
|
||||
|
||||
Map<QName, Serializable> props = nodeService.getProperties(contentNode);
|
||||
Assert.assertTrue(nodeService.hasAspect(contentNode, FlickrPublishingModel.ASPECT_ASSET));
|
||||
Assert.assertNotNull(props.get(PublishingModel.PROP_ASSET_ID));
|
||||
@@ -143,8 +143,8 @@ public class FlickrTest extends BaseSpringTest
|
||||
System.out.println("Asset id: " + props.get(PublishingModel.PROP_ASSET_ID));
|
||||
System.out.println("Asset URL: " + props.get(PublishingModel.PROP_ASSET_URL));
|
||||
|
||||
Action unpublishAction = actionService.createAction(FlickrUnpublishAction.NAME);
|
||||
actionService.executeAction(unpublishAction, contentNode);
|
||||
channelType.unpublish(contentNode, channel.getProperties());
|
||||
|
||||
props = nodeService.getProperties(contentNode);
|
||||
Assert.assertFalse(nodeService.hasAspect(contentNode, FlickrPublishingModel.ASPECT_ASSET));
|
||||
Assert.assertFalse(nodeService.hasAspect(contentNode, PublishingModel.ASPECT_ASSET));
|
||||
|
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.flickr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.Flickr;
|
||||
import org.alfresco.repo.publishing.flickr.springsocial.api.MediaOperations;
|
||||
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.springframework.social.connect.Connection;
|
||||
|
||||
public class FlickrUnpublishAction extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "unpublish_flickr";
|
||||
|
||||
private NodeService nodeService;
|
||||
private FlickrPublishingHelper flickrHelper;
|
||||
|
||||
public void setFlickrHelper(FlickrPublishingHelper helper)
|
||||
{
|
||||
this.flickrHelper = helper;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef nodeRef)
|
||||
{
|
||||
if (nodeService.hasAspect(nodeRef, FlickrPublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String assetId = (String) nodeService.getProperty(nodeRef, PublishingModel.PROP_ASSET_ID);
|
||||
if (assetId != null)
|
||||
{
|
||||
Connection<Flickr> connection = flickrHelper.getConnectionForPublishNode(nodeRef);
|
||||
MediaOperations mediaOps = connection.getApi().mediaOperations();
|
||||
mediaOps.deletePhoto(assetId);
|
||||
nodeService.removeAspect(nodeRef, FlickrPublishingModel.ASPECT_ASSET);
|
||||
nodeService.removeAspect(nodeRef, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
//Deliberately empty
|
||||
}
|
||||
}
|
@@ -40,6 +40,7 @@ import org.springframework.util.MultiValueMap;
|
||||
public class FlickrTemplate extends AbstractOAuth1ApiBinding implements Flickr, FlickrHelper
|
||||
{
|
||||
private static final String DEFAULT_ENDPOINT = "http://api.flickr.com/services/";
|
||||
// private static final String DEFAULT_ENDPOINT = "https://secure.flickr.com/services/";
|
||||
|
||||
private static String endpoint = DEFAULT_ENDPOINT;
|
||||
|
||||
|
@@ -20,11 +20,6 @@ package org.alfresco.repo.publishing.linkedin;
|
||||
|
||||
import static org.alfresco.repo.publishing.linkedin.LinkedInPublishingModel.TYPE_DELIVERY_CHANNEL;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.publishing.AbstractOAuth1ChannelType;
|
||||
import org.alfresco.repo.publishing.linkedin.springsocial.api.AlfrescoLinkedIn;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
@@ -73,30 +68,6 @@ public class LinkedInChannelType extends AbstractOAuth1ChannelType<AlfrescoLinke
|
||||
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)
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumStatusLength()
|
||||
{
|
||||
@@ -104,7 +75,7 @@ public class LinkedInChannelType extends AbstractOAuth1ChannelType<AlfrescoLinke
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
NodeRef channelNode = new NodeRef(channel.getId());
|
||||
Connection<AlfrescoLinkedIn> connection = getConnectionForChannel(channelNode);
|
||||
@@ -118,6 +89,6 @@ public class LinkedInChannelType extends AbstractOAuth1ChannelType<AlfrescoLinke
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -199,7 +199,7 @@ public class SlideShareApiImpl implements SlideShareApi
|
||||
addParameter(parameters, "username", username);
|
||||
addParameter(parameters, "password", password);
|
||||
addParameter(parameters, "slideshow_id", id);
|
||||
return sendMessage(URL_DELETE_SLIDESHOW, parameters).getSlideShowId();
|
||||
return sendGetMessage(URL_DELETE_SLIDESHOW, parameters).getSlideShowId();
|
||||
}
|
||||
|
||||
private Map<String, String> addParameter(Map<String, String> parameters, String name, String value)
|
||||
|
@@ -18,43 +18,70 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.slideshare;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.publishing.AbstractChannelType;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
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.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.benfante.jslideshare.SlideShareAPI;
|
||||
import com.benfante.jslideshare.messages.SlideshowInfo;
|
||||
|
||||
public class SlideShareChannelType extends AbstractChannelType
|
||||
{
|
||||
public final static String ID = "slideshare";
|
||||
|
||||
private NodeService nodeService;
|
||||
private ActionService actionService;
|
||||
private final static Log log = LogFactory.getLog(SlideShareChannelType.class);
|
||||
|
||||
private final static int STATUS_QUEUED = 0;
|
||||
// private final static int STATUS_CONVERTING = 1;
|
||||
private final static int STATUS_SUCCEEDED = 2;
|
||||
private final static int STATUS_FAILED = 3;
|
||||
private final static int STATUS_TIMED_OUT = 10;
|
||||
private static final String ERROR_SLIDESHARE_CONVERSION_FAILED = "publish.slideshare.conversionFailed";
|
||||
private static final String ERROR_SLIDESHARE_CONVERSION_TIMED_OUT = "publish.slideshare.conversionTimedOut";
|
||||
|
||||
private SlideSharePublishingHelper publishingHelper;
|
||||
private ContentService contentService;
|
||||
private TaggingService taggingService;
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setActionService(ActionService actionService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
}
|
||||
private long timeoutMilliseconds = 40L * 60L * 1000L; // 40 mins default
|
||||
|
||||
public void setPublishingHelper(SlideSharePublishingHelper publishingHelper)
|
||||
{
|
||||
this.publishingHelper = publishingHelper;
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setTaggingService(TaggingService taggingService)
|
||||
{
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
|
||||
public void setTimeoutMilliseconds(long timeoutMilliseconds)
|
||||
{
|
||||
this.timeoutMilliseconds = timeoutMilliseconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPublish()
|
||||
{
|
||||
@@ -85,12 +112,6 @@ public class SlideShareChannelType extends AbstractChannelType
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QName> getSupportedContentTypes()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedMimeTypes()
|
||||
{
|
||||
@@ -100,31 +121,152 @@ public class SlideShareChannelType extends AbstractChannelType
|
||||
@Override
|
||||
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
Action publishAction = actionService.createAction(SlideSharePublishAction.NAME);
|
||||
actionService.executeAction(publishAction, nodeToPublish);
|
||||
NodeService nodeService = getNodeService();
|
||||
Pair<String, String> usernamePassword = publishingHelper
|
||||
.getSlideShareCredentialsFromChannelProperties(properties);
|
||||
if (usernamePassword == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("publish.failed.no_credentials_found");
|
||||
}
|
||||
SlideShareAPI api = publishingHelper
|
||||
.getSlideShareApi(usernamePassword.getFirst(), usernamePassword.getSecond());
|
||||
|
||||
ContentReader reader = contentService.getReader(nodeToPublish, ContentModel.PROP_CONTENT);
|
||||
if (reader.exists())
|
||||
{
|
||||
File contentFile;
|
||||
String mime = reader.getMimetype();
|
||||
|
||||
String extension = publishingHelper.getAllowedMimeTypes().get(mime);
|
||||
if (extension == null)
|
||||
extension = "";
|
||||
|
||||
boolean deleteContentFileOnCompletion = false;
|
||||
|
||||
// SlideShare seems to work entirely off file extension, so we
|
||||
// always copy onto the
|
||||
// file system and upload from there.
|
||||
File tempDir = TempFileProvider.getLongLifeTempDir("slideshare");
|
||||
contentFile = TempFileProvider.createTempFile("slideshare", extension, tempDir);
|
||||
reader.getContent(contentFile);
|
||||
deleteContentFileOnCompletion = true;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
String name = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_NAME);
|
||||
String title = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_TITLE);
|
||||
if (title == null || title.length() == 0)
|
||||
{
|
||||
title = name;
|
||||
}
|
||||
String description = (String) nodeService.getProperty(nodeToPublish, ContentModel.PROP_DESCRIPTION);
|
||||
if (description == null || description.length() == 0)
|
||||
{
|
||||
description = title;
|
||||
}
|
||||
|
||||
List<String> tagList = taggingService.getTags(nodeToPublish);
|
||||
StringBuilder tags = new StringBuilder();
|
||||
for (String tag : tagList)
|
||||
{
|
||||
tags.append(tag);
|
||||
tags.append(' ');
|
||||
}
|
||||
|
||||
String assetId = api.uploadSlideshow(usernamePassword.getFirst(), usernamePassword.getSecond(), title,
|
||||
contentFile, description, tags.toString(), false, false, false, false, false);
|
||||
|
||||
String url = null;
|
||||
int status = STATUS_QUEUED;
|
||||
boolean finished = false;
|
||||
long timeoutTime = System.currentTimeMillis() + timeoutMilliseconds;
|
||||
// Fetch the slideshow info every 30 seconds until we timeout
|
||||
while (!finished)
|
||||
{
|
||||
SlideshowInfo slideInfo = api.getSlideshowInfo(assetId, "");
|
||||
if (slideInfo != null)
|
||||
{
|
||||
if (url == null)
|
||||
{
|
||||
url = slideInfo.getUrl();
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("SlideShare has provided a URL for asset " + assetId + ": " + url);
|
||||
}
|
||||
}
|
||||
status = slideInfo.getStatus();
|
||||
}
|
||||
finished = (status == STATUS_FAILED || status == STATUS_SUCCEEDED);
|
||||
|
||||
if (!finished)
|
||||
{
|
||||
if (System.currentTimeMillis() < timeoutTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(30000L);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_TIMED_OUT;
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status == STATUS_SUCCEEDED)
|
||||
{
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("File " + name + " has been published to SlideShare with id " + assetId + " at URL "
|
||||
+ url);
|
||||
}
|
||||
nodeService.addAspect(nodeToPublish, SlideSharePublishingModel.ASPECT_ASSET, null);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_ID, assetId);
|
||||
nodeService.setProperty(nodeToPublish, PublishingModel.PROP_ASSET_URL, url);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AlfrescoRuntimeException(status == STATUS_FAILED ? ERROR_SLIDESHARE_CONVERSION_FAILED
|
||||
: ERROR_SLIDESHARE_CONVERSION_TIMED_OUT);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deleteContentFileOnCompletion)
|
||||
{
|
||||
contentFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
Action unpublishAction = actionService.createAction(SlideShareUnpublishAction.NAME);
|
||||
actionService.executeAction(unpublishAction, nodeToUnpublish);
|
||||
NodeService nodeService = getNodeService();
|
||||
if (nodeService.hasAspect(nodeToUnpublish, SlideSharePublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String assetId = (String) nodeService.getProperty(nodeToUnpublish, PublishingModel.PROP_ASSET_ID);
|
||||
if (assetId != null)
|
||||
{
|
||||
Pair<String, String> usernamePassword = publishingHelper
|
||||
.getSlideShareCredentialsFromChannelProperties(properties);
|
||||
if (usernamePassword == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("publish.failed.no_credentials_found");
|
||||
}
|
||||
SlideShareApi api = publishingHelper.getSlideShareApi(usernamePassword.getFirst(), usernamePassword
|
||||
.getSecond());
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
api.deleteSlideshow(usernamePassword.getFirst(), usernamePassword.getSecond(), assetId);
|
||||
nodeService.removeAspect(nodeToUnpublish, SlideSharePublishingModel.ASPECT_ASSET);
|
||||
nodeService.removeAspect(nodeToUnpublish, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
{
|
||||
String url = null;
|
||||
if (node != null && nodeService.exists(node) && nodeService.hasAspect(node, SlideSharePublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
url = (String)nodeService.getProperty(node, PublishingModel.PROP_ASSET_URL);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco, but is derived from a file
|
||||
* Copyright 2008 The JSlideShare Team
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.alfresco.repo.publishing.slideshare;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
|
||||
import org.apache.commons.httpclient.NameValuePair;
|
||||
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.methods.multipart.StringPart;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.benfante.jslideshare.SlideShareConnector;
|
||||
import com.benfante.jslideshare.SlideShareErrorException;
|
||||
|
||||
public class SlideShareConnectorImpl implements SlideShareConnector
|
||||
{
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SlideShareConnectorImpl.class);
|
||||
|
||||
private String apiKey;
|
||||
private String sharedSecret;
|
||||
private HttpClient httpClient;
|
||||
|
||||
public SlideShareConnectorImpl()
|
||||
{
|
||||
httpClient = new HttpClient();
|
||||
httpClient.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
|
||||
}
|
||||
|
||||
public SlideShareConnectorImpl(String apiKey, String sharedSecret)
|
||||
{
|
||||
this();
|
||||
this.apiKey = apiKey;
|
||||
this.sharedSecret = sharedSecret;
|
||||
}
|
||||
|
||||
public String getApiKey()
|
||||
{
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public void setApiKey(String apiKey)
|
||||
{
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
public String getSharedSecret()
|
||||
{
|
||||
return sharedSecret;
|
||||
}
|
||||
|
||||
public void setSharedSecret(String sharedSecret)
|
||||
{
|
||||
this.sharedSecret = sharedSecret;
|
||||
}
|
||||
|
||||
|
||||
public InputStream sendMessage(String url, Map<String, String> parameters) throws IOException,
|
||||
SlideShareErrorException
|
||||
{
|
||||
PostMethod method = new PostMethod(url);
|
||||
method.addParameter("api_key", this.apiKey);
|
||||
Iterator<Map.Entry<String, String>> entryIt = parameters.entrySet().iterator();
|
||||
while (entryIt.hasNext())
|
||||
{
|
||||
Map.Entry<String, String> entry = entryIt.next();
|
||||
method.addParameter(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Date now = new Date();
|
||||
String ts = Long.toString(now.getTime() / 1000);
|
||||
String hash = DigestUtils.shaHex(this.sharedSecret + ts).toLowerCase();
|
||||
method.addParameter("ts", ts);
|
||||
method.addParameter("hash", hash);
|
||||
logger.debug("Sending POST message to " + method.getURI().getURI() + " with parameters "
|
||||
+ Arrays.toString(method.getParameters()));
|
||||
int statusCode = httpClient.executeMethod(method);
|
||||
if (statusCode != HttpStatus.SC_OK)
|
||||
{
|
||||
logger.debug("Server replied with a " + statusCode + " HTTP status code ("
|
||||
+ HttpStatus.getStatusText(statusCode) + ")");
|
||||
throw new SlideShareErrorException(statusCode, HttpStatus.getStatusText(statusCode));
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(method.getResponseBodyAsString());
|
||||
}
|
||||
InputStream result = new ByteArrayInputStream(method.getResponseBody());
|
||||
method.releaseConnection();
|
||||
return result;
|
||||
}
|
||||
|
||||
public InputStream sendMultiPartMessage(String url, Map<String, String> parameters, Map<String, File> files)
|
||||
throws IOException, SlideShareErrorException
|
||||
{
|
||||
PostMethod method = new PostMethod(url);
|
||||
List<Part> partList = new ArrayList<Part>();
|
||||
partList.add(createStringPart("api_key", this.apiKey));
|
||||
Date now = new Date();
|
||||
String ts = Long.toString(now.getTime() / 1000);
|
||||
String hash = DigestUtils.shaHex(this.sharedSecret + ts).toLowerCase();
|
||||
partList.add(createStringPart("ts", ts));
|
||||
partList.add(createStringPart("hash", hash));
|
||||
Iterator<Map.Entry<String, String>> entryIt = parameters.entrySet().iterator();
|
||||
while (entryIt.hasNext())
|
||||
{
|
||||
Map.Entry<String, String> entry = entryIt.next();
|
||||
partList.add(createStringPart(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
Iterator<Map.Entry<String, File>> entryFileIt = files.entrySet().iterator();
|
||||
while (entryFileIt.hasNext())
|
||||
{
|
||||
Map.Entry<String, File> entry = entryFileIt.next();
|
||||
partList.add(createFilePart(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
MultipartRequestEntity requestEntity = new MultipartRequestEntity(partList.toArray(new Part[partList.size()]),
|
||||
method.getParams());
|
||||
method.setRequestEntity(requestEntity);
|
||||
logger.debug("Sending multipart POST message to " + method.getURI().getURI() + " with parts " + partList);
|
||||
int statusCode = httpClient.executeMethod(method);
|
||||
if (statusCode != HttpStatus.SC_OK)
|
||||
{
|
||||
logger.debug("Server replied with a " + statusCode + " HTTP status code ("
|
||||
+ HttpStatus.getStatusText(statusCode) + ")");
|
||||
throw new SlideShareErrorException(statusCode, HttpStatus.getStatusText(statusCode));
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(method.getResponseBodyAsString());
|
||||
}
|
||||
InputStream result = new ByteArrayInputStream(method.getResponseBody());
|
||||
method.releaseConnection();
|
||||
return result;
|
||||
}
|
||||
|
||||
public InputStream sendGetMessage(String url, Map<String, String> parameters) throws IOException,
|
||||
SlideShareErrorException
|
||||
{
|
||||
GetMethod method = new GetMethod(url);
|
||||
NameValuePair[] params = new NameValuePair[parameters.size() + 3];
|
||||
int i = 0;
|
||||
params[i++] = new NameValuePair("api_key", this.apiKey);
|
||||
Iterator<Map.Entry<String, String>> entryIt = parameters.entrySet().iterator();
|
||||
while (entryIt.hasNext())
|
||||
{
|
||||
Map.Entry<String, String> entry = entryIt.next();
|
||||
params[i++] = new NameValuePair(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Date now = new Date();
|
||||
String ts = Long.toString(now.getTime() / 1000);
|
||||
String hash = DigestUtils.shaHex(this.sharedSecret + ts).toLowerCase();
|
||||
params[i++] = new NameValuePair("ts", ts);
|
||||
params[i++] = new NameValuePair("hash", hash);
|
||||
method.setQueryString(params);
|
||||
logger.debug("Sending GET message to " + method.getURI().getURI() + " with parameters "
|
||||
+ Arrays.toString(params));
|
||||
int statusCode = httpClient.executeMethod(method);
|
||||
if (statusCode != HttpStatus.SC_OK)
|
||||
{
|
||||
logger.debug("Server replied with a " + statusCode + " HTTP status code ("
|
||||
+ HttpStatus.getStatusText(statusCode) + ")");
|
||||
throw new SlideShareErrorException(statusCode, HttpStatus.getStatusText(statusCode));
|
||||
}
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(method.getResponseBodyAsString());
|
||||
}
|
||||
InputStream result = new ByteArrayInputStream(method.getResponseBody());
|
||||
method.releaseConnection();
|
||||
return result;
|
||||
}
|
||||
|
||||
private StringPart createStringPart(String name, String value)
|
||||
{
|
||||
StringPart stringPart = new StringPart(name, value);
|
||||
stringPart.setContentType(null);
|
||||
stringPart.setTransferEncoding(null);
|
||||
stringPart.setCharSet("UTF-8");
|
||||
return stringPart;
|
||||
}
|
||||
|
||||
private FilePart createFilePart(String name, File value) throws FileNotFoundException
|
||||
{
|
||||
FilePart filePart = new FilePart(name, value);
|
||||
filePart.setTransferEncoding(null);
|
||||
filePart.setCharSet(null);
|
||||
return filePart;
|
||||
}
|
||||
|
||||
}
|
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* 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.slideshare;
|
||||
|
||||
import java.io.File;
|
||||
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.publishing.PublishingModel;
|
||||
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.Pair;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.benfante.jslideshare.SlideShareAPI;
|
||||
import com.benfante.jslideshare.messages.SlideshowInfo;
|
||||
|
||||
public class SlideSharePublishAction extends ActionExecuterAbstractBase
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(SlideSharePublishAction.class);
|
||||
private final static int STATUS_QUEUED = 0;
|
||||
// private final static int STATUS_CONVERTING = 1;
|
||||
private final static int STATUS_SUCCEEDED = 2;
|
||||
private final static int STATUS_FAILED = 3;
|
||||
private final static int STATUS_TIMED_OUT = 10;
|
||||
public static final String NAME = "publish_slideshare";
|
||||
private static final String ERROR_SLIDESHARE_CONVERSION_FAILED = "publish.slideshare.conversionFailed";
|
||||
private static final String ERROR_SLIDESHARE_CONVERSION_TIMED_OUT = "publish.slideshare.conversionTimedOut";
|
||||
|
||||
private NodeService nodeService;
|
||||
private ContentService contentService;
|
||||
private TaggingService taggingService;
|
||||
private SlideSharePublishingHelper slideShareHelper;
|
||||
|
||||
private long timeoutMilliseconds = 40L * 60L * 1000L; // 40 mins default
|
||||
|
||||
public void setSlideShareHelper(SlideSharePublishingHelper slideShareHelper)
|
||||
{
|
||||
this.slideShareHelper = slideShareHelper;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setTaggingService(TaggingService taggingService)
|
||||
{
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
|
||||
public void setTimeoutMilliseconds(long timeoutMilliseconds)
|
||||
{
|
||||
this.timeoutMilliseconds = timeoutMilliseconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef nodeRef)
|
||||
{
|
||||
Pair<String, String> usernamePassword = slideShareHelper.getSlideShareCredentialsForNode(nodeRef);
|
||||
if (usernamePassword == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("publish.failed.no_credentials_found");
|
||||
}
|
||||
SlideShareAPI api = slideShareHelper
|
||||
.getSlideShareApi(usernamePassword.getFirst(), usernamePassword.getSecond());
|
||||
|
||||
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
||||
if (reader.exists())
|
||||
{
|
||||
File contentFile;
|
||||
String mime = reader.getMimetype();
|
||||
|
||||
String extension = slideShareHelper.getAllowedMimeTypes().get(mime);
|
||||
if (extension == null)
|
||||
extension = "";
|
||||
|
||||
boolean deleteContentFileOnCompletion = false;
|
||||
|
||||
// SlideShare seems to work entirely off file extension, so we
|
||||
// always copy onto the
|
||||
// file system and upload from there.
|
||||
File tempDir = TempFileProvider.getLongLifeTempDir("slideshare");
|
||||
contentFile = TempFileProvider.createTempFile("slideshare", extension, tempDir);
|
||||
reader.getContent(contentFile);
|
||||
deleteContentFileOnCompletion = true;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
||||
String title = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_TITLE);
|
||||
if (title == null || title.length() == 0)
|
||||
{
|
||||
title = name;
|
||||
}
|
||||
String description = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION);
|
||||
if (description == null || description.length() == 0)
|
||||
{
|
||||
description = title;
|
||||
}
|
||||
|
||||
List<String> tagList = taggingService.getTags(nodeRef);
|
||||
StringBuilder tags = new StringBuilder();
|
||||
for (String tag : tagList)
|
||||
{
|
||||
tags.append(tag);
|
||||
tags.append(' ');
|
||||
}
|
||||
|
||||
String assetId = api.uploadSlideshow(usernamePassword.getFirst(), usernamePassword.getSecond(), title,
|
||||
contentFile, description, tags.toString(), false, false, false, false, false);
|
||||
|
||||
String url = null;
|
||||
int status = STATUS_QUEUED;
|
||||
boolean finished = false;
|
||||
long timeoutTime = System.currentTimeMillis() + timeoutMilliseconds;
|
||||
// Fetch the slideshow info every 5 seconds for 5 minutes...
|
||||
while (!finished)
|
||||
{
|
||||
SlideshowInfo slideInfo = api.getSlideshowInfo(assetId, "");
|
||||
if (slideInfo != null)
|
||||
{
|
||||
if (url == null)
|
||||
{
|
||||
url = slideInfo.getUrl();
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("SlideShare has provided a URL for asset " + assetId + ": " + url);
|
||||
}
|
||||
}
|
||||
status = slideInfo.getStatus();
|
||||
}
|
||||
finished = (status == STATUS_FAILED || status == STATUS_SUCCEEDED);
|
||||
|
||||
if (!finished)
|
||||
{
|
||||
if (System.currentTimeMillis() < timeoutTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(30000L);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_TIMED_OUT;
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status == STATUS_SUCCEEDED)
|
||||
{
|
||||
if (log.isInfoEnabled())
|
||||
{
|
||||
log.info("File " + name + " has been published to SlideShare with id " + assetId + " at URL "
|
||||
+ url);
|
||||
}
|
||||
nodeService.addAspect(nodeRef, SlideSharePublishingModel.ASPECT_ASSET, null);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_ID, assetId);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_URL, url);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AlfrescoRuntimeException(status == STATUS_FAILED ? ERROR_SLIDESHARE_CONVERSION_FAILED
|
||||
: ERROR_SLIDESHARE_CONVERSION_TIMED_OUT);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deleteContentFileOnCompletion)
|
||||
{
|
||||
contentFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
}
|
||||
}
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.slideshare;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@@ -25,8 +26,7 @@ import java.util.TreeMap;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.node.encryption.MetadataEncryptor;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
|
||||
import com.benfante.jslideshare.SlideShareAPI;
|
||||
@@ -52,15 +52,9 @@ public class SlideSharePublishingHelper
|
||||
}
|
||||
|
||||
private Map<String, String> allowedMimeTypes = Collections.unmodifiableMap(DEFAULT_MIME_TYPES);
|
||||
private NodeService nodeService;
|
||||
private SlideShareConnector slideshareConnector;
|
||||
private MetadataEncryptor encryptor;
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setSlideshareConnector(SlideShareConnector slideshareConnector)
|
||||
{
|
||||
this.slideshareConnector = slideshareConnector;
|
||||
@@ -91,24 +85,17 @@ public class SlideSharePublishingHelper
|
||||
return new SlideShareApiImpl(slideshareConnector);
|
||||
}
|
||||
|
||||
public Pair<String, String> getSlideShareCredentialsForNode(NodeRef publishNode)
|
||||
public Pair<String, String> getSlideShareCredentialsFromChannelProperties(Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
Pair<String, String> result = null;
|
||||
if (nodeService.exists(publishNode))
|
||||
{
|
||||
NodeRef parent = nodeService.getPrimaryParent(publishNode).getParentRef();
|
||||
if (nodeService.hasAspect(parent, SlideSharePublishingModel.ASPECT_DELIVERY_CHANNEL))
|
||||
{
|
||||
String username = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_USERNAME, nodeService
|
||||
.getProperty(parent, PublishingModel.PROP_CHANNEL_USERNAME));
|
||||
String password = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_PASSWORD, nodeService
|
||||
.getProperty(parent, PublishingModel.PROP_CHANNEL_PASSWORD));
|
||||
String username = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_USERNAME,
|
||||
channelProperties.get(PublishingModel.PROP_CHANNEL_USERNAME));
|
||||
String password = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_PASSWORD,
|
||||
channelProperties.get(PublishingModel.PROP_CHANNEL_PASSWORD));
|
||||
if (username != null && password != null)
|
||||
{
|
||||
result = new Pair<String, String>(username, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -36,8 +36,6 @@ 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;
|
||||
@@ -115,6 +113,8 @@ public class SlideShareTest extends BaseSpringTest
|
||||
// text "YOUR_USER_NAME" and "YOUR_PASSWORD" appear.
|
||||
public void xtestSlideSharePublishAndUnpublishActions() throws Exception
|
||||
{
|
||||
final SlideShareChannelType channelType = (SlideShareChannelType)channelService.getChannelType(SlideShareChannelType.ID);
|
||||
final String channelName = GUID.generate();
|
||||
final List<NodeRef> nodes = transactionHelper.doInTransaction(new RetryingTransactionCallback<List<NodeRef>>()
|
||||
{
|
||||
public List<NodeRef> execute() throws Throwable
|
||||
@@ -127,7 +127,7 @@ public class SlideShareTest extends BaseSpringTest
|
||||
// "YOUR_PASSWORD");
|
||||
props.put(PublishingModel.PROP_CHANNEL_USERNAME, "YOUR_USER_NAME");
|
||||
props.put(PublishingModel.PROP_CHANNEL_PASSWORD, "YOUR_PASSWORD");
|
||||
Channel channel = channelService.createChannel(SlideShareChannelType.ID, GUID.generate(), props);
|
||||
Channel channel = channelService.createChannel(SlideShareChannelType.ID, channelName, props);
|
||||
|
||||
NodeRef channelNode = channel.getNodeRef();
|
||||
|
||||
@@ -162,29 +162,31 @@ public class SlideShareTest extends BaseSpringTest
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
Map<QName, Serializable> channelProperties = channelService.getChannelByName(channelName).getProperties();
|
||||
for (NodeRef node : nodes)
|
||||
{
|
||||
ActionService actionService = serviceRegistry.getActionService();
|
||||
Action publishAction = actionService.createAction(SlideSharePublishAction.NAME);
|
||||
actionService.executeAction(publishAction, node);
|
||||
channelType.publish(node, channelProperties);
|
||||
Map<QName, Serializable> props = nodeService.getProperties(node);
|
||||
Assert.assertTrue(nodeService.hasAspect(node, SlideSharePublishingModel.ASPECT_ASSET));
|
||||
Assert.assertNotNull(props.get(PublishingModel.PROP_ASSET_ID));
|
||||
Assert.assertNotNull(props.get(PublishingModel.PROP_ASSET_URL));
|
||||
|
||||
System.out.println("Test file: " + testNodeMap.get(node));
|
||||
System.out.println("Published test file: " + testNodeMap.get(node));
|
||||
System.out.println("SlideShare id: " + props.get(PublishingModel.PROP_ASSET_ID));
|
||||
System.out.println("SlideShare URL: " + props.get(PublishingModel.PROP_ASSET_URL));
|
||||
}
|
||||
|
||||
// Action unpublishAction =
|
||||
// actionService.createAction(SlideShareUnpublishAction.NAME);
|
||||
// actionService.executeAction(unpublishAction, node);
|
||||
// props = nodeService.getProperties(node);
|
||||
// Assert.assertFalse(nodeService.hasAspect(node,
|
||||
// SlideSharePublishingModel.ASPECT_ASSET));
|
||||
// Assert.assertNull(props.get(SlideSharePublishingModel.PROP_ASSET_ID));
|
||||
// Assert.assertNull(props.get(SlideSharePublishingModel.PROP_ASSET_URL));
|
||||
for (NodeRef node : nodes)
|
||||
{
|
||||
Map<QName, Serializable> props = nodeService.getProperties(node);
|
||||
channelType.unpublish(node, channelProperties);
|
||||
props = nodeService.getProperties(node);
|
||||
Assert.assertFalse(nodeService.hasAspect(node, SlideSharePublishingModel.ASPECT_ASSET));
|
||||
Assert.assertNull(props.get(PublishingModel.PROP_ASSET_ID));
|
||||
Assert.assertNull(props.get(PublishingModel.PROP_ASSET_URL));
|
||||
|
||||
System.out.println("Unpublished test file: " + testNodeMap.get(node));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 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.slideshare;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.action.executer.ActionExecuterAbstractBase;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
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.alfresco.util.Pair;
|
||||
|
||||
public class SlideShareUnpublishAction extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "unpublish_slideshare";
|
||||
|
||||
private NodeService nodeService;
|
||||
private SlideSharePublishingHelper slideShareHelper;
|
||||
|
||||
public void setSlideShareHelper(SlideSharePublishingHelper slideShareHelper)
|
||||
{
|
||||
this.slideShareHelper = slideShareHelper;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeImpl(Action action, NodeRef nodeRef)
|
||||
{
|
||||
if (nodeService.hasAspect(nodeRef, SlideSharePublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String assetId = (String) nodeService.getProperty(nodeRef, PublishingModel.PROP_ASSET_ID);
|
||||
if (assetId != null)
|
||||
{
|
||||
Pair<String, String> usernamePassword = slideShareHelper.getSlideShareCredentialsForNode(nodeRef);
|
||||
if (usernamePassword == null)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("publish.failed.no_credentials_found");
|
||||
}
|
||||
SlideShareApi api = slideShareHelper.getSlideShareApi(
|
||||
usernamePassword.getFirst(), usernamePassword.getSecond());
|
||||
|
||||
api.deleteSlideshow(usernamePassword.getFirst(), usernamePassword.getSecond(), assetId);
|
||||
nodeService.removeAspect(nodeRef, SlideSharePublishingModel.ASPECT_ASSET);
|
||||
nodeService.removeAspect(nodeRef, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
}
|
||||
}
|
@@ -99,7 +99,7 @@ public class TestChannelType1 extends AbstractChannelType
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
//Deliberately blank
|
||||
}
|
||||
|
@@ -99,7 +99,7 @@ public class TestChannelType2 extends AbstractChannelType
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
//Deliberately blank
|
||||
}
|
||||
|
@@ -99,7 +99,7 @@ public class TestChannelType3 extends AbstractChannelType
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
//Deliberately blank
|
||||
}
|
||||
|
@@ -18,11 +18,6 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.twitter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.publishing.AbstractOAuth1ChannelType;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -67,30 +62,6 @@ public class TwitterChannelType extends AbstractOAuth1ChannelType<Twitter>
|
||||
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)
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumStatusLength()
|
||||
{
|
||||
@@ -98,7 +69,7 @@ public class TwitterChannelType extends AbstractOAuth1ChannelType<Twitter>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
public void sendStatusUpdate(Channel channel, String status)
|
||||
{
|
||||
Connection<Twitter> connection = getConnectionForChannel(channel.getNodeRef());
|
||||
if (log.isInfoEnabled())
|
||||
@@ -111,7 +82,7 @@ public class TwitterChannelType extends AbstractOAuth1ChannelType<Twitter>
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -18,49 +18,84 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.youtube;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.content.filestore.FileContentReader;
|
||||
import org.alfresco.repo.publishing.AbstractChannelType;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.publishing.channels.Channel;
|
||||
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.service.namespace.QName;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.alfresco.util.collections.CollectionUtils;
|
||||
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 YouTubeChannelType extends AbstractChannelType
|
||||
{
|
||||
private final static Log log = LogFactory.getLog(YouTubeChannelType.class);
|
||||
private final static Set<String> DEFAULT_SUPPORTED_MIME_TYPES = CollectionUtils.unmodifiableSet(
|
||||
MimetypeMap.MIMETYPE_VIDEO_MPG,
|
||||
MimetypeMap.MIMETYPE_VIDEO_MP4,
|
||||
MimetypeMap.MIMETYPE_VIDEO_FLV,
|
||||
MimetypeMap.MIMETYPE_VIDEO_3GP,
|
||||
MimetypeMap.MIMETYPE_VIDEO_AVI,
|
||||
MimetypeMap.MIMETYPE_VIDEO_QUICKTIME,
|
||||
MimetypeMap.MIMETYPE_VIDEO_WMV
|
||||
);
|
||||
MimetypeMap.MIMETYPE_VIDEO_MPG, MimetypeMap.MIMETYPE_VIDEO_MP4, MimetypeMap.MIMETYPE_VIDEO_FLV,
|
||||
MimetypeMap.MIMETYPE_VIDEO_3GP, MimetypeMap.MIMETYPE_VIDEO_AVI, MimetypeMap.MIMETYPE_VIDEO_QUICKTIME,
|
||||
MimetypeMap.MIMETYPE_VIDEO_WMV);
|
||||
|
||||
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 Set<String> supportedMimeTypes = DEFAULT_SUPPORTED_MIME_TYPES;
|
||||
|
||||
public final static String ID = "youtube";
|
||||
private NodeService nodeService;
|
||||
private ActionService actionService;
|
||||
private YouTubePublishingHelper youTubeHelper;
|
||||
private ContentService contentService;
|
||||
private TaggingService taggingService;
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
public void setYouTubeHelper(YouTubePublishingHelper youTubeHelper)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
this.youTubeHelper = youTubeHelper;
|
||||
}
|
||||
|
||||
public void setActionService(ActionService actionService)
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.actionService = actionService;
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setTaggingService(TaggingService taggingService)
|
||||
{
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
|
||||
public void setSupportedMimeTypes(Set<String> supportedMimeTypes)
|
||||
@@ -98,12 +133,6 @@ public class YouTubeChannelType extends AbstractChannelType
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QName> getSupportedContentTypes()
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedMimeTypes()
|
||||
{
|
||||
@@ -113,31 +142,182 @@ public class YouTubeChannelType extends AbstractChannelType
|
||||
@Override
|
||||
public void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
Action youtubePublishAction = actionService.createAction(YouTubePublishAction.NAME);
|
||||
actionService.executeAction(youtubePublishAction, nodeToPublish);
|
||||
YouTubeService service = youTubeHelper.getYouTubeServiceFromChannelProperties(properties);
|
||||
if (service != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
uploadVideo(service, nodeToPublish);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.error("Failed to send asset to YouTube", ex);
|
||||
throw new AlfrescoRuntimeException("exception.publishing.youtube.publishFailed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties)
|
||||
{
|
||||
Action youtubeUnpublishAction = actionService.createAction(YouTubeUnpublishAction.NAME);
|
||||
actionService.executeAction(youtubeUnpublishAction, nodeToUnpublish);
|
||||
YouTubeService service = youTubeHelper.getYouTubeServiceFromChannelProperties(properties);
|
||||
if (service != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
removeVideo(service, nodeToUnpublish);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.error("Failed to remove asset from YouTube", ex);
|
||||
throw new AlfrescoRuntimeException("exception.publishing.youtube.unpublishFailed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Channel channel, String status, Map<QName, Serializable> properties)
|
||||
private void removeVideo(YouTubeService service, NodeRef nodeRef) throws MalformedURLException, IOException,
|
||||
ServiceException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
NodeService nodeService = getNodeService();
|
||||
if (nodeService.hasAspect(nodeRef, YouTubePublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String youtubeId = (String) nodeService.getProperty(nodeRef, PublishingModel.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);
|
||||
nodeService.removeAspect(nodeRef, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNodeUrl(NodeRef node)
|
||||
private void uploadVideo(YouTubeService service, NodeRef nodeRef) throws IOException, ServiceException,
|
||||
InterruptedException
|
||||
{
|
||||
String url = null;
|
||||
if (node != null && nodeService.exists(node) && nodeService.hasAspect(node, PublishingModel.ASPECT_ASSET))
|
||||
NodeService nodeService = getNodeService();
|
||||
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
||||
if (reader.exists())
|
||||
{
|
||||
url = (String)nodeService.getProperty(node, PublishingModel.PROP_ASSET_URL);
|
||||
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.addAspect(nodeRef, YouTubePublishingModel.ASPECT_ASSET, null);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_ID, videoId);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* 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.repo.publishing.PublishingModel;
|
||||
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.addAspect(nodeRef, YouTubePublishingModel.ASPECT_ASSET, null);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_ID, videoId);
|
||||
nodeService.setProperty(nodeRef, PublishingModel.PROP_ASSET_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -18,10 +18,12 @@
|
||||
*/
|
||||
package org.alfresco.repo.publishing.youtube;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.node.encryption.MetadataEncryptor;
|
||||
import org.alfresco.repo.publishing.PublishingModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -30,31 +32,22 @@ import com.google.gdata.client.youtube.YouTubeService;
|
||||
public class YouTubePublishingHelper
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(YouTubePublishingHelper.class);
|
||||
private NodeService nodeService;
|
||||
private MetadataEncryptor encryptor;
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setEncryptor(MetadataEncryptor encryptor)
|
||||
{
|
||||
this.encryptor = encryptor;
|
||||
}
|
||||
|
||||
public YouTubeService getYouTubeServiceForNode(NodeRef publishNode)
|
||||
public YouTubeService getYouTubeServiceFromChannelProperties(Map<QName, Serializable> channelProperties)
|
||||
{
|
||||
YouTubeService service = null;
|
||||
if (nodeService.exists(publishNode))
|
||||
if (channelProperties != null)
|
||||
{
|
||||
NodeRef parent = nodeService.getPrimaryParent(publishNode).getParentRef();
|
||||
if (nodeService.hasAspect(parent, YouTubePublishingModel.ASPECT_DELIVERY_CHANNEL))
|
||||
{
|
||||
String youtubeUsername = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_USERNAME, nodeService
|
||||
.getProperty(parent, PublishingModel.PROP_CHANNEL_USERNAME));
|
||||
String youtubePassword = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_PASSWORD, nodeService
|
||||
.getProperty(parent, PublishingModel.PROP_CHANNEL_PASSWORD));
|
||||
String youtubeUsername = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_USERNAME,
|
||||
channelProperties.get(PublishingModel.PROP_CHANNEL_USERNAME));
|
||||
String youtubePassword = (String) encryptor.decrypt(PublishingModel.PROP_CHANNEL_PASSWORD,
|
||||
channelProperties.get(PublishingModel.PROP_CHANNEL_PASSWORD));
|
||||
service = new YouTubeService("Alfresco",
|
||||
"AI39si78RHlniONCtnu9o8eBfwZToBAp2ZbbURm5eoJjj4gZi0LcxjDqJTzD35oYokmtFXbCo5ojofbimGnMlRbmNrh7-M7ZCw");
|
||||
try
|
||||
@@ -67,7 +60,6 @@ public class YouTubePublishingHelper
|
||||
log.error("Failed to connect to YouTube", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
|
@@ -31,8 +31,6 @@ 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;
|
||||
@@ -100,6 +98,9 @@ public class YouTubeTest extends BaseSpringTest
|
||||
//text "YOUR_USER_NAME" and "YOUR_PASSWORD" appear.
|
||||
public void xtestYouTubePublishAndUnpublishActions() throws Exception
|
||||
{
|
||||
final String channelName = GUID.generate();
|
||||
final YouTubeChannelType channelType = (YouTubeChannelType) channelService.getChannelType(YouTubeChannelType.ID);
|
||||
|
||||
final NodeRef vidNode = transactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
@@ -107,7 +108,7 @@ public class YouTubeTest extends BaseSpringTest
|
||||
Map<QName, Serializable> props = new HashMap<QName, Serializable>();
|
||||
props.put(PublishingModel.PROP_CHANNEL_USERNAME, "YOUR_USER_NAME");
|
||||
props.put(PublishingModel.PROP_CHANNEL_PASSWORD, "YOUR_PASSWORD");
|
||||
Channel channel = channelService.createChannel(YouTubeChannelType.ID, "YouTubeChannel", props);
|
||||
Channel channel = channelService.createChannel(YouTubeChannelType.ID, channelName, props);
|
||||
|
||||
NodeRef channelNode = channel.getNodeRef();
|
||||
Resource videoFile = new ClassPathResource("test/alfresco/TestVideoFile.MP4");
|
||||
@@ -128,9 +129,7 @@ public class YouTubeTest extends BaseSpringTest
|
||||
{
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
ActionService actionService = serviceRegistry.getActionService();
|
||||
Action publishAction = actionService.createAction(YouTubePublishAction.NAME);
|
||||
actionService.executeAction(publishAction, vidNode);
|
||||
channelType.publish(vidNode, channelService.getChannelByName(channelName).getProperties());
|
||||
Map<QName, Serializable> props = nodeService.getProperties(vidNode);
|
||||
Assert.assertTrue(nodeService.hasAspect(vidNode, YouTubePublishingModel.ASPECT_ASSET));
|
||||
Assert.assertNotNull(props.get(PublishingModel.PROP_ASSET_ID));
|
||||
@@ -138,8 +137,7 @@ public class YouTubeTest extends BaseSpringTest
|
||||
|
||||
System.out.println("YouTube video: " + props.get(PublishingModel.PROP_ASSET_ID));
|
||||
|
||||
Action unpublishAction = actionService.createAction(YouTubeUnpublishAction.NAME);
|
||||
actionService.executeAction(unpublishAction, vidNode);
|
||||
channelType.unpublish(vidNode, channelService.getChannelByName(channelName).getProperties());
|
||||
props = nodeService.getProperties(vidNode);
|
||||
Assert.assertFalse(nodeService.hasAspect(vidNode, YouTubePublishingModel.ASPECT_ASSET));
|
||||
Assert.assertNull(props.get(PublishingModel.PROP_ASSET_ID));
|
||||
|
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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.repo.publishing.PublishingModel;
|
||||
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
|
||||
{
|
||||
if (nodeService.hasAspect(nodeRef, YouTubePublishingModel.ASPECT_ASSET))
|
||||
{
|
||||
String youtubeId = (String) nodeService.getProperty(nodeRef, PublishingModel.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);
|
||||
nodeService.removeAspect(nodeRef, PublishingModel.ASPECT_ASSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
|
||||
{
|
||||
}
|
||||
}
|
@@ -63,8 +63,16 @@ public interface PublishingService
|
||||
void cancelPublishingEvent(String id);
|
||||
|
||||
/**
|
||||
* Retrieve the publishing queue associated with this publishing environment
|
||||
* @return A PublishingQueue object corresponding tho this environment's publishing queue
|
||||
* A factory method to create an empty publishing package that can be populated before being passed into
|
||||
* a call to the {@link PublishingQueue#scheduleNewEvent(PublishingDetails)} operation.
|
||||
* @return A publishing package that can be populated before being placed on the publishing queue.
|
||||
*/
|
||||
PublishingQueue getPublishingQueue();
|
||||
PublishingDetails createPublishingDetails();
|
||||
|
||||
/**
|
||||
* Adds the supplied publishing package onto the queue.
|
||||
* @param publishingDetails The publishing package that is to be enqueued
|
||||
* @return The identifier of the newly scheduled event
|
||||
*/
|
||||
String scheduleNewEvent(PublishingDetails publishingDetails);
|
||||
}
|
||||
|
@@ -56,9 +56,7 @@ public interface Channel
|
||||
|
||||
Map<QName, Serializable> getProperties();
|
||||
|
||||
void publish(NodeRef nodeToPublish);
|
||||
void unPublish(NodeRef nodeToUnpublish);
|
||||
void updateStatus(String status, String nodeUrl);
|
||||
void sendStatusUpdate(String status, String nodeUrl);
|
||||
|
||||
/**
|
||||
* Returns the URL for some published content given the content node in the editorial environment.
|
||||
|
@@ -23,6 +23,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.publishing.AbstractChannelType;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
@@ -38,7 +39,7 @@ public interface ChannelService
|
||||
* @param channelType The channel type to be registered.
|
||||
* @throws IllegalArgumentException if a channel type is already registered that has the same identifier as the supplied one
|
||||
*/
|
||||
void register(ChannelType channelType);
|
||||
void register(AbstractChannelType channelType);
|
||||
|
||||
/**
|
||||
* Retrieve the channel type that has the specified identifier
|
||||
|
@@ -19,7 +19,6 @@
|
||||
|
||||
package org.alfresco.service.cmr.publishing.channels;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -38,14 +37,12 @@ public interface ChannelType
|
||||
String getId();
|
||||
QName getChannelNodeType();
|
||||
|
||||
void publish(NodeRef nodeToPublish, Map<QName, Serializable> properties);
|
||||
void unpublish(NodeRef nodeToUnpublish, Map<QName, Serializable> properties);
|
||||
void updateStatus(Channel channel, String status, Map<QName, Serializable> properties);
|
||||
|
||||
boolean canPublish();
|
||||
boolean canUnpublish();
|
||||
boolean canPublishStatusUpdates();
|
||||
|
||||
void sendStatusUpdate(Channel channel, String status);
|
||||
|
||||
Set<String> getSupportedMimeTypes();
|
||||
Set<QName> getSupportedContentTypes();
|
||||
|
||||
|
Reference in New Issue
Block a user