org.betaconceptframework.astroboa.engine.jcr.dao.RepositoryUserDao.java Source code

Java tutorial

Introduction

Here is the source code for org.betaconceptframework.astroboa.engine.jcr.dao.RepositoryUserDao.java

Source

/*
 * 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.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.CmsApiConstants;
import org.betaconceptframework.astroboa.api.model.CmsRepositoryEntity;
import org.betaconceptframework.astroboa.api.model.RepositoryUser;
import org.betaconceptframework.astroboa.api.model.RepositoryUserType;
import org.betaconceptframework.astroboa.api.model.Space;
import org.betaconceptframework.astroboa.api.model.Taxonomy;
import org.betaconceptframework.astroboa.api.model.definition.Localization;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.api.model.io.ImportConfiguration;
import org.betaconceptframework.astroboa.api.model.io.ImportConfiguration.PersistMode;
import org.betaconceptframework.astroboa.api.model.query.criteria.ContentObjectCriteria;
import org.betaconceptframework.astroboa.api.model.query.criteria.RepositoryUserCriteria;
import org.betaconceptframework.astroboa.api.model.query.criteria.SpaceCriteria;
import org.betaconceptframework.astroboa.api.model.query.render.RenderProperties;
import org.betaconceptframework.astroboa.engine.cache.regions.JcrQueryCacheRegion;
import org.betaconceptframework.astroboa.engine.database.dao.CmsRepositoryEntityAssociationDao;
import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryHandler;
import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryResult;
import org.betaconceptframework.astroboa.engine.jcr.renderer.RepositoryUserRenderer;
import org.betaconceptframework.astroboa.engine.jcr.util.CmsLocalizationUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.CmsRepositoryEntityUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.Context;
import org.betaconceptframework.astroboa.engine.jcr.util.EntityAssociationDeleteHelper;
import org.betaconceptframework.astroboa.engine.jcr.util.EntityAssociationUpdateHelper;
import org.betaconceptframework.astroboa.engine.jcr.util.JcrNodeUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.RendererUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.SpaceUtils;
import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory;
import org.betaconceptframework.astroboa.model.factory.CmsRepositoryEntityFactoryForActiveClient;
import org.betaconceptframework.astroboa.model.impl.RepositoryUserImpl;
import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 
 * @author Gregory Chomatas (gchomatas@betaconcept.com)
 * @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
 *
 */
public class RepositoryUserDao extends JcrDaoSupport {

    @Autowired
    private CmsRepositoryEntityUtils cmsRepositoryEntityUtils;

    @Autowired
    private JcrQueryCacheRegion jcrQueryCacheRegion;

    @Autowired
    private RendererUtils rendererUtils;

    @Autowired
    private CmsQueryHandler cmsQueryHandler;

    @Autowired
    private RepositoryUserRenderer repositoryUserRenderer;

    @Autowired
    private CmsLocalizationUtils cmsLocalizationUtils;

    @Autowired
    private ContentObjectDao contentObjectDao;

    @Autowired
    private SpaceUtils spaceUtils;

    /**
     * Provides localized labels for folksonomies
     */
    private Localization defaultFolksonomyLocalization;

    /**
     * Provides localized labels for Spaces
     */
    private Localization defaultSpaceLocalization;

    @Autowired
    private CmsRepositoryEntityAssociationDao cmsRepositoryEntityAssociationDao;

    @Autowired
    private ImportDao importDao;

    public void setDefaultSpaceLocalization(Localization defaultSpaceLocalization) {
        this.defaultSpaceLocalization = defaultSpaceLocalization;
    }

    public void setDefaultFolksonomyLocalization(Localization defaultFolksonomyLocalization) {
        this.defaultFolksonomyLocalization = defaultFolksonomyLocalization;
    }

    public RepositoryUser getSystemRepositoryUser() {
        return getRepositoryUser(CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID);
    }

    public void removeRepositoryUserAndOwnedObjects(String repositoryUserId) {

        removeRepositoryUser(repositoryUserId, null, true);
    }

