/*
* Copyright (c) 2010-2017, b3log.org & hacpai.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.service;
import org.b3log.latke.Keys;
import org.b3log.latke.ioc.inject.Inject;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
import org.b3log.latke.repository.*;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.service.annotation.Service;
import org.b3log.latke.util.CollectionUtils;
import org.b3log.latke.util.Paginator;
import org.b3log.solo.model.Category;
import org.b3log.solo.model.Tag;
import org.b3log.solo.repository.CategoryRepository;
import org.b3log.solo.repository.CategoryTagRepository;
import org.b3log.solo.repository.TagRepository;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Category query service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.1, Apr 12, 2017
* @since 2.0.0
*/
@Service
public class CategoryQueryService {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(CategoryQueryService.class);
/**
* Category repository.
*/
@Inject
private CategoryRepository categoryRepository;
/**
* Tag repository.
*/
@Inject
private TagRepository tagRepository;
/**
* Category tag repository.
*/
@Inject
private CategoryTagRepository categoryTagRepository;
/**
* Gets most tag category.
*
* @param fetchSize the specified fetch size
* @return categories, returns an empty list if not found
*/
public List<JSONObject> getMostTagCategory(final int fetchSize) {
final Query query = new Query().addSort(Category.CATEGORY_ORDER, SortDirection.ASCENDING).
addSort(Category.CATEGORY_TAG_CNT, SortDirection.DESCENDING).
addSort(Keys.OBJECT_ID, SortDirection.DESCENDING).
setPageSize(fetchSize).setPageCount(1);
try {
final List<JSONObject> ret = CollectionUtils.jsonArrayToList(categoryRepository.get(query).optJSONArray(Keys.RESULTS));
for (final JSONObject category : ret) {
final List<JSONObject> tags = getTags(category.optString(Keys.OBJECT_ID));
category.put(Category.CATEGORY_T_TAGS, (Object) tags);
}
return ret;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Gets most tag category error", e);
return Collections.emptyList();
}
}
/**
* Gets a category's tags.
*
* @param categoryId the specified category id
* @return tags, returns an empty list if not found
*/
public List<JSONObject> getTags(final String categoryId) {
final List<JSONObject> ret = new ArrayList<JSONObject>();
final Query query = new Query().
setFilter(new PropertyFilter(Category.CATEGORY + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, categoryId));
try {
final List<JSONObject> relations = CollectionUtils.jsonArrayToList(
categoryTagRepository.get(query).optJSONArray(Keys.RESULTS));
for (final JSONObject relation : relations) {
final String tagId = relation.optString(Tag.TAG + "_" + Keys.OBJECT_ID);
final JSONObject tag = tagRepository.get(tagId);
ret.add(tag);
}
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets category [id=" + categoryId + "] tags error", e);
}
return ret;
}
/**
* Gets a category by the specified category URI.
*
* @param categoryURI the specified category URI
* @return category, returns {@code null} if not null
* @throws ServiceException service exception
*/
public JSONObject getByURI(final String categoryURI) throws ServiceException {
try {
final JSONObject ret = categoryRepository.getByURI(categoryURI);
if (null == ret) {
return null;
}
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets category [URI=" + categoryURI + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Gets a category by the specified category title.
*
* @param categoryTitle the specified category title
* @return category, returns {@code null} if not null
* @throws ServiceException service exception
*/
public JSONObject getByTitle(final String categoryTitle) throws ServiceException {
try {
final JSONObject ret = categoryRepository.getByTitle(categoryTitle);
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets category [title=" + categoryTitle + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Gets categories by the specified request json object.
*
* @param requestJSONObject the specified request json object, for example,
* "categoryTitle": "", // optional
* "paginationCurrentPageNum": 1,
* "paginationPageSize": 20,
* "paginationWindowSize": 10
* see {@link Pagination} for more details
* @return for example,
* <pre>
* {
* "pagination": {
* "paginationPageCount": 100,
* "paginationPageNums": [1, 2, 3, 4, 5]
* },
* "categories": [{
* "oId": "",
* "categoryTitle": "",
* "categoryDescription": "",
* ....
* }, ....]
* }
* </pre>
* @throws ServiceException service exception
* @see Pagination
*/
public JSONObject getCategoris(final JSONObject requestJSONObject) throws ServiceException {
final JSONObject ret = new JSONObject();
final int currentPageNum = requestJSONObject.optInt(Pagination.PAGINATION_CURRENT_PAGE_NUM);
final int pageSize = requestJSONObject.optInt(Pagination.PAGINATION_PAGE_SIZE);
final int windowSize = requestJSONObject.optInt(Pagination.PAGINATION_WINDOW_SIZE);
final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize).
addSort(Category.CATEGORY_ORDER, SortDirection.ASCENDING).
addSort(Category.CATEGORY_TAG_CNT, SortDirection.DESCENDING).
addSort(Keys.OBJECT_ID, SortDirection.DESCENDING);
if (requestJSONObject.has(Category.CATEGORY_TITLE)) {
query.setFilter(new PropertyFilter(Category.CATEGORY_TITLE, FilterOperator.EQUAL,
requestJSONObject.optString(Category.CATEGORY_TITLE)));
}
JSONObject result;
try {
result = categoryRepository.get(query);
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets categories failed", e);
throw new ServiceException(e);
}
final int pageCount = result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_PAGE_COUNT);
final JSONObject pagination = new JSONObject();
ret.put(Pagination.PAGINATION, pagination);
final List<Integer> pageNums = Paginator.paginate(currentPageNum, pageSize, pageCount, windowSize);
pagination.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
pagination.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
final JSONArray data = result.optJSONArray(Keys.RESULTS);
final List<JSONObject> categories = CollectionUtils.jsonArrayToList(data);
ret.put(Category.CATEGORIES, categories);
return ret;
}
/**
* Gets a category by the specified id.
*
* @param categoryId the specified id
* @return a category, return {@code null} if not found
* @throws ServiceException service exception
*/
public JSONObject getCategory(final String categoryId) throws ServiceException {
try {
final JSONObject ret = categoryRepository.get(categoryId);
if (null == ret) {
return null;
}
final List<JSONObject> tags = getTags(categoryId);
ret.put(Category.CATEGORY_T_TAGS, (Object) tags);
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets a category [categoryId=" + categoryId + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Whether a tag specified by the given tag title in a category specified by the given category id.
*
* @param tagTitle the given tag title
* @param categoryId the given category id
* @return {@code true} if the tag in the category, returns {@code false} otherwise
*/
public boolean containTag(final String tagTitle, final String categoryId) {
try {
final JSONObject category = categoryRepository.get(categoryId);
if (null == category) {
return true;
}
final JSONObject tag = tagRepository.getByTitle(tagTitle);
if (null == tag) {
return true;
}
final Query query = new Query().setFilter(
CompositeFilterOperator.and(
new PropertyFilter(Category.CATEGORY + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, categoryId),
new PropertyFilter(Tag.TAG + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, tag.optString(Keys.OBJECT_ID))));
return categoryTagRepository.count(query) > 0;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Check category tag [tagTitle=" + tagTitle + ", categoryId=" + categoryId + "] failed", e);
return true;
}
}
}