001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.impl.repository.language;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.velocity.exception.VelocityException;
020import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplate;
021import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplaterContract;
022import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
023import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinitionContract;
024import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
025import org.kuali.rice.krms.impl.repository.KrmsTypeRepositoryServiceImpl;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * This class translates requirement components into a specific
035 * natural language. This class is not thread safe.
036 */
037public class PropositionNaturalLanguageTemplater implements NaturalLanguageTemplaterContract {
038    /**
039     * SLF4J logging framework
040     */
041    private final static Logger logger = LoggerFactory.getLogger(PropositionNaturalLanguageTemplater.class);
042
043    private TranslationContextRegistry<TranslationContext> translationContextRegistry;
044
045    private KrmsTypeRepositoryService krmsTypeRepositoryService = new KrmsTypeRepositoryServiceImpl();
046
047    /**
048     * Relational operator token.
049     */
050    public final static String OPERATOR_TOKEN = "relationalOperator";
051    /**
052     * An integer value token.
053     */
054    public final static String CONSTANT_VALUE_TOKEN = "intValue";
055
056    /**
057     * Velocity template engine.
058     */
059    private VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();
060
061
062    /**
063     * Constructs a new proposition natural language templater.
064     */
065    public PropositionNaturalLanguageTemplater() {
066    }
067
068
069    /**
070     * Sets the template context registry.
071     *
072     * @param translationContextRegistry Template context registry
073     */
074    public void setTranslationContextRegistry(
075            final TranslationContextRegistry<TranslationContext> translationContextRegistry) {
076        this.translationContextRegistry = translationContextRegistry;
077    }
078
079    public String translate(NaturalLanguageTemplate naturalLanguageTemplate, Map<String, Object> parametersMap) {
080
081        if (naturalLanguageTemplate == null) {
082            return StringUtils.EMPTY;
083        }
084
085        Map<String, Object> contextMap = null;
086        try {
087            contextMap = buildContextMap(naturalLanguageTemplate.getTypeId(), parametersMap);
088        } catch (Exception e) {
089            e.printStackTrace();  //TODO hand back to service.
090        }
091
092        try {
093            String nl = this.templateEngine.evaluate(contextMap, naturalLanguageTemplate.getTemplate());
094            if (logger.isInfoEnabled()) {
095                logger.info("nl=" + nl);
096            }
097            return nl;
098        } catch (VelocityException e) {
099            String msg = "Generating template for proposition failed: template='" + naturalLanguageTemplate.getTemplate() + "', contextMap=" + contextMap;
100            logger.error(msg, e);
101            //TODO hand back to service throw new Exception(msg);
102        }
103        return "Error";
104    }
105
106    /**
107     * Builds a proposition type context map.
108     *
109     * @param typeId        the natural language template id
110     * @param parametersMap map containing the proposition parameter types and their values
111     * @throws java.lang.Exception Creating context map failed
112     */
113    private Map<String, Object> buildContextMap(String typeId, Map<String, Object> parametersMap) throws Exception {
114
115        Map<String, Object> contextMap = new HashMap<String, Object>();
116        //Add proposition constant to contextMap.
117        if (parametersMap.containsKey(PropositionParameterType.CONSTANT.getCode())) {
118            contextMap.put(CONSTANT_VALUE_TOKEN, (String) parametersMap.get(PropositionParameterType.CONSTANT.getCode()));
119        }
120        //Add proposition operator to contextMap.
121        if (parametersMap.containsKey(PropositionParameterType.OPERATOR.getCode())) {
122            contextMap.put(OPERATOR_TOKEN, (String) parametersMap.get(PropositionParameterType.OPERATOR.getCode()));
123        }
124        //Access type service to retrieve type name.
125        KrmsTypeDefinitionContract type = getKrmsTypeRepositoryService().getTypeById(typeId);
126        List<TranslationContext> translationContextList = this.translationContextRegistry.get(type.getName());
127        if (translationContextList == null || translationContextList.isEmpty()) {
128            return contextMap;
129        }
130
131        for (TranslationContext translationContext : translationContextList) {
132            Map<String, Object> cm = translationContext.createContextMap(parametersMap);
133            contextMap.putAll(cm);
134        }
135
136        if (logger.isInfoEnabled()) {
137            logger.info("contextMap=" + contextMap);
138        }
139        return contextMap;
140    }
141
142
143    private KrmsTypeRepositoryService getKrmsTypeRepositoryService() {
144        return krmsTypeRepositoryService;
145    }
146
147    public void setKrmsTypeRepositoryService(KrmsTypeRepositoryService krmsTypeRepositoryService) {
148        this.krmsTypeRepositoryService = krmsTypeRepositoryService;
149    }
150
151}