    private void removeRepositoryUser(String repositoryUserId, RepositoryUser alternativeUser,
            boolean removeObjectsWhoseOwnerIsTheUserToBeDeleted) {

        Context context = null;

        try {
            Session session = getSession();

            if (StringUtils.isBlank(repositoryUserId))
                throw new ItemNotFoundException("Undefined repository user id " + repositoryUserId);

            //         Retrieve user node to be removed
            Node repositoryUserNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForRepositoryUser(session,
                    repositoryUserId);

            if (repositoryUserNode == null)
                throw new CmsException("No repository User found with Id " + repositoryUserId);

            if (repositoryUserNode.hasProperty(CmsBuiltInItem.ExternalId.getJcrName())) {
                String externalId = repositoryUserNode.getProperty(CmsBuiltInItem.ExternalId.getJcrName())
                        .getString();

                if (CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID.equals(externalId)) {
                    throw new CmsException("Invalid delete operation. SYSTEM RepositoryUser cannot be deleted.");
                }
            }

            if (alternativeUser == null && !removeObjectsWhoseOwnerIsTheUserToBeDeleted) {
                throw new CmsException("No alternative user has been provided");
            }

            context = new Context(cmsRepositoryEntityUtils, cmsQueryHandler, session);

            //Save any alternative user
            if (alternativeUser != null) {
                updateRepositoryUserNode(session, alternativeUser, context);
            }

            //remove all node References
            removeReferencesForRepositoryUser(session, alternativeUser, removeObjectsWhoseOwnerIsTheUserToBeDeleted,
                    repositoryUserId, context);

            //remove user node
            repositoryUserNode.remove();

            session.save();

            //Notify cache
            //jcrQueryCacheRegion.removeRegion();

        } catch (Exception e) {
            throw new CmsException(e);
        } finally {
            if (context != null) {
                context.dispose();
                context = null;
            }
        }
    }

    public void removeRepositoryUser(String repositoryUserId, RepositoryUser alternativeUser) {

        removeRepositoryUser(repositoryUserId, alternativeUser, (alternativeUser == null));

    }

    public RepositoryUser saveRepositoryUser(Object repositoryUserSource) {

        if (repositoryUserSource == null) {
            throw new CmsException("Cannot save an empty RepositoryUser !");
        }

        if (repositoryUserSource instanceof String) {
            //Use importer to unmarshal String to RepositoryUser
            //and to save it as well.
            //What is happened is that importDao will create a RepositoryUser
            //and will pass it here again to save it. 
            ImportConfiguration configuration = ImportConfiguration.repositoryUser()
                    .persist(PersistMode.PERSIST_MAIN_ENTITY).build();

            return importDao.importRepositoryUser((String) repositoryUserSource, configuration);
        }

        if (!(repositoryUserSource instanceof RepositoryUser)) {
            throw new CmsException("Expecting either String or RepositoryUser and not "
                    + repositoryUserSource.getClass().getName());
        }

        RepositoryUser repositoryUser = (RepositoryUser) repositoryUserSource;

        Context context = null;
        try {
            Session session = getSession();

            context = new Context(cmsRepositoryEntityUtils, cmsQueryHandler, session);

            updateRepositoryUserNode(session, repositoryUser, context);

            session.save();

            //Inform cache
            //jcrQueryCacheRegion.removeRegion();

            return repositoryUser;
        } catch (Exception e) {
            throw new CmsException(e);
        } finally {
            if (context != null) {
                context.dispose();
                context = null;
            }
        }

    }

