com.sbux.loyalty.nlp.topicservice.GrammarService.java Source code

Java tutorial

Introduction

Here is the source code for com.sbux.loyalty.nlp.topicservice.GrammarService.java

Source

package com.sbux.loyalty.nlp.topicservice;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.gson.reflect.TypeToken;
import com.sbux.loyalty.nlp.Exception.InvalidGrammarException;
import com.sbux.loyalty.nlp.commands.JsonFileInputParseCommand;
import com.sbux.loyalty.nlp.config.ConfigBean;
import com.sbux.loyalty.nlp.config.ModelBinding;
import com.sbux.loyalty.nlp.config.RuleBasedModel;
import com.sbux.loyalty.nlp.core.datasources.DatasourceClient;
import com.sbux.loyalty.nlp.core.datasources.DatasourceClient.DatasourceFile;
import com.sbux.loyalty.nlp.databean.GrammarDiffRequestBody;
import com.sbux.loyalty.nlp.grammar.GrammarDeltaProcessor;
import com.sbux.loyalty.nlp.grammar.GrammarDeltaProcessor.GrammarDelta;
import com.sbux.loyalty.nlp.grammar.InvalidPreviewRequestException;
import com.sbux.loyalty.nlp.grammar.ModelValidator;
import com.sbux.loyalty.nlp.grammar.ModelValidator.ModelValidationResult;
import com.sbux.loyalty.nlp.grammar.OnlineConstraintMatcher;
import com.sbux.loyalty.nlp.grammar.OnlineConstraintMatcher.ConstraintMatchMessage;
import com.sbux.loyalty.nlp.grammar.OnlineConstraintMatcher.Filter;
import com.sbux.loyalty.nlp.grammar.OnlineConstraintMatcher.MatchResponse;
import com.sbux.loyalty.nlp.grammar.OnlineConstraintMatcher.StatsResponse;
import com.sbux.loyalty.nlp.grammar.TopicGrammar;
import com.sbux.loyalty.nlp.grammar.TopicGrammar.Constraint;
import com.sbux.loyalty.nlp.grammar.TopicGrammar.TopicGrammarNode;
import com.sbux.loyalty.nlp.grammar.TopicGrammarContainer;
import com.sbux.loyalty.nlp.util.GenericUtil;
import com.sbux.loyalty.nlp.util.JsonConvertor;
import com.sbux.loyalty.nlp.util.TextCache;

/**
 * This REST end point is to do CRUD operations on topic grammar.
 * @author aveettil
 *
 */
@Path("/model")
public class GrammarService {
    private static final Logger log = Logger.getLogger(GrammarService.class);
    int MAX_COMPARISON_SET_SIZE = 2000;
    public static final Map<String, Map<String, Integer>> topicCountCache = new HashMap<>();;

    //private static Map<String,Map<String,Integer>> topicCountMap= new HashMap<>();
    @GET
    @Produces("text/plain")
    public Response about() throws JSONException {

        JSONObject jsonObject = new JSONObject();

        jsonObject.put("Description", " provides API services related models");
        String result = jsonObject.toString();
        return Response.status(200).entity(result).build();
    }

