/* * 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 . */ 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; import static org.alfresco.repo.publishing.PublishingModel.PROP_CHANNEL_TYPE; import static org.alfresco.repo.publishing.PublishingModel.PROP_CHANNEL_TYPE_ID; 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; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.dictionary.TypeDefinition; 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; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.GUID; import org.alfresco.util.Pair; /** * @author Nick Smith * @since 4.0 * */ public class ChannelHelper { private static final QName ROOT_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "root"); private NodeService nodeService; private DictionaryService dictionaryService; private ContentService contentService; public ChannelHelper() { super(); } public ChannelHelper(NodeService nodeService, DictionaryService dictionaryService) { this.nodeService =nodeService; this.dictionaryService = dictionaryService; } public NodeRef createChannelNode(NodeRef parent, ChannelType channelType, String channelName, Map props) { QName channelQName = getChannelQName(channelName); QName channelNodeType = channelType.getChannelNodeType(); ChildAssociationRef channelAssoc = nodeService.createNode(parent, ASSOC_CONTAINS, channelQName, channelNodeType, props); NodeRef channelNode = channelAssoc.getChildRef(); QName rootNodeType = channelType.getContentRootNodeType(); ChildAssociationRef rootAssoc = nodeService.createNode(channelNode, ASSOC_CONTAINS, ROOT_NAME, rootNodeType); nodeService.addAspect(rootAssoc.getChildRef(), ASPECT_CONTENT_ROOT, null); return channelNode; } public Channel buildChannelObject(NodeRef nodeRef, ChannelService channelService) { if(nodeRef == null || nodeService.exists(nodeRef)==false) { return null; } Map props = nodeService.getProperties(nodeRef); 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, this); } public NodeRef addChannelToEnvironment(NodeRef environment, Channel channel, Map properties) { ChannelType channelType = channel.getChannelType(); String channelName = channel.getName(); return createChannelNode(environment, channelType, channelName, properties); } public Channel getChannel(NodeRef environment, String channelName, ChannelService channelService) { NodeRef channelNode = getChannelNodeForEnvironment(environment, channelName); if(channelNode != null) { return buildChannelObject(channelNode, channelService); } return null; } public NodeRef getChannelNodeForEnvironment(NodeRef environment, String channelName) { QName channelQName = getChannelQName(channelName); List channelAssocs = nodeService.getChildAssocs(environment, ASSOC_CONTAINS, channelQName); return getSingleValue(channelAssocs, true); } public NodeRef getChannelRootNode(NodeRef channel) { List rootAssocs = nodeService.getChildAssocs(channel, ASSOC_CONTAINS, ROOT_NAME); NodeRef root = getSingleValue(rootAssocs, true); if(root ==null || nodeService.hasAspect(root, ASPECT_CONTENT_ROOT)==false) { throw new IllegalStateException("All channels must have a root folder!"); } return root; } /** * Given a noderef from the editorial space (e.g. the doclib), this returns the corresponding noderef in the specified channel and environment. * @param source * @param environment * @param channelName * @return */ public NodeRef mapSourceToEnvironment(NodeRef source, NodeRef environment, String channelName) { NodeRef channel = getChannelNodeForEnvironment(environment, channelName); return mapSourceToEnvironment(source, channel); } /** * Given a noderef from the editorial space (e.g. the doclib), this returns the corresponding noderef in the specified channelt * @param source * @param channel * @return */ public NodeRef mapSourceToEnvironment(NodeRef source, NodeRef channel) { List parentAssocs = nodeService.getParentAssocs(source, ASSOC_SOURCE, RegexQNamePattern.MATCH_ALL); if(parentAssocs != null) { NodeRef root = getChannelRootNode(channel); for (ChildAssociationRef parentAssoc : parentAssocs) { NodeRef publishedNode = parentAssoc.getParentRef(); NodeRef parent = nodeService.getPrimaryParent(publishedNode).getParentRef(); if(root.equals(parent)) { return publishedNode; } } } return null; } /** * Given a published noderef, this returns the corresponding source noderef in the editorial space (doclib). * @param publishedNode * @return */ public NodeRef mapEnvironmentToSource(NodeRef publishedNode) { List childAssocs = nodeService.getChildAssocs(publishedNode, ASSOC_SOURCE, RegexQNamePattern.MATCH_ALL); return getSingleValue(childAssocs, true); } /** * Finds the {@link Channel} NodeRef and {@link ChannelType} id for a given node, if such a Channel exists. * @param node * @return a {@link Pair} containing the Channel {@link NodeRef} and ChannelType Id. */ public Pair findChannelAndType(NodeRef node) { Pair result = getChannelAndTypeIfChannel(node); if(result == null) { result = getChannelAndType(node); if(result == null) { ChildAssociationRef parentAssoc = nodeService.getPrimaryParent(node); if (parentAssoc != null) { NodeRef parent = parentAssoc.getParentRef(); if (parent != null) { result = findChannelAndType(parent); } } } } 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()); 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) { return QName.createQName(NamespaceService.APP_MODEL_1_0_URI, channelName); } private Pair getChannelAndTypeIfChannel(NodeRef node) { QName type = nodeService.getType(node); if(dictionaryService.isSubClass(type, TYPE_DELIVERY_CHANNEL)) { String channelTypeId = (String) nodeService.getProperty(node, PROP_CHANNEL_TYPE_ID); if(channelTypeId == null) { TypeDefinition typeDef = dictionaryService.getType(type); PropertyDefinition channelTypeProp = typeDef.getProperties().get(PROP_CHANNEL_TYPE_ID); if(channelTypeProp !=null) { channelTypeId = channelTypeProp.getDefaultValue(); } } return new Pair(node, channelTypeId); } return null; } private Pair getChannelAndType(NodeRef node) { NodeRef channel = (NodeRef) nodeService.getProperty(node, PROP_CHANNEL); if(channel != null) { String channelType = (String) nodeService.getProperty(node, PROP_CHANNEL_TYPE); return new Pair(channel, channelType); } return null; } private NodeRef getSingleValue(List assocs, boolean getChild) { if(assocs != null && assocs.size()==1 ) { ChildAssociationRef association = assocs.get(0); return getChild ? association.getChildRef() : association.getParentRef(); } return null; } public void sendStatusUpdates(NodeRef nodeToPublish, NodeRef channelNode, ChannelType channelType) { //TODO } /** * @param nodeService the nodeService to set */ public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } /** * @param dictionaryService the dictionaryService to set */ public void setDictionaryService(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; } /** * @param contentService the contentService to set */ public void setContentService(ContentService contentService) { this.contentService = contentService; } }