    public List<RepositoryUser> searchRepositoryUsers(RepositoryUserCriteria repositoryUserCriteria) {
        Session session = null;

        if (repositoryUserCriteria == null)
            throw new CmsException("Null repository user criteria");

        try {

            //For some reason user has asked for 0 limit
            //Returned an empty list. No need to perform the
            //query. this method output must be changed to CmsOutcome
            //in order to provide user with the total result count
            //even when limit is 0 , that is no result should be returned
            if (repositoryUserCriteria.getLimit() == 0) {
                return new ArrayList<RepositoryUser>();
            }

            List<RepositoryUser> repositoryUserList = null;

            if (repositoryUserCriteria.isCacheable()) {
                //Search in cache

                repositoryUserList = (List<RepositoryUser>) jcrQueryCacheRegion
                        .getJcrQueryResults(repositoryUserCriteria);
            }

            if (repositoryUserList != null)
                return repositoryUserList;
            else {

                session = getSession();

                repositoryUserList = new ArrayList<RepositoryUser>();

                //Need new instance in case during rendering render instructions are updated
                RenderProperties renderPropertiesForCache = rendererUtils
                        .copyRenderPropertiesFromCriteria(repositoryUserCriteria);

                //CmsQueryResultSecurityHandler cmsQueryResultSecurityHandler = new CmsQueryResultSecurityHandler(cmsQueryHandler, 
                //   repositoryUserCriteria,session, accessManager);

                CmsQueryResult cmsQueryResult = cmsQueryHandler.getNodesFromXPathQuery(session,
                        repositoryUserCriteria);

                NodeIterator nodeIterator = cmsQueryResult.getNodeIterator();

                Map<String, CmsRepositoryEntity> cachedRepositoryEntities = new HashMap<String, CmsRepositoryEntity>();

                List<String> repositoryUserIdsForCache = new ArrayList<String>();

                while (nodeIterator.hasNext()) {
                    RepositoryUser repositoryUser = renderRepositoryUserFromNode(nodeIterator.nextNode(), session,
                            repositoryUserCriteria.getRenderProperties(), cachedRepositoryEntities);
                    repositoryUserList.add(repositoryUser);
                    repositoryUserIdsForCache.add(repositoryUser.getId());
                }

                //Cache results
                if (repositoryUserCriteria.isCacheable()) {
                    if (!StringUtils.isBlank(repositoryUserCriteria.getXPathQuery())
                            && CollectionUtils.isNotEmpty(repositoryUserList)) {
                        jcrQueryCacheRegion.cacheJcrQueryResults(repositoryUserCriteria, repositoryUserList,
                                renderPropertiesForCache);
                    }
                }

                return repositoryUserList;
            }

        } catch (Exception e) {
            throw new CmsException(e);
        }

    }

    public RepositoryUser renderRepositoryUserFromNode(Node node, Session session,
            RenderProperties renderProperties, Map<String, CmsRepositoryEntity> cachedRepositoryEntities)
            throws RepositoryException {

        return repositoryUserRenderer.renderRepositoryUserNode(node, renderProperties, session,
                cachedRepositoryEntities);
    }

    private void updateRepositoryUserNode(Session session, RepositoryUser repositoryUser, Context context)
            throws RepositoryException {
        Node repositoryUserNode = retrieveOrCreateRepositoryUserNode(session, repositoryUser);

        populateRepositoryUserNode(repositoryUserNode, repositoryUser, session, context);

    }

    private Node retrieveOrCreateRepositoryUserNode(Session session, RepositoryUser repositoryUser)
            throws RepositoryException {
        //1. ExternalId is not provided. Search user using its identifier
        if (StringUtils.isBlank(repositoryUser.getExternalId())) {
            if (repositoryUser.getId() == null) {
                throw new CmsException("Repository user has not external id and no cms identifier");
            } else {
                //Search for a repository user node with provided identifier
                Node repositoryUserNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForRepositoryUser(session,
                        repositoryUser.getId());

                if (repositoryUserNode != null) {
                    return repositoryUserNode;
                } else {
                    throw new CmsException("Could not update repository user " + repositoryUser.toString()
                            + " because no repository user with such id is found in repository and externalId is not provided");
                }

            }
        } else {
            //2.External Id is provided. 
            //a. Check external Id belongs to SYSTEM user
            if (CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID.equals(repositoryUser.getExternalId())) {
                //SYSTEM user is updated. Retrieve system repository user node
                //In case repositoryUser instance has an identifier ignore it
                return retrieveSystemRepositoryUserNode(session, true);
            } else {
                //Check how many users exist with the same external id
                Node existingRepositoryUserNode = checkForDuplicateExternalId(repositoryUser, session);

                if (existingRepositoryUserNode != null) {
                    return existingRepositoryUserNode;
                } else {
                    //No node found with provided identifier and/or external Id. Create new node
                    return createRepositoryUserNode(repositoryUser, session);
                }
            }
        }

    }

