diff --git a/config/alfresco/web-publishing-context.xml b/config/alfresco/web-publishing-context.xml
index d5f7365587..afba82e006 100644
--- a/config/alfresco/web-publishing-context.xml
+++ b/config/alfresco/web-publishing-context.xml
@@ -55,6 +55,7 @@
+
diff --git a/source/java/org/alfresco/repo/publishing/ChannelHelper.java b/source/java/org/alfresco/repo/publishing/ChannelHelper.java
index 36f80b4e6c..ceb49b4c19 100644
--- a/source/java/org/alfresco/repo/publishing/ChannelHelper.java
+++ b/source/java/org/alfresco/repo/publishing/ChannelHelper.java
@@ -20,7 +20,10 @@
package org.alfresco.repo.publishing;
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
+import static org.alfresco.model.ContentModel.PROP_CONTENT;
+import static org.alfresco.model.ContentModel.PROP_CONTENT_PROPERTY_NAME;
import static org.alfresco.repo.publishing.PublishingModel.ASPECT_CONTENT_ROOT;
+import static org.alfresco.repo.publishing.PublishingModel.ASPECT_PUBLISHED;
import static org.alfresco.repo.publishing.PublishingModel.ASSOC_SOURCE;
import static org.alfresco.repo.publishing.PublishingModel.NAMESPACE;
import static org.alfresco.repo.publishing.PublishingModel.PROP_CHANNEL;
@@ -31,6 +34,7 @@ import static org.alfresco.repo.publishing.PublishingModel.TYPE_DELIVERY_CHANNEL
import java.io.Serializable;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -40,6 +44,8 @@ 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.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.ContentReader;
+import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.NamespaceService;
@@ -59,6 +65,7 @@ public class ChannelHelper
private NodeService nodeService;
private DictionaryService dictionaryService;
+ private ContentService contentService;
public ChannelHelper()
{
@@ -92,7 +99,7 @@ public class ChannelHelper
String channelTypeId = (String) props.get(PublishingModel.PROP_CHANNEL_TYPE_ID);
ChannelType channelType = channelService.getChannelType(channelTypeId);
String name = (String) props.get(ContentModel.PROP_NAME);
- return new ChannelImpl(channelType, nodeRef, name, nodeService);
+ return new ChannelImpl(channelType, nodeRef, name, this);
}
public NodeRef addChannelToEnvironment(NodeRef environment, Channel channel, Map properties)
@@ -196,10 +203,69 @@ public class ChannelHelper
return result;
}
+ public Map getChannelProperties(NodeRef channel)
+ {
+ return nodeService.getProperties(channel);
+ }
+
public ChildAssociationRef createMapping(NodeRef source, NodeRef publishedNode)
{
QName qName = QName.createQName(NAMESPACE, GUID.generate());
- return nodeService.addChild(publishedNode, source, ASSOC_SOURCE, qName);
+ ChildAssociationRef assoc = nodeService.addChild(publishedNode, source, ASSOC_SOURCE, qName);
+ nodeService.addAspect(source, ASPECT_PUBLISHED, null);
+ return assoc;
+ }
+
+ /**
+ * @param nodeToPublish
+ * @param channelType
+ * @return
+ */
+ public boolean canPublish(NodeRef nodeToPublish, ChannelType type)
+ {
+ if(type.canPublish() == false)
+ {
+ return false;
+ }
+ boolean isContentTypeSupported = isContentTypeSupported(nodeToPublish, type);
+ boolean isMimetypeSupported = isMimetypeSupported(nodeToPublish, type);
+ return isContentTypeSupported && isMimetypeSupported;
+ }
+
+ private boolean isMimetypeSupported(NodeRef nodeToPublish, ChannelType type)
+ {
+ Set supportedMimetypes = type.getSupportedMimetypes();
+ if (supportedMimetypes == null || supportedMimetypes.isEmpty())
+ {
+ return true;
+ }
+ QName contentProp = (QName) nodeService.getProperty(nodeToPublish, PROP_CONTENT_PROPERTY_NAME);
+ if (contentProp == null)
+ {
+ String defaultValue = dictionaryService.getProperty(PROP_CONTENT_PROPERTY_NAME).getDefaultValue();
+ contentProp = defaultValue == null ? PROP_CONTENT : QName.createQName(defaultValue);
+ }
+ ContentReader reader = contentService.getReader(nodeToPublish, contentProp);
+ return supportedMimetypes.contains(reader.getMimetype());
+ }
+
+ private boolean isContentTypeSupported(NodeRef nodeToPublish, ChannelType type)
+ {
+ Set supportedContentTypes = type.getSupportedContentTypes();
+ if(supportedContentTypes == null || supportedContentTypes.isEmpty())
+ {
+ return true;
+ }
+ QName contentType = nodeService.getType(nodeToPublish);
+ for (QName supportedType : supportedContentTypes)
+ {
+ if(contentType.equals(supportedType)
+ || dictionaryService.isSubClass(contentType, supportedType))
+ {
+ return true;
+ }
+ }
+ return false;
}
private QName getChannelQName(String channelName)
@@ -248,6 +314,12 @@ public class ChannelHelper
return null;
}
+ public void sendStatusUpdates(NodeRef nodeToPublish, NodeRef channelNode, ChannelType channelType)
+ {
+ //TODO
+
+ }
+
/**
* @param nodeService the nodeService to set
*/
@@ -263,4 +335,13 @@ public class ChannelHelper
{
this.dictionaryService = dictionaryService;
}
+
+ /**
+ * @param contentService the contentService to set
+ */
+ public void setContentService(ContentService contentService)
+ {
+ this.contentService = contentService;
+ }
+
}
diff --git a/source/java/org/alfresco/repo/publishing/ChannelHelperTest.java b/source/java/org/alfresco/repo/publishing/ChannelHelperTest.java
index bd798db016..b146bae782 100644
--- a/source/java/org/alfresco/repo/publishing/ChannelHelperTest.java
+++ b/source/java/org/alfresco/repo/publishing/ChannelHelperTest.java
@@ -19,8 +19,14 @@
package org.alfresco.repo.publishing;
+import static org.mockito.Mockito.*;
+import static junit.framework.Assert.*;
+
+import org.alfresco.service.cmr.publishing.channels.ChannelType;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -33,6 +39,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(locations = { "classpath:test/alfresco/test-web-publishing-context.xml"})
public class ChannelHelperTest
{
+ @Autowired
+ private ChannelHelper helper;
+
@Test
public void testMapNodeRef() throws Exception
{
@@ -44,5 +53,4 @@ public class ChannelHelperTest
// NodeRef unmappedNodeRef = environmentHelper.mapEnvironmentToEditorial(liveEnvironmentNode, mappedNodeRef);
// assertEquals(testNodeRef, unmappedNodeRef);
}
-
}
diff --git a/source/java/org/alfresco/repo/publishing/ChannelImpl.java b/source/java/org/alfresco/repo/publishing/ChannelImpl.java
index 50e51f44a6..4e3e8d94cb 100644
--- a/source/java/org/alfresco/repo/publishing/ChannelImpl.java
+++ b/source/java/org/alfresco/repo/publishing/ChannelImpl.java
@@ -25,7 +25,6 @@ import java.util.Map;
import org.alfresco.service.cmr.publishing.channels.Channel;
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;
/**
@@ -37,19 +36,19 @@ public class ChannelImpl implements Channel
private final NodeRef nodeRef;
private final ChannelType channelType;
private final String name;
- private final NodeService nodeService;
+ private final ChannelHelper channelHelper;
/**
* @param channelType
* @param name
* @param channelService
*/
- public ChannelImpl(ChannelType channelType, NodeRef nodeRef, String name, NodeService nodeService)
+ public ChannelImpl(ChannelType channelType, NodeRef nodeRef, String name, ChannelHelper channelHelper)
{
this.nodeRef = nodeRef;
this.channelType = channelType;
this.name = name;
- this.nodeService = nodeService;
+ this.channelHelper = channelHelper;
}
/**
@@ -81,7 +80,39 @@ public class ChannelImpl implements Channel
*/
public Map getProperties()
{
- return nodeService.getProperties(nodeRef);
+ return channelHelper.getChannelProperties(nodeRef);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void publish(NodeRef nodeToPublish)
+ {
+ if(channelHelper.canPublish(nodeToPublish, channelType))
+ {
+ channelType.publish(nodeToPublish, getProperties());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void unPublish(NodeRef nodeToUnpublish)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateStatus(String status)
+ {
+ // TODO Auto-generated method stub
+
}
}
diff --git a/source/java/org/alfresco/repo/publishing/MockChannelType.java b/source/java/org/alfresco/repo/publishing/MockChannelType.java
index 368c23984c..3f3bc5d754 100644
--- a/source/java/org/alfresco/repo/publishing/MockChannelType.java
+++ b/source/java/org/alfresco/repo/publishing/MockChannelType.java
@@ -19,9 +19,12 @@
package org.alfresco.repo.publishing;
+import java.io.Serializable;
import java.util.Map;
+import java.util.Set;
import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
@@ -65,4 +68,77 @@ public class MockChannelType extends AbstractChannelType
{
return ContentModel.TYPE_FOLDER;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void publish(NodeRef nodeToPublish, Map properties)
+ {
+ // NOOP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void unpublish(NodeRef nodeToUnpublish, Map properties)
+ {
+ //NOOP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateStatus(String status, Map properties)
+ {
+ //NOOP
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canPublish()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canUnpublish()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set getSupportedMimetypes()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set getSupportedContentTypes()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canPublishStatusUpdates()
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
diff --git a/source/java/org/alfresco/repo/publishing/PublishEventActionTest.java b/source/java/org/alfresco/repo/publishing/PublishEventActionTest.java
index 01a0be69be..64b3974185 100644
--- a/source/java/org/alfresco/repo/publishing/PublishEventActionTest.java
+++ b/source/java/org/alfresco/repo/publishing/PublishEventActionTest.java
@@ -32,9 +32,11 @@ import static org.alfresco.model.ContentModel.PROP_LONGITUDE;
import static org.alfresco.model.ContentModel.PROP_NAME;
import static org.alfresco.model.ContentModel.TYPE_CONTENT;
import static org.alfresco.repo.publishing.PublishingModel.ASSOC_LAST_PUBLISHING_EVENT;
+import static org.mockito.Mockito.*;
import java.io.Serializable;
import java.util.Calendar;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -42,6 +44,7 @@ import java.util.Set;
import javax.annotation.Resource;
+import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.publishing.MutablePublishingPackage;
import org.alfresco.service.cmr.publishing.PublishingPackage;
@@ -56,6 +59,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.junit.Test;
+import org.mockito.exceptions.verification.NeverWantedButInvoked;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -87,6 +91,7 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
private NodeRef root;
private NodeRef channel;
private String eventId;
+ private ChannelType channelType;
@Test
public void testPublishNodes() throws Exception
@@ -166,6 +171,8 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
// Update published node.
publishEventNode = publishNode(source);
+ NodeRef newPublishNode = channelHelper.mapSourceToEnvironment(source, channel);
+ assertEquals(publishedNode, newPublishNode);
// Published node shoudl still exist.
assertNotNull(publishedNode);
@@ -193,7 +200,9 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
// Update publish node
publishNode(source);
-
+ newPublishNode = channelHelper.mapSourceToEnvironment(source, channel);
+ assertEquals(publishedNode, newPublishNode);
+
aspects = nodeService.getAspects(source);
assertFalse(aspects.contains(ASPECT_GEOGRAPHIC));
@@ -202,6 +211,114 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
assertFalse(publishedProps.containsKey(PROP_LONGITUDE));
}
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testChannelTypePublishIsCalledOnPublish() throws Exception
+ {
+ // Create content node with appropriate aspects added.
+ NodeRef source = createContentNode(contentNodeName, content);
+
+ // Enable publishing on ChannelType.
+ when(channelType.canPublish()).thenReturn(true);
+
+ publishNode(source);
+ NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel);
+
+ // Check publish was called
+ verify(channelType, times(1)).publish(eq(publishedNode), anyMap());
+ }
+
+ public void testChannelTypePublishIsCalledOnUpdate() throws Exception
+ {
+ // Create content node with appropriate aspects added.
+ NodeRef source = createContentNode(contentNodeName, content);
+
+ // Publish source node but dont' call ChannelType.publish().
+ publishNode(source);
+ NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel);
+
+ // Check publish was not called.
+ verify(channelType, never()).publish(eq(publishedNode), anyMap());
+
+ // Enable publishing on ChannelType.
+ when(channelType.canPublish()).thenReturn(true);
+
+ // Update publish node
+ publishNode(source);
+
+ // Check publish was called on update
+ verify(channelType, times(1)).publish(eq(publishedNode), anyMap());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testSupportedContentTypes() throws Exception
+ {
+ // Create content node with appropriate aspects added.
+ NodeRef source = createContentNode(contentNodeName, content);
+
+ // Enable publishing on ChannelType.
+ when(channelType.canPublish()).thenReturn(true);
+
+ // Set supported type to cm:folder
+ Set contentTypes = Collections.singleton(ContentModel.TYPE_FOLDER);
+ when(channelType.getSupportedContentTypes()).thenReturn(contentTypes);
+
+ // Publish source node but don't call ChannelType.publish().
+ publishNode(source);
+ NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel);
+
+ verify(channelType, never()).publish(eq(publishedNode), anyMap());
+
+ // Change supported type to cm:content
+ contentTypes = Collections.singleton(ContentModel.TYPE_CONTENT);
+ when(channelType.getSupportedContentTypes()).thenReturn(contentTypes);
+
+ // Publish source node
+ publishNode(source);
+
+ verify(channelType, times(1)).publish(eq(publishedNode), anyMap());
+
+ // Change supported type to cm:cmobject
+ contentTypes = Collections.singleton(ContentModel.TYPE_CMOBJECT);
+ when(channelType.getSupportedContentTypes()).thenReturn(contentTypes);
+
+ // Publish source node
+ publishNode(source);
+
+ verify(channelType, times(2)).publish(eq(publishedNode), anyMap());
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testSupportedMimeTypes() throws Exception
+ {
+ // Create content node with appropriate aspects added.
+ NodeRef source = createContentNode(contentNodeName, content);
+
+ // Enable publishing on ChannelType.
+ when(channelType.canPublish()).thenReturn(true);
+
+ // Set supported type to XML
+ Set mimeTypes = Collections.singleton(MimetypeMap.MIMETYPE_XML);
+ when(channelType.getSupportedMimetypes()).thenReturn(mimeTypes);
+
+ // Publish source node but don't call ChannelType.publish().
+ publishNode(source);
+ NodeRef publishedNode = channelHelper.mapSourceToEnvironment(source, channel);
+
+ verify(channelType, never()).publish(eq(publishedNode), anyMap());
+
+ // Change supported type to plain text.
+ mimeTypes = Collections.singleton(MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ when(channelType.getSupportedMimetypes()).thenReturn(mimeTypes);
+
+ // Publish source node
+ publishNode(source);
+
+ verify(channelType, times(1)).publish(eq(publishedNode), anyMap());
+ }
+
private NodeRef publishNode(NodeRef source)
{
MutablePublishingPackage pckg = queue.createPublishingPackage();
@@ -238,10 +355,6 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
return source;
}
- /**
- * @param source
- * @param theContent
- */
private void writeContent(NodeRef source, String theContent)
{
ContentWriter writer = contentService.getWriter(source, PROP_CONTENT, true);
@@ -260,8 +373,12 @@ public class PublishEventActionTest extends AbstractPublishingIntegrationTest
public void setUp() throws Exception
{
super.setUp();
- ChannelType channelType = mockChannelType();
+ this.channelType = channelService.getChannelType(channelTypeId);
+ if(channelType == null)
+ {
+ this.channelType = mockChannelType();
channelService.register(channelType);
+ }
channelService.createChannel(siteId, channelTypeId, channelName, null);
this.channel = channelHelper.getChannelNodeForEnvironment(environment.getNodeRef(), channelName);
diff --git a/source/java/org/alfresco/repo/publishing/PublishingEventProcessor.java b/source/java/org/alfresco/repo/publishing/PublishingEventProcessor.java
index 3565430606..f4786d0f41 100644
--- a/source/java/org/alfresco/repo/publishing/PublishingEventProcessor.java
+++ b/source/java/org/alfresco/repo/publishing/PublishingEventProcessor.java
@@ -20,6 +20,7 @@
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;
@@ -113,18 +114,19 @@ public class PublishingEventProcessor
public NodeRef publishEntry(Channel channel, PublishingPackageEntry entry, NodeRef eventNode)
{
- NodeRef mappedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), channel.getNodeRef());
- if(mappedNode == null)
+ NodeRef publishedNode = channelHelper.mapSourceToEnvironment(entry.getNodeRef(), channel.getNodeRef());
+ if(publishedNode == null)
{
- mappedNode = publishNewNode(channel.getNodeRef(), entry.getSnapshot());
+ publishedNode = publishNewNode(channel.getNodeRef(), entry.getSnapshot());
}
else
{
- updatePublishedNode(mappedNode, entry);
+ updatePublishedNode(publishedNode, entry);
}
QName qName = QName.createQName(NAMESPACE, eventNode.getId());
- nodeService.addChild(mappedNode, eventNode, ASSOC_LAST_PUBLISHING_EVENT, qName);
- return mappedNode;
+ nodeService.addChild(publishedNode, eventNode, ASSOC_LAST_PUBLISHING_EVENT, qName);
+ channel.publish(publishedNode);
+ return publishedNode;
}
/**
@@ -190,6 +192,7 @@ public class PublishingEventProcessor
{
Set aspectsToRemove = nodeService.getAspects(publishedNode);
aspectsToRemove.removeAll(newAspects);
+ aspectsToRemove.remove(ASPECT_PUBLISHED);
for (QName aspectToRemove : aspectsToRemove)
{
nodeService.removeAspect(publishedNode, aspectToRemove);
diff --git a/source/java/org/alfresco/repo/publishing/WebPublishingTestSuite.java b/source/java/org/alfresco/repo/publishing/WebPublishingTestSuite.java
index f057fc8bca..3989919882 100644
--- a/source/java/org/alfresco/repo/publishing/WebPublishingTestSuite.java
+++ b/source/java/org/alfresco/repo/publishing/WebPublishingTestSuite.java
@@ -35,7 +35,8 @@ import org.junit.runners.Suite;
EnvironmentImplTest.class,
PublishingQueueImplTest.class,
PublishingPackageSerializerTest.class,
- PublishingIntegratedTest.class
+ PublishingIntegratedTest.class,
+ PublishEventActionTest.class
})
public class WebPublishingTestSuite
{
diff --git a/source/java/org/alfresco/service/cmr/publishing/channels/Channel.java b/source/java/org/alfresco/service/cmr/publishing/channels/Channel.java
index 899aa46f19..91a0dfb15b 100644
--- a/source/java/org/alfresco/service/cmr/publishing/channels/Channel.java
+++ b/source/java/org/alfresco/service/cmr/publishing/channels/Channel.java
@@ -46,4 +46,9 @@ public interface Channel
String getName();
Map getProperties();
-}
+
+ void publish(NodeRef nodeToPublish);
+ void unPublish(NodeRef nodeToUnpublish);
+ void updateStatus(String status);
+
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/service/cmr/publishing/channels/ChannelType.java b/source/java/org/alfresco/service/cmr/publishing/channels/ChannelType.java
index d3fb06117a..88029f413e 100644
--- a/source/java/org/alfresco/service/cmr/publishing/channels/ChannelType.java
+++ b/source/java/org/alfresco/service/cmr/publishing/channels/ChannelType.java
@@ -19,8 +19,11 @@
package org.alfresco.service.cmr.publishing.channels;
+import java.io.Serializable;
import java.util.Map;
+import java.util.Set;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.transfer.NodeFilter;
import org.alfresco.service.cmr.transfer.NodeFinder;
import org.alfresco.service.namespace.QName;
@@ -32,9 +35,18 @@ import org.alfresco.service.namespace.QName;
public interface ChannelType
{
String getId();
- Map getCapabilities();
QName getChannelNodeType();
QName getContentRootNodeType();
NodeFinder getNodeFinder();
NodeFilter getNodeFilter();
+ void publish(NodeRef nodeToPublish, Map properties);
+ void unpublish(NodeRef nodeToUnpublish, Map properties);
+ void updateStatus(String status, Map properties);
+
+ boolean canPublish();
+ boolean canUnpublish();
+ boolean canPublishStatusUpdates();
+
+ Set getSupportedMimetypes();
+ Set getSupportedContentTypes();
}