    /**
     * Returns all existing models and current version names
     * @param modelName
     * @param versionNumber
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("models")
    @GET
    @Produces("text/plain")
    public Response getAllModels(@PathParam("modelName") String modelName,
            @PathParam("version") double versionNumber, @Context UriInfo ui) throws Exception {
        try {
            ConfigBean.reset(); // force to get the latest from data source instead of cached configuration.
            String json = JsonConvertor.getJson(ConfigBean.getInstance().getRuleBasedModels());
            return Response.status(200).entity(json).build();
        } catch (Exception e) {
            log.error(e);
            return Response.status(500).entity(e.getMessage()).build();
        }
    }

    @Path("/diff/{channel}/{namespace}/{modelName}/{modelVersion}")
    @POST
    @Produces("text/plain")
    public Response getDiff(@PathParam("channel") String channel, @PathParam("namespace") String namespace,
            @PathParam("modelName") String modelName, @PathParam("modelVersion") double modelVersion,
            @Context UriInfo ui, String requestBodyJson) throws Exception {
        MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
        String size = queryParams.getFirst("limit");
        int comparisonBaseSize = MAX_COMPARISON_SET_SIZE;

        if (StringUtils.isNotBlank(size)) {
            comparisonBaseSize = Integer.parseInt(size);
        }
        DiffResult diffResult = getDiff(channel, namespace, modelName, modelVersion, requestBodyJson,
                comparisonBaseSize);
        return Response.status(diffResult.responseCode)
                .entity(diffResult.json == null ? diffResult.errorMEssage : diffResult.json).build();
    }

    // Match OPTIONS
    @Path("/diff/{channel}/{namespace}/{modelName}/{modelVersion}")
    @OPTIONS
    public Response options_getDiff() {
        return Response.status(Response.Status.NO_CONTENT).build();
    }

    @Path("/validate/{modelName}/{modelVersion}")
    @GET
    @Produces("application/json")
    public Response validateModel(@PathParam("modelName") String modelName,
            @PathParam("modelVersion") double modelVersion, @Context UriInfo ui) throws Exception {
        TopicGrammar grammar = TopicGrammarContainer.getTopicGrammar(modelName, modelVersion);
        ModelValidator modelValidator = new ModelValidator();
        ModelValidationResult result = modelValidator.validateModel(grammar);
        if (result.isSuccess())
            return Response.status(200).entity("SUCCESS").build();
        else
            return Response.status(200).entity(JsonConvertor.getJson(result.getErrorMessages())).build();
    }

    @Path("/validate/{modelName}")
    @GET
    @Produces("application/json")
    public Response validateModel(@PathParam("modelName") String modelName, @Context UriInfo ui) throws Exception {
        // update the model with a new version
        RuleBasedModel model = GenericUtil.getRuleBaseModel(modelName);
        return validateModel(modelName, model.getCurrentVersion(), ui);
    }

    public static class DiffResult {
        String json;
        String errorMEssage;
        int responseCode;

        public DiffResult(String json, String errorMEssage, int errorCode) {
            super();
            this.json = json;
            this.errorMEssage = errorMEssage;
            this.responseCode = errorCode;
        }

    }

    /**
     * Returns a Json String representing the diff between two models
     * @param channel
     * @param namespace
     * @param modelName
     * @param modelVersion
     * @param requestBodyJson
     * @param comparisonSetSize
     * @return
    * @throws Exception 
    * @throws InvalidGrammarException 
     */
    public DiffResult getDiff(String channel, String namespace, String modelName, double modelVersion,
            String requestBodyJson, int comparisonSetSize) throws InvalidGrammarException, Exception {
        GrammarDiffRequestBody grammarDiffRequestBody = JsonConvertor.getObjectFromJson(requestBodyJson,
                GrammarDiffRequestBody.class);

        TopicGrammar grammar = TopicGrammarContainer.getTopicGrammar(modelName, modelVersion);
        TopicGrammarNode node = grammar.getNodeWithPath(grammarDiffRequestBody.getTopicPath());
        long start = System.currentTimeMillis();
        Set<String> comparisonSet = getComparisonSetFromCache(channel, namespace, modelName, modelVersion,
                comparisonSetSize, grammarDiffRequestBody);
        Set<String> comparisonSet_short = new HashSet<>();
        int count = 0;
        for (String s : comparisonSet) {
            count++;
            comparisonSet_short.add(s);
            if (count > comparisonSetSize)
                break;
        }
        GrammarDelta delta = new GrammarDeltaProcessor().getDelta(node, grammarDiffRequestBody.getNewConstraints(),
                comparisonSet_short, true, 5);
        System.out.println("time to compute delta " + (System.currentTimeMillis() - start));
        // get the topicToReviews
        String json = JsonConvertor.getJson(delta);
        return new DiffResult(json, null, 200);
    }

    /**
     * Returns the grammar for a model name and version
     * @param modelName
     * @param versionName
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("{modelName}/{version}")
    @GET
    @Produces("text/plain")
    public Response getModel(@PathParam("modelName") String modelName, @PathParam("version") double versionNumber,
            @Context UriInfo ui) throws Exception {
        try {
            MultivaluedMap<String, String> queryParams = ui.getQueryParameters();

            String getRules = queryParams.getFirst("getRules");
            if (StringUtils.isBlank(getRules))
                getRules = "false";
            TopicGrammar grammar = TopicGrammarContainer.getTopicGrammar(modelName, versionNumber);
            //fillNodesWithNameAndPath(grammar);
            String json = null;
            String eTag = grammar.geteTag();

            if ("false".equalsIgnoreCase(getRules)) { // need only the node names. Strip rules from json
                json = JsonConvertor.getJson(grammar.getTopicNodes().keySet());

            } else {
                json = JsonConvertor.getJson(grammar.getTopicNodes());
            }
            return Response.status(200).header("ETag", eTag).entity(json).build();
        } catch (Exception e) {
            log.error(e);
            throw e;
        }
    }

    /**
      * Returns the grammar for a model name. Returns current version
      * @param modelName
      * @param ui
      * @return
      * @throws Exception
      */
    @Path("{modelName}")
    @GET
    @Produces("text/plain")
    public Response getModel(@PathParam("modelName") String modelName, @Context UriInfo ui) throws Exception {
        return getModel(modelName, TopicGrammarContainer.CURRENT_VERSION, ui);
    }