    public RepositoryUser createSystemRepositoryUser() {

        Context context = null;
        try {
            Session session = getSession();

            if (retrieveSystemRepositoryUserNode(session, false) != null) {
                throw new Exception("RepositoryUser SYSTEM already exists");
            }

            RepositoryUser systemUser = CmsRepositoryEntityFactoryForActiveClient.INSTANCE.getFactory()
                    .newRepositoryUser();
            systemUser.setExternalId(CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID);
            systemUser.setLabel(CmsApiConstants.SYSTEM_REPOSITORY_USER_LABEL);

            Node systemUserNode = createRepositoryUserNode(systemUser, session);

            context = new Context(cmsRepositoryEntityUtils, cmsQueryHandler, session);

            populateRepositoryUserNode(systemUserNode, systemUser, session, context);

            session.save();

            return systemUser;
        } catch (Exception e) {
            throw new CmsException(e);
        } finally {
            if (context != null) {
                context.dispose();
                context = null;
            }
        }

    }

    private Node retrieveSystemRepositoryUserNode(Session session, boolean throwExceptionIfNotFound)
            throws RepositoryException {

        RepositoryUserCriteria userCriteria = CmsCriteriaFactory.newRepositoryUserCriteria();
        userCriteria.doNotCacheResults();
        userCriteria.setLimit(1);
        userCriteria.addExternalIdEqualsCriterion(CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID);

        CmsQueryResult systemUserQueryResult = cmsQueryHandler.getNodesFromXPathQuery(session, userCriteria);

        if (systemUserQueryResult == null || systemUserQueryResult.getTotalRowCount() == 0) {
            if (throwExceptionIfNotFound) {
                throw new RepositoryException("Problem with locating system repository user node. Query "
                        + userCriteria.getXPathQuery() + " did not returned 1 node");
            } else {
                return null;
            }
        } else if (systemUserQueryResult.getTotalRowCount() == 1) {
            return systemUserQueryResult.getNodeIterator().nextNode();
        } else {
            throw new RepositoryException(
                    "Problem with locating system repository user node. Found more than one jcr nodes representing system repository user");
        }

    }

    private Node createRepositoryUserNode(RepositoryUser repositoryUser, Session session)
            throws RepositoryException {

        Node repositoryUserNode = JcrNodeUtils.addRepositoryUserNode(session);

        //Create CmsIdentifier
        cmsRepositoryEntityUtils.createCmsIdentifier(repositoryUserNode, repositoryUser, true);

        return repositoryUserNode;
    }

    private void populateRepositoryUserNode(Node repositoryUserNode, RepositoryUser repositoryUser, Session session,
            Context context) throws RepositoryException {

        String repositoryUserExternalId = repositoryUser.getExternalId();

        //External Id. Update it only if it does not exists
        if (!repositoryUserNode.hasProperty(CmsBuiltInItem.ExternalId.getJcrName())) {
            repositoryUserNode.setProperty(CmsBuiltInItem.ExternalId.getJcrName(), repositoryUserExternalId);
        }
        //or it is not SYSTEM RepositoyUser ExternalId and it is not the same with the one existed
        else {
            String existingExternalId = repositoryUserNode.getProperty(CmsBuiltInItem.ExternalId.getJcrName())
                    .getString();

            boolean repositoryUserExternalIdIsDifferentThanExisting = !existingExternalId
                    .equals(repositoryUserExternalId);

            if (repositoryUserExternalIdIsDifferentThanExisting) {
                if (CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID.equals(existingExternalId)) {
                    throw new RepositoryException(
                            "Invalid operation. Tried to update SYSTEM repository user externalId.");
                } else {
                    repositoryUserNode.setProperty(CmsBuiltInItem.ExternalId.getJcrName(),
                            repositoryUserExternalId);
                }
            }
        }

        //Label
        repositoryUserNode.setProperty(CmsBuiltInItem.Label.getJcrName(), repositoryUser.getLabel());

        //User Type
        if (repositoryUser.getUserType() == null) {
            repositoryUser.setUserType(RepositoryUserType.User);
        }

        repositoryUserNode.setProperty(CmsBuiltInItem.UserType.getJcrName(),
                repositoryUser.getUserType().toString());

        populateSpace(repositoryUser, repositoryUserNode, session, context);

        populateFolksonomy(repositoryUser, repositoryUserNode, session);

        // TODO Preferences Implement method
        populatePreferences(repositoryUser, repositoryUserNode);
    }

