com.zaizi.sensefy.jscript.SensefySearch.java Source code

Java tutorial

Introduction

Here is the source code for com.zaizi.sensefy.jscript.SensefySearch.java

Source

/**
 * Copyright (C) 2015 Zaizi (sensefy@zaizi.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 com.zaizi.sensefy.jscript;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.jscript.Search;
import org.alfresco.repo.jscript.ValueConverter;
import org.json.JSONException;

import com.zaizi.sensefy.service.SensefyService;

/**
 * Javascript root object to perform searches on Sensefy.
 */
public class SensefySearch extends Search {
    /**
     * The Sensefy service class.
     */
    private SensefyService sensefyService;

    /**
     * Default page size.
     * The default value set in share config is 50.
     * Since we can't access share config from Alfresco, let's just use 1k to have some margin in case it is changed up.
     */
    private static final int DEFAULT_MAX_RESULTS = 1000;

    /**
     * Default skip count
     * The default value is 0: begin from the start.
     */
    private static final int DEFAULT_SKIP_COUNT = 0;

    /**
     * Key for the query field in the request object.
     */
    private static final String QUERY_FIELD = "query";
    /**
     * Key for the filters field in the request object.
     */
    private static final String FILTERS_FIELD = "filters";
    /**
     * Key for the timezone offset object in the request object.
     */
    private static final String TIMEZONE_OFFSET_FIELD = "tzoffset";
    /**
     * Error message to be logged when trying to perform a search without defining a query.
     */
    private static final String QUERY_MISSING_MESSAGE = "Failed to search: Missing mandatory 'query' value.";
    /**
     * Key for the max items field in the request object.
     */
    private static final String MAX_ITEMS_FIELD = "maxItems";
    /**
     * Key for the start index field in the request object.
     */
    private static final String START_INDEX_FIELD = "startIndex";
    /**
     * Key for the sort column field in the request object.
     */
    private static final String SORT_COLUMN_FIELD = "column";
    /**
     * Key for the sort direction field in the request object.
     */
    private static final String SORT_ASCENDING_FIELD = "ascending";
    /**
     * String representation of an empty JSON object to return when the search can't be run.
     */
    private static final String EMPTY_JSON_STRING = "{}";
    /**
     * Key for the pagination object in the request object.
     */
    private static final String PAGE_OBJECT = "page";
    /**
     * Key for the sort object in the request object.
     */
    private static final String SORT_OBJECT = "sort";

    /**
     * Retrieve the query from the serializable map.
     * @param def the serializable map from JavaScript.
     * @return the query string.
     */
    private String getQuery(Map<Serializable, Serializable> def) {
        String query = (String) def.get(QUERY_FIELD);
        if (query == null || query.isEmpty()) {
            throw new AlfrescoRuntimeException(QUERY_MISSING_MESSAGE);
        }
        return query;
    }

    /**
     * Retrieve the filters from the serializable map.
     * @param def the serializable map from JavaScript.
     * @return the query string.
     */
    private String getFilters(Map<Serializable, Serializable> def) {
        String filters = (String) def.get(FILTERS_FIELD);
        if (filters == null) {
            return "";
        }
        return filters;
    }

    /**
     * Retrieve the timezone offset of the current client.
     * This is used to add padding to the dateRange facets.
     * @param def the serializable map from JavaScript.
     * @return the timezone offset of the current user.
     */
    private Integer getTimezoneOffset(Map<Serializable, Serializable> def) {
        Integer tzoffset = 0;
        Object tzObjectOffset = def.get(TIMEZONE_OFFSET_FIELD);
        if (tzObjectOffset instanceof Number) {
            tzoffset = ((Number) tzObjectOffset).intValue();
        }
        return tzoffset;
    }

