org.sindice.analytics.servlet.JsonResponseWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.sindice.analytics.servlet.JsonResponseWriter.java

Source

/*******************************************************************************
 * Copyright (c) 2012 National University of Ireland, Galway. All Rights Reserved.
 *
 *
 * This project is a free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This project 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this project. If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package org.sindice.analytics.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringEscapeUtils;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.openrdf.sindice.query.parser.sparql.ast.ASTIRI;
import org.openrdf.sindice.query.parser.sparql.ast.ASTQName;
import org.openrdf.sindice.query.parser.sparql.ast.SimpleNode;
import org.openrdf.sindice.query.parser.sparql.ast.SyntaxTreeBuilder;
import org.sindice.analytics.queryProcessor.QueryProcessor;
import org.sindice.analytics.queryProcessor.QueryProcessor.POFMetadata;
import org.sindice.analytics.queryProcessor.QueryProcessor.RecommendationType;
import org.sindice.analytics.ranking.Label;
import org.sindice.analytics.ranking.LabelsRanking;
import org.sindice.analytics.ranking.ScoreLabel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JsonResponseWriter implements ResponseWriter<String> {

    private static final Logger logger = LoggerFactory.getLogger(JsonResponseWriter.class);
    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public String createSuccessAnswer(RecommendationType type, POFMetadata pofMetadata,
            List<LabelsRanking> recommendations) {
        final Map<String, Object> jsonStructure = new HashMap<String, Object>();
        final String json;

        try {
            final boolean isClass = type.equals(RecommendationType.CLASS);

            jsonStructure.put(ResponseStructure.STATUS, ResponseStructure.SUCCESS);
            jsonStructure.put(ResponseStructure.RESULTS, new HashMap<String, Map>());

            // Add bindings to the results
            final ArrayList<Map> lrList = new ArrayList<Map>();
            ((HashMap<String, List<Map>>) jsonStructure.get(ResponseStructure.RESULTS))
                    .put(ResponseStructure.RANKINGS, lrList);

            for (LabelsRanking lr : recommendations) {

                // the total number of recommendations
                ((HashMap<String, Object>) jsonStructure.get(ResponseStructure.RESULTS))
                        .put(ResponseStructure.COUNT, lr.getLabelList().size());

                final HashMap<String, Object> lrJson = new HashMap<String, Object>();
                final ArrayList<Map<String, Object>> bindings = new ArrayList<Map<String, Object>>();

                lrList.add(lrJson);
                lrJson.put(ResponseStructure.NAME, lr.getName());
                lrJson.put(ResponseStructure.BINDINGS, bindings);
                for (ScoreLabel sug : lr.getLabelList()) {
                    // Add the recommendations, the value and number of occurrences
                    final Map<String, Object> rec = new HashMap<String, Object>();
                    rec.put(ResponseStructure.VALUE, sug.getRecommendation());
                    rec.put(ResponseStructure.COUNT, sug.getScore());
                    rec.put(ResponseStructure.STATUS, sug.getRecommendationType());

                    if (isClass) {
                        // For classes, the predicates that define them and their counts
                        addClassAttributes(sug, rec);
                    }
                    bindings.add(rec);
                }
            }

            // by default, substitutions are disabled
            jsonStructure.put(ResponseStructure.CA_REPLACE, false);
            jsonStructure.put(ResponseStructure.REC_REPLACE, false);
            // add current class attribute substitution data
            if (isClass) {
                addClassAttributeSubstitution(pofMetadata, jsonStructure);
            }
            // add other substitution data, e.g., for keyword search
            addRecSubstitution(pofMetadata, jsonStructure);

            json = mapper.writeValueAsString(jsonStructure);
        } catch (JsonGenerationException e) {
            logger.error("Unable to create JSON response: {}", e);
            return createErrorAnswer(type, e);
        } catch (JsonMappingException e) {
            logger.error("Unable to create JSON response: {}", e);
            return createErrorAnswer(type, e);
        } catch (IOException e) {
            logger.error("Unable to create JSON response: {}", e);
            return createErrorAnswer(type, e);
        }
        return json;
    }

    private String getValue(SimpleNode n) {
        if (n instanceof ASTIRI) {
            return ((ASTIRI) n).getValue();
        } else if (n instanceof ASTQName) {
            return ((ASTQName) n).getValue();
        }
        return null;
    }

    private void addRecSubstitution(final POFMetadata pofMetadata, final Map<String, Object> jsonStructure) {
        final List<Object> keyword = pofMetadata.pofNode.getMetadata() == null ? null
                : pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.Keyword);
        final List<Object> prefix = pofMetadata.pofNode.getMetadata() == null ? null
                : pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.Prefix);
        final ArrayList<Object> lineStart = pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.BeginLine);
        final ArrayList<Object> lineEnd = pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.EndLine);
        final ArrayList<Object> columnStart = pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.BeginColumn);
        final ArrayList<Object> columnEnd = pofMetadata.pofNode.getMetadata(SyntaxTreeBuilder.EndColumn);
        final String value;

        if ((keyword != null || prefix != null)
                && (lineStart == null || lineEnd == null || columnStart == null || columnEnd == null)) {
            logger.error("Unable to get recommendation position. Disabling substitution");
        }
        if (keyword != null) {
            value = (String) keyword.get(0);
            jsonStructure.put(ResponseStructure.REC_REPLACE, true);
            jsonStructure.put(ResponseStructure.REC_SUBSTITUTION,
                    getSubstitutionData(value, (Integer) lineStart.get(0), (Integer) lineEnd.get(0),
                            (Integer) columnStart.get(0), (Integer) columnEnd.get(0)));
        } else if (prefix != null) {
            value = (String) prefix.get(0);
            jsonStructure.put(ResponseStructure.REC_REPLACE, true);
            jsonStructure.put(ResponseStructure.REC_SUBSTITUTION,
                    getSubstitutionData(value, (Integer) lineStart.get(0), (Integer) lineEnd.get(0),
                            (Integer) columnStart.get(0), (Integer) columnEnd.get(0)));
        }
    }

    private void addClassAttributeSubstitution(final POFMetadata pofMetadata,
            final Map<String, Object> jsonStructure) {
        final String value = getValue(pofMetadata.pofClassAttribute);
        final ArrayList<Object> lineStart = pofMetadata.pofClassAttribute.getMetadata(SyntaxTreeBuilder.BeginLine);
        final ArrayList<Object> lineEnd = pofMetadata.pofClassAttribute.getMetadata(SyntaxTreeBuilder.EndLine);
        final ArrayList<Object> columnStart = pofMetadata.pofClassAttribute
                .getMetadata(SyntaxTreeBuilder.BeginColumn);
        final ArrayList<Object> columnEnd = pofMetadata.pofClassAttribute.getMetadata(SyntaxTreeBuilder.EndColumn);

        if (lineStart == null || lineEnd == null || columnStart == null || columnEnd == null) {
            logger.error("Unable to get the class attribute position. Disabling substitution");
        } else if (value == null) {
            logger.error("Unable to get the class attribute value. Disabling substitution");
        } else {
            final int ls = (Integer) lineStart.get(0);
            final int le = (Integer) lineEnd.get(0);
            final int cs = (Integer) columnStart.get(0);
            final int ce = (Integer) columnEnd.get(0);
            jsonStructure.put(ResponseStructure.CA_REPLACE, true);
            // "a" has been expanded
            jsonStructure.put(ResponseStructure.CA_SUBSTITUTION,
                    getSubstitutionData(cs == ce ? "a" : value, ls, le, cs, ce));
        }
    }

    private Map<String, Object> getSubstitutionData(String value, int lineStart, int lineEnd, int columnStart,
            int columnEnd) {
        final Map<String, Object> data = new HashMap<String, Object>();
        final Map<String, Integer> start = new HashMap<String, Integer>();
        final Map<String, Integer> end = new HashMap<String, Integer>();

        start.put(ResponseStructure.LINE, lineStart);
        start.put(ResponseStructure.CH, columnStart);
        data.put(ResponseStructure.START, start);

        end.put(ResponseStructure.LINE, lineEnd);
        end.put(ResponseStructure.CH, columnEnd);
        data.put(ResponseStructure.END, end);
        data.put(ResponseStructure.VALUE, value);
        return data;
    }

    private void addClassAttributes(final ScoreLabel sug, final Map<String, Object> rec) {
        final ArrayList<Map<String, Object>> contexts = new ArrayList<Map<String, Object>>();

        for (Label label : sug.getLabels()) {
            final String value = (String) label.getContext().get(QueryProcessor.CLASS_ATTRIBUTE_LABEL_VAR).get(0);
            final int count = Integer
                    .valueOf(label.getContext().get(QueryProcessor.CLASS_ATTRIBUTE_CARD_VAR).get(0).toString());
            if (contexts.isEmpty()) { // init
                final Map<String, Object> types = new HashMap<String, Object>();
                types.put(ResponseStructure.VALUE, value);
                types.put(ResponseStructure.COUNT, count);
                contexts.add(types);
            } else {
                boolean isPresent = false;
                for (Map<String, Object> ct : contexts) {
                    if (ct.containsValue(value)) {
                        isPresent = true;
                        ct.put(ResponseStructure.COUNT, ((Integer) ct.get(ResponseStructure.COUNT)) + count);
                        break;
                    }
                }
                if (!isPresent) { // add the new class attribute
                    final Map<String, Object> types = new HashMap<String, Object>();
                    types.put(ResponseStructure.VALUE, value);
                    types.put(ResponseStructure.COUNT, count);
                    contexts.add(types);
                }
            }
        }
        rec.put("class_attributes", contexts);
    }

    @Override
    public String createErrorAnswer(RecommendationType type, Throwable e) {
        String msg = e.getLocalizedMessage();
        return "{\"results\":{\"bindings\":[]},\"" + ResponseStructure.STATUS + "\": \"" + ResponseStructure.ERROR
                + "\",\"" + ResponseStructure.MESSAGE + "\":\""
                + StringEscapeUtils.escapeJava(msg.substring(msg.indexOf(':') + 2)) + "\"}";
    }

    @Override
    public String createEmptyAnswer(String msg) {
        return "{\"results\":{\"bindings\":[]},\"" + ResponseStructure.STATUS + "\": \"" + ResponseStructure.NONE
                + "\",\"" + ResponseStructure.MESSAGE + "\":\"" + StringEscapeUtils.escapeJava(msg) + "\"}";
    }

}