    /**
     * Deletes a model name and current version from cache
     * @param modelName
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("cache/{modelName}")
    @DELETE
    @Produces("text/plain")
    public Response deleteModelFromcache(@PathParam("modelName") String modelName, @Context UriInfo ui) {
        try {
            double version = GenericUtil.getRuleBaseModel(modelName).getCurrentVersion();
            TopicGrammarContainer.deleteFromCache(modelName, version);
            return Response.status(200)
                    .entity("Successfully deleted model " + modelName + " version " + version + " from cache")
                    .build();
        } catch (Exception e) {
            log.error(e);
            return Response.status(500).entity("Error : " + e.getMessage()).build();
        }
    }

    /**
     * Deletes a model name and version from cache
     * @param modelName
     * @param version
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("cache/{modelName}/{version}")
    @DELETE
    @Produces("text/plain")
    public Response deleteModelFromcache(@PathParam("modelName") String modelName,
            @PathParam("version") double version, @Context UriInfo ui) throws Exception {
        TopicGrammarContainer.deleteFromCache(modelName, version);
        return Response.status(200)
                .entity("Successfully deleted model " + modelName + " version " + version + " from cache").build();
    }

    /**
    * Returns a preview of the texts matching the constraints
    * @param channel
    * @param namespace
    * @param ui
    * @param requestBody
    * @return
    */
    @Path("preview/{channel}/{namespace}")
    @POST
    @Produces("text/plain")
    public Response getPreview(@PathParam("channel") String channel, @PathParam("namespace") String namespace,
            @QueryParam("diff") boolean diff, @Context UriInfo ui, String requestBody) {
        try {
            ConstraintMatchMessage msg = JsonConvertor.getObjectFromJson(requestBody, ConstraintMatchMessage.class);
            if (diff)
                msg.setDiffrequest(diff);
            OnlineConstraintMatcher matcher = new OnlineConstraintMatcher();
            List<MatchResponse> response = matcher.getMatchingTexts(msg, diff);
            String json = JsonConvertor.getJson(new PreviewResponse(response, matcher.getJobId()));
            return Response.status(200).entity(json).build();
        } catch (InvalidPreviewRequestException e) {
            log.info(e);
            return Response.status(400).entity(e.getMessage()).build();
        } catch (Exception e1) {
            log.error(e1);
            return Response.status(500).entity(e1.getMessage()).build();
        }
    }

    private static class PreviewResponse {
        String jobId;
        List<MatchResponse> response;

        public PreviewResponse(List<MatchResponse> response, String jobId) {
            super();
            this.response = response;
            this.jobId = jobId;
        }

    }

    /**
    * Returns the counts of matching previews
    * @param channel
    * @param namespace
    * @param ui
    * @param requestBody
    * @return
    */
    @Path("preview/stats/{jobId}")
    @GET
    @Produces("text/plain")
    public Response getPreviewStats(@PathParam("jobId") String jobId, @Context UriInfo ui, String requestBody) {
        try {
            Map<String, StatsResponse> responseMap = OnlineConstraintMatcher.statsResponseMap.get(jobId);
            if (responseMap == null) {
                return Response.status(404).entity("job id " + jobId + " not found").build();
            }
            String json = JsonConvertor.getJson(responseMap);
            return Response.status(200).entity(json).build();
        } catch (InvalidPreviewRequestException e) {
            log.info(e);
            return Response.status(400).entity(e.getMessage()).build();
        } catch (Exception e1) {
            log.error(e1);
            return Response.status(500).entity(e1.getMessage()).build();
        }
    }

