/**
* Copyright (C) 2005-2007 BetaCONCEPT LP.
*
* This program 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 2
* of the License, or (at your option) any later version.
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* 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.taxonomy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.faces.application.FacesMessage;
import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.Taxonomy;
import org.betaconceptframework.astroboa.api.model.Topic;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType;
import org.betaconceptframework.astroboa.api.model.query.CmsOutcome;
import org.betaconceptframework.astroboa.api.model.query.criteria.TopicCriteria;
import org.betaconceptframework.astroboa.api.service.TopicService;
import org.betaconceptframework.astroboa.commons.comparator.TopicLocalizedLabelComparator;
import org.betaconceptframework.astroboa.commons.comparator.TopicNameComparator;
import org.betaconceptframework.astroboa.console.jsf.LocalizationEdit;
import org.betaconceptframework.astroboa.console.seam.SeamEventNames;
import org.betaconceptframework.astroboa.console.security.LoggedInRepositoryUser;
import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory;
import org.betaconceptframework.astroboa.model.factory.CmsRepositoryEntityFactory;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.betaconceptframework.ui.jsf.utility.JSFUtilities;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.core.Events;
import org.richfaces.event.DropEvent;
/**
* @author gchomatas
* Created on Oct 26, 2007
*/
@Name("tagEdit")
@Scope(ScopeType.CONVERSATION)
/**
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public class TagEdit extends LocalizationEdit {
private static final long serialVersionUID = 1L;
private LoggedInRepositoryUser loggedInRepositoryUser;
private TopicService topicService;
private String labelSortOrder = "ASC";
private String nameSortOrder = "ASC";
private Topic toBeDeletedTag;
private Topic editedTag;
private boolean editedTagBelongsToAFolksonomy;
private Topic newParent;
private boolean editedTagBecomeRootTopic = false;
private boolean editedTagChangedTaxonomy = false;
private CmsRepositoryEntityFactory cmsRepositoryEntityFactory;
private String validateEditedTag() {
//Validate Topic Name
if (StringUtils.isNotBlank(editedTag.getName())){
if (!CmsConstants.SystemNamePattern.matcher(editedTag.getName()).matches()){
JSFUtilities.addMessage(null, "topic.edit.invalid.system.name", new String[]{editedTag.getName()}, FacesMessage.SEVERITY_WARN);
return "error";
}
}
//Finally check is there is another topic with the same name
TopicCriteria topicCriteria = CmsCriteriaFactory.newTopicCriteria();
//topicCriteria.getRenderProperties().renderValuesForLocale(JSFUtilities.getLocaleAsString());
//Create all possible names with lower and upper case
//Nevertheless if topic name is 'TesT' and there is already a Topic named
//'teST' this query will miss it
/*List<String> names = new ArrayList<String>();
names.add(editedTag.getName().toLowerCase());
names.add(editedTag.getName().toUpperCase());
names.add(editedTag.getName());
*/
//topicCriteria.setMultipleNamesEqualsCriterion(names, Condition.OR);
topicCriteria.addNameEqualsCaseInsensitiveCriterion(editedTag.getName().toLowerCase());
topicCriteria.setOffsetAndLimit(0,1);
if (editedTag.getId() != null){
topicCriteria.addIdNotEqualsCriterion(editedTag.getId());
}
CmsOutcome<Topic> otherTopics = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_LIST);
if (otherTopics != null && otherTopics.getCount() > 0){
Topic topicWithSameSystemName = otherTopics.getResults().get(0);
String topicPath = topicWithSameSystemName.getAvailableLocalizedLabel(localeSelector.getLocaleString());
Topic parent = topicWithSameSystemName.getParent();
while (parent != null) {
topicPath = parent.getAvailableLocalizedLabel(localeSelector.getLocaleString()) + "->" + topicPath;
parent = parent.getParent();
}
topicPath = topicWithSameSystemName.getTaxonomy().getAvailableLocalizedLabel(localeSelector.getLocaleString()) + "->" + topicPath;
JSFUtilities.addMessage(null, "topic.non.unique.system.name", new String[]{topicPath}, FacesMessage.SEVERITY_WARN);
return "error";
}
// validate Localized Labels
return updateLocalizedLabelsMapInEditedLocalizationEntity(editedTag);
}
public void saveTag_UIAction() {
//Check if this is a new topic/tag
boolean isNewTag = (editedTag.getId() == null)?true : false;
String saveResult = null;
try {
saveResult = validateEditedTag();
if ("success".equals(saveResult)) {
//Get topic parent's previous id
String previousParentId = editedTag.getParent() != null ? editedTag.getParent().getId() : null;
//Change parent if a new one is provided and topic is not a tag
if (!editedTagBelongsToAFolksonomy && newParent != null){
editedTag.setParent(newParent);
//Get its parent taxonomy if not the same
if (!newParent.getTaxonomy().getId().equals(editedTag.getTaxonomy().getId())){
editedTag.setTaxonomy(newParent.getTaxonomy());
editedTagChangedTaxonomy = true;
}
}
//Save topic/tag
topicService.save(editedTag);
//Inform UI only if topic is a tag and a new one
if (isNewTag && editedTagBelongsToAFolksonomy) // add tag into user folksonomy so that it is visible from the UI
loggedInRepositoryUser.getRepositoryUser().getFolksonomy().addRootTopic(editedTag);
JSFUtilities.addMessage(null, "topic.save.successful", null, FacesMessage.SEVERITY_INFO);
try{
//In case topic belongs to a regular taxonomy raise events
//for taxonomy tree to be updated
if (!editedTagBelongsToAFolksonomy){
//Notify that a topic has been updated
if (!isNewTag)
Events.instance().raiseEvent(SeamEventNames.TOPIC_SAVED, editedTag);
if (editedTagChangedTaxonomy){
//Force tree to rebuild again
Events.instance().raiseEvent(SeamEventNames.NEW_TAXONOMY_TREE);
}
else if (isNewTag || newParent != null || editedTagBecomeRootTopic){
if (previousParentId != null)
//Events.instance().raiseEvent(SeamEventNames.REMOVE_TOPIC_TREE_NODE, editedTag.getId());
Events.instance().raiseEvent(SeamEventNames.RELOAD_TOPIC_TREE_NODE, previousParentId);
else
//Previous parent was taxonomy
Events.instance().raiseEvent(SeamEventNames.RELOAD_TAXONOMY_TREE_NODE, editedTag.getTaxonomy().getId());
//We send new parent's id in order to reload its children
if (newParent != null)
Events.instance().raiseEvent(SeamEventNames.RELOAD_TOPIC_TREE_NODE, newParent.getId());
if (editedTagBecomeRootTopic && previousParentId != null)
Events.instance().raiseEvent(SeamEventNames.RELOAD_TAXONOMY_TREE_NODE, editedTag.getTaxonomy().getId());
}
}
}
catch (Exception e) {
JSFUtilities.addMessage(null, "topic.taxonomy.refresh.error", null, FacesMessage.SEVERITY_ERROR);
getLogger().error("Seam events processing on topic or tag save",e);
//Since an exception is thrown raise event to reload topic if it exists in tree
if (!isNewTag)
Events.instance().raiseEvent(SeamEventNames.RELOAD_TOPIC_TREE_NODE, editedTag.getId());
}
}
}
catch (Exception e) {
if (e instanceof CmsException && e.getMessage() != null && e.getMessage().contains("Cannot move topic")){
JSFUtilities.addMessage(null, "topic.relocate.error", null, FacesMessage.SEVERITY_ERROR);
}
else{
JSFUtilities.addMessage(null, "topic.save.error", null, FacesMessage.SEVERITY_ERROR);
}
getLogger().error("Topic could not be saved",e);
//Since an exception is thrown raise event to reload topic if it exists in tree
if (!isNewTag)
Events.instance().raiseEvent(SeamEventNames.RELOAD_TOPIC_TREE_NODE, editedTag.getId());
}
}
public void reset() {
editedTag = null;
editedLocalizedLabels = null;
labelSortOrder = "NONE";
nameSortOrder = "NONE";
editedTagBelongsToAFolksonomy =false;
newParent = null;
editedTagBecomeRootTopic = false;
editedTagChangedTaxonomy = false;
}
public void addTag_UIAction() {
createNewEditedTag(loggedInRepositoryUser.getRepositoryUser().getFolksonomy(), null);
}
public void createNewEditedTag(Taxonomy taxonomy, Topic parent){
reset();
Topic tag = cmsRepositoryEntityFactory.newTopic();
tag.setTaxonomy(taxonomy);
tag.setOwner(loggedInRepositoryUser.getRepositoryUser());
tag.setAllowsReferrerContentObjects(true);
tag.setParent(parent);
editedTag = tag;
editedLocalizedLabels = new ArrayList<LocalizedLabel>();
//create the first label
addLocalizedLabel_UIAction();
editedTagBelongsToAFolksonomy = taxonomy != null && taxonomy.getId() != null && taxonomy.getId().equals(loggedInRepositoryUser.getRepositoryUser().getFolksonomy().getId());
newParent = null;
labelSortOrder = "NONE";
nameSortOrder = "NONE";
editedTagBecomeRootTopic =false;
editedTagChangedTaxonomy = false;
}
private String getLocalizedNameForTopicEntity(){
if (editedTagBelongsToAFolksonomy)
return JSFUtilities.getLocalizedMessage("Tag", null);
return JSFUtilities.getLocalizedMessage("Topic", null);
}
public void markToBeDeletedTag_UIAction(Topic tag) {
toBeDeletedTag = tag;
}
public void deleteTag_UIAction(Topic toBeDeletedTag) {
try {
topicService.deleteTopicTree(toBeDeletedTag.getId());
//Nullify to force reload
loggedInRepositoryUser.getRepositoryUser().getFolksonomy().setRootTopics(null);
JSFUtilities.addMessage(null, "topic.cascadingDelete.succesful", new String[]{getLocalizedNameForTopicEntity()}, FacesMessage.SEVERITY_INFO);
reset();
}
catch (Exception e) {
JSFUtilities.addMessage(null, "topic.cascadingDelete.error", FacesMessage.SEVERITY_WARN);
getLogger().error("Tag could not be saved",e);
}
}
public void editTag_UIAction(Topic tag) {
reset();
editedTag = tag;
editedTagBelongsToAFolksonomy = tag.getTaxonomy() != null &&
tag.getTaxonomy().getName() != null &&
Taxonomy.REPOSITORY_USER_FOLKSONOMY_NAME.equals(tag.getTaxonomy().getName());
fillLocalizedLabelBuffer(editedTag);
}
public void sortByLabel() {
List<Topic> userTags = loggedInRepositoryUser.getRepositoryUser().getFolksonomy().getRootTopics();
if ("ASC".equals(labelSortOrder)) {
Collections.reverse(userTags);
labelSortOrder = "DESC";
}
else if ("DESC".equals(labelSortOrder)) {
Collections.reverse(userTags);
labelSortOrder = "ASC";
}
else {
Collections.sort(userTags, new TopicLocalizedLabelComparator(JSFUtilities.getLocaleAsString()));
labelSortOrder = "ASC";
}
}
public void sortByName() {
List<Topic> userTags = loggedInRepositoryUser.getRepositoryUser().getFolksonomy().getRootTopics();
if ("ASC".equals(nameSortOrder)) {
Collections.reverse(userTags);
nameSortOrder = "DESC";
}
else if ("DESC".equals(nameSortOrder)) {
Collections.reverse(userTags);
nameSortOrder = "ASC";
}
else {
Collections.sort(userTags, new TopicNameComparator());
nameSortOrder = "ASC";
}
}
public void changeParentDraggedAndDropped_Listener(DropEvent dropEvent){
Object draggedObject = dropEvent.getDragValue();
if (draggedObject == null){
JSFUtilities.addMessage(null, "topic.draggedAndDroppedObjectIsNull" , FacesMessage.SEVERITY_WARN);
return;
}
if ( draggedObject instanceof Taxonomy){
final Taxonomy draggedTaxonomy = (Taxonomy)draggedObject;
//Edited Tag become root topic. Check if its taxonomy is changed as well
String previousTaxonomyId = editedTag.getTaxonomy().getId();
String draggedTaxonomyId = draggedTaxonomy.getId();
if (StringUtils.isBlank(previousTaxonomyId)){
JSFUtilities.addMessage(null, "topic.changeParentTaxonomy.oldParentTaxonomyHasNoId", FacesMessage.SEVERITY_WARN);
getLogger().error("Tag parent could not be saved as its taxonomy does not have an id",editedTag.getTaxonomy());
}
if (StringUtils.isBlank(draggedTaxonomyId)){
JSFUtilities.addMessage(null, "topic.changeParentTaxonomy.draggedAndDroppedTaxonomyHasNoId", FacesMessage.SEVERITY_WARN);
getLogger().error("Tag parent could not be saved as dragged taxonomy does not have an id",draggedTaxonomy);
}
editedTagChangedTaxonomy = ! previousTaxonomyId.equals(draggedTaxonomyId);
//Nullify parent
editedTag.setParent(null);
editedTag.setTaxonomy(draggedTaxonomy);
this.newParent = null;
editedTagBecomeRootTopic = true;
}
else{
if ( !(draggedObject instanceof Topic)){
JSFUtilities.addMessage(null, "topic.changeParentTopic.draggedAndDroppedEntityIsNotATopic" , FacesMessage.SEVERITY_WARN);
return;
}
Topic newParentTopic = (Topic)draggedObject;
//Check that new parent is the same with editedTag
if (editedTag.getId() != null && newParentTopic.getId().equals(editedTag.getId())){
JSFUtilities.addMessage(null, "topic.changeParentTopic.topicCannotBeTheParentOfItself" , FacesMessage.SEVERITY_ERROR);
return;
}
//Check that new parent is not descendant of editedTag
Topic parentOfNewParent = newParentTopic.getParent();
while (parentOfNewParent != null){
if (parentOfNewParent.getId().equals(editedTag.getId())){
JSFUtilities.addMessage(null, "topic.changeParentTopic.childTopicCannotBeAParentTopicToo" , FacesMessage.SEVERITY_ERROR);
return;
}
parentOfNewParent = parentOfNewParent.getParent();
}
this.newParent = newParentTopic;
editedTagBecomeRootTopic = false;
editedTagChangedTaxonomy = false;
}
}
public Topic getNewParent() {
return newParent;
}
public List<LocalizedLabel> getEditedTagLabels() {
return editedLocalizedLabels;
}
public Topic getEditedTag() {
return editedTag;
}
public void setLoggedInRepositoryUser(
LoggedInRepositoryUser loggedInRepositoryUser) {
this.loggedInRepositoryUser = loggedInRepositoryUser;
}
public void setTopicService(TopicService topicService) {
this.topicService = topicService;
}
public void setToBeDeletedTag(Topic toBeDeletedTag) {
this.toBeDeletedTag = toBeDeletedTag;
}
public void setCmsRepositoryEntityFactory(
CmsRepositoryEntityFactory cmsRepositoryEntityFactory) {
this.cmsRepositoryEntityFactory = cmsRepositoryEntityFactory;
}
}