    private Node checkForDuplicateExternalId(RepositoryUser repositoryUserToBeSaved, Session session)
            throws RepositoryException, ValueFormatException, PathNotFoundException {
        RepositoryUserCriteria userCriteria = CmsCriteriaFactory.newRepositoryUserCriteria();
        userCriteria.doNotCacheResults();
        userCriteria.setLimit(2);
        userCriteria.addExternalIdEqualsCriterion(repositoryUserToBeSaved.getExternalId());

        CmsQueryResult usersWithTheSameExternalId = cmsQueryHandler.getNodesFromXPathQuery(session, userCriteria);

        if (usersWithTheSameExternalId != null) {
            if (usersWithTheSameExternalId.getTotalRowCount() > 1) {
                throw new RepositoryException("Found more than one repository users with the same external id "
                        + repositoryUserToBeSaved.getExternalId());
            }

            if (usersWithTheSameExternalId.getTotalRowCount() == 1) {
                if (repositoryUserToBeSaved.getId() == null) {
                    throw new RepositoryException("A repository user with the same external id "
                            + repositoryUserToBeSaved.getExternalId() + " already exists.");
                } else {
                    Node existingRepositoryUserNode = usersWithTheSameExternalId.getNodeIterator().nextNode();

                    //Must be the same node
                    if (!existingRepositoryUserNode.hasProperty(CmsBuiltInItem.CmsIdentifier.getJcrName())
                            || !existingRepositoryUserNode.getProperty(CmsBuiltInItem.CmsIdentifier.getJcrName())
                                    .getString().equals(repositoryUserToBeSaved.getId())) {
                        throw new RepositoryException("A repository user with the same external id "
                                + repositoryUserToBeSaved.getExternalId() + " already exists.");
                    }

                    return existingRepositoryUserNode;
                }
            }
        }

        //No other node found with the same external id. in case identifier is provided

        return null;

    }