    @Path("preview/{jobId}/{startOffset}/{endOffset}")
    @GET
    @Produces("text/plain")
    public Response getPreview(@PathParam("jobId") String jobId, @PathParam("startOffset") int startOffset,
            @PathParam("endOffset") int endOffset, @Context UriInfo ui, String requestBody) {
        try {
            if (startOffset > endOffset) {
                return Response.status(403)
                        .entity("start offset " + startOffset + " is greater than end offset " + endOffset).build();
            }
            List<MatchResponse> responseList = OnlineConstraintMatcher.resultRsponseMap.get(jobId);
            if (responseList == null) {
                return Response.status(404).entity("job id " + jobId + " not found").build();
            }

            if (responseList.size() < endOffset) {
                endOffset = responseList.size();
            }
            List<MatchResponse> resultList = new ArrayList<>();
            for (int i = startOffset - 1; i < endOffset; i++) {
                resultList.add(responseList.get(i));
            }
            String json = JsonConvertor.getJson(new PreviewResponse(resultList, jobId));
            return Response.status(200).entity(json).build();
        } catch (InvalidPreviewRequestException e) {
            log.info(e);
            return Response.status(400).entity(e.getMessage()).build();
        } catch (Exception e1) {
            log.error(e1);
            return Response.status(500).entity(e1.getMessage()).build();
        }
    }

    /**
     * warms up the preview request so that lambda is ready and set to go 
     * @param ui
     * @return
     */
    @Path("preview/warmup")
    @GET
    @Produces("text/plain")
    public Response warmUpPreview(@Context UriInfo ui) {
        try {
            List<Constraint> l = new ArrayList<>();
            Constraint c = new Constraint();
            c.setName("c1");
            c.setKeywordsRule(
                    "accepted, accepts, accept, ((allow, allowed, allows, able, unable, \"could not\", \"can not\", cannot, \"would not let\", \"did not let\") AND (use, used, using, uses)), acceptance");
            c.setAndWords2Rule(
                    "store, location, license?, target, \"barnes and noble\", \"barnes & noble\", kroger, hilton, stores, locations, country, usa, america, \"us cards\", \"card was not accepted\", countries, england, uk, britain, travel, travelling, albertsons, \"barnes n nobles\", barnes, \"the starbucks\", korea, pos, germany, \"puerto rico\", abroad, foreign, safeway, caribbean, franchise, franchises, \"they would not accept\", hospital, \"saudi arabia\", \"b&n\", disney, university, campus, airport, school, kiosk, kiosks, paris, bahamas, motorway, \"new york city\", canada, albertson, nobles, , OWNERSHIP_TYPE:ls, OWNERSHIP_TYPE:fr, OWNERSHIP_TYPE:bn, OWNERSHIP_TYPE:fs");
            l.add(c);
            Filter filter = new Filter();
            filter.setChannel("fsc");
            filter.setNamespace("ccc");
            //filter.setModelName("xLIBStarbucksCardMSRLibrary");
            filter.setStartDt("2016-08-01");
            filter.setEndDt("2016-08-01");

            //filter.setModelVersion(1.0);
            ConstraintMatchMessage msg = new ConstraintMatchMessage(l, filter);
            msg.setMinResponse(5);

            new OnlineConstraintMatcher().getMatchingTexts(msg, false);
            return Response.status(200).entity("SUCCESS").build();
        } catch (InvalidPreviewRequestException e) {
            log.info(e);
            return Response.status(400).entity(e.getMessage()).build();
        } catch (Exception e1) {
            log.error(e1);
            return Response.status(500).entity(e1.getMessage()).build();
        }
    }

