/* * 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.api.service; import java.util.List; import org.betaconceptframework.astroboa.api.model.CmsRepositoryEntity; import org.betaconceptframework.astroboa.api.model.ContentObject; import org.betaconceptframework.astroboa.api.model.LocalizableEntity; import org.betaconceptframework.astroboa.api.model.Taxonomy; import org.betaconceptframework.astroboa.api.model.Topic; import org.betaconceptframework.astroboa.api.model.TopicReferenceProperty; import org.betaconceptframework.astroboa.api.model.definition.Localization; 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.criteria.CmsQueryContext; import org.betaconceptframework.astroboa.api.model.query.criteria.TopicCriteria; /** * Service providing methods for managing {@link Topic topics}. * * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public interface TopicService { /** * Delete all {@link Topic topics} recursively starting from specified <code>topicIdOrName</code>. * * Deletes also all {@link ContentObject content object} references * to deleted topics. * * @param topicIdOrName * {@link Topic#getId() Topic's id} or {@link Topic#getName() Topic's name} . * @return <code>true</code> if topic has been successfully deleted, <code>false</code> if or no topic with the provided id or name is found. */ boolean deleteTopicTree(String topicIdOrName); /** * Returns mostly used topics of a specific taxonomy. * * Any taxonomy name is accepted, including reserved taxonomies * ({@link Taxonomy#SUBJECT_TAXONOMY_NAME}, {@link Taxonomy#REPOSITORY_USER_FOLKSONOMY_NAME}). * * @param taxonomyName * {@link Taxonomy#getName() Taxonomy name}. * @param offset * Index of first result row * {@link CmsQueryContext#setOffset} * @param limit * Index of last result row * {@link CmsQueryContext#setLimit} * @return Mostly used topics of a specific taxonomy. */ CmsOutcome<Topic> getMostlyUsedTopics(String taxonomyName, int offset, int limit); /** * Returns a list of {@link ContentObject contentObject} identifiers which * contain one or more {@link TopicReferenceProperty property} whose value(s) is a * {#link Topic topic} with the provided <code>topicId</code>. * * This method is used mainly for lazy loading purposes. It should not used directly * from user since it is fired internally on * {@link Topic#getReferrerContentObjects()} method. * * @param topicId Topic identifier. * * @return A list of content object identifiers. */ List<String> getContentObjectIdsWhichReferToTopic(String topicId); /** * Returns count of {@link ContentObject contentObject} identifiers which * contain one or more {@link TopicReferenceProperty property} whose value(s) is a * {#link Topic topic} with the provided <code>topicId</code>. * * This method is used mainly for lazy loading purposes. It should not used directly * from user since it is fired internally on {@link Topic#getNumberOfReferrerContentObjects()} method. * * @param topicId Topic identifier. * * @return Number of content objects which refer to topic. */ int getCountOfContentObjectIdsWhichReferToTopic(String topicId); /** * Single point of retrieving a {@link Topic} from a repository. * * <p> * A topic can be retrieved as XML, as JSON or as a {@link Topic} instance. * Each one of these representations can be specified through {@link ResourceRepresentationType} * which has been designed in such a way that the returned type is available * in compile time, avoiding unnecessary and ugly type castings. * * <pre> * String topicXML = topicService.getTopic("id", ResourceRepresentationType.XML, FetchLevel.ENTITY); * * String topicJSON = topicService.getTopic("id", ResourceRepresentationType.JSON, FetchLevel.ENTITY_AND_CHILDREN); * * Topic topic = topicService.getTopic("id", ResourceRepresentationType.TOPIC_INSTANCE, FetchLevel.FULL); * * CmsOutcome<Topic> topicOutcome = topicService.getTopic("id", ResourceRepresentationType.TOPIC_LIST, FetchLevel.FULL); * * </pre> * </p> * * <p> * You may have noticed that {@link ResourceRepresentationType#TOPIC_LIST} represents a list of * topics, rather than one and therefore its use in this context is not recommended. * Nevertheless, if used, a list containing one topic will be provided. * </p> * * <p> * Users have also the option to specify whether to fetch only topic's properties, * or to load its children as well as the whole topic tree. This is a way to control * lazy loading by pre-fetching topic children. Bear in mind that lazy loading mechanism * is meaningful only when {@link Topic} or {@link CmsOutcome} instance is returned. Other * representations (XML and JSON) do not support lazy loading. * * </p> * * <p> * Also, in cases where no output type is defined, a {@link Topic} instance * is returned. * </p> * * <p> * In JSON representation, note that root element has been stripped out. * i.e result will look like this * * <pre> * {"cmsIdentifier":"092831be-43a4-4357-8bd8-5b9b43807f87","name":"myTopic","localization":{"label":{"en":"My first topic"}}}} * </pre> * * and not like this * * <pre> * {"topic":{"cmsIdentifier":"092831be-43a4-4357-8bd8-5b9b43807f87","name":"myTopic","localization":{"label":{"en":"My first topic"}}}}} * </pre> * * </p> * * <p> * Finally, in case no topic is found for provided <code>topicId</code>, * <code>null</code>is returned. * </p> * * @param <T> {@link String}, {@link Topic} or {@link CmsOutcome} * @param topicIdOrName {@link Topic#getId() topic id} or {@link Topic#getName() topic name} * @param output Topic representation output, one of XML, JSON or {@link Topic}. Default is {@link ResourceRepresentationType#TOPIC_INSTANCE} * @param fetchLevel Specify whether to load {@link Topic}'s only properties, its children as well or the whole {@link Topic} tree. * Default is {@link FetchLevel#ENTITY} * @param prettyPrint <code>true</code> to enable pretty printer functionality such as * adding identation and linefeeds in order to make output more human readable, <code>false<code> otherwise. Only useful if * * @return A topic as XML, JSON or {@link Topic}, or <code>null</code> of none is found. */ <T> T getTopic(String topicIdOrName, ResourceRepresentationType<T> output, FetchLevel fetchLevel, boolean prettyPrint); /** * Save or update a {@link Topic topic}. * * <p> * This method expects either a {@link Topic} instance * or a {@link String} instance which corresponds to an XML or * JSON representation of the entity to be saved. * </p> * * <p> * If no {@link Topic#getTaxonomy() taxonomy} is provided * {@link Taxonomy#SUBJECT_TAXONOMY_NAME subject taxonomy} will be * used. * </p> * * <p> * Whether save or update process is followed depends on whether <code>topic</code> * is a new topic or not. <code>topic</code> is considered new if there is no * {@link Topic#getId() id} or <code>id</code> is provided but there is * no {@link Topic topic} in repository for the provided <code>id</code>. In this case * <code>topic</code> will be saved with the provided <code>id</code>. * </p> * * <p> * The following steps take place in the save process (<code>topic</code> is considered new) * * <ul> * <li> Create a new {@link CmsRepositoryEntity#getId() id} or use the provided <code>id</code>. * <li> Relate <code>topic</code> with the provided {@link Topic#getOwner() owner}. * Topic's owner MUST already exist. If not, an exception is thrown. * <li> Locate <code>topic</code>'s parent topic using its identifier. If no parent is found an exception is thrown. * If no parent identifier is provided then topic will be placed under its taxonomy. * <li> Save localized labels for <code>topic</code>. * <li> Save {@link Topic#getOrder() order}. * <li> Save {@link Topic#getName() name}. * <li> Save {@link Topic#isAllowsReferrerContentObjects() allowsContentObjectReferences}. * <li> Save or update all of its {@link Topic#getChildren() child topics}. * </ul> * </p> * * <p> * The following steps take place in the update process (<code>topic</code> already exists in repository) * * <ul> * <li> Relate <code>topic</code> with the provided {@link Topic#getOwner() owner} only * if the provided owner is different from already existed owner. * Topic's owner MUST already exist. If not, an exception is thrown. * <li> Update <code>topic</code>'s parent ONLY if provided parent identifier is different than one existed. * <li> Update localized labels for <code>topic</code>. * <li> Update {@link Topic#getOrder() order}. * <li> Update {@link Topic#getName() name}. * <li> Update {@link Topic#isAllowsReferrerContentObjects() allowsContentObjectReferences}. * <li> Update {@link Topic#getParent() parent}, in case it has been changed. This corresponds * to moving <code>topic</code>.In this case new <code>topic</code>'s parent * must exist and must belong to the same {@link Taxonomy taxonomy} with * <code>topic</code>. * </ul> * </p> * * * @param topic * Topic to be saved or updated. * @return Newly created or updated Topic */ Topic save(Object topic); /** * Query topics using {@link TopicCriteria} and specifying * result output representation. * * <p> * Query results can be retrieved as XML, as JSON or as a {@link CmsOutcome<Topic>} instance. * Each one of these representations can be specified through {@link ResourceRepresentationType} * which has been designed in such a way that the returned type is available * in compile time, avoiding unnecessary and ugly type castings. * * <pre> * String resultAsXML = topicService.searchTopics(topicCriteria, ResourceRepresentationType.XML); * * String resultAsJSON = topicService.searchTopics(topicCriteria, ResourceRepresentationType.JSON); * * Topic topic = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_INSTANCE); * * CmsOutcome<Topic> resultAsOutcome = topicService.searchTopics(topicCriteria, ResourceRepresentationType.TOPIC_LIST); * * </pre> * </p> * * <p> * You may have noticed that {@link ResourceRepresentationType#TOPIC_INSTANCE} represents one content object * only, rather than a list and therefore its use in this context is not recommended. However in the following * cases a single content object or null is returned, instead of throwing an exception. * * <ul> * <li>User specified limit to be 1 ({@link TopicCriteria#setLimit(1)}). * In this case the first content object matching criteria is returned, or null if none matched criteria.<li> * <li>User specified no limit or limit greater than 1. In this case if more than one topics match * criteria an exception is thrown</li> * </ul> * </p> * * <p> * Also, in cases where no output type is defined a {@link CmsOutcome<Topic>} instance is returned. * </p> * * <p> * In JSON representation, note that root element has been stripped out. * i.e result will look like this * * <pre> * {"cmsIdentifier":"092831be-43a4-4357-8bd8-5b9b43807f87","name":"myTopic","localization":{"label":{"en":"My first topic"}}}} * </pre> * * and not like this * * <pre> * {"topic":{"cmsIdentifier":"092831be-43a4-4357-8bd8-5b9b43807f87","name":"myTopic","localization":{"label":{"en":"My first topic"}}}}} * </pre> * * </p> * * <p> * Finally, if no result is found, * * <ul> * <li><code>null</code> is returned if <code>output</code> {@link ResourceRepresentationType#TOPIC_INSTANCE}</li> * <li><pre>{ * "totalResourceCount" : "0", * "offset" : "0" * } * </pre> is returned if <code>output</code> {@link ResourceRepresentationType#JSON}</li> * <li><pre><?xml version="1.0" encoding="UTF-8"?> * <bccmsapi:resourceResponse * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" * xmlns:bccmsmodel="http://www.betaconceptframework.org/schema/astroboa/model" * xmlns:astroboa-api="http://www.betaconceptframework.org/schema/astroboa/api" * offset="0" * totalResourceCount="0" * /> * </pre> is returned if <code>output</code> {@link ResourceRepresentationType#XML}</li> * <li>empty {@link CmsOutcome<Topic>} is returned if <code>output</code> {@link ResourceRepresentationType#TOPIC_LIST}</li> * </ul> * </p> * * @param <T> {@link String}, {@link Topic} or {@link CmsOutcome} * @param topicCriteria * Topic search criteria. * @param output Topic representation output, one of XML, JSON or {@link Topic}. * Default is {@link ResourceRepresentationType#TOPIC_LIST} * * @return Topics as XML, JSON or {@link CmsOutcome<Topic>} */ <T> T searchTopics(TopicCriteria topicCriteria, ResourceRepresentationType<T> output); }