    private void populateFolksonomy(RepositoryUser repositoryUser, Node repositoryUserNode, Session session)
            throws RepositoryException {

        Taxonomy repositoryUserFolksonomy = repositoryUser.getFolksonomy();

        if (repositoryUserFolksonomy == null) {
            ((RepositoryUserImpl) repositoryUser)
                    .setFolksonomy(cmsRepositoryEntityFactoryForActiveClient.newTaxonomy());
            repositoryUserFolksonomy = repositoryUser.getFolksonomy();
        }

        //Folksonomy node should have already been created. No need to check for it existence
        Node folksonomyNode = repositoryUserNode.getNode(CmsBuiltInItem.Folksonomy.getJcrName());

        //If repository user folksonomy has no localized labels use the default
        if (!repositoryUserFolksonomy.hasLocalizedLabels()
                && MapUtils.isNotEmpty(defaultFolksonomyLocalization.getLocalizedLabels())) {
            repositoryUserFolksonomy.getLocalizedLabels()
                    .putAll(defaultFolksonomyLocalization.getLocalizedLabels());
        }

        //Update localization for repository user folksonomy
        cmsLocalizationUtils.updateCmsLocalization(repositoryUserFolksonomy, folksonomyNode);

        // In case repository user is a new user and its folksonomy does not have a name
        String providedFolksonomyName = repositoryUserFolksonomy.getName();
        if (StringUtils.isBlank(providedFolksonomyName)) {
            repositoryUserFolksonomy.setName(folksonomyNode.getName());
        } else {
            //Folksonomy Name is a fixed name and should never change
            if (!folksonomyNode.getName().equals(providedFolksonomyName)) {
                throw new RepositoryException("Invalid folksonomy name " + providedFolksonomyName);
            }
        }

        //Create Folksonomy Identifier if folksonomy is a new one
        if (folksonomyNode.isNew()) {
            if (cmsRepositoryEntityUtils.hasCmsIdentifier(folksonomyNode)) {
                //This should never happen
                throw new CmsException("Folskonomy jcr node is new but an idnetifier property already exists");
            }

            //Create a Astroboa identifier for folskonomy or use the one provided
            cmsRepositoryEntityUtils.createCmsIdentifier(folksonomyNode, repositoryUserFolksonomy, true);
        } else {
            //Folksonomy node is not new. Check that an identifier exists
            if (!cmsRepositoryEntityUtils.hasCmsIdentifier(folksonomyNode)) {
                cmsRepositoryEntityUtils.createCmsIdentifier(folksonomyNode, repositoryUserFolksonomy, true);
            } else {
                String folksonomyIdentifier = cmsRepositoryEntityUtils.getCmsIdentifier(folksonomyNode);

                //User has provided an identifier for folksonomy.
                //Check if it matches with the one in folksonomy jcr node
                if (repositoryUserFolksonomy.getId() != null) {
                    if (!repositoryUserFolksonomy.getId().equals(folksonomyIdentifier)
                            && !StringUtils.equals(CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID,
                                    repositoryUser.getExternalId())) {
                        throw new CmsException("Folksonomy identifier " + folksonomyIdentifier
                                + " for repository user " + repositoryUser.getLabel()
                                + " does not match with the provided identifier "
                                + repositoryUserFolksonomy.getId());
                    }
                } else {
                    //User does not have an identifier for folksonomy. Update its value
                    repositoryUserFolksonomy.setId(folksonomyIdentifier);
                }
            }
        }

    }

    private void populatePreferences(RepositoryUser repositoryUser, Node repositoryUserNode) {

    }

