org.betaconceptframework.astroboa.console.jsf.edit.ContentObjectEdit.java Source code

Java tutorial

Introduction

Here is the source code for org.betaconceptframework.astroboa.console.jsf.edit.ContentObjectEdit.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.console.jsf.edit;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.servlet.ServletContext;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.BinaryChannel;
import org.betaconceptframework.astroboa.api.model.BinaryProperty;
import org.betaconceptframework.astroboa.api.model.CalendarProperty;
import org.betaconceptframework.astroboa.api.model.ComplexCmsProperty;
import org.betaconceptframework.astroboa.api.model.ComplexCmsRootProperty;
import org.betaconceptframework.astroboa.api.model.ContentObject;
import org.betaconceptframework.astroboa.api.model.Space;
import org.betaconceptframework.astroboa.api.model.StringProperty;
import org.betaconceptframework.astroboa.api.model.Topic;
import org.betaconceptframework.astroboa.api.model.TopicReferenceProperty;
import org.betaconceptframework.astroboa.api.model.definition.ComplexCmsPropertyDefinition;
import org.betaconceptframework.astroboa.api.model.definition.ContentObjectTypeDefinition;
import org.betaconceptframework.astroboa.api.model.exception.CmsConcurrentModificationException;
import org.betaconceptframework.astroboa.api.model.exception.CmsNonUniqueContentObjectSystemNameException;
import org.betaconceptframework.astroboa.api.model.io.FetchLevel;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.api.model.query.CmsOutcome;
import org.betaconceptframework.astroboa.api.model.query.ContentAccessMode;
import org.betaconceptframework.astroboa.api.model.query.criteria.ContentObjectCriteria;
import org.betaconceptframework.astroboa.api.security.CmsRole;
import org.betaconceptframework.astroboa.api.security.management.Person;
import org.betaconceptframework.astroboa.api.service.ContentService;
import org.betaconceptframework.astroboa.api.service.DefinitionService;
import org.betaconceptframework.astroboa.api.service.SpaceService;
import org.betaconceptframework.astroboa.api.service.TopicService;
import org.betaconceptframework.astroboa.console.commons.CMSUtilities;
import org.betaconceptframework.astroboa.console.commons.ContentObjectStatefulSearchService;
import org.betaconceptframework.astroboa.console.commons.ContentObjectUIWrapper;
import org.betaconceptframework.astroboa.console.commons.ContentObjectUIWrapperFactory;
import org.betaconceptframework.astroboa.console.commons.Utils;
import org.betaconceptframework.astroboa.console.jsf.ContentObjectList;
import org.betaconceptframework.astroboa.console.jsf.LoggedInRepositoryUserSettings;
import org.betaconceptframework.astroboa.console.jsf.PageController;
import org.betaconceptframework.astroboa.console.jsf.UIComponentBinding;
import org.betaconceptframework.astroboa.console.jsf.edit.ComplexCmsPropertyEdit.EditorTab;
import org.betaconceptframework.astroboa.console.jsf.edit.draft.DraftItem;
import org.betaconceptframework.astroboa.console.jsf.space.UserSpaceNavigation;
import org.betaconceptframework.astroboa.console.jsf.taxonomy.LazyLoadingTopicTreeNode;
import org.betaconceptframework.astroboa.console.jsf.visitor.CmsPropertyValidatorVisitor;
import org.betaconceptframework.astroboa.console.seam.SeamEventNames;
import org.betaconceptframework.astroboa.console.security.IdentityStoreRunAsSystem;
import org.betaconceptframework.astroboa.console.security.LoggedInRepositoryUser;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.context.SecurityContext;
import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory;
import org.betaconceptframework.astroboa.model.factory.CmsRepositoryEntityFactory;
import org.betaconceptframework.astroboa.security.CmsRoleAffiliationFactory;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.betaconceptframework.astroboa.util.CmsConstants.ContentObjectStatus;
import org.betaconceptframework.astroboa.util.DateUtils;
import org.betaconceptframework.astroboa.util.PropertyPath;
import org.betaconceptframework.ui.jsf.AbstractUIBean;
import org.betaconceptframework.ui.jsf.utility.JSFUtilities;
import org.betaconceptframework.utility.ImageUtils;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.Events;
import org.jboss.seam.international.LocaleSelector;
import org.jboss.seam.international.TimeZoneSelector;
import org.richfaces.event.DropEvent;
import org.springframework.mail.javamail.ConfigurableMimeFileTypeMap;
import org.springframework.web.context.support.ServletContextResource;

/**
 * @author Gregory Chomatas (gchomatas@betaconcept.com)
 * @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
 *
 */
@Name("contentObjectEdit")
@Scope(ScopeType.CONVERSATION)
public class ContentObjectEdit extends AbstractUIBean {

    private static final long serialVersionUID = 1L;

    private static final String CLEAR_CONTENT_OBJECT_EDIT_AND_LOAD_AGAIN_XHTML = "/clearContentObjectEditAndLoadAgain.xhtml";

    // injected beans
    private ContentObjectList contentObjectList;
    private DefinitionService definitionService;
    private ContentService contentService;
    private SpaceService spaceService;
    private UserSpaceNavigation userSpaceNavigation;
    private CMSUtilities cmsUtilities;
    private ContentObjectUIWrapperFactory contentObjectUIWrapperFactory;
    private LoggedInRepositoryUser loggedInRepositoryUser;

    private PageController pageController;
    private CmsPropertyValidatorVisitor cmsPropertyValidatorVisitor;
    private TopicService topicService;

    @In(create = true)
    private IdentityStoreRunAsSystem identityStoreRunAsSystem;

    @In(create = true)
    private LoggedInRepositoryUserSettings loggedInRepositoryUserSettings;

    @In(required = false)
    UIComponentBinding uiComponentBinding;

    @In
    private LocaleSelector localeSelector;

    @In(create = true)
    private LanguageSelector languageSelector;

    private String contentObjectTitle;
    private String contentObjectTypeLocalizedName;

    // if an error occurs when saving a new content object there is a possibility that it has been assigned an id despite the error during saving.
    //therefore the existence of an id is not a safe criterion to find out if a content object is new and we explicitly keep a boolean variable for this.
    private boolean newContentObject;

    private String contentObjectTypeForNewObject;

    //private TreeNode contentObjectAsTreeData;

    private String selectedContentObjectIdentifier;
    private ContentObjectUIWrapper selectedContentObjectForEdit;

    private final Integer DO_NOT_ATTACH_TO_SPACE = 1;
    private final Integer ATTACH_TO_MY_ROOT_SPACE = 2;
    private final Integer ATTACH_TO_SELECTED_SPACE = 3;

    public enum AccessRight {
        canBeReadBy, canBeUpdatedBy, canBeDeletedBy, canBeTaggedBy,
    }

    private Space spaceToCopyNewObject;

    private String selectedTopicIdForRemovalFromContentObjectSubject;
    private String selectedLoggedInUserTagId;

    private List<SelectItem> selectedLanguages;

    //Four instances of the same Spring Prototype Bean injected
    private ComplexCmsPropertyEdit complexCmsPropertyEdit;
    private ComplexCmsPropertyEdit profilePropertyEdit;
    private ComplexCmsPropertyEdit extraPropertyEdit;

    private String newTagLabel;

    /* The following four properties hold the security setting that the user has selected
     * (through radio buttons) for each of the four types of access rights defined for content objects (read, update, delete, tag).
     * The are 3 possible security settings for each type of access right: ALL(1), NONE(0), ONLY_THE_SPECIFIED_GROUPS_AND_USERS(3)
     * 
     */
    //private Integer radioButtonSelectionForCanBeReadBy;
    //private Integer radioButtonSelectionForCanBeUpdatedBy;
    //private Integer radioButtonSelectionForCanBeDeletedBy;
    //private Integer radioButtonSelectionForCanBeTaggedBy;

    //Used by accessibility-tab.xhtml and is a replacement of the above individual 
    // Integer values. This map contains four entries
    //one for each access list. Since JSF and EL parser does not handle map paremters whose key is an
    //enum, map's key is an enum but take values from the AccessRight enum
    private Map<String, String> radioButtonSelectionMap = new HashMap<String, String>();

    /* If the user selects the security setting: ONLY_THE_SPECIFIED_GROUPS_AND_USERS(3), then
     * for the 4 types of access rights we use the following 4 lists of HashMaps to hold for each type of access rights 
     * the corresponding set of user groups and individual users that are granted with the specific access right.
     * The HashMaps have 2 keys: "userOrGroupId" and  "userOrGroupName" and their respective values hold the group or user id (the external id in a crm or DB which holds info about users and groups) and the
     * group or user name which is used by the UI to present meaningful names instead of ids
     */
    //private List<Map<String,String>> canBeReadByUserList = new ArrayList<Map<String,String>>();
    //private List<Map<String,String>> canBeUpdatedByUserList = new ArrayList<Map<String,String>>();
    //private List<Map<String,String>> canBeDeletedByUserList = new ArrayList<Map<String,String>>();
    //private List<Map<String,String>> canBeTaggedByUserList = new ArrayList<Map<String,String>>();

    //Group above variables to a Map by AccessRight
    //oSince JSF and EL parser does not handle map paremters whose key is an
    //enum, map's key is an enum but take values from the AccessRight enum
    private Map<String, List<Map<String, String>>> userListByAccessRight = new HashMap<String, List<Map<String, String>>>();

    private ConfigurableMimeFileTypeMap mimeTypesMap;

    private List<String> listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated = new ArrayList<String>();

    //Corresponds to input text for adding new creator to a content object
    private String newCreatorName;

    private List<ComplexCmsPropertyBreadCrumb> fixedPropertyBreadCrumbs = new ArrayList<ComplexCmsPropertyBreadCrumb>();
    private List<ComplexCmsPropertyBreadCrumb> extraPropertyBreadCrumbs = new ArrayList<ComplexCmsPropertyBreadCrumb>();

    private final static String defaultFixedPropertyEditorPagePath = "/WEB-INF/pageComponents/edit/fixedPropertiesEditor.xhtml";
    private final static String defaultExtraPropertyEditorPagePath = "/WEB-INF/pageComponents/edit/extraPropertiesEditor.xhtml";
    private String complexCmsPropertyEditorPagePath = defaultFixedPropertyEditorPagePath;

    private ContentObject explicitlySetContentObjectForEdit;

    private String selectedPersonOrRoleTextFilter;

    private CmsRepositoryEntityFactory cmsRepositoryEntityFactory;

