/* * 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.search; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.faces.application.FacesMessage; import javax.faces.event.ActionEvent; import javax.faces.model.SelectItem; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.betaconceptframework.astroboa.api.model.ContentObject; import org.betaconceptframework.astroboa.api.model.Topic; import org.betaconceptframework.astroboa.api.model.ValueType; import org.betaconceptframework.astroboa.api.model.io.FetchLevel; import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType; import org.betaconceptframework.astroboa.api.model.query.CacheRegion; import org.betaconceptframework.astroboa.api.model.query.CmsOutcome; import org.betaconceptframework.astroboa.api.model.query.Order; import org.betaconceptframework.astroboa.api.model.query.QueryOperator; import org.betaconceptframework.astroboa.api.model.query.criteria.ContentObjectCriteria; import org.betaconceptframework.astroboa.api.model.query.criteria.Criterion; import org.betaconceptframework.astroboa.api.model.query.criteria.LocalizationCriterion; import org.betaconceptframework.astroboa.api.model.query.criteria.SimpleCriterion; import org.betaconceptframework.astroboa.api.model.query.criteria.TopicCriteria; import org.betaconceptframework.astroboa.api.service.ContentService; import org.betaconceptframework.astroboa.api.service.DefinitionService; import org.betaconceptframework.astroboa.api.service.TopicService; import org.betaconceptframework.astroboa.commons.comparator.TopicLocalizedLabelComparator; import org.betaconceptframework.astroboa.console.commons.ContentObjectUIWrapper; import org.betaconceptframework.astroboa.console.commons.ContentObjectUIWrapperFactory; import org.betaconceptframework.astroboa.console.jsf.clipboard.ContentObjectItem; import org.betaconceptframework.astroboa.console.jsf.taxonomy.LazyLoadingTopicTreeNode; import org.betaconceptframework.astroboa.model.factory.CmsCriteriaFactory; import org.betaconceptframework.astroboa.model.factory.CriterionFactory; import org.betaconceptframework.astroboa.model.impl.item.CmsBuiltInItem; import org.betaconceptframework.astroboa.util.CmsConstants; import org.betaconceptframework.astroboa.util.PropertyPath; import org.betaconceptframework.ui.jsf.utility.JSFUtilities; import org.richfaces.event.DropEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Used in Advance Search page to wrap criteria defined from user * * @author Savvas Triantafyllou (striantafillou@betaconcept.gr) * */ /** * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public class CriterionWrapper { private final Logger logger = LoggerFactory.getLogger(getClass()); private String propertyLocalizedLabel; private String propertyPath; private QueryOperator queryOperator; private Object value; private ValueType propertyValueType; private Order order; private List<SelectItem> queryOperatorsAsSelectItems; private String suggestionLocalizedLabelPattern; private TopicService topicService; private ContentService contentService; private ContentObjectUIWrapperFactory contentObjectUIWrapperFactory; private List<String> acceptedContentTypes; private List<String> acceptedTaxonomies; public CriterionWrapper(TopicService topicService, ContentService contentService, ContentObjectUIWrapperFactory contentObjectUIWrapperFactory, DefinitionService definitionService){ this.topicService = topicService; this.contentService = contentService; this.contentObjectUIWrapperFactory = contentObjectUIWrapperFactory; acceptedContentTypes = definitionService.getContentObjectTypes(); //Add a generic one if (acceptedContentTypes != null){ acceptedContentTypes.add(ValueType.ObjectReference.toString()); } } public String getPropertyPath() { return propertyPath; } public void setPropertyPath(String propertyPath) { this.propertyPath = propertyPath; } public QueryOperator getQueryOperator() { return queryOperator; } public void setQueryOperator(QueryOperator queryOperator) { this.queryOperator = queryOperator; } public Object getValue() { if (value == null && ValueType.Boolean == propertyValueType){ //Specify default value for Boolean type value = Boolean.TRUE.toString(); } return value; } public void setValue(Object value) { this.value = value; } public void setPropertyValueType(ValueType propertyValueType) { this.propertyValueType = propertyValueType; } public Criterion getCriterion() throws InvalidInputForCmsPropertyTypeException{ if (StringUtils.isNotBlank(propertyPath) && queryOperator != null){ SimpleCriterion simpleCriterion = CriterionFactory.newSimpleCriterion(); simpleCriterion.setOperator(getQueryOperator()); if ((ValueType.Complex == propertyValueType || ValueType.Binary == propertyValueType) && ( queryOperator == QueryOperator.IS_NOT_NULL || queryOperator == QueryOperator.IS_NULL)){ //Looking for existence of a binary property //It is the same thing as searching for the identifier of this property //This is a dirty way to avoid adding more complexity to //backend repository //Due to issue https://issues.apache.org/jira/browse/JCR-1447 //This criterion may not work as expected simpleCriterion.setProperty(PropertyPath.createFullPropertyPath(getPropertyPath(), CmsBuiltInItem.CmsIdentifier.getJcrName())); } else simpleCriterion.setProperty(getPropertyPath()); if (value != null){ if (ValueType.TopicReference == propertyValueType && value != null && value instanceof Topic) { simpleCriterion.addValue(((Topic)value).getId()); } else if (ValueType.ObjectReference == propertyValueType && value != null && value instanceof ContentObject) { simpleCriterion.addValue(((ContentObject)value).getId()); } else{ if (QueryOperator.CONTAINS == queryOperator && value != null){ if (ValueType.Binary == propertyValueType){ //Build a new criterion return CriterionFactory.contains(simpleCriterion.getProperty(), value.toString()); } else{ return CriterionFactory.contains(simpleCriterion.getProperty(), value.toString()); } } else{ if (ValueType.Boolean == propertyValueType){ simpleCriterion.addValue(Boolean.valueOf((String)value)); } else if (ValueType.Long == propertyValueType){ try{ simpleCriterion.addValue(Long.valueOf((String)value)); }catch(Exception e){ throw new InvalidInputForCmsPropertyTypeException( JSFUtilities.getLocalizedMessage("errors.integerNumber", new String[]{propertyLocalizedLabel}) ,e); } } else if (ValueType.Double == propertyValueType){ try{ simpleCriterion.addValue(Double.valueOf((String)value)); }catch(Exception e){ throw new InvalidInputForCmsPropertyTypeException( JSFUtilities.getLocalizedMessage("errors.decimalNumber", new String[]{propertyLocalizedLabel}) ,e); } } else{ simpleCriterion.addValue(value); } } } } return simpleCriterion; } return null; } public void clear() { propertyPath = null; queryOperator = null; value = null; propertyLocalizedLabel = null; queryOperatorsAsSelectItems = null; propertyValueType = null; order = null; acceptedTaxonomies = null; } public List<SelectItem> getQueryOperatorsAsSelectItems() { if (CollectionUtils.isNotEmpty(queryOperatorsAsSelectItems)) return queryOperatorsAsSelectItems; queryOperatorsAsSelectItems = new ArrayList<SelectItem>(); if (propertyValueType != null){ switch (propertyValueType) { case Complex: queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); break; case Binary: queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.CONTAINS, JSFUtilities.getLocalizedMessage("query.operator.contains", null))); break; case Boolean: queryOperatorsAsSelectItems.add(new SelectItem(null, "")); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.EQUALS, QueryOperator.EQUALS.getOp())); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); break; case TopicReference: case ObjectReference: queryOperator = QueryOperator.NOT_EQUALS; queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.NOT_EQUALS, QueryOperator.NOT_EQUALS.getOp())); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.EQUALS, QueryOperator.EQUALS.getOp())); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); break; case String: queryOperatorsAsSelectItems.add(new SelectItem(null, "")); //queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.LIKE, JSFUtilities.getLocalizedMessage("query.operator.like", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.NOT_EQUALS, QueryOperator.NOT_EQUALS.getOp())); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.EQUALS, QueryOperator.EQUALS.getOp())); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.CONTAINS, JSFUtilities.getLocalizedMessage("query.operator.contains", null))); break; case Double: case Long: case Date: queryOperatorsAsSelectItems.add(new SelectItem(null, "")); for (QueryOperator queryOperator : QueryOperator.values()) { if (queryOperator != QueryOperator.LIKE && queryOperator != QueryOperator.CONTAINS){ if (QueryOperator.IS_NOT_NULL == queryOperator){ queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NOT_NULL, JSFUtilities.getLocalizedMessage("query.operator.not.null", null))); } else if (QueryOperator.IS_NULL == queryOperator){ queryOperatorsAsSelectItems.add(new SelectItem(QueryOperator.IS_NULL, JSFUtilities.getLocalizedMessage("query.operator.null", null))); } else{ queryOperatorsAsSelectItems.add(new SelectItem(queryOperator, queryOperator.getOp())); } } } break; default: break; } } return queryOperatorsAsSelectItems; } public void addDraggedAndDroppedTopicAsCriterionValue_Listener(DropEvent dropEvent) { LazyLoadingTopicTreeNode topicTreeNode = (LazyLoadingTopicTreeNode) dropEvent.getDragValue(); addSelectedTopic_UIAction(topicTreeNode.getTopic()); } public void addSelectedTopic_UIAction(Topic selectedTopic){ value = selectedTopic; } public List<Topic> findTopics_UIAction(Object event) { try { String selectedTopicLabel = event.toString(); //Do not proceed if selected topic label is empty if (StringUtils.isBlank(selectedTopicLabel)) return null; List<Topic> results = new ArrayList<Topic>(); //Localized Label criterion LocalizationCriterion localizationCriterion = CriterionFactory.newLocalizationCriterion(); localizationCriterion.setLocale(JSFUtilities.getLocaleAsString()); localizationCriterion.addLocalizedLabel(selectedTopicLabel+ CmsConstants.ANY_NAME); localizationCriterion.setQueryOperator(QueryOperator.CONTAINS); TopicCriteria topicCriteria = CmsCriteriaFactory.newTopicCriteria(); //Add taxonomy criterion if its definition provides such restriction if (CollectionUtils.isNotEmpty(acceptedTaxonomies)){ //Only one taxonomy if (acceptedTaxonomies.size() == 1){ //topicCriteria.getRenderProperties().renderValuesForLocale(JSFUtilities.getLocaleAsString()); topicCriteria.setOffsetAndLimit(0,30); topicCriteria.addOrderByLocale(JSFUtilities.getLocaleAsString(), Order.ascending); topicCriteria.addAllowsReferrerContentObjectsCriterion(true); topicCriteria.addCriterion(localizationCriterion); topicCriteria.addTaxonomyNameEqualsCriterion(acceptedTaxonomies.get(0)); CmsOutcome<Topic> cmsOutcome = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_LIST); results = cmsOutcome.getResults(); } else{ //More than one taxonomies. //Perform one query per taxonomy and then sort results for (String acceptedTaxonomy : acceptedTaxonomies){ topicCriteria.reset(); //topicCriteria.getRenderProperties().renderValuesForLocale(JSFUtilities.getLocaleAsString()); topicCriteria.setOffsetAndLimit(0,30); topicCriteria.addOrderByLocale(JSFUtilities.getLocaleAsString(), Order.ascending); topicCriteria.addAllowsReferrerContentObjectsCriterion(true); topicCriteria.addCriterion(localizationCriterion); topicCriteria.addTaxonomyNameEqualsCriterion(acceptedTaxonomy); CmsOutcome<Topic> cmsOutcome = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_LIST); if (cmsOutcome != null && cmsOutcome.getCount() > 0){ results.addAll(cmsOutcome.getResults()); } } //finally sort results if (results.size() > 2){ Collections.sort(results, new TopicLocalizedLabelComparator(JSFUtilities.getLocaleAsString())); } } } else{ topicCriteria.addAllowsReferrerContentObjectsCriterion(true); topicCriteria.addCriterion(localizationCriterion); //No taxonomy criterion proceed normally CmsOutcome<Topic> cmsOutcome = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_LIST); results = cmsOutcome.getResults(); } return results; } catch (Exception e) { logger.error("Error while loading Topics ",e); return null; } } public List<ContentObjectUIWrapper> findContentObjects_UIAction(Object event) { try { String selectedContentObjectTitle = event.toString(); //Do not proceed if selected topic label is empty if (StringUtils.isBlank(selectedContentObjectTitle)) return null; ContentObjectCriteria contentObjectCriteria = CmsCriteriaFactory.newContentObjectCriteria(); //contentObjectCriteria.getRenderProperties().renderValuesForLocale(JSFUtilities.getLocaleAsString()); contentObjectCriteria.setOffsetAndLimit(0,15); contentObjectCriteria.addOrderProperty("profile.title", Order.ascending); if (acceptedContentTypes != null && (acceptedContentTypes.size() > 1 || ! ValueType.ObjectReference.toString().equals(acceptedContentTypes.get(0)))){ List<String> contentObjectTypes = new ArrayList<String>(acceptedContentTypes); contentObjectCriteria.addContentObjectTypesEqualsAnyCriterion(contentObjectTypes); } //Profile Title criterion Criterion profileTitleCriterion = CriterionFactory.like("profile.title", "%"+selectedContentObjectTitle+"%"); contentObjectCriteria.addCriterion(profileTitleCriterion); CmsOutcome<ContentObject> cmsOutcome = contentService.searchContentObjects(contentObjectCriteria, ResourceRepresentationType.CONTENT_OBJECT_LIST); List<ContentObjectUIWrapper> wrappedContentObjects = new ArrayList<ContentObjectUIWrapper>(); if (cmsOutcome.getCount() > 0) { List<ContentObject> cmsOutcomeRowList = cmsOutcome.getResults(); for (ContentObject cmsOutcomeRow : cmsOutcomeRowList) { wrappedContentObjects.add(contentObjectUIWrapperFactory.getInstance(cmsOutcomeRow)); } } return wrappedContentObjects; } catch (Exception e) { logger.error("Error while loading Content Objects ",e); return null; } } public void addSelectedContentObject_UIAction(ContentObject selectedContentObject){ value = selectedContentObject; } public void addDraggedAndDroppedContentObject_Listener(DropEvent dropEvent) { ContentObjectItem contentObjectItem = (ContentObjectItem) dropEvent.getDragValue(); if (StringUtils.isNotBlank(contentObjectItem.getId())){ //A Content Object has been dragged //Load Content object from repository ContentObject contentObject = contentService.getContentObject( contentObjectItem.getId(), ResourceRepresentationType.CONTENT_OBJECT_INSTANCE, FetchLevel.ENTITY, CacheRegion.NONE, null, false); if (contentObject == null) JSFUtilities.addMessage(null, "Δεν υπάρχει Αντικείμενο με αναγνωριστικό "+ contentObjectItem.getId() , FacesMessage.SEVERITY_WARN); else{ addSelectedContentObject_UIAction(contentObject); } } } public String getLocalizedLabelForCurrentLocaleForContentObjectTypeValue(){ if (value != null && propertyValueType == ValueType.ObjectReference && value instanceof ContentObject){ Object contentObject = getValue(); if (contentObject != null){ try{ return ((ContentObject)contentObject).getTypeDefinition().getDisplayName().getLocalizedLabelForLocale(JSFUtilities.getLocaleAsString()); } catch(Exception e){ logger.error("", e); return ""; } } } return ""; } public void clearOrder_Listener(){ order = null; } public void clearOrder_Listener(ActionEvent actionEvent){ Object eventObject = actionEvent.getSource(); eventObject.toString(); } public String getPropertyLocalizedLabel() { return propertyLocalizedLabel; } public void setPropertyLocalizedLabel(String propertyLocalizedLabel) { this.propertyLocalizedLabel = propertyLocalizedLabel; } public ValueType getPropertyValueType() { return propertyValueType; } public String getSuggestionLocalizedLabelPattern() { return suggestionLocalizedLabelPattern; } public void setSuggestionLocalizedLabelPattern( String suggestionLocalizedLabelPattern) { this.suggestionLocalizedLabelPattern = suggestionLocalizedLabelPattern; } public List<String> getAcceptedContentTypes() { return acceptedContentTypes; } public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } /** * @param acceptedTaxonomies */ public void setAcceptedTaxonomies(List<String> acceptedTaxonomies) { this.acceptedTaxonomies = acceptedTaxonomies; } public List<String> getAcceptedTaxonomies() { return acceptedTaxonomies; } /** * @param acceptedContentTypes2 */ public void setAcceptedContentTypes(List<String> acceptedContentTypes) { this.acceptedContentTypes = acceptedContentTypes; } }