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

Java tutorial

Introduction

Here is the source code for org.betaconceptframework.astroboa.engine.jcr.dao.ContentDao.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.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;

import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DurationFormatUtils;
import org.betaconceptframework.astroboa.api.model.BinaryChannel;
import org.betaconceptframework.astroboa.api.model.CalendarProperty;
import org.betaconceptframework.astroboa.api.model.CmsProperty;
import org.betaconceptframework.astroboa.api.model.CmsRepositoryEntity;
import org.betaconceptframework.astroboa.api.model.ContentObject;
import org.betaconceptframework.astroboa.api.model.ContentObjectFolder;
import org.betaconceptframework.astroboa.api.model.StringProperty;
import org.betaconceptframework.astroboa.api.model.definition.CmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition;
import org.betaconceptframework.astroboa.api.model.exception.CmsConcurrentModificationException;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.api.model.io.FetchLevel;
import org.betaconceptframework.astroboa.api.model.io.ImportConfiguration;
import org.betaconceptframework.astroboa.api.model.io.ImportConfiguration.PersistMode;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.api.model.io.SerializationConfiguration;
import org.betaconceptframework.astroboa.api.model.query.CacheRegion;
import org.betaconceptframework.astroboa.api.model.query.CmsOutcome;
import org.betaconceptframework.astroboa.api.model.query.criteria.ContentObjectCriteria;
import org.betaconceptframework.astroboa.api.model.query.render.RenderProperties;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.engine.cache.regions.JcrQueryCacheRegion;
import org.betaconceptframework.astroboa.engine.jcr.io.SerializationBean.CmsEntityType;
import org.betaconceptframework.astroboa.engine.jcr.query.CalendarInfo;
import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryHandler;
import org.betaconceptframework.astroboa.engine.jcr.query.CmsQueryResult;
import org.betaconceptframework.astroboa.engine.jcr.renderer.BinaryChannelRenderer;
import org.betaconceptframework.astroboa.engine.jcr.renderer.ContentObjectFolderRenderer;
import org.betaconceptframework.astroboa.engine.jcr.renderer.ContentObjectRenderer;
import org.betaconceptframework.astroboa.engine.jcr.util.CmsRepositoryEntityUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.Context;
import org.betaconceptframework.astroboa.engine.jcr.util.JcrNodeUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.JcrValueUtils;
import org.betaconceptframework.astroboa.engine.jcr.util.VersionUtils;
import org.betaconceptframework.astroboa.engine.model.lazy.local.LazyComplexCmsPropertyLoader;
import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory;
import org.betaconceptframework.astroboa.model.impl.ComplexCmsPropertyImpl;
import org.betaconceptframework.astroboa.model.impl.ContentObjectImpl;
import org.betaconceptframework.astroboa.model.impl.SaveMode;
import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem;
import org.betaconceptframework.astroboa.model.impl.item.ContentObjectProfileItem;
import org.betaconceptframework.astroboa.model.impl.item.DefinitionReservedName;
import org.betaconceptframework.astroboa.model.impl.item.JcrBuiltInItem;
import org.betaconceptframework.astroboa.model.impl.query.CmsOutcomeImpl;
import org.betaconceptframework.astroboa.model.impl.query.render.RenderPropertiesImpl;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.betaconceptframework.astroboa.util.DateUtils;
import org.betaconceptframework.astroboa.util.PropertyPath;
import org.betaconceptframework.astroboa.util.TreeDepth;
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 ContentDao extends JcrDaoSupport {

    private final Logger logger = LoggerFactory.getLogger(ContentDao.class);

    @Autowired
    private CmsRepositoryEntityUtils cmsRepositoryEntityUtils;

    @Autowired
    private ContentObjectDao contentObjectDao;

    @Autowired
    private JcrQueryCacheRegion jcrQueryCacheRegion;

    @Autowired
    private ContentDefinitionDao contentDefinitionDao;

    @Autowired
    private BinaryChannelRenderer binaryChannelRenderer;

    @Autowired
    private ContentObjectFolderRenderer contentObjectFolderRenderer;

    @Autowired
    private ContentObjectRenderer contentObjectRenderer;

    @Autowired
    private VersionUtils versionUtils;

    @Autowired
    private LazyComplexCmsPropertyLoader lazyComplexCmsPropertyLoader;

    @Autowired
    private CmsQueryHandler cmsQueryHandler;

    @Autowired
    private SerializationDao serializationDao;

    @Autowired
    private ImportDao importDao;

    /**
     * 
     * @param contentObject
     * @param version
     * @param lockToken
     * @param updateLastModificationTime Flag to indicate that profile.modified should be updated
     * @return
     */
    public ContentObject saveContentObject(Object contentSource, boolean version, String lockToken,
            boolean updateLastModificationTime, Context context) {

        long start = System.currentTimeMillis();

        if (contentSource == null) {
            throw new CmsException("Cannot save null content object");
        }

        if (contentSource instanceof String) {

            logger.debug(" Starting saving content object. First import will take place");

            //Use importer to unmarshal String to ContentObject
            //and to save it as well.
            //What is happened is that importDao will create a ContentObject
            //and will pass it to ContentServiceImpl to save it. 
            //It will end up in this method again as a ContentObject
            //if it passes the check of SecureContentObjectSaveAspect
            ImportConfiguration configuration = ImportConfiguration.object()
                    .persist(PersistMode.PERSIST_ENTITY_TREE).version(version)
                    .updateLastModificationTime(updateLastModificationTime).build();

            return importDao.importContentObject((String) contentSource, configuration);
        }

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

        ContentObject contentObject = (ContentObject) contentSource;

        logger.debug(" Starting saving content object {}", contentObject.getSystemName());

        SaveMode saveMode = null;

        Session session = null;

        boolean disposeContextWhenSaveIsFinished = false;

        try {

            saveMode = cmsRepositoryEntityUtils.determineSaveMode(contentObject);

            //Populate content node with appropriate information
            if (context == null) {
                context = new Context(cmsRepositoryEntityUtils, cmsQueryHandler, getSession());
                disposeContextWhenSaveIsFinished = true;
            }

            session = context.getSession();

            if (StringUtils.isNotBlank(lockToken)) {
                session.getWorkspace().getLockManager().addLockToken(lockToken);
            }

            primaryCheck(contentObject);

            Node contentObjectNode = null;
            Calendar modifiedDateBeforeSave = null;

            switch (saveMode) {
            case INSERT:

                contentObjectNode = createNewContentObjectNode(contentObject, session, false);

                break;
            case UPDATE:
                contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session,
                        contentObject.getId());

                if (contentObjectNode == null) {
                    //User has provided an id for content object. Create a new one with the specified id
                    contentObjectNode = createNewContentObjectNode(contentObject, session, true);
                } else {

                    //If node is locked and no valid lock token is provided then an exception is thrown
                    session.getWorkspace().getVersionManager().checkout(contentObjectNode.getPath());

                    modifiedDateBeforeSave = retrieveProfileModifiedFromContentObjectNode(contentObjectNode);

                    checkModificationDateBeforeSave(contentObject, updateLastModificationTime,
                            modifiedDateBeforeSave);
                }

                break;
            default:
                break;
            }

            contentObjectDao.populateContentObjectNode(session, contentObject, contentObjectNode, saveMode,
                    context);

            //Check if someone has already been saved by another user
            checkModificationDateAfterSave(contentObject, updateLastModificationTime, contentObjectNode,
                    modifiedDateBeforeSave);

            session.save();

            if (version) {
                session.getWorkspace().getVersionManager().checkin(contentObjectNode.getPath());
            }

            //This must run after save was successful because these changes cannot not be rolled back
            ((ComplexCmsPropertyImpl) contentObject.getComplexCmsRootProperty())
                    .clearCmsPropertyNameWhichHaveBeenLoadedAndRemovedList();

            return contentObject;

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

                if (StringUtils.isNotBlank(lockToken)) {
                    try {
                        session.getWorkspace().getLockManager().removeLockToken(lockToken);
                    } catch (RepositoryException e) {
                        logger.error("Lock token " + lockToken + " could not be removed", e);
                    }
                }
            }

            logger.debug(" Saved ContentObject {} in {}", contentObject.getSystemName(),
                    DurationFormatUtils.formatDurationHMS(System.currentTimeMillis() - start));

        }

    }

    private void checkModificationDateAfterSave(ContentObject contentObject, boolean updateLastModificationTime,
            Node contentObjectNode, Calendar modifiedDateBeforeSave)
            throws RepositoryException, ValueFormatException, PathNotFoundException, VersionException,
            LockException, ConstraintViolationException {

        if (modifiedDateBeforeSave != null) {
            //Retrieve modified date now
            Calendar modifiedDateAfterSave = retrieveProfileModifiedFromContentObjectNode(contentObjectNode);

            if (modifiedDateAfterSave != null
                    && modifiedDateAfterSave.getTimeInMillis() != modifiedDateBeforeSave.getTimeInMillis()) {

                String pattern = "dd/MM/yyyy HH:mm:ss.SSSZ";
                throw new CmsConcurrentModificationException("Content Object " + contentObject.getId() + "/"
                        + contentObject.getSystemName()
                        + " has been concurrently modified by another user or current user has tried to "
                        + " set a value for  profile.modified property. \n" + " profile.modified BEFORE save : "
                        + DateUtils.format(modifiedDateBeforeSave, pattern) + "\n"
                        + " profile.modified AFTER save : " + DateUtils.format(modifiedDateAfterSave, pattern));
            } else {
                //Profile.modified will be updated if updateLastModificationTime is set to true
                //or profile.modified has no values
                if (updateLastModificationTime || modifiedDateAfterSave == null) {

                    //Update modification date
                    Calendar modifiedDate = Calendar.getInstance();

                    //Update jcr node
                    contentObjectNode.getProperty("profile/modified").setValue(modifiedDate);

                    //Update ContentObject
                    if (contentObject.getComplexCmsRootProperty().isChildPropertyLoaded("profile.modified")) {
                        ((CalendarProperty) contentObject.getCmsProperty("profile.modified"))
                                .setSimpleTypeValue(modifiedDate);
                    }
                }
            }
        }
    }

    private Calendar checkModificationDateBeforeSave(ContentObject contentObject,
            boolean updateLastModificationTime, Calendar modifiedDateBeforeSave) {

        if (modifiedDateBeforeSave != null) {
            //Make a check if provided ContentObject has a different modified date
            if (contentObject.getComplexCmsRootProperty() != null
                    && contentObject.getComplexCmsRootProperty().isChildPropertyLoaded("profile.modified")) {
                CalendarProperty modifiedDateProvidedByUserProperty = (CalendarProperty) contentObject
                        .getCmsProperty("profile.modified");

                boolean throwException = false;

                if (modifiedDateProvidedByUserProperty.hasValues()) {

                    Calendar modifiedDateProvidedByUser = modifiedDateProvidedByUserProperty.getSimpleTypeValue();

                    if (modifiedDateProvidedByUser == null || modifiedDateProvidedByUser
                            .getTimeInMillis() != modifiedDateBeforeSave.getTimeInMillis()) {
                        throwException = true;
                    } else {
                        return modifiedDateBeforeSave;
                    }
                }

                if (throwException) {
                    String pattern = "dd/MM/yyyy HH:mm:ss.SSSZ";
                    throw new CmsConcurrentModificationException("Content Object " + contentObject.getId() + "/"
                            + contentObject.getSystemName()
                            + " has been concurrently modified by another user or current user has tried to "
                            + " set a value for  profile.modified property. \n"
                            + " profile.modified BEFORE save :   \t"
                            + DateUtils.format(modifiedDateBeforeSave, pattern) + "(full info "
                            + modifiedDateBeforeSave.toString() + ")\n"
                            + " profile.modified provided by user save : "
                            + (modifiedDateProvidedByUserProperty.hasNoValues() ? " No date "
                                    : DateUtils.format(modifiedDateProvidedByUserProperty.getSimpleTypeValue(),
                                            pattern))
                            + "(full info " + modifiedDateProvidedByUserProperty.getSimpleTypeValue() + ")");
                }
            }
        }

        return null;
    }

    private Calendar retrieveProfileModifiedFromContentObjectNode(Node contentObjectNode)
            throws RepositoryException, ValueFormatException, PathNotFoundException {
        if (!contentObjectNode.hasProperty("profile/modified")) {
            return null;
        } else {
            return contentObjectNode.getProperty("profile/modified").getDate();
        }

    }

    private void primaryCheck(ContentObject contentObject) throws Exception {
        final String type = contentObject.getContentObjectType();
        //Check if this type is defined
        if (StringUtils.isBlank(type))
            throw new CmsException("Invalid type " + type);

        if (!contentDefinitionDao.hasContentObjectTypeDefinition(type))
            throw new CmsException("Unregistered content object type " + type + " in repository "
                    + AstroboaClientContextHolder.getActiveRepositoryId());

    }

    private Node createNewContentObjectNode(ContentObject contentObject, Session session, boolean useProvidedId)
            throws Exception {

        String type = contentObject.getContentObjectType();

        //      Get Type folder node. If it does not exist, it will be Created
        Node contentTypeFolderNode = JcrNodeUtils.retrieveOrCreateContentTypeFolderNode(session, type);

        CalendarInfo calendarInfo = new CalendarInfo(Calendar.getInstance());

        //Profile will provide year/month/day information
        String profileCreatedPropertyPath = ContentObjectProfileItem.Created.getItemForQuery().getLocalPart();

        //Check that property created is defined for type
        ContentObjectTypeDefinition typeDefinition = contentDefinitionDao.getContentObjectTypeDefinition(type);

        if (typeDefinition.hasCmsPropertyDefinition(profileCreatedPropertyPath)) {
            CalendarProperty createdProperty = (CalendarProperty) contentObject
                    .getCmsProperty(profileCreatedPropertyPath);

            if (createdProperty == null) {
                //Should never happen
                throw new CmsException("Content type " + typeDefinition.getName()
                        + " defines built in property profile.created but could not create property instance");
            }

            Calendar created = (createdProperty.hasNoValues()) ? null
                    : (Calendar) createdProperty.getSimpleTypeValue();

            if (created != null) {
                //In case create date has unset YEAR, MONTH, OR DAY
                //Calendar Info will set default values
                calendarInfo = new CalendarInfo(created);
            }

            //Update Created date
            createdProperty.setSimpleTypeValue(calendarInfo.getCalendar());

        } else {
            //Should never happen
            throw new CmsException("Content type " + typeDefinition.getName()
                    + " does not define built in property profile.created");
        }

        //If minute folder does not exist, it will be Created         
        Node contentObjectParentNode = JcrNodeUtils.createContentObjectParentNode(contentTypeFolderNode,
                calendarInfo);

        //Add new node. 
        //Node's name will be the same with typeName
        Node contentObjectNode = JcrNodeUtils.addContentObjectNode(contentObjectParentNode, type);

        //Create or use provided astroboa identifier
        cmsRepositoryEntityUtils.createCmsIdentifier(contentObjectNode, contentObject, useProvidedId);

        //Add modified date
        String profileModifiedPropertyPath = ContentObjectProfileItem.Modified.getItemForQuery().getLocalPart();

        if (typeDefinition.hasCmsPropertyDefinition(profileModifiedPropertyPath)) {
            CalendarProperty modifiedProperty = (CalendarProperty) contentObject
                    .getCmsProperty(profileModifiedPropertyPath);

            if (modifiedProperty.hasNoValues()) {
                modifiedProperty.setSimpleTypeValue(calendarInfo.getCalendar());
            }
        } else {
            //Should never happen
            throw new CmsException("Content type " + typeDefinition.getName()
                    + " does not define built in property profile.modified");
        }

        return contentObjectNode;
    }

    public BinaryChannel getBinaryChannelById(String binaryChannelId) {
        Session session = null;

        if (StringUtils.isBlank(binaryChannelId))
            throw new CmsException("Blank binary channel id");

        try {

            session = getSession();

            Node binaryChannelNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForBinaryChannel(session,
                    binaryChannelId);

            return binaryChannelRenderer.render(binaryChannelNode, true);

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

    public List<ContentObjectFolder> getRootContentObjectFolders(String locale) {
        return getRootContentObjectFolders(TreeDepth.ZERO.asInt(), locale);
    }

    public List<ContentObjectFolder> getRootContentObjectFolders(int depth, String locale) {
        Session session = null;
        try {

            session = getSession();

            Node contentObjectRootNode = JcrNodeUtils.getContentObjectRootNode(session);

            NodeIterator contentObjectRootFolderNodes = contentObjectRootNode.getNodes();

            List<ContentObjectFolder> outcome = new ArrayList<ContentObjectFolder>();

            while (contentObjectRootFolderNodes.hasNext())
                outcome.add(contentObjectFolderRenderer.render(session, contentObjectRootFolderNodes.nextNode(),
                        depth, false, locale));

            return outcome;

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

    public ContentObjectFolder getContentObjectFolderTree(String parentFolderId, int depth,
            boolean renderContentObjectIds, String locale) {
        Session session = null;
        try {
            session = getSession();

            Node contentObjectFolderNode = JcrNodeUtils.getNodeByNativeRepositoryIdentifier(session,
                    parentFolderId);

            return contentObjectFolderRenderer.render(session, contentObjectFolderNode, depth,
                    renderContentObjectIds, locale);

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

    public boolean deleteContentObject(String objectIdOrSystemName) {

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

            //Retrieve content object node

            Node contentObjectNode = getContentObjectNodeByIdOrSystemName(objectIdOrSystemName);

            if (contentObjectNode != null) {

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

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

                session.save();

                return true;
            }

            logger.info("Object [] does not exist and therefore cannot be deleted", objectIdOrSystemName);
            return false;
            //Clear cache
            //jcrQueryCacheRegion.removeRegion();

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

    }

    public ContentObject getContentObjectByVersionName(String contentObjectId, String versionName, String locale,
            CacheRegion cacheRegion) {

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

            //Retrieve content object version history node
            VersionHistory contentObjectVersionHistory = versionUtils.getVersionHistoryForNode(session,
                    contentObjectId);

            if (contentObjectVersionHistory == null) {
                return null;
            }

            RenderProperties renderProperties = new RenderPropertiesImpl();
            //renderProperties.renderValuesForLocale(locale);
            renderProperties.renderVersionForContentObject(versionName);

            return contentObjectRenderer.render(session, contentObjectVersionHistory, renderProperties,
                    new HashMap<String, ContentObjectTypeDefinition>(), new HashMap<String, CmsRepositoryEntity>());

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

    public <T> T searchContentObjects(ContentObjectCriteria contentObjectCriteria,
            ResourceRepresentationType<T> contentObjectOutput) {

        T queryResult = null;
        boolean queryReturnedAtLeastOneResult = false;

        ByteArrayOutputStream os = null;

        try {

            //Check if criteria is provided
            if (contentObjectCriteria == null) {
                return generateEmptyOutcome(contentObjectOutput);
            }

            //Initialize null parameters (if any) 
            if (contentObjectOutput == null) {
                contentObjectOutput = (ResourceRepresentationType<T>) ResourceRepresentationType.CONTENT_OBJECT_LIST;
            }

            //Check cache
            if (contentObjectCriteria.isCacheable()) {

                queryResult = (T) jcrQueryCacheRegion.getJcrQueryResults(contentObjectCriteria,
                        contentObjectOutput.getTypeAsString());

                if (queryResult != null) {
                    return queryResult;
                }
            }

            //User requested Objects as return type
            if (ResourceRepresentationType.CONTENT_OBJECT_INSTANCE.equals(contentObjectOutput)
                    || ResourceRepresentationType.CONTENT_OBJECT_LIST.equals(contentObjectOutput)) {

                CmsOutcome<ContentObject> outcome = contentObjectDao.searchContentObjects(contentObjectCriteria,
                        getSession());

                //User requested one ContentObject. Throw an exception if more than
                //one returned
                if (ResourceRepresentationType.CONTENT_OBJECT_INSTANCE.equals(contentObjectOutput)) {
                    queryResult = (T) returnSingleContentObjectFromOutcome(contentObjectCriteria, outcome);
                    queryReturnedAtLeastOneResult = queryResult != null;
                } else {

                    //Return type is CmsOutcome.
                    queryResult = (T) outcome;
                    queryReturnedAtLeastOneResult = outcome.getCount() > 0;
                }

            } else if (ResourceRepresentationType.XML.equals(contentObjectOutput)
                    || ResourceRepresentationType.JSON.equals(contentObjectOutput)) {

                //User requested output to be XML or JSON
                os = new ByteArrayOutputStream();

                SerializationConfiguration serializationConfiguration = SerializationConfiguration.object()
                        .prettyPrint(contentObjectCriteria.getRenderProperties().isPrettyPrintEnabled())
                        .representationType(contentObjectOutput).serializeBinaryContent(false).build();

                long numberOfResutls = serializationDao.serializeSearchResults(getSession(), contentObjectCriteria,
                        os, FetchLevel.ENTITY, serializationConfiguration);

                queryReturnedAtLeastOneResult = numberOfResutls > 0;

                queryResult = (T) new String(os.toByteArray(), "UTF-8");

            } else {
                throw new CmsException("Invalid resource representation type for content object search results "
                        + contentObjectOutput);
            }

            if (contentObjectCriteria.isCacheable()) {
                String xpathQuery = contentObjectCriteria.getXPathQuery();
                if (!StringUtils.isBlank(xpathQuery) && queryReturnedAtLeastOneResult) {
                    jcrQueryCacheRegion.cacheJcrQueryResults(contentObjectCriteria, queryResult,
                            contentObjectCriteria.getRenderProperties(), contentObjectOutput.getTypeAsString());
                }
            }

            return queryResult;

        }

        catch (RepositoryException ex) {
            throw new CmsException(ex);
        } catch (Exception e) {
            throw new CmsException(e);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    private ContentObject returnSingleContentObjectFromOutcome(ContentObjectCriteria contentObjectCriteria,
            CmsOutcome<ContentObject> outcome) {
        //User set limit to 1. Return content object found
        //a result is returned
        if (outcome.getLimit() == 1) {
            if (CollectionUtils.isNotEmpty(outcome.getResults())) {
                return outcome.getResults().get(0);
            } else {
                return null;
            }
        } else {
            //User specified limit different than 1 (either no  limit or greater than 1)
            if (outcome.getCount() > 1) {
                throw new CmsException(
                        outcome.getCount() + " content objects matched criteria, user has specified limit "
                                + contentObjectCriteria.getLimit()
                                + " but she also requested return type to be a single ContentObject.");
            } else {
                if (CollectionUtils.isNotEmpty(outcome.getResults())) {
                    return outcome.getResults().get(0);
                } else {
                    return null;
                }
            }
        }
    }

    private <T> T generateEmptyOutcome(ResourceRepresentationType<T> contentObjectOutput) {
        if (contentObjectOutput != null
                && contentObjectOutput.equals(ResourceRepresentationType.CONTENT_OBJECT_LIST)) {
            return (T) new CmsOutcomeImpl<T>(0, 0, 0);
        } else {
            return null;
        }
    }

    public String lockContentObject(String contentObjectId) {
        Session session = null;
        try {

            session = getSession();

            Node contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session,
                    contentObjectId);

            if (contentObjectNode == null) {
                return null;
            }

            //Deep lock and open-scoped
            if (!contentObjectNode.isLocked())
                session.getWorkspace().getLockManager().lock(contentObjectNode.getPath(), true, false,
                        Long.MAX_VALUE, "");

            String lockToken = session.getWorkspace().getLockManager().getLock(contentObjectNode.getPath())
                    .getLockToken();

            if (lockToken != null) {
                session.getWorkspace().getVersionManager().checkout(contentObjectNode.getPath());
                contentObjectNode.setProperty(DefinitionReservedName.Locktoken.getJcrName(), lockToken);
            } else {
                //Lock Operation may have failed. Try get locktoken from contentObjectNode
                if (contentObjectNode.hasProperty(DefinitionReservedName.Locktoken.getJcrName()))
                    lockToken = contentObjectNode.getProperty(DefinitionReservedName.Locktoken.getJcrName())
                            .getString();
            }

            session.save();

            return lockToken;

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

    }

    public void removeLockFromContentObject(String contentObjectId, String lockToken) {
        Session session = null;
        try {
            session = getSession();

            Node contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session,
                    contentObjectId);

            if (contentObjectNode != null && contentObjectNode.isLocked()) {
                //Deep lock and open-scoped
                session.getWorkspace().getLockManager().addLockToken(lockToken);

                session.getWorkspace().getLockManager().unlock(contentObjectNode.getPath());

                //Unset contentObject equivalent property
                if (contentObjectNode.hasProperty(DefinitionReservedName.Locktoken.getJcrName())) {
                    session.getWorkspace().getVersionManager().checkout(contentObjectNode.getPath());
                    contentObjectNode.getProperty(DefinitionReservedName.Locktoken.getJcrName()).remove();
                }

                session.save();
            }
        } catch (RepositoryException ex) {
            throw new CmsException(ex);
        } catch (Exception e) {
            throw new CmsException(e);
        }

    }

    public boolean isContentObjectLocked(String contentObjectId) {
        Session session = null;
        try {
            session = getSession();

            Node contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session,
                    contentObjectId);

            if (contentObjectNode == null) {
                return false;
            }

            return contentObjectNode.isLocked();

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

    public void increaseContentObjectViewCounter(String contentObjectId, long counter) {

        Session session = null;
        try {

            session = getSession();

            Node contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(session,
                    contentObjectId);

            if (contentObjectNode == null) {
                logger.warn("Unable to find content object with id " + contentObjectId
                        + ". Property 'viewCounter' is not increased");
            } else {
                session.getWorkspace().getVersionManager().checkout(contentObjectNode.getPath());

                contentObjectDao.increaseViewCounter(contentObjectNode, counter);

                session.save();
            }

        } catch (RepositoryException ex) {
            logger.error("", ex);
            throw new CmsException(ex);
        } catch (Exception e) {
            logger.error("", e);
            throw new CmsException(e);
        }
    }

    public List<CmsProperty<?, ?>> loadChildCmsProperty(String childPropertyName,
            String parentComplexCmsPropertyDefinitionFullPath,
            String jcrNodeUUIDWhichCorrespondsToParentComplexCmsProperty,
            String jcrNodeUUIDWhichCorrespondsToContentObejct, RenderProperties renderProperties) throws Exception {

        CmsPropertyDefinition currentChildPropertyDefinition = contentDefinitionDao.getCmsPropertyDefinition(
                PropertyPath.createFullPropertyPath(parentComplexCmsPropertyDefinitionFullPath, childPropertyName));

        //Since definition does not exist and its parent is a content object type, which  
        //derives from the fact that parent full path has only one level
        //check if child refers to an aspect
        if (currentChildPropertyDefinition == null
                && !parentComplexCmsPropertyDefinitionFullPath.contains(CmsConstants.PERIOD_DELIM)) {
            currentChildPropertyDefinition = contentDefinitionDao.getAspectDefinition(childPropertyName);

            //At this point if such a definition exists we cannot tell that the aspect found is actually defined
            //for the content object which contains parent complex property.
            //This will be detected once the created template is actually added to the content object

        }

        if (currentChildPropertyDefinition == null) {
            logger.warn(
                    "No cms property definition is provided for property {}.{} . ( parent node UUID {} and content object node UUID {} )",
                    new Object[] { parentComplexCmsPropertyDefinitionFullPath, childPropertyName,
                            jcrNodeUUIDWhichCorrespondsToParentComplexCmsProperty,
                            jcrNodeUUIDWhichCorrespondsToContentObejct });
            return null;
        } else {
            return lazyComplexCmsPropertyLoader.renderChildProperty(currentChildPropertyDefinition,
                    jcrNodeUUIDWhichCorrespondsToParentComplexCmsProperty,
                    jcrNodeUUIDWhichCorrespondsToContentObejct, renderProperties, getSession(), null);
        }
    }

    public void moveAspectToNativePropertyForAllContentObjectsOFContentType(String aspect, String newPropertyName,
            String contentType) {

        if (StringUtils.isBlank(aspect)) {
            throw new CmsException("No aspect is provided");
        }

        if (StringUtils.isBlank(contentType)) {
            throw new CmsException("No content type is provided");
        }

        Session session = null;
        try {

            session = getSession();
            ContentObjectCriteria contentObjectCriteria = CmsCriteriaFactory.newContentObjectCriteria(contentType);

            CmsQueryResult contentObjectResults = cmsQueryHandler.getNodesFromXPathQuery(session,
                    contentObjectCriteria, true);

            if (contentObjectResults.getTotalRowCount() > 0) {

                NodeIterator contentObjectNodesIterator = (NodeIterator) contentObjectResults.getNodeIterator();

                int count = 0;
                while (contentObjectNodesIterator.hasNext()) {

                    Node contentObjectNode = contentObjectNodesIterator.nextNode();

                    if (contentObjectNode.isNodeType(CmsBuiltInItem.StructuredContentObject.getJcrName())) {
                        if (contentObjectNode.hasProperty(CmsBuiltInItem.Aspects.getJcrName())) {
                            Value[] values = contentObjectNode.getProperty(CmsBuiltInItem.Aspects.getJcrName())
                                    .getValues();

                            logger.info("ContentObjectNode " + contentObjectNode.getPath() + " has aspects "
                                    + printValues(values));

                            if (values != null) {
                                for (Value value : values) {
                                    if (value.getString() != null && value.getString().equals(aspect)) {

                                        //Aspect found. Remove it from array
                                        JcrValueUtils.removeValue(contentObjectNode, CmsBuiltInItem.Aspects,
                                                session.getValueFactory().createValue(aspect), true);

                                        count++;

                                        if (contentObjectNode.hasProperty(CmsBuiltInItem.Aspects.getJcrName())) {
                                            logger.info(
                                                    "After removal ContentObjectNode " + contentObjectNode.getPath()
                                                            + " has aspects " + printValues(values));
                                        } else {
                                            logger.info("After removal ContentObjectNode "
                                                    + contentObjectNode.getPath() + " does not have any aspect ");
                                        }

                                        //Refactor the property only if the provided is different
                                        if (StringUtils.isNotBlank(newPropertyName)
                                                && !newPropertyName.equals(aspect)) {

                                            if (!contentObjectNode.hasNode(aspect)) {
                                                logger.warn("Although aspect " + aspect + " was found in "
                                                        + CmsBuiltInItem.Aspects.getJcrName()
                                                        + " no child property named after aspect "
                                                        + " was found. Check further if there is a bug");
                                            } else {
                                                NodeIterator aspectNodes = contentObjectNode.getNodes(aspect);

                                                if (aspectNodes.getSize() > 1) {
                                                    logger.warn(
                                                            "There are more than one child properties named after aspect "
                                                                    + aspect + ". This is however not the case."
                                                                    + "Check further if there is a bug. Refactoring will taking place normally as by now this property is a native property"
                                                                    + " and therefore can have multiple occurences. Make sure this is depicted in content type definition of "
                                                                    + contentType);
                                                }

                                                while (aspectNodes.hasNext()) {
                                                    Node aspectNode = aspectNodes.nextNode();

                                                    session.move(aspectNode.getPath(), contentObjectNode.getPath()
                                                            + CmsConstants.FORWARD_SLASH + newPropertyName);
                                                }
                                            }
                                        }

                                        break;
                                    }
                                }
                            }
                        }
                    } else {
                        throw new CmsException("In a query for content objects of type " + contentType
                                + " this node " + contentObjectNode.getPath()
                                + " found in results but it is not a structured content object node");
                    }
                }

                session.save();

                logger.info("Successfully move aspect in " + count + " content objects");
            }
        } catch (RepositoryException ex) {
            throw new CmsException(ex);
        } catch (Exception e) {
            throw new CmsException(e);
        }

    }

    private String printValues(Value[] values) throws Exception {
        if (values == null) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (Value value : values) {
            stringBuilder.append(value.getString() + " ");
        }

        return stringBuilder.toString();
    }

    public Node getContentObjectNodeByIdOrSystemName(String contentObjectIdOrSystemName) {
        try {
            Node contentObjectNode = null;

            if (CmsConstants.UUIDPattern.matcher(contentObjectIdOrSystemName).matches()) {
                contentObjectNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForContentObject(getSession(),
                        contentObjectIdOrSystemName);

                if (contentObjectNode != null) {
                    return contentObjectNode;
                }
            } else {
                ContentObjectCriteria contentObjectCriteria = CmsCriteriaFactory.newContentObjectCriteria();
                contentObjectCriteria.addSystemNameEqualsCriterion(contentObjectIdOrSystemName);
                contentObjectCriteria.setOffsetAndLimit(0, 1);

                CmsQueryResult nodes = cmsQueryHandler.getNodesFromXPathQuery(getSession(), contentObjectCriteria,
                        true);

                if (nodes.getTotalRowCount() > 0) {
                    return ((NodeIterator) nodes.getNodeIterator()).nextNode();
                }
            }

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

    @SuppressWarnings("unchecked")
    public <T> T serializeContentObject(String contentObjectIdOrSystemName, CacheRegion cacheRegion,
            ResourceRepresentationType<T> contentObjectOutput, List<String> propertyPathsToInclude,
            FetchLevel fetchLevel, boolean serializeBinaryContent, boolean prettyPrint) {

        ByteArrayOutputStream os = null;

        try {

            //Default values
            if (contentObjectOutput == null) {
                contentObjectOutput = (ResourceRepresentationType<T>) ResourceRepresentationType.CONTENT_OBJECT_INSTANCE;
            }

            T contentObject = null;

            //Check cache
            contentObject = getContentObjectFromcache(contentObjectIdOrSystemName, cacheRegion,
                    contentObjectOutput);

            if (contentObject != null) {
                return contentObject;
            }

            //Content Object is not in the cache
            //Continue with the default values
            if (fetchLevel == null) {
                fetchLevel = FetchLevel.ENTITY;
            }

            propertyPathsToInclude = generateIfNecessaryPropertyPathsWhoseValuesWillBeIncludedInSerialization(
                    fetchLevel, propertyPathsToInclude, contentObjectOutput);

            Node contentObjectNode = getContentObjectNodeByIdOrSystemName(contentObjectIdOrSystemName);

            if (contentObjectNode == null) {
                return generateEmptyOutcome(contentObjectOutput);
            }

            if (ResourceRepresentationType.CONTENT_OBJECT_INSTANCE.equals(contentObjectOutput)
                    || ResourceRepresentationType.CONTENT_OBJECT_LIST.equals(contentObjectOutput)) {

                RenderProperties renderProperties = new RenderPropertiesImpl();

                if (FetchLevel.FULL == fetchLevel) {
                    renderProperties.renderAllContentObjectProperties(true);
                }

                contentObject = (T) contentObjectRenderer.render(getSession(), contentObjectNode, renderProperties,
                        new HashMap<String, ContentObjectTypeDefinition>(),
                        new HashMap<String, CmsRepositoryEntity>());

                //Load properties
                if (CollectionUtils.isNotEmpty(propertyPathsToInclude)) {
                    for (String propertyPath : propertyPathsToInclude) {
                        ((ContentObject) contentObject).getCmsProperty(propertyPath);
                    }
                }

                //Return appropriate type
                if (ResourceRepresentationType.CONTENT_OBJECT_LIST.equals(contentObjectOutput)) {

                    //Return type is CmsOutcome.
                    CmsOutcome<ContentObject> outcome = new CmsOutcomeImpl<ContentObject>(1, 0, 1);
                    outcome.getResults().add((ContentObject) contentObject);

                    contentObject = (T) outcome;
                }

            } else if (ResourceRepresentationType.XML.equals(contentObjectOutput)
                    || ResourceRepresentationType.JSON.equals(contentObjectOutput)) {

                os = new ByteArrayOutputStream();

                SerializationConfiguration serializationConfiguration = SerializationConfiguration.object()
                        .prettyPrint(prettyPrint).representationType(contentObjectOutput)
                        .serializeBinaryContent(serializeBinaryContent).build();

                serializationDao.serializeCmsRepositoryEntity(contentObjectNode, os, CmsEntityType.OBJECT,
                        propertyPathsToInclude, fetchLevel, true, serializationConfiguration);

                contentObject = (T) new String(os.toByteArray(), "UTF-8");
            } else {
                throw new CmsException("Unsupported resource representation type for content object serialization "
                        + contentObjectOutput);
            }

            if (cacheRegion != null) {
                jcrQueryCacheRegion.cacheContentObject(contentObjectIdOrSystemName, contentObject, cacheRegion,
                        contentObjectOutput.getTypeAsString());
            }

            return contentObject;

        } catch (RepositoryException ex) {
            throw new CmsException(ex);
        } catch (Exception e) {
            throw new CmsException(e);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    private List<String> generateIfNecessaryPropertyPathsWhoseValuesWillBeIncludedInSerialization(
            FetchLevel fetchLevel, List<String> propertyPathsToInclude,
            ResourceRepresentationType<?> contentObjectOutput) {

        //Property Paths to be included in the serialization are ignored id FetchLevel is FULL
        if (fetchLevel == FetchLevel.FULL) {
            return null;
        }

        if (CollectionUtils.isEmpty(propertyPathsToInclude)) {

            //FetchLevel is either ENTITY or ENTITY_AND_CHILDREN but user did not specify any properties at all.
            //In this case profile.title is returned and owner

            propertyPathsToInclude = new ArrayList<String>();

            propertyPathsToInclude.add("profile.title");

            //Owner is always serialized when type is CONTENT_OBJECT_INSTANCE or CONTENT_OBJECT_LIST
            //as it is a special case of a property 
            //However in the cases of XML or JSON, it should be specified as a regular one
            if (ResourceRepresentationType.XML.equals(contentObjectOutput)
                    || ResourceRepresentationType.JSON.equals(contentObjectOutput)) {

                propertyPathsToInclude.add(CmsConstants.OWNER_ELEMENT_NAME);
            }
        }

        return propertyPathsToInclude;
    }

    private <T> T getContentObjectFromcache(String contentObjectIdOrSystemName, CacheRegion cacheRegion,
            ResourceRepresentationType<T> contentObjectOutput) throws Exception {
        if (cacheRegion != null) {
            return (T) jcrQueryCacheRegion.getContentObjectFromCache(contentObjectIdOrSystemName, cacheRegion,
                    contentObjectOutput.getTypeAsString());
        }

        return null;
    }

    /**
     * @param contetObjectId
     * @return
     */
    public ContentObject copyContentObject(String contentObjectId) {

        if (StringUtils.isBlank(contentObjectId)) {
            return null;
        }

        ContentObject contentObjectToBeCopied = serializeContentObject(contentObjectId, CacheRegion.NONE,
                ResourceRepresentationType.CONTENT_OBJECT_INSTANCE, null, FetchLevel.FULL, true, false);

        if (contentObjectToBeCopied == null) {
            logger.warn("Could not retrieve content object with id {}. Copy operation cannot continue",
                    contentObjectId);
            return null;
        }

        ((ContentObjectImpl) contentObjectToBeCopied).clean();

        int index = 0;

        String systemNameToSearch = null;
        if (StringUtils.isNotBlank(contentObjectToBeCopied.getSystemName())) {
            systemNameToSearch = new String(contentObjectToBeCopied.getSystemName().getBytes());

            if (systemNameToSearch.startsWith("copy")) {
                systemNameToSearch = systemNameToSearch.replaceFirst("copy[0-9]*", "");
            }

            //Locate other copies in order to provide the correct copy index
            ContentObjectCriteria contentObjectCriteria = CmsCriteriaFactory.newContentObjectCriteria();
            contentObjectCriteria.addSystemNameContainsCriterion("*" + systemNameToSearch);
            contentObjectCriteria.setOffsetAndLimit(0, 0);
            contentObjectCriteria.setCacheable(CacheRegion.NONE);

            CmsOutcome<ContentObject> outcome = searchContentObjects(contentObjectCriteria,
                    ResourceRepresentationType.CONTENT_OBJECT_LIST);

            if (outcome != null) {
                index = (int) outcome.getCount();
            }
        }

        String newIndexAsString = index == 0 ? "" : String.valueOf(index + 1);

        //Adjust systemName
        if (contentObjectToBeCopied.getSystemName() == null) {
            contentObjectToBeCopied.setSystemName("copy" + newIndexAsString);
        } else {
            if (contentObjectToBeCopied.getSystemName().startsWith("copy")) {
                contentObjectToBeCopied.setSystemName(contentObjectToBeCopied.getSystemName()
                        .replaceFirst("copy[0-9]*", "copy" + newIndexAsString));
            } else {
                contentObjectToBeCopied
                        .setSystemName("copy" + newIndexAsString + contentObjectToBeCopied.getSystemName());
            }
        }

        //Adjust title
        StringProperty titleProperty = (StringProperty) contentObjectToBeCopied.getCmsProperty("profile.title");

        String title = titleProperty.getSimpleTypeValue();

        boolean titleHasChanged = false;

        for (int i = 1; i <= index; i++) {
            if (title.endsWith(" " + String.valueOf(i))) {
                titleProperty.setSimpleTypeValue(
                        StringUtils.substringBeforeLast(title, String.valueOf(i)) + newIndexAsString);
                titleHasChanged = true;
                break;
            }
        }

        if (!titleHasChanged) {
            titleProperty.setSimpleTypeValue(title + " " + newIndexAsString);
        }

        return contentObjectToBeCopied;

    }

    public boolean valueForPropertyExists(String propertyPath,
            String jcrNodeUUIDWhichCorrespondsToParentComplexCmsProperty) throws Exception {

        return lazyComplexCmsPropertyLoader.valueForPropertyExists(propertyPath,
                jcrNodeUUIDWhichCorrespondsToParentComplexCmsProperty, getSession());
    }

    public List<ContentObject> saveContentObjectResourceCollection(Object contentSource, boolean version,
            boolean updateLastModificationTime, String lockToken) {

        long start = System.currentTimeMillis();

        if (contentSource == null) {
            return new ArrayList<ContentObject>();
        }

        if (contentSource instanceof String) {

            logger.debug(" Starting saving content object resource collection.");

            //Use importer to unmarshal String to ContentObject
            //and to save it as well.
            //What is happened is that importDao will create a ContentObject
            //and will pass it to ContentServiceImpl to save it. 
            //It will end up in this method again as a ContentObject
            //if it passes the check of SecureContentObjectSaveAspect
            ImportConfiguration configuration = ImportConfiguration.object()
                    .persist(PersistMode.PERSIST_ENTITY_TREE).version(version)
                    .updateLastModificationTime(updateLastModificationTime).build();

            return importDao.importResourceCollection((String) contentSource, configuration);
        }

        if (!(contentSource instanceof List)) {
            throw new CmsException(
                    "Expecting either String or List<ContentObject> and not " + contentSource.getClass().getName());
        }

        logger.debug(" Starting saving content object collection");

        Session session = null;

        Context context = null;

        List<ContentObject> contentObjects = (List<ContentObject>) contentSource;

        try {

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

            session = context.getSession();

            if (StringUtils.isNotBlank(lockToken)) {
                session.getWorkspace().getLockManager().addLockToken(lockToken);
            }

            for (ContentObject contentObject : contentObjects) {
                contentObject = saveContentObject(contentObject, version, lockToken, updateLastModificationTime,
                        context);
            }

            session.save();

            return contentObjects;

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

            if (StringUtils.isNotBlank(lockToken)) {
                try {
                    session.getWorkspace().getLockManager().removeLockToken(lockToken);
                } catch (RepositoryException e) {
                    logger.error("Lock token " + lockToken + " could not be removed", e);
                }
            }

            logger.debug(" Saved ContentObject collection  in {}",
                    DurationFormatUtils.formatDurationHMS(System.currentTimeMillis() - start));

        }
    }

    public byte[] getBinaryChannelContent(String jcrNodeUUIDWhichCorrespondsToTheBinaryChannel) {

        Session session = null;

        if (StringUtils.isBlank(jcrNodeUUIDWhichCorrespondsToTheBinaryChannel))
            throw new CmsException("Blank binary channel id");

        try {

            session = getSession();

            Node binaryChannelNode = cmsRepositoryEntityUtils.retrieveUniqueNodeForBinaryChannel(session,
                    jcrNodeUUIDWhichCorrespondsToTheBinaryChannel);

            if (binaryChannelNode == null) {
                logger.warn("Binary Channel Id {} does not correspond to a valid JCR node");
                return null;
            }

            if (binaryChannelNode.hasProperty(JcrBuiltInItem.JcrData.getJcrName())) {
                return (byte[]) JcrValueUtils.getObjectValue(
                        binaryChannelNode.getProperty(JcrBuiltInItem.JcrData.getJcrName()).getValue());
            } else {
                return null;
            }

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

    }
}