    /**
     * Retrieve the maximum number of results from the serializable map.
     * @param page the serializable map from JavaScript.
     * @return the maximum number of results to return
     */
    private int getMaxResults(Map<Serializable, Serializable> page) {
        int maxResults = DEFAULT_MAX_RESULTS;
        if (page != null && page.get(MAX_ITEMS_FIELD) != null) {
            Object maxItems = page.get(MAX_ITEMS_FIELD);
            if (maxItems instanceof Number) {
                maxResults = ((Number) maxItems).intValue();
            } else if (maxItems instanceof String) {
                // try and convert to int (which it what it should be!)
                maxResults = Integer.parseInt((String) maxItems);
            }
        }
        return maxResults;
    }

    /**
     * Retrieve the index of the first result to query from the serializable map.
     * @param page the serializable map from JavaScript.
     * @return the start index from which to query.
     */
    private int getSkipCount(Map<Serializable, Serializable> page) {
        int skipResults = DEFAULT_SKIP_COUNT;
        if (page != null && page.get(START_INDEX_FIELD) != null) {
            Object skipCount = page.get(START_INDEX_FIELD);
            if (skipCount instanceof Number) {
                skipResults = ((Number) page.get(START_INDEX_FIELD)).intValue();
            } else if (skipCount instanceof String) {
                // try and convert to int (which it what it should be!)
                skipResults = Integer.parseInt((String) skipCount);
            }
        }
        return skipResults;
    }

    /**
     * Retrieve the sorting preferences from the serializable object.
     * @param sort the list serializable maps from JavaScript.
     * @return a list of the SortColumn object representing which colomns to sort on in what order.
     */
    private SortColumn[] getSortParameter(List<Map<Serializable, Serializable>> sort) {
        SortColumn[] sortColumns = null;
        if (sort != null) {
            sortColumns = new SortColumn[sort.size()];
            int index = 0;
            for (Map<Serializable, Serializable> column : sort) {
                String strCol = (String) column.get(SORT_COLUMN_FIELD);
                if (strCol != null && !strCol.isEmpty()) {
                    Boolean boolAsc = (Boolean) column.get(SORT_ASCENDING_FIELD);
                    boolean ascending = boolAsc != null ? boolAsc.booleanValue() : false;
                    sortColumns[index++] = new SortColumn(strCol, ascending);
                }
            }
        }
        return sortColumns;
    }

    /**
     * Executes a query on Sensefy based on the supplied search definition object.
     * @param search Search definition object as above
     * @return Array of ScriptNode results
     * @throws JSONException when the JSON returned by sensefy is badly formatted
     * @throws IOException when it failed to properly retrieve the result from sensefy
     */
    public String sensefyQuery(Object search) throws IOException, JSONException {
        String results = EMPTY_JSON_STRING;

        if (search instanceof Serializable) {
            Serializable obj = new ValueConverter().convertValueForRepo((Serializable) search);

            if (obj instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<Serializable, Serializable> def = (Map<Serializable, Serializable>) obj;

                // get query
                String query = this.getQuery(def);

                // get filters
                String filters = this.getFilters(def);

                // get timezone offset
                Integer tzoffset = this.getTimezoneOffset(def);

                // get first and count attributes
                @SuppressWarnings("unchecked")
                Map<Serializable, Serializable> page = (Map<Serializable, Serializable>) def.get(PAGE_OBJECT);
                int maxResults = this.getMaxResults(page);
                int skipResults = this.getSkipCount(page);

                // get sort attributes
                @SuppressWarnings("unchecked")
                List<Map<Serializable, Serializable>> sort = (List<Map<Serializable, Serializable>>) def
                        .get(SORT_OBJECT);
                SortColumn[] sortColumns = this.getSortParameter(sort);

                results = this.sensefyService.search(query, filters, skipResults, maxResults, sortColumns,
                        tzoffset);
            }
        }

        return results;
    }

    /**
     * @return the sensefyService
     */
    public SensefyService getSensefyService() {
        return sensefyService;
    }

    /**
     * @param sensefyService the sensefyService to set
     */
    public void setSensefyService(SensefyService sensefyService) {
        this.sensefyService = sensefyService;
    }
}