    /**
     * Updates a model and returns the latest version after updating it.
     * @param modelName
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("{modelName}")
    @PUT
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces("text/plain")
    public Response updateModel(@PathParam("modelName") String modelName, @Context UriInfo ui, String json)
            throws Exception {
        try {
            // validate model
            ModelValidator.ModelValidationResult modelValidationResult = new ModelValidator().validateModel(json);

            if (modelValidationResult.isSuccess()) {
                double newVersion = 1.0;
                // update the model with a new version
                RuleBasedModel model = GenericUtil.getRuleBaseModel(modelName);
                if (model == null) {
                    // JIRA - https://starbucks-analytics.atlassian.net/browse/DS-1056
                    newVersion = createNewModel(modelName, json);

                } else {
                    newVersion = updateConfigWithNewVersion(model, json);
                }
                // TODO: store the diff
                return Response.status(201).entity(newVersion + "").build();
            } else {
                return Response.status(400).entity("Invalid model : Excption is "
                        + JsonConvertor.getJson(modelValidationResult.getErrorMessages())).build();
            }
        } catch (Exception e) {
            log.error(e);
            throw e;
        }
    }

    // Match OPTIONS
    @Path("{modelName}")
    @OPTIONS
    public Response optionsAll() {
        return Response.status(Response.Status.NO_CONTENT).build();
    }

    /**
     * 
     * @param modelName
     * @throws Exception 
     */
    private double createNewModel(String modelName, String json) throws Exception {

        RuleBasedModel modelNew = new RuleBasedModel();
        double defaultVersion = 1.0;
        String filename = modelName + ".json";
        ConfigBean instance = ConfigBean.getInstance();
        String namespacesBasePath = instance.getModelFileBasePath();

        String grammarFileLocation = namespacesBasePath + "/" + modelName + "/grammar";

        modelNew.setActive("true");
        modelNew.setCurrentVersion(defaultVersion);
        modelNew.setFileName(filename);
        modelNew.setAlias(modelName);
        modelNew.setName(modelName);
        modelNew.setGrammarFileLocation(grammarFileLocation);

        instance.getRuleBasedModels().add(modelNew);
        ConfigBean.setInstance(instance);

        double newVersion = createConfigWithDefaultVersion(modelNew, json);
        return newVersion;
    }

    /**
     * Update the model given the path and the constraints in the path
     * @param modelName
     * @param path
     * @param ui
     * @param json
     * @return
     * @throws Exception
     */
    @Path("{modelName}/node")
    @PUT
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public Response updateModel(@PathParam("modelName") String modelName, @QueryParam("path") String path,
            @Context UriInfo ui, String json) throws Exception {
        try {
            // validate model
            RuleBasedModel model = GenericUtil.getRuleBaseModel(modelName);
            if (model == null) {
                return Response.status(404).entity("model " + modelName + " does not exist").build();
            }
            TopicGrammar topicGrammar = TopicGrammarContainer.getTopicGrammar(modelName, model.getCurrentVersion());
            TopicGrammarNode node = topicGrammar.getNodeWithPath(path);
            if (node == null) {
                return Response.status(404).entity("path " + path + " not found in model " + modelName).build();
            }
            Type collectionType = new TypeToken<List<Constraint>>() {
            }.getType();
            List<Constraint> constraints = JsonConvertor.getObjectFromJson(json, collectionType);
            node.setConstrainsts(constraints);
            ModelValidator.ModelValidationResult modelValidationResult = new ModelValidator()
                    .validateModel(topicGrammar);
            if (modelValidationResult.isSuccess()) {
                // update the model with a new version

                double newVersion = updateConfigWithNewVersion(model, topicGrammar);
                // TODO: store the diff
                return Response.status(201).entity(newVersion + "").build();
            } else {
                return Response.status(400).entity("Invalid model : Exception is "
                        + JsonConvertor.getJson(modelValidationResult.getErrorMessages())).build();
            }
        } catch (Exception e) {
            log.error(e);
            throw e;
        }
    }

    // Match OPTIONS
    @Path("{modelName}/node")
    @OPTIONS
    public Response options_updateModel() {
        return Response.status(Response.Status.NO_CONTENT).build();
    }

    /**
     * Returns a given node specified by path argument
     * @param modelName
     * @param path
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("{modelName}/node")
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Response getModelPath(@PathParam("modelName") String modelName, @QueryParam("path") String path,
            @Context UriInfo ui) throws Exception {
        try {
            // validate model
            RuleBasedModel model = GenericUtil.getRuleBaseModel(modelName);
            if (model == null) {
                return Response.status(404).entity("Model " + modelName + " not found").build();
            }
            TopicGrammar topicGrammar = TopicGrammarContainer.getTopicGrammar(modelName, model.getCurrentVersion());
            TopicGrammarNode node = topicGrammar.getNodeWithPath(path);
            if (node == null) {
                return Response.status(404).entity("path " + path + " not found in model " + modelName).build();
            } else {
                return Response.status(201).entity(JsonConvertor.getJson(node)).build();
            }

        } catch (Exception e) {
            log.error(e);
            throw e;
        }
    }

    /**
     * 
     * @param channel
     * @param namespace
     * @param modelName
     * @param modelVersion
     * @param comparisonSetSize
     * @param grammarDiffRequestBody
     * @return
     * @throws Exception
     */
    public Set<String> getComparisonSetFromCache(String channel, String namespace, String modelName,
            double modelVersion, int comparisonSetSize, GrammarDiffRequestBody grammarDiffRequestBody)
            throws Exception {

        return TextCache.getInstance(channel, namespace).getTexts();
    }