    private void populateSpace(RepositoryUser repositoryUser, Node repositoryUserNode, Session session,
            Context context) throws RepositoryException {

        Space repositoryUserSpace = repositoryUser.getSpace();
        if (repositoryUserSpace == null) {
            ((RepositoryUserImpl) repositoryUser).setSpace(cmsRepositoryEntityFactoryForActiveClient.newSpace());
            repositoryUserSpace = repositoryUser.getSpace();
        }

        if (!repositoryUser.getSpace().hasLocalizedLabels()
                && MapUtils.isNotEmpty(defaultSpaceLocalization.getLocalizedLabels())) {
            repositoryUser.getSpace().getLocalizedLabels().putAll(defaultSpaceLocalization.getLocalizedLabels());
        }

        if (repositoryUserSpace.getName() == null) {
            repositoryUserSpace.setName("spaceForUser" + repositoryUser.getExternalId());
        }

        //Since Space name must follow a specific pattern, check if repository user space name is valid.
        //if not then issue a warning and replace value with a default value.
        if (!cmsRepositoryEntityUtils.isValidSystemName(repositoryUserSpace.getName())) {
            //First try to remove all white spaces, in case space name has not changed since it was first created by the 
            //following line of code
            //repositoryUserSpace.setName("Space for user"+ repositoryUser.getExternalId());
            String nameWithoutWhiteSpaces = StringUtils.deleteWhitespace(repositoryUserSpace.getName());

            if (!cmsRepositoryEntityUtils.isValidSystemName(nameWithoutWhiteSpaces)) {
                //Name is still invalid. Issue a warning and replace name so that save can continue safely
                logger.warn(
                        "Repository User's '{}' Space name '{}' does not follow pattern {} and to will change to 'spaceForUser'. "
                                + " In order to provide a different name you must explicitly save RepositotyUser Space by using SpaceService.",
                        new Object[] { repositoryUser.getLabel(), repositoryUserSpace.getName(),
                                CmsConstants.SYSTEM_NAME_REG_EXP });
            } else {
                repositoryUserSpace.setName(nameWithoutWhiteSpaces);
            }
        }

        //Create Space if it does not exist
        Node spaceNode = null;

        if (!repositoryUserNode.hasNode(CmsBuiltInItem.Space.getJcrName())) {

            repositoryUserSpace.setOwner(repositoryUser);
            repositoryUserSpace.setOrder(Long.valueOf(1));

            //Create new node
            spaceNode = JcrNodeUtils.addSpaceNode(repositoryUserNode, CmsBuiltInItem.Space.getJcrName());

            //Create a Astroboa identifier for space or use the one provided
            cmsRepositoryEntityUtils.createCmsIdentifier(spaceNode, repositoryUserSpace, true);

            //Set Owner
            //Inform associations about relation between new space and repository user
            EntityAssociationUpdateHelper<RepositoryUser> repositoryUserAssociationUpdateHelper = new EntityAssociationUpdateHelper<RepositoryUser>(
                    session, cmsRepositoryEntityAssociationDao, context);

            repositoryUserAssociationUpdateHelper.setReferrerCmsRepositoryEntityNode(spaceNode);
            repositoryUserAssociationUpdateHelper.setReferrerPropertyName(CmsBuiltInItem.OwnerCmsIdentifier);
            repositoryUserAssociationUpdateHelper.setValuesToBeAdded(Arrays.asList(repositoryUser));
            repositoryUserAssociationUpdateHelper.update();
        } else {
            spaceNode = repositoryUserNode.getNode(CmsBuiltInItem.Space.getJcrName());

            if (!repositoryUser.getSpace().hasLocalizedLabels()
                    && MapUtils.isNotEmpty(defaultSpaceLocalization.getLocalizedLabels())) {
                repositoryUser.getSpace().getLocalizedLabels()
                        .putAll(defaultSpaceLocalization.getLocalizedLabels());
            }

            //Space node is not new. Check that an identifier exists
            if (!cmsRepositoryEntityUtils.hasCmsIdentifier(spaceNode)) {
                cmsRepositoryEntityUtils.createCmsIdentifier(spaceNode, repositoryUserSpace, true);
            } else {

                String spaceIdentifier = cmsRepositoryEntityUtils.getCmsIdentifier(spaceNode);

                //User has provided an identifier for space
                //Check if it matches with the one in space jcr node only if space does not represent SYSTEM's space
                if (repositoryUserSpace.getId() != null) {
                    if (!repositoryUserSpace.getId().equals(spaceIdentifier)
                            && !StringUtils.equals(CmsApiConstants.SYSTEM_REPOSITORY_USER_EXTRENAL_ID,
                                    repositoryUser.getExternalId())) {
                        throw new CmsException("Space identifier " + spaceIdentifier + " for repository user "
                                + repositoryUser.getLabel() + " does not match with the provided identifier "
                                + repositoryUserSpace.getId());
                    }
                } else {
                    //User does not have an identifier for space. Update its value
                    repositoryUserSpace.setId(spaceIdentifier);
                }
            }
        }

        //Update localization for repository user space
        spaceUtils.updateLocalizedLabels(repositoryUser.getSpace(), spaceNode);

        //Populate Node with default values
        spaceUtils.updateOrder(repositoryUser.getSpace(), spaceNode);
        spaceUtils.updateName(repositoryUser.getSpace(), spaceNode);

    }

    private void removeReferencesForRepositoryUser(Session session, RepositoryUser alternativeUser,
            boolean removeObjectsWhoseOwnerIsTheUserToBeDeleted, String repositoryUserId, Context context)
            throws Exception {

        if (removeObjectsWhoseOwnerIsTheUserToBeDeleted) {
            removeObjectsWhoseOwnerIsTheUserToBeDeleted(session, repositoryUserId, context);
        } else {

            RepositoryUser userToBeRemoved = cmsRepositoryEntityFactoryForActiveClient.newRepositoryUser();
            userToBeRemoved.setId(repositoryUserId);

            EntityAssociationDeleteHelper<RepositoryUser> repositoryUserRemover = new EntityAssociationDeleteHelper<RepositoryUser>(
                    session, cmsRepositoryEntityAssociationDao, context);

            if (alternativeUser != null) {
                repositoryUserRemover.setCmsRepositoryEntityIdReplacement(alternativeUser.getId());
            }

            repositoryUserRemover.setCmsRepositoryEntityIdToBeRemoved(userToBeRemoved.getId());

            repositoryUserRemover.removeOrReplaceAllReferences(RepositoryUser.class);
        }
    }