    protected String editContentObjectFromDraft_UIAction(ContentObject contentObject) {
        if (contentObject == null) {
            getLogger().error("Error while loading content object from draft. Content Object is null");
            JSFUtilities.addMessage(null, "object.edit.load.error", null, FacesMessage.SEVERITY_ERROR);
            return null;
        }

        if (contentObject.getId() != null) {
            setSelectedContentObjectIdentifier(contentObject.getId());
            explicitlySetContentObjectForEdit(contentObject);

            return editContentObjectAndDisplayDefaultPage_UIAction();
        } else {
            //Content object without id
            setSelectedContentObjectIdentifier(null);
            explicitlySetContentObjectForEdit(contentObject);

            //We do not want to create new content
            newContentObject = true;
            contentObjectTypeForNewObject = null;
            selectedContentObjectForEdit = contentObjectUIWrapperFactory.getInstance(contentObject);
            contentObjectTypeLocalizedName = selectedContentObjectForEdit.getContentObject().getTypeDefinition()
                    .getDisplayName().getLocalizedLabelForLocale(JSFUtilities.getLocaleAsString());
            contentObjectTitle = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                    .getCmsProperty("profile.title")).getSimpleTypeValue();

            /* initialize the security input components (i.e. radio buttons which allow the user to select if ALL, NONE or SELECTED GROUPS/USERS have a specific access right) 
             * Also initialize the lists which are used by the UI to present the groups/users granted with each type of access right (i.e. read / update / delete / tag).
             * The access right lists in the content object hold only user / group ids which are not very meaningful to the end user.
             */
            initializeInputAndOutputUIComponentsRelatedtoSecurityProperties();

            return initializeContentObjectEdit();
        }
    }

    protected String editContentObject_UIAction() {
        explicitlySetContentObjectForEdit = null;
        return editContentObjectAndDisplayDefaultPage_UIAction();
    }

    protected String editContentObjectAndDisplayDefaultPage_UIAction() {

        if (getSelectedContentObjectIdentifier() != null) {
            try {
                ContentObject selectedContentObject = getSelectedContentObject();

                selectedContentObjectForEdit = contentObjectUIWrapperFactory.getInstance(selectedContentObject);
                contentObjectTypeLocalizedName = selectedContentObjectForEdit.getContentObject().getTypeDefinition()
                        .getDisplayName().getLocalizedLabelForLocale(JSFUtilities.getLocaleAsString());
                contentObjectTitle = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("profile.title")).getSimpleTypeValue();

                /* initialize the security input components (i.e. radio buttons which allow the user to select if ALL, NONE or SELECTED GROUPS/USERS have a specific access right) 
                 * Also initialize the lists which are used by the UI to present the groups/users granted with each type of access right (i.e. read / update / delete / tag).
                 * The access right lists in the content object hold only user / group ids which are not very meaningful to the end user. 
                 */
                initializeInputAndOutputUIComponentsRelatedtoSecurityProperties();

            } catch (Exception e) {
                getLogger().error("Error while loading content objects ", e);
                JSFUtilities.addMessage(null, "object.edit.load.error", null, FacesMessage.SEVERITY_ERROR);
                //pageController.loadPageComponentInDynamicUIArea(DynamicUIAreaPageComponent.ContentObjectList.getDynamicUIAreaPageComponent());
                return null;
            }
        } else { // it is a new content object. Lets initialize it
            try {
                initializeNewContentObject();
            } catch (Exception e) {
                getLogger().error("Error while generating template for new content object ", e);
                JSFUtilities.addMessage(null, "object.edit.error.creating.new.content.object", null,
                        FacesMessage.SEVERITY_ERROR);
                //pageController.loadPageComponentInDynamicUIArea(DynamicUIAreaPageComponent.ContentObjectList.getDynamicUIAreaPageComponent());
                return null;
            }
        }

        //generateCmsPropertiesTree();

        return initializeContentObjectEdit();

    }

    private String initializeContentObjectEdit() {
        complexCmsPropertyEdit.setEditedContentObject(selectedContentObjectForEdit.getContentObject());
        complexCmsPropertyEdit.setEditorTab(EditorTab.FIXED_PROPERTIES);
        profilePropertyEdit.setEditedContentObject(selectedContentObjectForEdit.getContentObject());
        profilePropertyEdit.setEditorTab(EditorTab.ADMIN_PROPERTY);
        extraPropertyEdit.setEditedContentObject(selectedContentObjectForEdit.getContentObject());
        extraPropertyEdit.setEditorTab(EditorTab.EXTRA_PROPERTIES);

        loadComplexCmsPropertyToComplexCmsPropertyEditor(
                selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty(),
                complexCmsPropertyEdit);

        profilePropertyEdit.editComplexCmsProperty(
                (ComplexCmsProperty<ComplexCmsPropertyDefinition, ComplexCmsProperty<?, ?>>) selectedContentObjectForEdit
                        .getContentObject().getCmsProperty("profile"));

        listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated.clear();

        if (cmsPropertyValidatorVisitor == null) {
            cmsPropertyValidatorVisitor = new CmsPropertyValidatorVisitor(definitionService);
        } else {
            cmsPropertyValidatorVisitor.reset(true);
        }

        complexCmsPropertyEdit.setCmsPropertyValidatorVisitor(cmsPropertyValidatorVisitor);

        profilePropertyEdit.setCmsPropertyValidatorVisitor(cmsPropertyValidatorVisitor);

        extraPropertyEdit.setCmsPropertyValidatorVisitor(cmsPropertyValidatorVisitor);

        return null;
    }

    private ContentObject getSelectedContentObject() {
        if (explicitlySetContentObjectForEdit != null) {
            return explicitlySetContentObjectForEdit;
        } else {
            return (ContentObject) contentService.getContentObject(selectedContentObjectIdentifier,
                    ResourceRepresentationType.CONTENT_OBJECT_INSTANCE, FetchLevel.ENTITY, null, null, true);
        }
    }

    private void createFixedPropertyBreadCrumbs(ComplexCmsProperty<?, ?> complexCmsProperty) {

        fixedPropertyBreadCrumbs.clear();

        ComplexCmsProperty<?, ?> currentProperty = complexCmsProperty;

        do {
            String localizedLabel = (currentProperty instanceof ComplexCmsRootProperty
                    ? selectedContentObjectForEdit.getContentObject().getTypeDefinition().getDisplayName()
                            .getLocalizedLabelForLocale(localeSelector.getLocaleString())
                    : currentProperty.getAvailableLocalizedLabel(localeSelector.getLocaleString()));

            if (StringUtils.isBlank(localizedLabel))
                localizedLabel = currentProperty.getName();

            //If property has multiple values add the value index to label
            if (currentProperty.getPropertyDefinition().isMultiple()) {
                int index = PropertyPath.extractIndexFromPath(currentProperty.getPath());
                if (index == PropertyPath.NO_INDEX)
                    index = 0;
                localizedLabel += CmsConstants.LEFT_BRACKET + index + CmsConstants.RIGHT_BRACKET;
            }

            // check if the schema defines child properties that their values need to be appended in property localized name as extra identifiers 
            String propertyLabel = ((ComplexCmsProperty<?, ?>) currentProperty)
                    .getPropertyLabel(localeSelector.getLocaleString());
            if (StringUtils.isNotBlank(propertyLabel)) {
                localizedLabel += " - " + propertyLabel;
            }

            if (currentProperty instanceof ComplexCmsRootProperty) {
                //Root property does not have a path
                fixedPropertyBreadCrumbs.add(new ComplexCmsPropertyBreadCrumb(localizedLabel,
                        selectedContentObjectForEdit.getContentObject().getTypeDefinition().getName()));
            } else {
                fixedPropertyBreadCrumbs
                        .add(new ComplexCmsPropertyBreadCrumb(localizedLabel, currentProperty.getPath()));
            }

            currentProperty = currentProperty.getParentProperty();

        } while (currentProperty != null);

        if (fixedPropertyBreadCrumbs.size() > 1)
            Collections.reverse(fixedPropertyBreadCrumbs);

    }

    private void createExtraPropertyBreadCrumbs(ComplexCmsProperty<?, ?> complexCmsProperty) {

        extraPropertyBreadCrumbs.clear();

        ComplexCmsProperty<?, ?> currentProperty = complexCmsProperty;

        do {
            String localizedLabel;
            // if we are the level of the root property then the bread crumb label will be "Extra Properties" instead of the object type label in order to allow the user go back
            // to the extra properties form
            if (currentProperty instanceof ComplexCmsRootProperty) {
                localizedLabel = JSFUtilities.getStringI18n("object.edit.tab.extraProperties");

                // instead of a real property path we will create this bread crumb with the string 'EXTRA_PROPERIES' as path. 
                // This will force a return to the extra properties form
                extraPropertyBreadCrumbs.add(new ComplexCmsPropertyBreadCrumb(localizedLabel, "EXTRA_PROPERTIES"));
            } else {
                localizedLabel = currentProperty.getAvailableLocalizedLabel(localeSelector.getLocaleString());

                if (StringUtils.isBlank(localizedLabel))
                    localizedLabel = currentProperty.getName();

                //If property has multiple values add the value index to label
                if (currentProperty.getPropertyDefinition().isMultiple()) {
                    int index = PropertyPath.extractIndexFromPath(currentProperty.getPath());
                    if (index == PropertyPath.NO_INDEX)
                        index = 0;
                    localizedLabel += CmsConstants.LEFT_BRACKET + index + CmsConstants.RIGHT_BRACKET;
                }

                // check if the schema defines child properties that their values need to be appended in property localized name as extra identifiers 
                String propertyLabel = ((ComplexCmsProperty<?, ?>) currentProperty)
                        .getPropertyLabel(localeSelector.getLocaleString());
                if (StringUtils.isNotBlank(propertyLabel)) {
                    localizedLabel += " - " + propertyLabel;
                }

                extraPropertyBreadCrumbs
                        .add(new ComplexCmsPropertyBreadCrumb(localizedLabel, currentProperty.getPath()));
            }

            currentProperty = currentProperty.getParentProperty();

        } while (currentProperty != null);

        if (extraPropertyBreadCrumbs.size() > 1)
            Collections.reverse(extraPropertyBreadCrumbs);

    }

    //private void generateCmsPropertiesTree() {

    /*List<String> aspects = selectedContentObjectForEdit.getContentObject().getAspects();
        
       Events.instance().raiseEvent(SeamEventNames.NEW_CMS_DEFINITION_TREE, 
        selectedContentObjectForEdit.getContentObject().getContentObjectType(), 
        aspects);
        
       if (CollectionUtils.isNotEmpty(aspects)){
     selectedAspects = new String[aspects.size()];
     selectedContentObjectForEdit.getContentObject().getAspects().toArray(selectedAspects);
       }*/

    /*Events.instance().raiseEvent(SeamEventNames.NEW_CMS_PROPERTIES_TREE, 
        selectedContentObjectForEdit.getContentObject());
        
       List<String> aspects = selectedContentObjectForEdit.getContentObject().getAspects();
       if (CollectionUtils.isNotEmpty(aspects)){
     selectedAspects = new String[aspects.size()];
     selectedContentObjectForEdit.getContentObject().getAspects().toArray(selectedAspects);
       }
        
    }   */

    private void initializeNewContentObject() throws Exception {
        newContentObject = true;
        ContentObject contentObject;

        // get a content object template for the user selected content type. Profile and Accessibility properties are also initialized
        if (contentObjectTypeForNewObject == null) {
            //Check in pageController
            contentObjectTypeForNewObject = pageController
                    .getContentObjectTypeToUseWhenLoadingClearedContentObjectEditForm();

            //Found no content object type found throw new Exception
            if (contentObjectTypeForNewObject == null) {
                newContentObject = false;
                JSFUtilities.addMessage(null, "object.edit.error.no.content.type", null,
                        FacesMessage.SEVERITY_ERROR);
                throw new Exception(
                        "ContentObject Type for the generation of a new content object has not been provided");
            } else {
                //Clear value
                pageController.setContentObjectTypeToUseWhenLoadingClearedContentObjectEditForm(null);
            }
        }

        contentObject = cmsRepositoryEntityFactory.newObjectForType(contentObjectTypeForNewObject);

        selectedContentObjectForEdit = contentObjectUIWrapperFactory.getInstance(contentObject);

        if (contentObject.getComplexCmsRootProperty().isChildPropertyDefined("profile.language")) {
            ((StringProperty) contentObject.getCmsProperty("profile.language"))
                    .addSimpleTypeValue(JSFUtilities.getLocaleAsString());
        }

        // get the current user and set the owner of this new content object accordingly
        contentObject.setOwner(loggedInRepositoryUser.getRepositoryUser());

        // initialize the creator with the name of the owner
        if (contentObject.getComplexCmsRootProperty().isChildPropertyDefined("profile.creator")) {
            ((StringProperty) contentObject.getCmsProperty("profile.creator"))
                    .addSimpleTypeValue(loggedInRepositoryUser.getRepositoryUser().getLabel());
        }

        // initialize content type localized name for presentation at the form
        contentObjectTypeLocalizedName = contentObject.getTypeDefinition().getDisplayName()
                .getLocalizedLabelForLocale(JSFUtilities.getLocaleAsString());

        // initialize the default accessibility values setting appropriately the corresponding input components in the form (i.e. the radio button default values)

        clearUIAccessRightLists();

        radioButtonSelectionMap.put(AccessRight.canBeReadBy.toString(), "1");// READ BY ALL
        radioButtonSelectionMap.put(AccessRight.canBeUpdatedBy.toString(), "2"); // UPDATED BY NONE (only owner is allowed)
        radioButtonSelectionMap.put(AccessRight.canBeDeletedBy.toString(), "2"); // DELETED BY NONE (only owner is allowed)
        radioButtonSelectionMap.put(AccessRight.canBeTaggedBy.toString(), "1"); // TAGGED BY ALL

        contentObjectTitle = null;
    }

    private void loadComplexCmsPropertyToComplexCmsPropertyEditor(ComplexCmsProperty<?, ?> complexCmsProperty,
            ComplexCmsPropertyEdit complexCmsPropertyEdit) {

        //Find appropriate template to load
        String cmsPropertyTemplatePath = "/WEB-INF/pageComponents/";

        String definitionFullPath = complexCmsProperty.getPropertyDefinition().getFullPath();

        complexCmsPropertyEditorPagePath = cmsPropertyTemplatePath + "edit/propertyTemplates/"
                + generateCmsPropertyTemplateName(definitionFullPath) + "-editor.xhtml";

        try {

            ServletContextResource templateResource = new ServletContextResource(
                    (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext(),
                    complexCmsPropertyEditorPagePath);

            if (!templateResource.exists()) {

                //Template for property was not found. 
                //Check if there is a template for this complex property as a global one
                //and not in terms of its type
                String definitionPath = complexCmsProperty.getPropertyDefinition().getPath();

                complexCmsPropertyEditorPagePath = cmsPropertyTemplatePath + "edit/propertyTemplates/"
                        + generateCmsPropertyTemplateName(definitionPath) + "-editor.xhtml";

                templateResource = new ServletContextResource(
                        (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext(),
                        complexCmsPropertyEditorPagePath);

                if (!templateResource.exists()) {
                    throw new Exception();
                }
            }

        } catch (Exception e) {
            logger.debug("Template '" + complexCmsPropertyEditorPagePath + "' for cms property '"
                    + definitionFullPath + "' not found. Loading default " + defaultFixedPropertyEditorPagePath);

            //Return default template
            if (complexCmsPropertyEdit.getEditorTab().equals(EditorTab.FIXED_PROPERTIES)) {
                complexCmsPropertyEditorPagePath = defaultFixedPropertyEditorPagePath;
            } else if (complexCmsPropertyEdit.getEditorTab().equals(EditorTab.EXTRA_PROPERTIES)) {
                complexCmsPropertyEditorPagePath = defaultExtraPropertyEditorPagePath;
            }
        } finally {
            //Render with default editor
            complexCmsPropertyEdit.editComplexCmsProperty(complexCmsProperty);
        }

        //Create bread crumbs
        if (complexCmsPropertyEdit.getEditorTab().equals(EditorTab.FIXED_PROPERTIES)) {
            createFixedPropertyBreadCrumbs(complexCmsProperty);
        } else {
            createExtraPropertyBreadCrumbs(complexCmsProperty);
        }

    }

    private String generateCmsPropertyTemplateName(String definitionFullPath) {
        return definitionFullPath.replaceAll("\\.", "-");
    }

    public void removeExtraProperty_UIAction(String propertyName) {

        if (selectedContentObjectForEdit != null && selectedContentObjectForEdit.getContentObject() != null) {
            try {
                //   Remove aspect from list in ContentObject
                if (!selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                        .hasAspect(propertyName)) {
                    logger.warn("Unable to remove extra property '" + propertyName + "' from content object "
                            + selectedContentObjectForEdit.getContentObject().getId()
                            + " because extra property does not exist in content object");
                } else {
                    ComplexCmsProperty<?, ?> extraProperty = (ComplexCmsProperty<?, ?>) selectedContentObjectForEdit
                            .getContentObject().getCmsProperty(propertyName);
                    selectedContentObjectForEdit.getContentObject().removeCmsProperty(propertyName);
                    extraPropertyEdit.reloadEditedCmsProperties();
                    JSFUtilities.addMessage(null, "object.edit.removeExtraProperty.success",
                            new String[] {
                                    extraProperty.getAvailableLocalizedLabel(localeSelector.getLocaleString()) },
                            FacesMessage.SEVERITY_INFO);
                }
            } catch (Exception e) {
                logger.error("", e);
                JSFUtilities.addMessage(null, "object.edit.removeExtraProperty.error", null,
                        FacesMessage.SEVERITY_ERROR);
            }
        }

    }

    /*
    public void addAspectToComplexProperty_UIAction(String newlyAddedAspect){
       if (selectedContentObjectForEdit != null){
     try{
        //Aspect is new. Add to content object
        //selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty().addAspect(newlyAddedAspect);
        selectedContentObjectForEdit.getContentObject().getCmsProperty(newlyAddedAspect);
        
        //Aspect path now contains content object type
        showSelectedComplexPropertyForPath_UIAction(newlyAddedAspect);
        
     }
     catch (Exception e){
        logger.error("",e); 
        JSFUtilities.addMessage(null, "object.edit.add.aspect.error", null, FacesMessage.SEVERITY_ERROR); 
     }
       }
    }
    */

    /* Extra properties are properties that are not statically defined in object type schemas
     * They can be dynamically added in any object instance.
     * Any complex property type defined outside of an object type definition can be used as a prototype for adding extra properties to object instances.
     * When a user selects to add an extra property from the available prototypes, this method displays the property form in the console editor 
     * The property name is the name of the prototype.
     */
    public void showNewExtraProperty_UIAction(String propertyName) {
        ComplexCmsProperty<?, ?> extraProperty = (ComplexCmsProperty<?, ?>) selectedContentObjectForEdit
                .getContentObject().getCmsProperty(propertyName);
        if (extraProperty != null) {
            extraPropertyEdit.reloadEditedCmsProperties();
            JSFUtilities.addMessage(null, "object.edit.addExtraProperty.success",
                    new String[] { extraProperty.getAvailableLocalizedLabel(localeSelector.getLocaleString()) },
                    FacesMessage.SEVERITY_INFO);
        } else {
            JSFUtilities.addMessage(null, "object.edit.addExtraProperty.error", null, FacesMessage.SEVERITY_WARN);
        }
    }

    // This method displays the selected complex property either in the properties or in the extra properties tab according to which complexCmsPropertyEdit instance has been passed to the method
    @Observer({ SeamEventNames.NEW_COMPLEX_CMS_PROPERTY_ADDED })
    public void showSelectedComplexPropertyForPath_UIAction(String complexCmsPropertyPath,
            ComplexCmsPropertyEdit complexCmsPropertyEdit) {

        if (StringUtils.isNotBlank(complexCmsPropertyPath)) {

            // when path equals 'EXTRA_PROPERTIES' we set the edited property in the complexPropertiesEdit 
            // to be null in order to force loading the extra properties form. 
            // We also se the template to be used and we reset the extra properties bread crumbs array
            if (complexCmsPropertyPath.equals("EXTRA_PROPERTIES")) {
                complexCmsPropertyEdit.editComplexCmsProperty(null);
                complexCmsPropertyEditorPagePath = defaultExtraPropertyEditorPagePath;
                extraPropertyBreadCrumbs = new ArrayList<ComplexCmsPropertyBreadCrumb>();
            } else {

                try {

                    ComplexCmsProperty<?, ?> complexCmsProperty = null;

                    if (selectedContentObjectForEdit.getContentObject().getTypeDefinition().getName()
                            .equals(complexCmsPropertyPath)) {
                        //Load root property
                        complexCmsProperty = selectedContentObjectForEdit.getContentObject()
                                .getComplexCmsRootProperty();
                    } else {
                        complexCmsProperty = (ComplexCmsProperty<?, ?>) selectedContentObjectForEdit
                                .getContentObject().getCmsProperty(complexCmsPropertyPath);
                    }

                    if (complexCmsProperty == null) {
                        //Complex Cms Property is either not defined or
                        //is a multiple complex cms property
                        if (selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                                .isChildPropertyDefined(complexCmsPropertyPath)) {

                            //Create a template for complex cms property
                            complexCmsProperty = (ComplexCmsProperty<?, ?>) complexCmsPropertyEdit
                                    .getEditedComplexCmsProperty()
                                    .createNewValueForMulitpleComplexCmsProperty(complexCmsPropertyPath);

                        }
                    }

                    if (complexCmsProperty == null) {
                        logger.warn("Attempt to create and load complex cms Property " + complexCmsPropertyPath
                                + " failed");
                    } else {
                        //Load complex cms property editor only if complex cms property was found
                        loadComplexCmsPropertyToComplexCmsPropertyEditor(complexCmsProperty,
                                complexCmsPropertyEdit);
                    }
                } catch (Exception e) {
                    logger.error("", e);
                    JSFUtilities.addMessage(null, "application.unknown.error.message", null,
                            FacesMessage.SEVERITY_WARN);
                }
            }
        }
    }

    //Save a content object without version
    //Temporarily sets loggedInRepositoryUserSetting for creatingVersion on save to false
    //performs save and then restores previous value
    private String disableCreateVersionAndSaveContentObject() {

        boolean previousValue = Boolean.valueOf(loggedInRepositoryUserSettings.isCreateVersionUponSuccessfulSave());

        loggedInRepositoryUserSettings.setCreateVersionUponSuccessfulSave(false);

        String saveOutcome = saveContentObject();

        loggedInRepositoryUserSettings.setCreateVersionUponSuccessfulSave(previousValue);

        return saveOutcome;
    }

    public String saveContentObject_UIAction() {
        //We care about the outcome only if it is about
        //clear
        String saveOutcome = saveContentObject();

        if (StringUtils.isNotBlank(saveOutcome)
                && CLEAR_CONTENT_OBJECT_EDIT_AND_LOAD_AGAIN_XHTML.equals(saveOutcome)) {
            return saveOutcome;
        } else {
            //Return null to stay in the same page
            return null;
        }

    }

    private String saveContentObject() {

        String contentObjectPreparationOutcome = "error";

        boolean contentObjectWasSavedInRepository = false;

        String providedSystemName = selectedContentObjectForEdit.getContentObject().getSystemName() != null
                ? new String(selectedContentObjectForEdit.getContentObject().getSystemName())
                : null;

        // we will need this to know if we have been required to use admin privileges  in order to successfully save the object 
        boolean adminRoleHasBeenAdded = false;
        // and these in order to add admin privileges if we are required to do so
        SecurityContext securityContext = null;
        String roleAdminForActiveRepository = null;

        try {
            // first do some checks and prepare content object for save
            contentObjectPreparationOutcome = prepareContentObjectForSave();

            // if checks and preparation were successful we now we may proceed to save the content object
            if (contentObjectPreparationOutcome.equals("contentObjectReadyForSave")) {

                //Generate draftItemId before save as during save an id is created
                String draftItemId = DraftItem
                        .generateDraftItemIdForCmsRepositoryEntity(selectedContentObjectForEdit.getContentObject());

                // Sent an event just before saving to allow custom observers to perform actions or change the object
                // We are providing a default observer that looks for a specially named script objects in the repository and
                // runs the script. This allows users to dynamically add code for this event directly through astroboa console
                // The script object should have a system name equal to the event name, i.e. "org.betaconceptframework.astroboa.console.contentObjectReadyForSave".
                // Additionally the script object should be owned by SYSTEM to prevent unauthorized users from changing the behaviour of content object editing.
                // Finally the script itself should be a GROOVY class implementing the "PreSaveGroovyActionInterface"
                // Example:
                //   import org.betaconceptframework.astroboa.api.model.*;
                //   import org.betaconceptframework.astroboa.console.jsf.edit.PreSaveGroovyAction;
                //   import org.slf4j.Logger;
                //
                //   public class PreSaveAction implements PreSaveGroovyAction {
                //
                //      public void run(ContentObject contentObject, Logger logger) {
                //         // do some actions
                //      }
                //   }
                //
                // A common case for adding custom script code is to automatically alter 
                // object accessibility settings according to some common rules set by each organization
                if (!selectedContentObjectForEdit.getContentObject().getSystemName()
                        .equals(SeamEventNames.CONTENT_OBJECT_READY_FOR_SAVE)) { // We do not want to sent the event if the edited object is the script object itself that handles the event
                    Events.instance().raiseEvent(SeamEventNames.CONTENT_OBJECT_READY_FOR_SAVE,
                            new Object[] { selectedContentObjectForEdit.getContentObject() });
                }

                // we save the content object
                // but before we should check if the object type is a subclass of personType and the logged in username is the same as the username stored in the person object 
                // "personAuthentication.username" property. In other words we should detect the case that a user tries to save her user profile. 
                // If such a case exists then we should check if the user is the owner of the object (usually she is not because an admin will create the accounts). 
                // If not then we should perform the save as an admin on behalf of the user.
                if (selectedContentObjectForEdit.isLoggedInUsersPersonProfile()
                        && !selectedContentObjectForEdit.getContentObject().getOwner().getExternalId()
                                .equals(loggedInRepositoryUser.getIdentity())) {

                    // we will emulate a run as functionality adding the admin role into user roles and after the save we will remove it
                    securityContext = AstroboaClientContextHolder.getActiveSecurityContext();
                    roleAdminForActiveRepository = CmsRoleAffiliationFactory.INSTANCE
                            .getCmsRoleAffiliationForActiveRepository(CmsRole.ROLE_ADMIN);

                    if (securityContext != null && !securityContext.hasRole(roleAdminForActiveRepository)) {
                        adminRoleHasBeenAdded = securityContext.addRole(roleAdminForActiveRepository);
                    }
                }

                contentService.save(selectedContentObjectForEdit.getContentObject(),
                        loggedInRepositoryUserSettings.isCreateVersionUponSuccessfulSave(), true, null);

                //Flag indicating that object was saved in repository
                contentObjectWasSavedInRepository = true;

                // make necessary resets in views and objects before leaving edit mode
                //   resetViewAndState();

                // change the header message of the content object list panel
                contentObjectList.setContentObjectListHeaderMessage(JSFUtilities
                        .getStringI18n("object.list.message.contentObjectListHeaderMessageAfterContentObjectSave"));

                // Update the accessibility UI components in the case the pre-save actions 
                // (any code triggered by the CONTENT_OBJECT_READY_FOR_SAVE event) have altered accessibility property
                initializeInputAndOutputUIComponentsRelatedtoSecurityProperties();

                // generate a success message
                JSFUtilities.addMessage(null, "object.edit.successful.save.info.message", null,
                        FacesMessage.SEVERITY_INFO);

                if (listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated.size() > 0)
                    Events.instance().raiseEvent(SeamEventNames.UPDATE_NO_OF_CONTENT_OBJECT_REFERRERS,
                            listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated);

                listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated.clear();

                //Reset loggedinRepositoryUser's root topics
                //in order to force aspect to reload them from database
                resetLoggedInRepositoryUserFolksonomyRootTopics();

                //Notify content type tree if content object is new
                if (newContentObject) {
                    Events.instance().raiseEvent(SeamEventNames.CONTENT_OBJECT_ADDED, new Object[] {
                            selectedContentObjectForEdit.getContentObject().getContentObjectType(),
                            selectedContentObjectForEdit.getContentObject().getId(),
                            (selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                                    .isChildPropertyDefined("profile.created")
                                            ? ((CalendarProperty) selectedContentObjectForEdit.getContentObject()
                                                    .getCmsProperty("profile.created")).getSimpleTypeValue()
                                            : Calendar.getInstance()) });
                } else {
                    Events.instance().raiseEvent(SeamEventNames.CONTENT_OBJECT_UPDATED,
                            new Object[] { selectedContentObjectForEdit.getContentObject().getContentObjectType(),
                                    selectedContentObjectForEdit.getContentObject().getId() });
                }

                //Raise a special event for draft. LoggedInRepositoryUser is needed
                Events.instance().raiseEvent(SeamEventNames.CONTENT_OBJECT_MODIFIED,
                        new Object[] { loggedInRepositoryUser.getRepositoryUser().getId(), draftItemId });

                // Reset the extra properties editor in order to reload the extra properties list
                // We need this in the case that the user has added an extra property, added no values in it 
                // and after the successful save the empty property has been automatically removed from the object 
                extraPropertyEdit.reloadEditedCmsProperties();
            } else {
                return contentObjectPreparationOutcome;
            }

        } catch (CmsNonUniqueContentObjectSystemNameException e) {
            if (!contentObjectWasSavedInRepository) {
                //Produce error message only if content object was not saved at all
                JSFUtilities.addMessage(null, "object.edit.non.unique.system.name",
                        new String[] { selectedContentObjectForEdit.getContentObject().getSystemName() },
                        FacesMessage.SEVERITY_WARN);

                if (newContentObject) {
                    selectedContentObjectForEdit.getContentObject().setId(null);
                }
            }

            return "error";

        } catch (CmsConcurrentModificationException e) {
            JSFUtilities.addMessage(null, "object.edit.save.concurrentModificationError", null,
                    FacesMessage.SEVERITY_WARN);

            if (newContentObject) {
                selectedContentObjectForEdit.getContentObject().setId(null);
            }

            return "error";

        } catch (Exception e) {
            getLogger().error("Content Object could not be saved", e);

            if (!contentObjectWasSavedInRepository) {
                //Produce error message only if content object was not saved at all
                JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);
                if (newContentObject) {
                    selectedContentObjectForEdit.getContentObject().setId(null);
                }
            }

            return "error";

        } finally {
            if (adminRoleHasBeenAdded) {
                securityContext.removeRole(roleAdminForActiveRepository);
            }
        }

        //check if content object's system name was not unique 
        if (newContentObject && selectedContentObjectForEdit.getContentObject().getSystemName() != null
                && selectedContentObjectForEdit.getContentObject().getId() != null
                && selectedContentObjectForEdit.getContentObject().getSystemName()
                        .endsWith(selectedContentObjectForEdit.getContentObject().getId())) {
            JSFUtilities.addMessage(null, "object.edit.save.system.name.provided",
                    providedSystemName != null ? new String[] { providedSystemName } : new String[] { "" },
                    FacesMessage.SEVERITY_WARN);
        }

        // check if user wishes to copy the content object to a SPACE_INSTANCE

        try {

            if (spaceToCopyNewObject != null) {

                String contentObjectId = selectedContentObjectForEdit.getContentObject().getId();

                spaceToCopyNewObject.addContentObjectReference(contentObjectId);
                spaceService.save(spaceToCopyNewObject);
                // recreate space items
                userSpaceNavigation.getUserSpaceItems();

                // reset selected space to prevent coping it in successive saves of the same object
                spaceToCopyNewObject = null;

                // generate a success message
                JSFUtilities.addMessage(null, "object.edit.sucessfully.attach.content.object.to.space", null,
                        FacesMessage.SEVERITY_INFO);
            }

        } catch (Exception e) {
            JSFUtilities.addMessage(null, "object.edit.space.attach.error", null, FacesMessage.SEVERITY_ERROR);
            getLogger().error("Content Object could not be attached to requested SPACE_INSTANCE", e);
            return "error";

        }

        //Decide if editor should be closed
        /*
        if (contentObjectPreparationOutcome.equals("contentObjectReadyForSave")) {
               
           //Copy to clipboard
           if (loggedInRepositoryUserSettings.isCopyContentObjectToClipboardUponSuccessfulSave()){
        clipboard.copyContentObjectToClipboard_UIAction(
              selectedContentObjectForEdit.getContentObject().getId(), 
              selectedContentObjectForEdit.getContentObject().getSystemName(), 
              ((StringProperty) selectedContentObjectForEdit.getContentObject().getCmsProperty("profile.title")).getSimpleTypeValue(),
              selectedContentObjectForEdit.getContentObjectTypeForCurrentLocale(),
              selectedContentObjectForEdit.getContentObject().getContentObjectType());
           }
               
           if (newContentObject && loggedInRepositoryUserSettings.isOpenNewContentObjectEditorUponSuccessfulSave()){
        pageController.setContentObjectTypeToUseWhenLoadingClearedContentObjectEditForm(selectedContentObjectForEdit.getContentObject().getContentObjectType());
        return CLEAR_CONTENT_OBJECT_EDIT_AND_LOAD_AGAIN_XHTML;
           }
        }
        */

        //Remained in the same page. Set newContentObject flag to false
        if (contentObjectWasSavedInRepository) {
            newContentObject = false;
        }
        return contentObjectPreparationOutcome;

    }

    private void resetLoggedInRepositoryUserFolksonomyRootTopics() {
        loggedInRepositoryUser.getRepositoryUser().getFolksonomy().setRootTopics(null);
    }

    private String prepareContentObjectForSave() throws Exception {

        // generate the accessibility properties from the user provided input values (through the accessibility tab in the content object UI form)
        String methodOutcome = generateContentObjectAccessibilityPropertiesFromUIFormInputValues();
        if (methodOutcome.equals("error"))
            return "error";

        // the following is a fix for profile.language. If it is an empty list we should nullify it because the pick list UI component 
        // generates an immutable ArrayList that prevents the repository engine to add the default value (as is set in XSD)
        //StringProperty language = (StringProperty)selectedContentObjectForEdit.getContentObjectProperty().get("profile.language");
        //if (language != null && CollectionUtils.isEmpty(language.getSimpleTypeValues())) {
        //   language.setSimpleTypeValues(null);
        //}

        //Validate ContentObject properties
        validateProperties();

        // check if all mandatory properties have been provided. The checking method produces the appropriate UI messages when a property is missing 
        //if (mandatoryPropertiesMissing()) {
        if (cmsPropertyValidatorVisitor.mandatoryPropertiesAreMissing()) {
            JSFUtilities.addMessage(null, "object.edit.error.required", null, FacesMessage.SEVERITY_WARN);
            return "error";
        }

        if (cmsPropertyValidatorVisitor.hasErrors())
            return "error";

        // Perform a specific validation in case content object is of 'portal' type
        if (CmsConstants.PORTAL_CONTENT_OBJECT_TYPE
                .equals(selectedContentObjectForEdit.getContentObject().getContentObjectType())) {

            String portalSystemName = selectedContentObjectForEdit.getContentObject().getSystemName();

            //Look for duplicate portalSystem name
            ContentObjectCriteria portalCriteria = CmsCriteriaFactory.newContentObjectCriteria();

            portalCriteria.addContentObjectTypeEqualsCriterion(CmsConstants.PORTAL_CONTENT_OBJECT_TYPE);
            portalCriteria.addSystemNameEqualsCriterion(portalSystemName);

            if (selectedContentObjectForEdit.getContentObject().getId() != null) {
                portalCriteria.addIdNotEqualsCriterion(selectedContentObjectForEdit.getContentObject().getId());
            }
            portalCriteria.doNotCacheResults();
            portalCriteria.setOffsetAndLimit(0, 1);

            CmsOutcome<ContentObject> portalOutcome = contentService.searchContentObjects(portalCriteria,
                    ResourceRepresentationType.CONTENT_OBJECT_LIST);

            if (portalOutcome != null && portalOutcome.getCount() > 0) {
                JSFUtilities.addMessage(null, "object.edit.already.existing.portal.system.name",
                        new String[] { portalSystemName }, FacesMessage.SEVERITY_WARN);
                return "error";
            }
        }

        //Perform one final check. In case content object status is scheduledForPublication but no
        //webPublication.webPublicationStartDate is provided throw a mandatory error message
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        if (contentObjectStatusProperty != null && contentObjectStatusProperty.hasValues()) {
            String contentObjectStatus = contentObjectStatusProperty.getSimpleTypeValue();

            if (StringUtils.equals(ContentObjectStatus.scheduledForPublication.toString(), contentObjectStatus)) {
                //Check webPublicationStartDate property
                CalendarProperty webPublicationStartDateProperty = ((CalendarProperty) selectedContentObjectForEdit
                        .getContentObject().getCmsProperty("webPublication.webPublicationStartDate"));

                if (webPublicationStartDateProperty == null || webPublicationStartDateProperty.hasNoValues()) {
                    String propertyLocalizedLabel = (webPublicationStartDateProperty == null
                            ? JSFUtilities.getLocalizedMessage("object.edit.web.publication.start.date", null)
                            : webPublicationStartDateProperty.getLocalizedLabelOfFullPathforLocaleWithDelimiter(
                                    JSFUtilities.getLocaleAsString(), " > "));

                    JSFUtilities.addMessage("webPublication.webPublicationStartDate", "errors.required",
                            new String[] { propertyLocalizedLabel }, FacesMessage.SEVERITY_WARN);

                    return "error";

                }
            }
        }

        return "contentObjectReadyForSave";

    }

    private void validateProperties() {

        ContentObjectTypeDefinition contentObjectTypeDefinition = (ContentObjectTypeDefinition) definitionService
                .getCmsDefinition(selectedContentObjectForEdit.getContentObject().getContentObjectType(),
                        ResourceRepresentationType.DEFINITION_INSTANCE, false);

        cmsPropertyValidatorVisitor.reset(false);

        cmsPropertyValidatorVisitor.validateContentObjectProperties(selectedContentObjectForEdit.getContentObject(),
                contentObjectTypeDefinition);
    }

    /*private boolean mandatoryPropertiesMissing() throws Exception {
        
       boolean mandatoryPropertiesMissing = false;
        
       // check for mandatory fields in Administrative Bundles
    //   if (mandatoryPropertiesOfAdministrativeBundlesMissing())
       //   mandatoryPropertiesMissing = true;
        
       // check if all mandatory content type properties have been provided
       if (mandatoryPropertiesOfContentTypeMissing(selectedContentObjectForEdit.getContentObject().getContentObjectType()))
     mandatoryPropertiesMissing = true;
        
        
       // if content type is textBased, image, audio or video
       //if (selectedContentObjectForEdit.isFile()) {
        
     //Check if  binary channels exist or have been uploaded
     //if (selectedContentObjectForEdit.getContentObject().getBinaryChannels() == null) {
        //JSFUtilities.addMessage(null, "contentObjectEdit.noFileHasBeenUploadedError", null, FacesMessage.SEVERITY_ERROR);
     //}
       //}
        
       return mandatoryPropertiesMissing;
    }
        
        
    private boolean mandatoryPropertiesOfContentTypeMissing(String contentType) throws Exception {
        
       boolean mandatoryPropertiesMissing = false;
        
     MandatoryPropertyDefinitionVisitor mandatoryPropertyDefinitionVisitor = new MandatoryPropertyDefinitionVisitor(selectedContentObjectForEdit.getContentObject());
     ContentObjectTypeDefinition contentObjectTypeDefinition = definitionService.getContentObjectTypeDefinition(contentType);
        
     contentObjectTypeDefinition.accept(mandatoryPropertyDefinitionVisitor);
     mandatoryPropertiesMissing = mandatoryPropertyDefinitionVisitor.mandatoryPropertiesAreMissing();
        
       return mandatoryPropertiesMissing;
    }*/

    public void grantAccessRightToDraggedAndDroppedUserOrRole_Listener(DropEvent dropEvent) {
        String typeOfAccessRight = (String) dropEvent.getDropValue();
        String typeOfDraggedObject = dropEvent.getDragType();

        Map<String, String> userOrGroupMap = new HashMap<String, String>();
        if ("user".equals(typeOfDraggedObject)) {
            Person user = (Person) dropEvent.getDragValue();
            userOrGroupMap.put("userOrGroupId", user.getUsername());
            userOrGroupMap.put("userOrGroupName",
                    StringUtils.isBlank(user.getDisplayName()) ? user.getUsername() : user.getDisplayName());
        } else if ("role".equals(typeOfDraggedObject)) {
            String personGroup = (String) dropEvent.getDragValue();
            userOrGroupMap.put("userOrGroupId", personGroup);
            userOrGroupMap.put("userOrGroupName",
                    Utils.retrieveDisplayNameForRoleOrPerson(identityStoreRunAsSystem, personGroup));
        }

        grantAccessRightToPersonOrRole(AccessRight.valueOf(typeOfAccessRight), userOrGroupMap);
    }

    public void grantAccessRightToPerson(Person person, AccessRight typeOfAccessRight) {

        Map<String, String> userOrGroupMap = new HashMap<String, String>();
        userOrGroupMap.put("userOrGroupId", person.getUsername());
        userOrGroupMap.put("userOrGroupName",
                StringUtils.isBlank(person.getDisplayName()) ? person.getUsername() : person.getDisplayName());

        grantAccessRightToPersonOrRole(typeOfAccessRight, userOrGroupMap);

    }

    public void grantAccessRightToPersonOrRole(AccessRight typeOfAccessRight, Map<String, String> userOrRoleMap) {

        if (typeOfAccessRight != null) {

            if (!userListByAccessRight.containsKey(typeOfAccessRight.toString())) {
                userListByAccessRight.put(typeOfAccessRight.toString(), new ArrayList<Map<String, String>>());
            }

            List<Map<String, String>> userList = userListByAccessRight.get(typeOfAccessRight.toString());

            if (userList != null) {
                if (userOrGroupIsNotInAccessRightList(userList, userOrRoleMap.get("userOrGroupName")))
                    userList.add(userOrRoleMap);
                else {
                    logger.warn("User already in access right list. selection is ignored");
                    JSFUtilities.addMessage(null, "object.edit.accessibility.value.already.exists.warning", null,
                            FacesMessage.SEVERITY_WARN);
                }
            }
        }
    }

    public void removeUserOrGroupFromAccessRightList_UIAction(List<HashMap<String, String>> accessRightList,
            HashMap<String, String> userOrGroup) {
        accessRightList.remove(userOrGroup);
    }

    private boolean userOrGroupIsNotInAccessRightList(List<Map<String, String>> accessRightList,
            String userOrGroupName) {
        if (CollectionUtils.isEmpty(accessRightList))
            return true;
        for (Map<String, String> userHashMap : accessRightList) {
            if (userHashMap.get("userOrGroupName").equals(userOrGroupName))
                return false;
        }
        return true;
    }

    private String generateContentObjectAccessibilityPropertiesFromUIFormForAccessRight(AccessRight accessRight,
            StringProperty accessibilityProperty) {
        if (accessRight == null) {
            return "error";
        }

        if (radioButtonSelectionMap.containsKey(accessRight.toString())) {

            switch (Integer.parseInt(radioButtonSelectionMap.get(accessRight.toString()))) {
            case 1:

                if (accessibilityProperty.hasValues()) {
                    accessibilityProperty.getSimpleTypeValues().clear();
                }

                accessibilityProperty.addSimpleTypeValue(ContentAccessMode.ALL.toString());

                break;
            case 2:

                if (accessibilityProperty.hasValues()) {
                    accessibilityProperty.getSimpleTypeValues().clear();
                }

                accessibilityProperty.addSimpleTypeValue(ContentAccessMode.NONE.toString());

                break;
            case 3:

                List<Map<String, String>> userList = userListByAccessRight.get(accessRight.toString());
                if (userList == null || userList.size() == 0) {
                    JSFUtilities.addMessage(null,
                            "object.edit.accessibility.value.user.group." + accessRight.toString() + ".empty", null,
                            FacesMessage.SEVERITY_ERROR);
                    return "error";
                }
                copyUIAccessRightListToContentObjectAccessRightList(userList,
                        accessibilityProperty.getSimpleTypeValues());
                break;

            default:
                // we do not support any other value. reset radio button to default, generate an error message and return
                JSFUtilities.addMessage(null, "object.edit.invalid.accessibility.value",
                        new String[] { radioButtonSelectionMap.get(accessRight.toString()) },
                        FacesMessage.SEVERITY_WARN);

                radioButtonSelectionMap.put(accessRight.toString(), "1");

                return "error";

            }

            return "success";
        }

        return "success";

    }

    private String generateContentObjectAccessibilityPropertiesFromUIFormInputValues() {
        // do nothing if no accessibility properties exist
        if (!selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                .isChildPropertyDefined("accessibility"))
            return "success";
        // Load Accessibility properties
        StringProperty canBeReadBy = (StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeReadBy");
        StringProperty canBeUpdatedBy = (StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeUpdatedBy");
        StringProperty canBeDeletedBy = (StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeDeletedBy");
        StringProperty canBeTaggedBy = (StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeTaggedBy");

        String outcome = generateContentObjectAccessibilityPropertiesFromUIFormForAccessRight(
                AccessRight.canBeReadBy, canBeReadBy);

        if (!"error".equals(outcome)) {

            outcome = generateContentObjectAccessibilityPropertiesFromUIFormForAccessRight(
                    AccessRight.canBeUpdatedBy, canBeUpdatedBy);

            if (!"error".equals(outcome)) {
                outcome = generateContentObjectAccessibilityPropertiesFromUIFormForAccessRight(
                        AccessRight.canBeDeletedBy, canBeDeletedBy);

                if (!"error".equals(outcome)) {
                    return generateContentObjectAccessibilityPropertiesFromUIFormForAccessRight(
                            AccessRight.canBeTaggedBy, canBeTaggedBy);
                } else {
                    return "error";
                }
            } else {
                return "error";
            }
        } else {
            return "error";
        }

    }

    /* Copy an access right list from content object into a list which is more appropriate for UI presentation. Actually turn user and group ids to meaningful names.
     * The access right lists in the content object holds only user / group ids which are not very meaningful to the end user. So we connect to the crm database, we read the
     * user / group names and generate the access rights lists which are used by the UI to present meaningful info about access rights 
     */
    private void copyContentObjectAccessRightListToUIAccessRightList(List<String> contentObjectAccessRightList,
            List<Map<String, String>> uiAccessRightList) {
        for (String prefixedUserOrGroupId : contentObjectAccessRightList) {
            Map<String, String> userOrGroup = new HashMap<String, String>();
            userOrGroup.put("userOrGroupId", prefixedUserOrGroupId);

            userOrGroup.put("userOrGroupName",
                    Utils.retrieveDisplayNameForRoleOrPerson(identityStoreRunAsSystem, prefixedUserOrGroupId));

            uiAccessRightList.add(userOrGroup);
        }
    }

    /* This method does the opposite function of "copyContentObjectAccessRightListToUIAccessRightList" method
     * It gets an access right list genetated by the UI after user interaction and produces the appropriate access right list for insertion into the content object
     */
    private void copyUIAccessRightListToContentObjectAccessRightList(List<Map<String, String>> uiAccessRightList,
            List<String> contentObjectAccessRightList) {

        //Remove old values and add new ones
        contentObjectAccessRightList.clear();
        for (Map<String, String> userOrGroup : uiAccessRightList) {
            contentObjectAccessRightList.add(userOrGroup.get("userOrGroupId"));
        }
    }

    private void initializeInputAndOutputUIComponentsRelatedtoSecurityProperty(AccessRight accessRight,
            List<String> accessValuesList, String defaultAccessRightValue) {

        if (CollectionUtils.isNotEmpty(accessValuesList)) {

            if (accessValuesList.get(0).equals(ContentAccessMode.ALL.toString())) {
                radioButtonSelectionMap.put(accessRight.toString(), "1");
            } else if (accessValuesList.get(0).equals(ContentAccessMode.NONE.toString())) {
                radioButtonSelectionMap.put(accessRight.toString(), "2");
            } else {
                radioButtonSelectionMap.put(accessRight.toString(), "3");
                copyContentObjectAccessRightListToUIAccessRightList(accessValuesList,
                        userListByAccessRight.get(accessRight.toString()));
            }
        } else {
            if (StringUtils.isBlank(defaultAccessRightValue)) {
                //Default value for access right
                radioButtonSelectionMap.put(accessRight.toString(), "1");
            } else {
                if (StringUtils.equals(ContentAccessMode.ALL.toString(), defaultAccessRightValue)) {
                    radioButtonSelectionMap.put(accessRight.toString(), "1");
                } else if (StringUtils.equals(ContentAccessMode.NONE.toString(), defaultAccessRightValue)) {
                    radioButtonSelectionMap.put(accessRight.toString(), "2");
                }
            }
        }

    }

    private void initializeInputAndOutputUIComponentsRelatedtoSecurityProperties() {
        // do nothing if no accessibility properties exist
        if (!selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                .isChildPropertyDefined("accessibility"))
            return;

        // Create Accessibility Lists
        List<String> canBeReadByList = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeReadBy")).getSimpleTypeValues();
        List<String> canBeUpdatedByList = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeUpdatedBy")).getSimpleTypeValues();
        List<String> canBeDeletedByList = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeDeletedBy")).getSimpleTypeValues();
        List<String> canBeTaggedByList = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("accessibility.canBeTaggedBy")).getSimpleTypeValues();

        clearUIAccessRightLists();

        initializeInputAndOutputUIComponentsRelatedtoSecurityProperty(AccessRight.canBeReadBy, canBeReadByList,
                ContentAccessMode.ALL.toString());
        initializeInputAndOutputUIComponentsRelatedtoSecurityProperty(AccessRight.canBeUpdatedBy,
                canBeUpdatedByList, ContentAccessMode.NONE.toString());
        initializeInputAndOutputUIComponentsRelatedtoSecurityProperty(AccessRight.canBeDeletedBy,
                canBeDeletedByList, ContentAccessMode.NONE.toString());
        initializeInputAndOutputUIComponentsRelatedtoSecurityProperty(AccessRight.canBeTaggedBy, canBeTaggedByList,
                ContentAccessMode.ALL.toString());
    }

    private void clearUIAccessRightLists() {

        if (radioButtonSelectionMap == null) {
            radioButtonSelectionMap = new HashMap<String, String>();
        } else {
            radioButtonSelectionMap.clear();
        }

        if (userListByAccessRight == null) {
            userListByAccessRight = new HashMap<String, List<Map<String, String>>>();
        } else {
            userListByAccessRight.clear();
        }

        for (AccessRight accessRight : AccessRight.values()) {
            userListByAccessRight.put(accessRight.toString(), new ArrayList<Map<String, String>>());
        }

    }

    public void removeTopicFromContentObjectSubject_UIAction() {
        try {
            getSelectedContentObjectForEdit()
                    .removeTopicFromContentObjectSubject(selectedTopicIdForRemovalFromContentObjectSubject);
            updateListOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated(
                    selectedTopicIdForRemovalFromContentObjectSubject);
        } catch (Exception e) {
            logger.error("", e);
            JSFUtilities.addMessage(null, "application.unknown.error.message", null, FacesMessage.SEVERITY_WARN);
            return;
        }
    }

    public void addNewTagToContentObjectSubject_UIAction() {
        if (StringUtils.isNotBlank(newTagLabel)) {
            //   check if the new tag exists in user tags
            Topic newUserTag = cmsUtilities.createNewUserTag(newTagLabel, JSFUtilities.getLocaleAsString(),
                    loggedInRepositoryUser.getRepositoryUser());
            if (cmsUtilities.findTopicInTopicListByLocalizedTopicLabel(
                    loggedInRepositoryUser.getRepositoryUser().getFolksonomy().getRootTopics(),
                    newTagLabel) != null) {
                logger.warn("The user tag is not a new tag since it is already in user tags");
                JSFUtilities.addMessage(null, "object.edit.tag.already.exists", null, FacesMessage.SEVERITY_WARN);
                return;
            }

            // check if the new tag is already in contentObject subject. Remember that the new tags are saved with the object and are not yet in the list of user tags, so the above check is not enough 
            if (cmsUtilities
                    .findTopicInTopicListByLocalizedTopicLabel(
                            ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                                    .getCmsProperty("profile.subject")).getSimpleTypeValues(),
                            newTagLabel) != null) {
                logger.warn("The user tag is already in content object subject.");
                JSFUtilities.addMessage(null, "object.edit.tag.already.selected", null, FacesMessage.SEVERITY_WARN);
                return;
            }

            // if we have reached this point everything is ok. Let proceed to add the new  tag
            //Save Tag
            topicService.save(newUserTag);

            //Attach tag to content object
            ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                    .getCmsProperty("profile.subject")).addSimpleTypeValue(newUserTag);

            // reset tag value
            newTagLabel = null;

            //Reset loggedinRepositoryUser's root topics
            //in order to force aspect to reload them from database
            resetLoggedInRepositoryUserFolksonomyRootTopics();

        } else {
            logger.error("An empty label has been provided. User Tag cannot be created with an empty label");
            JSFUtilities.addMessage(null, "object.edit.empty.tag.error", null, FacesMessage.SEVERITY_WARN);

        }
    }

    public void addExistingUserTagToContentObjectSubject_UIAction() {
        Topic selectedLoggedInUserTag = cmsUtilities.findTopicInTopicListByTopicId(
                loggedInRepositoryUser.getRepositoryUser().getFolksonomy().getRootTopics(),
                selectedLoggedInUserTagId);
        if (selectedLoggedInUserTag != null) {
            //   check if the selected tag is already in contentObject subject 
            if (cmsUtilities.findTopicInTopicListByLocalizedTopicLabel(
                    ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                            .getCmsProperty("profile.subject")).getSimpleTypeValues(),
                    selectedLoggedInUserTag.getAvailableLocalizedLabel(JSFUtilities.getLocaleAsString())) != null) {
                logger.warn("The selected tag is already in content object subject.");
                JSFUtilities.addMessage(null, "object.edit.tag.already.selected", null, FacesMessage.SEVERITY_WARN);
                return;
            }

            // if we reached this point everything is ok. Let proceed to add the selected tag
            ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                    .getCmsProperty("profile.subject")).addSimpleTypeValue(selectedLoggedInUserTag);
        } else {
            logger.error(
                    "Some strange problem occured. Selected tag is not present in logged in user Tags List (loggedInUserTags)");
            JSFUtilities.addMessage(null, "application.unknown.error.message", null, FacesMessage.SEVERITY_WARN);
            return;

        }
        setSelectedLoggedInUserTagId(null);

    }

    public void addDraggedAndDroppedSpace_Listener(DropEvent dropEvent) {
        spaceToCopyNewObject = (Space) dropEvent.getDragValue();
    }

    @Observer({ SeamEventNames.UPDATE_LIST_OF_TOPICS_WHOSE_NUMBER_OF_CO_REFERENCES_SHOULD_CHANGE })
    public void updateListOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated(String topicId) {
        listOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated.add(topicId);
    }

    public void addDraggedAndDroppedTopicToContentObjectProfileSubject_Listener(DropEvent dropEvent) {
        LazyLoadingTopicTreeNode topicTreeNode = (LazyLoadingTopicTreeNode) dropEvent.getDragValue();

        //Check that dropped Topic belongs to Subject Taxonomy
        Topic droppedTopic = topicTreeNode.getTopic();

        //Check that Dropped Topic belongs to an accepted taxonomy
        List<String> acceptedTaxonomies = selectedContentObjectForEdit.getAcceptedTaxonomiesForProfileSubject();
        if (CollectionUtils.isNotEmpty(acceptedTaxonomies)) {
            String droppedTopicTaxonomyName = null;
            if (droppedTopic != null && droppedTopic.getTaxonomy() != null) {
                droppedTopicTaxonomyName = droppedTopic.getTaxonomy().getName();
            }

            if (StringUtils.isEmpty(droppedTopicTaxonomyName)
                    || !acceptedTaxonomies.contains(droppedTopicTaxonomyName)) {
                JSFUtilities.addMessage(null, "object.edit.invalid.topic.does.not.belong.to.accepted.taxonomies",
                        null, FacesMessage.SEVERITY_WARN);
                return;
            }
        }

        //Load existing subject topics
        List<Topic> subjectTopics = ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("profile.subject")).getSimpleTypeValues();

        String selectedTopicId = droppedTopic.getId();

        // check if selected topic is already in subject
        boolean topicExists = false;
        for (Topic subjectTopic : subjectTopics) {
            // we check first if topic Id exists because there may be new user tags in the list and new tags do not have an id yet 
            if (subjectTopic.getId() != null && subjectTopic.getId().equals(selectedTopicId)) {
                topicExists = true;
                break;
            }
        }

        if (!topicExists) {
            ((TopicReferenceProperty) selectedContentObjectForEdit.getContentObject()
                    .getCmsProperty("profile.subject")).addSimpleTypeValue(topicTreeNode.getTopic());

            JSFUtilities.addMessage(null, "object.edit.topic.added.to.content.object", null,
                    FacesMessage.SEVERITY_INFO);

            updateListOfTopicIdsWhoseNumberOfContentObjectReferrersShouldBeUpdated(
                    topicTreeNode.getTopic().getId());

        } else
            JSFUtilities.addMessage(null, "object.edit.topic.already.exists", null, FacesMessage.SEVERITY_WARN);

    }

    public void removeCreator_UIAction(Integer index) {
        if (index != null) {
            StringProperty creator = (StringProperty) selectedContentObjectForEdit.getContentObjectProperty()
                    .get("profile.creator");
            if (creator != null)
                creator.removeSimpleTypeValue(index);
        }
    }

    public void removeLanguage_UIAction(Integer index) {
        if (index != null) {
            StringProperty language = (StringProperty) selectedContentObjectForEdit.getContentObjectProperty()
                    .get("profile.language");
            if (language != null)
                language.removeSimpleTypeValue(index);
        }
    }

    public void addNewCreator_UIAction() {
        if (StringUtils.isNotBlank(newCreatorName)) {
            StringProperty creator = (StringProperty) selectedContentObjectForEdit.getContentObjectProperty()
                    .get("profile.creator");
            if (creator != null)
                creator.addSimpleTypeValue(newCreatorName);
        }

        newCreatorName = null;
    }

    public boolean isThumbnailPropertyDefinedForEditedContentObject() {
        return selectedContentObjectForEdit.getContentObject() != null
                && selectedContentObjectForEdit.getContentObject().getTypeDefinition() != null
                && selectedContentObjectForEdit.getContentObject().getTypeDefinition()
                        .hasCmsPropertyDefinition("thumbnail");
    }

    /*
     * This method generates a thumbnail from a binary channel of mime type jpeg and
     * saves outcome to property 'thumbnail', if there is any property defined for this type
     */
    public void generateThumbnailFromSelectedBinaryChannel_UIAction(Integer indexOfSimpleCmsPropertyWrapper,
            Integer indexOfSimpleCmsPropertyValueWrapper) {

        //Check if content object type definition has a 'thumbnail' property
        if (selectedContentObjectForEdit.getContentObject().getTypeDefinition()
                .hasCmsPropertyDefinition("thumbnail")) {

            //Retrieve simple cms property wrapper which contains binary channel
            SimpleCmsPropertyValueWrapper binaryPropertyValueWrapper = complexCmsPropertyEdit
                    .getSimpleCmsPropertyValueWrapper(indexOfSimpleCmsPropertyWrapper,
                            indexOfSimpleCmsPropertyValueWrapper);
            BinaryChannel binaryChannelWhoseThumbnailWillBeCreated = binaryPropertyValueWrapper
                    .getBinaryChannelValue();

            if (binaryChannelWhoseThumbnailWillBeCreated == null
                    || binaryChannelWhoseThumbnailWillBeCreated.getContent() == null) {
                logger.error("Could not find selected binary channel in order to create thumbnail");
                JSFUtilities.addMessage(null, "application.unknown.error.message", null,
                        FacesMessage.SEVERITY_WARN);
                return;
            }

            String mimeType = binaryChannelWhoseThumbnailWillBeCreated.getMimeType();

            //Generate Thumbnail only for specific mimetTypes
            if (mimeType != null && (mimeType.equals("image/jpeg") || mimeType.equals("image/gif")
                    || mimeType.equals("image/png") || mimeType.equals("image/x-png"))) {

                BinaryProperty thumbnailProperty = (BinaryProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("thumbnail");
                if (thumbnailProperty == null) {
                    logger.error("Could not find 'thumbnail' property for content object "
                            + selectedContentObjectForEdit.getContentObject().getId());
                    JSFUtilities.addMessage(null, "application.unknown.error.message", null,
                            FacesMessage.SEVERITY_WARN);
                    return;
                }

                try {
                    // the method name for generating the thumbnail is misleading. It gets a JPEG, PNG or GIF image and generated a thumbnail in PNG format  
                    byte[] thumbnailContent = ImageUtils.changeAspectRatioAndResize(
                            binaryChannelWhoseThumbnailWillBeCreated.getContent(), "image/png", 128, 0, 1.0,
                            "TOPLEFT");

                    BinaryChannel thumbnailBinaryChannel = thumbnailProperty.getSimpleTypeValue();
                    if (thumbnailBinaryChannel == null) {
                        thumbnailBinaryChannel = cmsRepositoryEntityFactory.newBinaryChannel();
                        thumbnailBinaryChannel.setName(thumbnailProperty.getName());
                        thumbnailProperty.setSimpleTypeValue(thumbnailBinaryChannel);
                    }

                    // we will append the suffix "-Thumbnail" after the original image file name to generate a name for the (supposed to be) filename of the thumbnail
                    thumbnailBinaryChannel.setSourceFilename(
                            binaryChannelWhoseThumbnailWillBeCreated.getSourceFilename().split("\\.")[0]
                                    + "-Thumbnail.png");
                    thumbnailBinaryChannel.setMimeType("image/png");
                    thumbnailBinaryChannel.setModified(Calendar.getInstance());
                    thumbnailBinaryChannel.setContent(thumbnailContent);
                    thumbnailBinaryChannel.setEncoding(binaryChannelWhoseThumbnailWillBeCreated.getEncoding());

                    // if binary channel has an id reset the id so UI knows it is a new binary channel
                    thumbnailBinaryChannel.setId(null);

                    JSFUtilities.addMessage(null, "object.edit.thubnail.created", null, FacesMessage.SEVERITY_INFO);

                    // We should update the thumnail property at the UI. So we add the thumbnail wrapper index to the list of wrappers that should be updated by the UI
                    complexCmsPropertyEdit.setWrapperIndexesToUpdate(
                            Collections.singleton(complexCmsPropertyEdit.getIndexOfPropertyWrapper("thumbnail")));

                } catch (Exception e) {
                    logger.error("Could not generate thumbnail ", e);
                    JSFUtilities.addMessage(null, "application.unknown.error.message", null,
                            FacesMessage.SEVERITY_WARN);
                    return;
                }
            }

        }

    }

    public String permanentlyRemoveContentObjectUIAction() {
        final String contentObjectId = selectedContentObjectForEdit.getContentObject().getId();
        // Check if the object has an identifier i.e. it has already been  saved in the repository. We can not remove a non saved object
        if (contentObjectId != null) {
            try {

                Calendar createdDate = ((CalendarProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("profile.created")).getSimpleTypeValue();

                contentService.deleteContentObject(contentObjectId);

                Events.instance().raiseEvent(SeamEventNames.CONTENT_OBJECT_DELETED,
                        new Object[] { selectedContentObjectForEdit.getContentObject().getContentObjectType(),
                                contentObjectId, createdDate });
            } catch (Exception e) {
                JSFUtilities.addMessage(null, "object.edit.contentObjectCouldNotBePermanentlyRemovedError", null,
                        FacesMessage.SEVERITY_ERROR);
                getLogger().error("The content object could not be permanently deleted. The error is: ", e);
                return null;
            }
        } else {
            JSFUtilities.addMessage(null, "application.unknown.error.message", null, FacesMessage.SEVERITY_WARN);
            getLogger().error(
                    "permanentlyRemoveContentObjectUIAction(): The content object could not be removed because it has not an identifier. Possibly you have tried to remove an object that has not yet been saved into the repository. This is UI problem that allowed to access this method");
            return null;
        }
        // generate a success message, reset the browsing trees to accommodate the change and finally change the view to show the conentObjectListPanel 
        JSFUtilities.addMessage(null, "object.edit.successful.delete.info.message", null,
                FacesMessage.SEVERITY_INFO);

        // reset search results table
        ContentObjectStatefulSearchService contentObjectStatefulSearchService = (ContentObjectStatefulSearchService) JSFUtilities
                .getBeanFromSpringContext("contentObjectStatefulSearchService");
        ContentObjectList contentObjectList = (ContentObjectList) JSFUtilities
                .getBeanFromSpringContext("contentObjectList");

        // reset data page and decrease search results count
        contentObjectStatefulSearchService
                .setSearchResultSetSize(contentObjectStatefulSearchService.getSearchResultSetSize() - 1);
        if (contentObjectStatefulSearchService.getSearchResultSetSize() > 0) {
            contentObjectStatefulSearchService.getReturnedContentObjects().reset();
        } else {

            contentObjectStatefulSearchService.setReturnedContentObjects(null);
            UIComponentBinding uiComponentBinding = (UIComponentBinding) Contexts.getEventContext()
                    .get("uiComponentBinding");
            if (uiComponentBinding != null) {
                uiComponentBinding.setListViewContentObjectTableComponent(null);
                uiComponentBinding.setListViewContentObjectTableScrollerComponent(null);
            }
        }

        contentObjectList.setContentObjectListHeaderMessage(null);

        // remove object from conversation context
        Contexts.getConversationContext().remove("contentObjectEdit");
        Contexts.getConversationContext().flush();
        return null;
    }

    public void handleWorkFlowActivation(ValueChangeEvent vce) {
        String workflow = (String) vce.getNewValue();
        StringProperty contentObjectStatus = (StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("profile.contentObjectStatus");
        if (workflow != null && workflow.equals("webPublishing")) {

            //Normally this property should exist.

            if (contentObjectStatus == null) {
                //Create property
                contentObjectStatus = (StringProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("profile.contentObjectStatus");
            }

            // set content object status to authored
            contentObjectStatus.setSimpleTypeValue("authored");

        }
    }

    public void activatePublicationScheduling_UIAction() {
        // change content object status to "scheduledForPublication"
        // but before save old status in the case the save is not successful in order to put status back in the old value
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        String previousStatus = contentObjectStatusProperty.getSimpleTypeValue();
        contentObjectStatusProperty.setSimpleTypeValue("scheduledForPublication");

        // remove it from workflow
        // but before save workflow in the case the save is not successful in order to put workflow back
        StringProperty workflowProperty = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("workflow.managedThroughWorkflow"));
        String workflow = workflowProperty.getSimpleTypeValue();
        workflowProperty.setSimpleTypeValue(null);

        //Flag to indicate whether publication start date was not found and thus created automatically
        Calendar today = null;

        CalendarProperty webPublicationStartDateProperty;

        try {
            if (selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                    .isChildPropertyDefined("webPublication")) {
                webPublicationStartDateProperty = (CalendarProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("webPublication.webPublicationStartDate");
            } else {
                //Create webPublication aspect
                webPublicationStartDateProperty = (CalendarProperty) selectedContentObjectForEdit.getContentObject()
                        .getCmsProperty("webPublicationType.webPublicationStartDate");
            }

            //Check if webPublicationStartDate has a date

            if (webPublicationStartDateProperty.getSimpleTypeValue() == null) {
                today = Calendar.getInstance(TimeZoneSelector.instance().getTimeZone(),
                        LocaleSelector.instance().getLocale());
                webPublicationStartDateProperty.setSimpleTypeValue(today);
            }

            String saveActionOutcome = disableCreateVersionAndSaveContentObject();

            if (StringUtils.equals(saveActionOutcome, "error")) {
                // save was NOT successful restore previous state
                contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
                workflowProperty.setSimpleTypeValue(workflow);
            } else {
                JSFUtilities.addMessage(null, "object.edit.status.changed.info.message",
                        new String[] { JSFUtilities.getParameterisedStringI18n(
                                "content.object.profile.status.scheduledForPublication", null) },
                        FacesMessage.SEVERITY_INFO);

                if (today != null)
                    JSFUtilities.addMessage(null, "object.edit.webpublicationdate.set.info",
                            new String[] { DateUtils.format(today, "dd/MM/yyyy HH:mm") },
                            FacesMessage.SEVERITY_INFO);

                // refresh the list of content objects which are submitted for publication
                //ContentObjectSearchByStatus searchByStatusAndPresentation = (ContentObjectSearchByStatus) JSFUtilities.getBeanFromFacesContext("contentObjectSearchByStatusAndPresentation");
                //if (searchByStatusAndPresentation != null)
                //searchByStatusAndPresentation.findContentObjectsSubmittedForWebPublishing_ExpandListener(null);

            }
        } catch (Exception e) {
            // save was NOT successful restore previous state
            contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            workflowProperty.setSimpleTypeValue(workflow);

            getLogger().error("Error while activating publication scheduling ", e);
            JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);

        }

    }

    public void submitContentObjectForWebPublication_UIAction() {
        // change content object status to submitted
        // but before save old status in the case the save is not successful in order to put status back in the old value
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        String previousStatus = contentObjectStatusProperty.getSimpleTypeValue();
        contentObjectStatusProperty.setSimpleTypeValue("submitted");

        // Check if workflow has been activated
        // but before save workflow in the case the save is not successful in order to put workflow back
        StringProperty workflowProperty = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                .getCmsProperty("workflow.managedThroughWorkflow"));
        String previousWorkflow = workflowProperty.getSimpleTypeValue();

        if (previousWorkflow == null) {
            workflowProperty.setSimpleTypeValue("webPublishing");
        }

        try {
            String saveActionOutcome = disableCreateVersionAndSaveContentObject();
            if (StringUtils.equals(saveActionOutcome, "error")) {
                contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            } else {
                // the save was successful
                JSFUtilities.addMessage(null, "object.edit.status.changed.info.message",
                        new String[] { JSFUtilities
                                .getParameterisedStringI18n("content.object.profile.status.submitted", null) },
                        FacesMessage.SEVERITY_INFO);
            }
        } catch (Exception e) {
            contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            workflowProperty.setSimpleTypeValue(previousWorkflow);
            getLogger().error("Error while submitting content object for web publication ", e);
            JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);

        }
    }

    public void temporarilyRejectContentObjectForReauthoring_UIAction() {
        // change content object status to temporarilyRejectedForReauthoring
        // but before save old status in the case the save is not successful in order to put status back in the old value
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        String previousStatus = contentObjectStatusProperty.getSimpleTypeValue();
        contentObjectStatusProperty
                .setSimpleTypeValue(CmsConstants.ContentObjectStatus.temporarilyRejectedForReauthoring.toString());

        try {
            String saveActionOutcome = disableCreateVersionAndSaveContentObject();
            if (StringUtils.equals(saveActionOutcome, "error")) {
                contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            } else {
                // the save was successful
                JSFUtilities.addMessage(null, "object.edit.status.changed.info.message",
                        new String[] { JSFUtilities.getParameterisedStringI18n(
                                "content.object.profile.status.temporarilyRejectedForReauthoring", null) },
                        FacesMessage.SEVERITY_INFO);
            }
        } catch (Exception e) {
            contentObjectStatusProperty.setSimpleTypeValue(previousStatus);

            getLogger().error("Error while temporarily reject content object for reauthoring", e);
            JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);

        }
    }

    public void publishContentObject_UIAction() {
        // change content object status to null
        // but before save old status in the case the save is not successfull in order to put status back in the old value
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        String previousStatus = contentObjectStatusProperty.getSimpleTypeValue();
        contentObjectStatusProperty.setSimpleTypeValue(CmsConstants.ContentObjectStatus.published.toString());

        // remove it from workflow if it is already in a workflow
        // but before save workflow in the case the save is not successful in order to put workflow back
        StringProperty workflowProperty = null;
        String workflow = null;
        if (selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                .isChildPropertyDefined("workflow")) {
            workflowProperty = ((StringProperty) selectedContentObjectForEdit.getContentObject()
                    .getCmsProperty("workflow.managedThroughWorkflow"));
            workflow = workflowProperty.getSimpleTypeValue();
            workflowProperty.setSimpleTypeValue(null);
        }

        // if there is a web publication property then set the start date
        boolean publicationStartDateHasBeenSet = false;
        Calendar now = null;
        if (selectedContentObjectForEdit.getContentObject().getComplexCmsRootProperty()
                .isChildPropertyDefined("webPublication")) {
            now = Calendar.getInstance(TimeZoneSelector.instance().getTimeZone(),
                    LocaleSelector.instance().getLocale());
            CalendarProperty webPublicationStartDateProperty = (CalendarProperty) selectedContentObjectForEdit
                    .getContentObject().getCmsProperty("webPublication.webPublicationStartDate");
            webPublicationStartDateProperty.setSimpleTypeValue(now);
            publicationStartDateHasBeenSet = true;
        }

        try {
            String saveActionOutcome = disableCreateVersionAndSaveContentObject();
            if (StringUtils.equals(saveActionOutcome, "error")) {
                contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            } else {
                // the save was successful
                JSFUtilities.addMessage(null, "object.edit.status.changed.info.message",
                        new String[] { JSFUtilities
                                .getParameterisedStringI18n("content.object.profile.status.published", null) },
                        FacesMessage.SEVERITY_INFO);

                if (publicationStartDateHasBeenSet) {
                    JSFUtilities.addMessage(null, "object.edit.webpublicationdate.set.info",
                            new String[] { DateUtils.format(now, "dd/MM/yyyy HH:mm") }, FacesMessage.SEVERITY_INFO);
                }
            }
        } catch (Exception e) {
            contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            if (workflowProperty != null) {
                workflowProperty.setSimpleTypeValue(workflow);
            }
            getLogger().error("Error while un-publishing content object ", e);
            JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);

        }

    }

    public void unPublishContentObject_UIAction() {
        // change content object status to null
        // but before save old status in the case the save is not successfull in order to put status back in the old value
        StringProperty contentObjectStatusProperty = ((StringProperty) selectedContentObjectForEdit
                .getContentObject().getCmsProperty("profile.contentObjectStatus"));
        String previousStatus = contentObjectStatusProperty.getSimpleTypeValue();
        contentObjectStatusProperty.setSimpleTypeValue(null);

        try {
            String saveActionOutcome = disableCreateVersionAndSaveContentObject();
            if (StringUtils.equals(saveActionOutcome, "error")) {
                contentObjectStatusProperty.setSimpleTypeValue(previousStatus);
            } else {
                // the save was successful
                JSFUtilities.addMessage(null, "object.edit.status.changed.info.message",
                        new String[] { JSFUtilities
                                .getParameterisedStringI18n("content.object.profile.status.not.defined", null) },
                        FacesMessage.SEVERITY_INFO);
            }
        } catch (Exception e) {
            contentObjectStatusProperty.setSimpleTypeValue(previousStatus);

            getLogger().error("Error while un-publishing content object ", e);
            JSFUtilities.addMessage(null, "object.edit.save.error", null, FacesMessage.SEVERITY_ERROR);

        }

    }

    public String abbreviateString(String stringToAbbreviate, int maxWidth) {
        if (stringToAbbreviate != null) {
            return StringUtils.abbreviate(stringToAbbreviate, maxWidth);
        } else {
            return "";
        }
    }

    public List<Map<String, String>> getMatchedPersonsOrRolesUIAction(Object event) {
        try {

            List<Map<String, String>> userOrGroupListMap = new ArrayList<Map<String, String>>();

            String selectedPersonOrRoleTextFilter = event.toString();

            //get persons
            List<Person> persons = (List<Person>) identityStoreRunAsSystem.execute("findUsers",
                    new Class<?>[] { String.class }, new Object[] { selectedPersonOrRoleTextFilter });

            if (CollectionUtils.isNotEmpty(persons)) {

                for (Person user : persons) {
                    // check if user has an account, i.e. if a username exists
                    if (user.getUsername() != null) {
                        Map<String, String> userOrGroupMap = new HashMap<String, String>();
                        userOrGroupMap.put("userOrGroupId", user.getUsername());
                        userOrGroupMap.put("userOrGroupName",
                                StringUtils.isBlank(user.getDisplayName()) ? user.getUsername()
                                        : user.getDisplayName());
                        userOrGroupMap.put("label", user.getDisplayName() + " ( " + user.getUsername() + " ) ");

                        userOrGroupListMap.add(userOrGroupMap);
                    }
                }
            }

            //get roles
            List<String> roles = (List<String>) identityStoreRunAsSystem.execute("listRoles",
                    new Class<?>[] { String.class }, new Object[] { selectedPersonOrRoleTextFilter });

            if (CollectionUtils.isNotEmpty(roles)) {

                for (String role : roles) {
                    String displayName = Utils.retrieveDisplayNameForRoleOrPerson(identityStoreRunAsSystem, role);

                    Map<String, String> userOrGroupMap = new HashMap<String, String>();
                    userOrGroupMap.put("userOrGroupId", role);
                    userOrGroupMap.put("userOrGroupName", displayName);
                    userOrGroupMap.put("label", displayName);
                    userOrGroupListMap.add(userOrGroupMap);
                }
            }

            return userOrGroupListMap;
        } catch (Exception e) {
            logger.error("Error while loading Persons ", e);
            return null;
        }

    }

    public void setContentService(ContentService contentService) {
        this.contentService = contentService;
    }

    public void setContentObjectUIWrapperFactory(ContentObjectUIWrapperFactory contentObjectUIWrapperFactory) {
        this.contentObjectUIWrapperFactory = contentObjectUIWrapperFactory;
    }

    public void setContentObjectList(ContentObjectList contentObjectList) {
        this.contentObjectList = contentObjectList;
    }

    public void setDefinitionService(DefinitionService definitionService) {
        this.definitionService = definitionService;
    }

    public String getSelectedContentObjectIdentifier() {
        return selectedContentObjectIdentifier;
    }

    public void setSelectedContentObjectIdentifier(String selectedContentObjectIdentifier) {
        this.selectedContentObjectIdentifier = selectedContentObjectIdentifier;
    }

    public String getContentObjectTitle() {
        return contentObjectTitle;
    }

    public ContentObjectUIWrapper getSelectedContentObjectForEdit() {
        return selectedContentObjectForEdit;
    }

    /*public TreeNode getContentObjectAsTreeData() {
       return contentObjectAsTreeData;
    }*/

    public String getNewTagLabel() {
        return newTagLabel;
    }

    public void setNewTagLabel(String newTagLabel) {
        this.newTagLabel = newTagLabel;
    }

    public String getContentObjectTypeLocalizedName() {
        return contentObjectTypeLocalizedName;
    }

    public void setLoggedInRepositoryUser(LoggedInRepositoryUser loggedInRepositoryUser) {
        this.loggedInRepositoryUser = loggedInRepositoryUser;
    }

    /**
     * @return the radioButtonSelectionMap
     */
    public Map<String, String> getRadioButtonSelectionMap() {
        return radioButtonSelectionMap;
    }

    /**
     * @return the userListByAccessRight
     */
    public Map<String, List<Map<String, String>>> getUserListByAccessRight() {
        return userListByAccessRight;
    }

    public void setSpaceService(SpaceService spaceService) {
        this.spaceService = spaceService;
    }

    public void setSelectedTopicIdForRemovalFromContentObjectSubject(
            String selectedTopicIdForRemovalFromContentObjectSubject) {
        this.selectedTopicIdForRemovalFromContentObjectSubject = selectedTopicIdForRemovalFromContentObjectSubject;
    }

    public void setCmsUtilities(CMSUtilities cmsUtilities) {
        this.cmsUtilities = cmsUtilities;
    }

    public void setSelectedLoggedInUserTagId(String selectedLoggedInUserTagId) {
        this.selectedLoggedInUserTagId = selectedLoggedInUserTagId;
    }

    public void setContentObjectTypeForNewObject(String contentObjectTypeForNewObject) {
        this.contentObjectTypeForNewObject = contentObjectTypeForNewObject;
    }

    public String getContentObjectTypeForNewObject() {
        return contentObjectTypeForNewObject;
    }

    public ConfigurableMimeFileTypeMap getMimeTypesMap() {
        return mimeTypesMap;
    }

    public void setMimeTypesMap(ConfigurableMimeFileTypeMap mimeTypesMap) {
        this.mimeTypesMap = mimeTypesMap;
    }

    public ComplexCmsPropertyEdit getComplexCmsPropertyEdit() {
        return complexCmsPropertyEdit;
    }

    public ComplexCmsPropertyEdit getProfilePropertyEdit() {
        return profilePropertyEdit;
    }

    public void setPageController(PageController pageController) {
        this.pageController = pageController;
    }

    public String getNewCreatorName() {
        return newCreatorName;
    }

    public void setNewCreatorName(String newCreatorName) {
        this.newCreatorName = newCreatorName;
    }

    public Space getSpaceToCopyNewObject() {
        return spaceToCopyNewObject;
    }

    public void setSpaceToCopyNewObject(Space spaceToCopyNewObject) {
        this.spaceToCopyNewObject = spaceToCopyNewObject;
    }

    public String getComplexCmsPropertyEditorPagePath() {
        return complexCmsPropertyEditorPagePath;
    }

    public List<ComplexCmsPropertyBreadCrumb> getFixedPropertyBreadCrumbs() {
        return fixedPropertyBreadCrumbs;
    }

    public List<ComplexCmsPropertyBreadCrumb> getExtraPropertyBreadCrumbs() {
        return extraPropertyBreadCrumbs;
    }

    public void setTopicService(TopicService topicService) {
        this.topicService = topicService;
    }

    public void explicitlySetContentObjectForEdit(ContentObject explicitlySetContentObjectForEdit) {

        this.explicitlySetContentObjectForEdit = explicitlySetContentObjectForEdit;

        if (explicitlySetContentObjectForEdit != null) {
            this.selectedContentObjectIdentifier = explicitlySetContentObjectForEdit.getId();
        }
    }

    public void setCmsRepositoryEntityFactory(CmsRepositoryEntityFactory cmsRepositoryEntityFactory) {
        this.cmsRepositoryEntityFactory = cmsRepositoryEntityFactory;
    }

    /**
     * @return the selectedRepositoryUserExternalIdOrLabel
     */
    public String getSelectedPersonOrRoleTextFilter() {
        return selectedPersonOrRoleTextFilter;
    }

    /**
     * @param selectedPersonTextFilter the selectedPersonTextFilter to set
     */
    public void setSelectedPersonOrRoleTextFilter(String selectedPersonOrRoleTextFilter) {
        this.selectedPersonOrRoleTextFilter = selectedPersonOrRoleTextFilter;
    }

    public List<SelectItem> getSelectedLanguages() {
        return selectedLanguages;
    }

    public void setSelectedLanguages(List<SelectItem> selectedLanguages) {
        this.selectedLanguages = selectedLanguages;
    }

    public void setUserSpaceNavigation(UserSpaceNavigation userSpaceNavigation) {
        this.userSpaceNavigation = userSpaceNavigation;
    }

    public ComplexCmsPropertyEdit getExtraPropertyEdit() {
        return extraPropertyEdit;
    }

    public void setExtraPropertyEdit(ComplexCmsPropertyEdit extraPropertyEdit) {
        this.extraPropertyEdit = extraPropertyEdit;
    }

}