    /**
     * 
     * @param channel
     * @param namespace
     * @param modelName
     * @param modelVersion
     * @param comparisonSetSize
     * @param grammarDiffRequestBody
     * @return
     * @throws Exception
     */
    public List<String> getComparisonSet(String channel, String namespace, String modelName, double modelVersion,
            int comparisonSetSize, GrammarDiffRequestBody grammarDiffRequestBody) throws Exception {
        List<String> comparisonSet = new ArrayList<>();
        // get the comparison base
        ModelBinding modelBinding = GenericUtil.getModelBinding(channel, namespace, modelName);

        if (modelBinding == null) {
            new DiffResult(null, "No model binding for  channel = " + channel + " namespace = " + namespace
                    + " modelName = " + modelName + " found", 404);
        }

        String dataFolder = GenericUtil.getNamespace(channel, namespace).getDataFolder();

        String topicToTextFolder = GenericUtil.getTopicToTextOutputFolder(modelBinding.getTopicToTextFolder(),
                modelVersion, grammarDiffRequestBody.getTopicPathWihtoutModelName(), null, -1, -1, -1);
        // we get the topicToTextFolder for the topic path. get all the dates and sequenceNumber associated with the data. That will form as the basis for comparison
        // why? because input data in those files contains the given topic
        List<DatasourceFile> dataSourceFiles = DatasourceClient.getDefaultDatasourceClient()
                .getListOfFilesInFolder(topicToTextFolder);
        String dataFolderContainingTopic = null;
        String topicToTextFile = null;
        for (DatasourceFile df : dataSourceFiles) {
            String dateAndSequenceNumber = GenericUtil
                    .getDateAndSequenceNumberFromTopicToTextOutputFolder(df.getName());
            dataFolderContainingTopic = dataFolder + "/" + dateAndSequenceNumber;
            topicToTextFile = df.getName();
            break;
        }
        if (dataFolderContainingTopic == null) {
            return comparisonSet;
        }
        String[] lines = DatasourceClient.getDefaultDatasourceClient().readFileAsString(dataFolderContainingTopic)
                .split("\n");

        int i = 0;
        for (String line : lines) {
            i++;

            JsonFileInputParseCommand command = new JsonFileInputParseCommand(channel, namespace);
            command.setRow(line).parse(null);
            String text = command.getJsonNlpInputBean().getText();
            comparisonSet.add(text);
            if (i == comparisonSetSize) // limiting the size
                break;
        }
        // add lines from the topic to Text
        lines = DatasourceClient.getDefaultDatasourceClient().readFileAsString(topicToTextFile).split("\n");
        i = 0;
        for (String line : lines) {
            i++;
            comparisonSet.add(line);

            if (i == comparisonSetSize) // limiting the size
                break;
        }
        return comparisonSet;
    }

    /**
     * Returns the current version number
     * @param modelName
     * @param ui
     * @return
     * @throws Exception
     */
    @Path("currentVersionNo/{modelName}")
    @GET
    @Produces("text/plain")
    public Response getCurrentVersionNo(@PathParam("modelName") String modelName, @Context UriInfo ui)
            throws Exception {
        double currentVersion = GenericUtil.getRuleBaseModel(modelName).getCurrentVersion();
        return Response.status(200).entity(currentVersion + "").build();
    }

    /**
     * Returns a map of topic counts
     * @param channel
     * @param namespace
     * @param modelName
     * @param date
     * @return
    * @throws Exception 
    * @throws IOException 
     */
    protected Map<String, Map<String, Integer>> getTopicCount(String topicCOuntFolder)
            throws IOException, Exception {
        String json = DatasourceClient.getDefaultDatasourceClient()
                .readFileAsString(topicCOuntFolder + "/data.txt");
        TypeToken<Map<String, Map<String, Integer>>> typeToken = new TypeToken<Map<String, Map<String, Integer>>>() {
        };
        return JsonConvertor.getObjectFromJson(json, typeToken.getType());
    }