    private void removeObjectsWhoseOwnerIsTheUserToBeDeleted(Session session, String repositoryUserId,
            Context context) throws RepositoryException {

        removeContentObjectsOwnedByUser(repositoryUserId, session, context);

        removeSpacesOwnedByUser(repositoryUserId, session, context);

    }

    private void removeContentObjectsOwnedByUser(String repositoryUserId, Session session, Context context)
            throws RepositoryException {

        ContentObjectCriteria contentObjectCriteria = CmsCriteriaFactory.newContentObjectCriteria();
        contentObjectCriteria.addOwnerIdEqualsCriterion(repositoryUserId);

        NodeIterator contentObjectNodesFound = cmsQueryHandler
                .getNodesFromXPathQuery(session, contentObjectCriteria).getNodeIterator();

        while (contentObjectNodesFound.hasNext()) {
            Node contentObjectNode = contentObjectNodesFound.nextNode();

            contentObjectDao.removeContentObjectNode(contentObjectNode, true, session, context);
        }

    }

    private void removeSpacesOwnedByUser(String repositoryUserId, Session session, Context context)
            throws RepositoryException {
        Map<String, Node> spacesToBeDeleted = new HashMap<String, Node>();

        SpaceCriteria spaceCriteria = CmsCriteriaFactory.newSpaceCriteria();
        spaceCriteria.addOwnerIdEqualsCriterion(repositoryUserId);

        NodeIterator spacesFound = cmsQueryHandler.getNodesFromXPathQuery(session, spaceCriteria).getNodeIterator();

        while (spacesFound.hasNext()) {
            Node spaceNode = spacesFound.nextNode();

            //Organization Space is not to be deleted
            if (Space.ORGANIZATION_SPACE_NAME.equalsIgnoreCase(spaceNode.getName())) {
                throw new CmsException(Space.ORGANIZATION_SPACE_NAME + " cannot be deleted");
            }

            Node parent = spaceNode.getParent();

            if (!parent.isNodeType(CmsBuiltInItem.RepositoryUser.getJcrName())
                    && !spacesToBeDeleted.containsKey(spaceNode.getIdentifier())) {
                boolean found = false;
                //Iterate through space tree to see if its parent is marked for deletion
                while (parent != null && parent.isNodeType(CmsBuiltInItem.Space.getJcrName())) {
                    if (!spacesToBeDeleted.containsKey(parent.getIdentifier())) {
                        parent = parent.getParent();
                    } else {
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    spacesToBeDeleted.put(spaceNode.getIdentifier(), spaceNode);
                }
            }
        }

        if (MapUtils.isNotEmpty(spacesToBeDeleted)) {
            for (Node node : spacesToBeDeleted.values()) {
                spaceUtils.removeSpaceJcrNode(node, session, true, context);
            }
        }
    }

    public RepositoryUser getRepositoryUser(String externalId) {

        if (StringUtils.isBlank(externalId)) {
            throw new CmsException("No external id provided");
        }

        RepositoryUserCriteria repositoryUserCriteria = CmsCriteriaFactory.newRepositoryUserCriteria();
        repositoryUserCriteria.addExternalIdEqualsCriterion(externalId);
        repositoryUserCriteria.setOffsetAndLimit(0, 1);

        List<RepositoryUser> repositoryUsers = searchRepositoryUsers(repositoryUserCriteria);

        if (CollectionUtils.isNotEmpty(repositoryUsers) && repositoryUsers.size() > 1) {
            throw new CmsException("Found more than one repository user with external id " + externalId);
        }

        return repositoryUsers.isEmpty() ? null : repositoryUsers.get(0);

    }
}