/* * Copyright (C) 2005-2012 BetaCONCEPT Limited * * This file is part of Astroboa. * * Astroboa 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. * * Astroboa 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 Astroboa. If not, see <http://www.gnu.org/licenses/>. */ package org.betaconceptframework.astroboa.engine.jcr.util; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import javax.jcr.AccessDeniedException; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.ValueFormatException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.betaconceptframework.astroboa.api.model.CmsApiConstants; import org.betaconceptframework.astroboa.api.model.RepositoryUser; import org.betaconceptframework.astroboa.api.model.Topic; import org.betaconceptframework.astroboa.api.model.ValueType; import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition; import org.betaconceptframework.astroboa.api.model.definition.Localization; import org.betaconceptframework.astroboa.api.model.definition.TopicReferencePropertyDefinition; import org.betaconceptframework.astroboa.api.model.exception.CmsException; import org.betaconceptframework.astroboa.api.model.query.criteria.TopicCriteria; import org.betaconceptframework.astroboa.engine.database.dao.CmsRepositoryEntityAssociationDao; import org.betaconceptframework.astroboa.engine.database.model.CmsRepositoryEntityAssociation; import org.betaconceptframework.astroboa.engine.jcr.dao.ContentDefinitionDao; import org.betaconceptframework.astroboa.engine.jcr.dao.RepositoryUserDao; import org.betaconceptframework.astroboa.engine.jcr.dao.TaxonomyDao; import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryHandler; import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryResult; import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory; import org.betaconceptframework.astroboa.model.impl.TopicImpl; import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem; import org.betaconceptframework.astroboa.util.CmsConstants; import org.betaconceptframework.astroboa.util.PropertyPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; /** * * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public class TopicUtils { final Logger logger = LoggerFactory.getLogger(TopicUtils.class); @Autowired private CmsRepositoryEntityUtils cmsRepositoryEntityUtils; @Autowired private CmsLocalizationUtils cmsLocalizationUtils; @Autowired private CmsRepositoryEntityAssociationDao cmsRepositoryEntityAssociationDao; @Autowired private TaxonomyDao taxonomyDao; @Autowired private ContentDefinitionDao contentDefinitionDao; @Autowired private CmsQueryHandler cmsQueryHandler; @Autowired private RepositoryUserDao repositoryUserDao; public Node addNewTopicJcrNode(Node parentTopicJcrNode, Topic topic, Session session, boolean useProvidedId, Context context) throws RepositoryException { Node topicJcrNode = JcrNodeUtils.addTopicNode(parentTopicJcrNode, CmsBuiltInItem.Topic.getJcrName()); cmsRepositoryEntityUtils.createCmsIdentifier(topicJcrNode, topic, useProvidedId); return populateTopicJcrNode(topic, session, topicJcrNode,useProvidedId, context); } private Node populateTopicJcrNode(Topic topic, Session session, Node topicJcrNode, boolean useProvidedId, Context context) throws RepositoryException { //Update OwnerId updateOwner(topic, topicJcrNode, session, context); //Update Localized Labels updateLocalizedLabels(topic, topicJcrNode); //Update order updateOrder(topic, topicJcrNode); // Update updateName(session, topic, topicJcrNode, context); // Update ContentObjectReferenceable updateAllowsReferrerContentObject(topic, topicJcrNode); // Save or update children saveOrUpdateChildren(topic, session, topicJcrNode, context); return topicJcrNode; } private void saveOrUpdateChildren(Topic topic, Session session, Node topicJcrNode, Context context) throws RepositoryException { if (topic.isChildrenLoaded()){ List<Topic> children = topic.getChildren(); //Add topic node to cache if (topicJcrNode != null){ context.cacheTopicNode(topicJcrNode, true); } //Now insert new subTaxonomyNode if (CollectionUtils.isNotEmpty(children)){ for (Topic child: children){ ((TopicImpl)child).detectCycle(null); Node childNode = null; if (child.getId() != null){ childNode = updateTopic(session, child, topicJcrNode, context); } else{ childNode = addNewTopicJcrNode(topicJcrNode, child, session, false, context); } if (childNode != null){ context.cacheTopicNode(childNode, true); } } } } } private void updateAllowsReferrerContentObject(Topic topic, Node topicJcrNode) throws RepositoryException { if ( ((TopicImpl)topic).allowsReferrerContentObjectsHasBeenSet() || ! topicJcrNode.hasProperty(CmsBuiltInItem.AllowsReferrerContentObjects.getJcrName())){ topicJcrNode.setProperty(CmsBuiltInItem.AllowsReferrerContentObjects.getJcrName(), topic.isAllowsReferrerContentObjects()); } else{ topic.setAllowsReferrerContentObjects(topicJcrNode.getProperty(CmsBuiltInItem.AllowsReferrerContentObjects.getJcrName()).getBoolean()); } } private void updateName(Session session, Topic topic, Node topicJcrNode, Context context) throws RepositoryException { if (StringUtils.isBlank(topic.getName())){ //User has provided no name. if (topicJcrNode.hasProperty(CmsBuiltInItem.Name.getJcrName())){ //Topic already has a name. Update entity and return. There is no need to check for a duplicate topic.setName(topicJcrNode.getProperty(CmsBuiltInItem.Name.getJcrName()).getString()); return; } //Topic does not have a name. Search for an english localized label String possibleSystemName = null; if (topic.hasLocalizedLabels()){ possibleSystemName = topic.getLocalizedLabelForLocale(Locale.ENGLISH.toString()); if (StringUtils.isBlank(possibleSystemName)){ //Get the first valid localized label for (String label : topic.getLocalizedLabels().values()){ possibleSystemName = cmsRepositoryEntityUtils.fixSystemName(label); if (StringUtils.isNotBlank(possibleSystemName)){ break; } } } else{ possibleSystemName = cmsRepositoryEntityUtils.fixSystemName(possibleSystemName); } } if (StringUtils.isNotBlank(possibleSystemName)){ topic.setName(possibleSystemName); } } if (topic.getName() != null){ if (topicJcrNode.hasProperty(CmsBuiltInItem.Name.getJcrName())){ //Topic already has a name. If name has not changed, return if (StringUtils.equals(topicJcrNode.getProperty(CmsBuiltInItem.Name.getJcrName()).getString(), topic.getName())){ return; } } if (!cmsRepositoryEntityUtils.isValidSystemName(topic.getName())){ throw new RepositoryException("Topic name '"+topic.getName()+"' is not valid. It should match pattern "+CmsConstants.SYSTEM_NAME_REG_EXP); } // Make sure that no other topic exists with same system name TopicCriteria topicCriteria = CmsCriteriaFactory.newTopicCriteria(); topicCriteria.addNameEqualsCriterion(topic.getName()); if (topic.getId() != null) { topicCriteria.addIdNotEqualsCriterion(topic.getId()); } //Normally it should not be more than one topicCriteria.setOffsetAndLimit(0, 2); CmsQueryResult sameNameTopicsInTaxonomy = cmsQueryHandler.getNodesFromXPathQuery(session, topicCriteria); if (sameNameTopicsInTaxonomy.getTotalRowCount() != 0) { //Retrieve taxonomy path StringBuilder topicPaths = new StringBuilder(); NodeIterator nodeIterator = sameNameTopicsInTaxonomy.getNodeIterator(); while (nodeIterator.hasNext()){ topicPaths.append("\n"); topicPaths.append(nodeIterator.nextNode().getPath()); } throw new RepositoryException("Topic name '" + topic.getName() + "' is used by the following topic :"+ topicPaths.toString()); } else{ //Query is conducted in persistent data and not in nodes which exist in the session //In this case, look if another topic jcr node with the same name in the context with the same name Node cachedTopicNode = context.getNodeFromCache(topic.getName()); if (cachedTopicNode != null && ! cachedTopicNode.isSame(topicJcrNode)){ throw new RepositoryException("Topic name '" + topic.getName() + "' already exists. Probably you are importing many " + " topics at once and you have provided more than one topic with name "+ topic.getName()); } } topicJcrNode.setProperty(CmsBuiltInItem.Name.getJcrName(), topic.getName()); } } private void updateOrder(Topic topic, Node topicJcrNode) throws RepositoryException { if (topic.getOrder() != null) topicJcrNode.setProperty(CmsBuiltInItem.Order.getJcrName(), topic.getOrder()); else topicJcrNode.setProperty(CmsBuiltInItem.Order.getJcrName(), JcrValueUtils.getJcrNull()); } public void updateLocalizedLabels(Localization localization, Node topicJcrNode) throws RepositoryException { cmsLocalizationUtils.updateCmsLocalization(localization, topicJcrNode); } public void updateOwner(Topic topic, Node topicJcrNode, Session session, Context context) throws RepositoryException { //Topic owner is always System user or a Repository User if topic is under user's folksonomy RepositoryUser topicOwner = retrieveOwnerForTopic(topic, topicJcrNode); if (topicOwner == null){ setSystemUserAsTopicOwner(topic, repositoryUserDao.getSystemRepositoryUser()); } else{ //Set or replace owner. We ignore the owner provided by the user. if (topic.getOwner() == null){ topic.setOwner(topicOwner); } else if (! usersAreTheSame(topic.getOwner(), topicOwner)){ logger.info("Topic {}'s owner will be replaced with repository user {}", topic.toString(), topicOwner); topic.setOwner(topicOwner); } } //Update owner id only if existing owner id is not the same String newOwnerId = topicOwner.getId(); if (!topicJcrNode.hasProperty(CmsBuiltInItem.OwnerCmsIdentifier.getJcrName()) || !topicJcrNode.getProperty(CmsBuiltInItem.OwnerCmsIdentifier.getJcrName()).getString().equals(newOwnerId)){ EntityAssociationUpdateHelper<RepositoryUser> repositoryUserAssociationUpdateHelper = new EntityAssociationUpdateHelper<RepositoryUser>(session,cmsRepositoryEntityAssociationDao, context); repositoryUserAssociationUpdateHelper.setReferrerCmsRepositoryEntityNode(topicJcrNode); repositoryUserAssociationUpdateHelper.setReferrerPropertyName(CmsBuiltInItem.OwnerCmsIdentifier); repositoryUserAssociationUpdateHelper.setValuesToBeAdded(Arrays.asList(topicOwner)); repositoryUserAssociationUpdateHelper.update(); } } private RepositoryUser retrieveOwnerForTopic(Topic topic, Node topicJcrNode) throws ItemNotFoundException, AccessDeniedException, RepositoryException, ValueFormatException, PathNotFoundException { //Locate the taxonomy of the topic. If the taxonomy is a folksonomy then set the owner to be the //repository user of this folksonomy, otherwise set the owner to be the system user Node taxonomyNode = topicJcrNode.getParent(); while (taxonomyNode != null){ if (StringUtils.equals(CmsBuiltInItem.Folksonomy.getJcrName(), taxonomyNode.getName())){ //Topic belongs to a repository user's folksonomy Node repositoryUserNode = taxonomyNode.getParent(); if (repositoryUserNode == null){ throw new CmsException("Topic "+topic.toString()+ " corresponds to jcr node "+topicJcrNode.getPath() + " which belongs to a folksonomy "+ taxonomyNode.getPath() + " but cannot retrieve parent node"); } if (repositoryUserNode.hasProperty(CmsBuiltInItem.ExternalId.getJcrName())){ RepositoryUser topicOwner = repositoryUserDao.getRepositoryUser(repositoryUserNode.getProperty(CmsBuiltInItem.ExternalId.getJcrName()).getString()); if (topicOwner == null){ throw new CmsException("Topic "+topic.toString()+ " corresponds to jcr node "+topicJcrNode.getPath() + " which belongs to a folksonomy "+ taxonomyNode.getPath() + " of the user "+ repositoryUserNode.getPath()+ " but could not create a RepositoryUser instance with externalId "+ repositoryUserNode.getProperty(CmsBuiltInItem.ExternalId.getJcrName()).getString()); } return topicOwner; } else{ throw new CmsException("Topic "+topic.toString()+ " corresponds to jcr node "+topicJcrNode.getPath() + " which belongs to a folksonomy "+ taxonomyNode.getPath() + " of the user "+ repositoryUserNode.getPath()+ " who does not have an externalId"); } } else if (taxonomyNode.isNodeType(CmsBuiltInItem.Taxonomy.getJcrName())){ return repositoryUserDao.getSystemRepositoryUser(); } taxonomyNode = taxonomyNode.getParent(); } return null; } public Node updateTopic(Session session, Topic topic, Node parentTopicJcrNode, Context context) throws RepositoryException { Node topicJcrNode = context.retrieveNodeForTopic(topic.getId()); if (topicJcrNode == null){ if (topic.getId() != null){ //User has specified an id for TaxonomyNode. Create a new one if(parentTopicJcrNode == null){ if (topic.getTaxonomy() == null){ //Taxonomy is not provided and topic is a new topic. //Add new topic to the default taxonomy cmsRepositoryEntityUtils.addDefaultTaxonomyToTopic(topic); } parentTopicJcrNode = retrieveParentTopicNode(session, topic, context); } return addNewTopicJcrNode(parentTopicJcrNode, topic, session, true, context); } else throw new CmsException("Found no topic with id "+topic.getId()); } updateOwner(topic, topicJcrNode, session,context); updateLocalizedLabels(topic, topicJcrNode); updateName(session, topic, topicJcrNode, context); //Retrieve taxonomy name Node currentTaxonomyNode = JcrNodeUtils.getTaxonomyJcrNode(topicJcrNode, true); String currentTaxonomyName = currentTaxonomyNode.getName(); if (topic.getParent() != null){ updateTopicParent(currentTaxonomyName, topic, topicJcrNode, session, context); } else{ //Topic has become a root Node. if (topic.getTaxonomy() == null || ( StringUtils.isBlank(topic.getTaxonomy().getId()) && StringUtils.isBlank(topic.getTaxonomy().getName()))){ //User provided no taxonomy info. Thus simply check that topic jcr node is under a taxonomy node if (! currentTaxonomyNode.isNodeType(CmsBuiltInItem.Taxonomy.getJcrName())){ throw new CmsException("Topic "+topic.getId()+ ":" + topic.getName() + " cannot be saved under node "+topicJcrNode.getParent().getPath()+ " because this node does not correspond to a taxonomy"); } //At this point topic has not changed its taxonomy, therefore there is no need //to search all objects which relate to this topic if their property accepts //topic's taxonomy //checkThatReferrerContentObjectsAcceptNewTaxonomy(currentTaxonomyName, topic, session ,currentTaxonomyName); } else{ //Get taxonomy Node Node taxonomyNode = retrieveTaxonomyJcrNodeForTopic(session, topic); if (taxonomyNode == null){ throw new CmsException("Unable to locate JCR node for taxonomy "+ topic.getTaxonomy().getName()); } //Since topic is a root topic then its parent must be a taxonomy node if (!topicJcrNode.getParent().getIdentifier().equals(taxonomyNode.getIdentifier())){ checkThatReferrerContentObjectsAcceptNewTaxonomy(currentTaxonomyName, topic, session ,topic.getTaxonomy().getName()); session.move(topicJcrNode.getPath(), taxonomyNode.getPath()+CmsConstants.FORWARD_SLASH+topicJcrNode.getName()); } } } updateOrder(topic, topicJcrNode); updateAllowsReferrerContentObject(topic, topicJcrNode); return topicJcrNode; } private void checkThatReferrerContentObjectsAcceptNewTaxonomy( String currentTaxonomyName, Topic topic, Session session, String newTaxonomyName) throws RepositoryException { //Get all content object associations to this topic List<CmsRepositoryEntityAssociation> contentObjectAssociationsToTopic = cmsRepositoryEntityAssociationDao.getAllAssociationsOfReferencedEntity(topic.getId(), Topic.class); Map<String, List<String>> topicPropertyPathsPerTaxonomies = contentDefinitionDao.getTopicPropertyPathsPerTaxonomies(); if (CollectionUtils.isNotEmpty(contentObjectAssociationsToTopic)){ for (CmsRepositoryEntityAssociation contentObjectAssociationToTopic : contentObjectAssociationsToTopic){ Node contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session, contentObjectAssociationToTopic.getReferrerCmsRepositoryEntityId()); if (contentObjectNode == null){ throw new CmsException("Found no content object node for "+contentObjectAssociationToTopic.getReferrerCmsRepositoryEntityId()); } if (!contentObjectNode.hasProperty(CmsBuiltInItem.ContentObjectTypeName.getJcrName())){ throw new CmsException("Content object node for "+contentObjectNode.getPath() + " contains no content object type"); } String contentObjectTypeName = contentObjectNode.getProperty(CmsBuiltInItem.ContentObjectTypeName.getJcrName()).getString(); List<String> topicPropertyPathsForCurrentTaxonomy = topicPropertyPathsPerTaxonomies.get(currentTaxonomyName); String propertyPath = null; if (topicPropertyPathsForCurrentTaxonomy != null){ for (String topicPropertyPath : topicPropertyPathsForCurrentTaxonomy){ if (topicPropertyPath.endsWith(contentObjectAssociationToTopic.getReferrerPropertyName())){ propertyPath = topicPropertyPath; break; } } } if (propertyPath == null){ topicPropertyPathsForCurrentTaxonomy = topicPropertyPathsPerTaxonomies.get(CmsConstants.ANY_TAXONOMY); if (topicPropertyPathsForCurrentTaxonomy != null){ for (String topicPropertyPath : topicPropertyPathsForCurrentTaxonomy){ if (topicPropertyPath.endsWith(contentObjectAssociationToTopic.getReferrerPropertyName())){ propertyPath = topicPropertyPath; break; } } } } if (propertyPath == null){ throw new CmsException("Found no topic property path for property "+ contentObjectAssociationToTopic.getReferrerPropertyName()); } CmsPropertyDefinition topicPropertyDefinition = null; try { topicPropertyDefinition = contentDefinitionDao.getCmsPropertyDefinition(propertyPath, contentObjectTypeName); } catch (Exception e) { throw new CmsException(); } if (topicPropertyDefinition == null){ throw new CmsException("Found no topic property definition for "+PropertyPath.createFullPropertyPath(contentObjectTypeName, propertyPath)); } if (topicPropertyDefinition.getValueType() != ValueType.TopicReference){ throw new CmsException("Property "+PropertyPath.createFullPropertyPath(contentObjectTypeName, propertyPath)+ " does not correspond to a topic definition "+ topicPropertyDefinition.getFullPath()); } final List<String> acceptedTaxonomies = ((TopicReferencePropertyDefinition)topicPropertyDefinition).getAcceptedTaxonomies(); if (CollectionUtils.isNotEmpty(acceptedTaxonomies) && ! acceptedTaxonomies.contains(newTaxonomyName)){ throw new CmsException("Cannot move topic "+ topic.getName() + " to taxonomy "+ newTaxonomyName + " because topic is referenced by content object "+ contentObjectAssociationToTopic.getReferrerCmsRepositoryEntityId() + " whose topic property "+ topicPropertyDefinition.getFullPath() + " does not accept taxonomy "+ newTaxonomyName); } } } if (topic.getNumberOfChildren() > 0){ final List<Topic> children = topic.getChildren(); for (Topic child : children){ checkThatReferrerContentObjectsAcceptNewTaxonomy(currentTaxonomyName, child, session, newTaxonomyName); } } } private void updateTopicParent(String currentTaxonomyName, Topic topic, Node topicJcrNode, Session session, Context context) throws RepositoryException { if (topic == null || topic.getParent() ==null){ throw new CmsException("No parent topic provided."); } Topic parentTopic = topic.getParent(); Node newParentTopicJcrNode = context.retrieveNodeForTopic(parentTopic.getId()); if (newParentTopicJcrNode == null){ //check cache with parent's name newParentTopicJcrNode = context.retrieveNodeForTopic(parentTopic.getName()); if (newParentTopicJcrNode == null){ throw new CmsException("Unable to retrieve jcr node for parent topic "+parentTopic.toString()+" of topic "+topic.toString()+". Topic jcr node "+topicJcrNode.getPath()); } } //New Parent's Primary Type can only be Topic or a Taxonomy if (!newParentTopicJcrNode.isNodeType(topicJcrNode.getPrimaryNodeType().getName())){ if (! newParentTopicJcrNode.isNodeType(CmsBuiltInItem.Taxonomy.getJcrName())) throw new CmsException("Parent topic can only be a topic or a taxonomy"); } //Change Parent only if current parent is not the same if (!topicJcrNode.getParent().getIdentifier().equals(newParentTopicJcrNode.getIdentifier())){ Node parentTaxonomyNode = JcrNodeUtils.getTaxonomyJcrNode(newParentTopicJcrNode, true); String parentTaxonomyName = parentTaxonomyNode.getName(); session.move(topicJcrNode.getPath(), newParentTopicJcrNode.getPath()+CmsConstants.FORWARD_SLASH+topicJcrNode.getName()); if (!StringUtils.equals(currentTaxonomyName, parentTaxonomyName)){ checkThatReferrerContentObjectsAcceptNewTaxonomy(currentTaxonomyName, topic, session, parentTaxonomyName); } } } public void removeTopicJcrNode(Node topicJcrNode, Session session, boolean removeJcrNode, Context context) throws RepositoryException{ EntityAssociationDeleteHelper<Topic> entityAssociationDeleteHelper = new EntityAssociationDeleteHelper<Topic>(session,cmsRepositoryEntityAssociationDao, context); removeTopicFromAssociations(entityAssociationDeleteHelper, topicJcrNode); NodeIterator children = null; if (topicJcrNode.isNodeType(CmsBuiltInItem.Topic.getJcrName())) children = topicJcrNode.getNodes(CmsBuiltInItem.Topic.getJcrName()); if (children != null){ while (children.hasNext()){ removeTopicJcrNode(children.nextNode(), session, false, context); //Do not remove child jcr node as its parent will be removed } } if (removeJcrNode){ topicJcrNode.remove(); } } private void removeTopicFromAssociations(EntityAssociationDeleteHelper<Topic> entityAssociationDeleteHelper, Node topicJcrNode) throws RepositoryException { entityAssociationDeleteHelper.setCmsRepositoryEntityIdToBeRemoved(cmsRepositoryEntityUtils.getCmsIdentifier(topicJcrNode)); entityAssociationDeleteHelper.removeOrReplaceAllReferences(Topic.class); } /** * retrieve topic's parent. If no id is specified, taxonomy node is returned instead * @param session * @param parent * @return * @throws CMSDaoException * @throws Exception */ public Node retrieveParentTopicNode(Session session, Topic topic, Context context) throws RepositoryException { Node parentTopicNode = null; Topic parentTopic = topic.getParent(); if (parentTopic != null){ if (parentTopic.getId()!=null){ parentTopicNode = context.retrieveNodeForTopic(parentTopic.getId()); } if (parentTopicNode==null && parentTopic.getName()!=null){ parentTopicNode = context.retrieveNodeForTopic(parentTopic.getName()); } if (parentTopicNode == null){ throw new CmsException("Could not find jcr node for topic "+parentTopic.toString()); } } if (parentTopicNode != null){ return parentTopicNode; } else{ return retrieveTaxonomyJcrNodeForTopic(session, topic); } } private Node retrieveTaxonomyJcrNodeForTopic(Session session, Topic topic) throws RepositoryException, PathNotFoundException { //Check taxonomy String taxonomyName = (topic.getTaxonomy() == null)? null : topic.getTaxonomy().getName(); //Parent Topic is null. Topic is a root Topic. Search for its Taxonomy if (StringUtils.isBlank(taxonomyName)){ //Check if id is provided String taxonomyId = (topic.getTaxonomy() == null)? null : topic.getTaxonomy().getId(); if (StringUtils.isNotBlank(taxonomyId)){ //Look for taxonomy node using its id try{ return cmsRepositoryEntityUtils.retrieveUniqueNodeForCmsRepositoryEntityId(session, taxonomyId); }catch(Exception e){ logger.error("",e); throw new CmsException("No taxonomy is provided and no parent is defined"); } } throw new CmsException("No taxonomy is provided and no parent is defined"); } if (taxonomyName.equals(CmsBuiltInItem.Folksonomy.getJcrName())) { // Topic's Taxonomy is Topic Owner's Folksonomy if (topic.getOwner() == null || StringUtils.isBlank(topic.getOwner().getId())) throw new CmsException("Topic Owner has not been preprocessed. No id found "); RepositoryUser topicOwner = topic.getOwner(); // Get repository user node // TODO Test this case as it is possible that for a new repository user // the following method should return null since query does not take into account // uncommitted changes made so far in session Node repositoryUserNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForRepositoryUser(session, topicOwner.getId()); if (repositoryUserNode == null) throw new CmsException("Repository User "+ topic.getOwner().toString() + " does not exist in repository"); return repositoryUserNode.getNode(CmsBuiltInItem.Folksonomy.getJcrName()); } else //Retrieve Taxonomy Jcr Node return taxonomyDao.getTaxonomyJcrNode(session, taxonomyName, true); } public void setSystemUserAsTopicOwner(Topic topic, RepositoryUser systemUser) { if (topic != null){ //Set system user as topic owner if topic does not have any user //or it happens to have another user which is not permitted if (! usersAreTheSame(topic.getOwner(), systemUser)){ if (!StringUtils.equals(systemUser.getExternalId(), CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID)){ throw new CmsException("Cannot set topic owner repository User "+systemUser.getExternalId()); } topic.setOwner(systemUser); } if (topic.isChildrenLoaded()){ List<Topic> childTopics = topic.getChildren(); if (CollectionUtils.isNotEmpty(childTopics)){ for (Topic child : childTopics){ RepositoryUser childOwner = child.getOwner(); //One of them is null therefore change child's taxonomy if ( childOwner == null){ setSystemUserAsTopicOwner(child, systemUser); } else{ //Child does have an owner //Proceed only if they are not the same if (childOwner != systemUser || ! StringUtils.equals(childOwner.getId(), systemUser.getId())){ setSystemUserAsTopicOwner(child, systemUser); } } } } } } } private boolean usersAreTheSame(RepositoryUser user1 , RepositoryUser user2){ if (user1 == null || user2 == null){ return false; } if (user1 == user2){ return true; } if (user1.getId() != null && StringUtils.equals(user1.getId(), user2.getId())){ return true; } if (user1.getExternalId() != null && StringUtils.equals(user1.getExternalId(), user2.getExternalId())){ return true; } return false; } }