    /**
     * Returns topic count for a given source directory, after recursively traversing through it. Actual count data is assumed to be 
     * in a file called data.txt
     * @param file
     * @param topicCounts
     * @throws IOException
     * @throws Exception
     */
    protected void getTopicCount(DatasourceFile file, Map<String, Integer> topicCounts)
            throws IOException, Exception {
        List<DatasourceFile> files = DatasourceClient.getDefaultDatasourceClient()
                .getListOfFilesInFolder(file.getName());
        for (DatasourceFile df : files) {
            if (df.isDirecttory()) {
                getTopicCount(df, topicCounts);
            } else {
                if (df.getName().endsWith("data.txt")) {
                    String[] countData = DatasourceClient.getDefaultDatasourceClient()
                            .readFileAsString(df.getName()).split("=");
                    topicCounts.put(countData[0], Integer.parseInt(countData[1]));
                }
            }
        }
    }

    /**
     * 
     * @param model
     * @param topicGrammar
     * @return
     * @throws IOException
     * @throws Exception
     */
    private synchronized double updateConfigWithNewVersion(RuleBasedModel model, TopicGrammar topicGrammar)
            throws IOException, Exception {
        synchronized (model) {
            String json = JsonConvertor.getJson(topicGrammar.getTopicNodes());
            return updateConfigWithNewVersion(model, json);
        }
    }

    private void fillNodesWithNameAndPath(TopicGrammar topicGrammar) {
        for (TopicGrammarNode node : topicGrammar.getTopicNodes().values()) {
            node.setName(node.getName());
            node.setPath(node.getPath()); // explicitly set Path so that it can be serialized into json
        }
    }

    /**
     * 
     * @param model
     * @param json
     * @return
     * @throws IOException
     * @throws Exception
     */
    private synchronized double createConfigWithDefaultVersion(RuleBasedModel model, String json)
            throws IOException, Exception {
        double newVersion = 1.0;
        String newVersionFilePath = model.getGrammarFileLocation() + "/1.0/"
                + model.getFileName().replace(".csv", ".json");

        // create new version file
        DatasourceClient.getDefaultDatasourceClient().createFile(newVersionFilePath, json);

        // update the current version to new version
        model.setCurrentVersion(newVersion);
        ConfigBean.storeConfig(ConfigBean.getInstance());
        GenericUtil.reset(); // reset the configuration
        return newVersion;
    }

    /**
     * 
     * @param model
     * @param json
     * @return
     * @throws IOException
     * @throws Exception
     */
    private double updateConfigWithNewVersion(RuleBasedModel model, String json) throws IOException, Exception {
        synchronized (model) {
            double newVersion = model.getCurrentVersion() + 1.0;
            String newVersionFilePath = model.getGrammarFileLocation() + "/" + newVersion + "/"
                    + model.getFileName().replace(".csv", ".json");

            // create new version file
            DatasourceClient.getDefaultDatasourceClient().createFile(newVersionFilePath, json);

            // update the current version to new version
            model.setCurrentVersion(newVersion);
            ConfigBean.storeConfig(ConfigBean.getInstance());
            GenericUtil.reset(); // reset the configuration
            return newVersion;
        }
    }

    public static void main(String[] args) throws InvalidGrammarException, Exception {
        //       String requestBody = "{\"topicPath\":\"cs all volume|in-store experience|in-store - customer service\",\"newConstraints\":[{\"notWords\":\"\",\"andWords1\":\"\",\"andWords2\":\"\",\"keywords\":\"milk\"}]}";
        //       DiffResult result = new GrammarService().getDiff("ccc", "default", "csAllVolume", 1.0, requestBody, 1000);
        //       System.out.println(result.json);

        TopicGrammar grammar = TopicGrammarContainer.getTopicGrammar("csAllVolume", 1.0);
        TopicGrammarNode node = grammar.getNodeWithPath("cs all volume|digital|digital - in-store wi-fi access");
        System.out.println(JsonConvertor.getJson(node.getConstrainsts()));
        String json = JsonConvertor.getJson(node.getConstrainsts());

        Type collectionType = new TypeToken<List<Constraint>>() {
        }.getType();

        List<Constraint> constraints = JsonConvertor.getObjectFromJson(json, collectionType);
        node.setConstrainsts(constraints);
        ModelValidator.ModelValidationResult modelValidationResult = new ModelValidator().validateModel(grammar);
    }

}