001    /*
002     * To change this template, choose Tools | Templates
003     * and open the template in the editor.
004     */
005    package org.kuali.rice.krms.impl.repository;
006    
007    import java.util.ArrayList;
008    import java.util.LinkedHashMap;
009    import java.util.List;
010    import java.util.Map;
011    
012    import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
013    import org.kuali.rice.krms.api.repository.NaturalLanguageTree;
014    import org.kuali.rice.krms.api.repository.RuleManagementService;
015    import org.kuali.rice.krms.api.repository.TranslateBusinessMethods;
016    import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
017    import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition;
018    import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplate;
019    import org.kuali.rice.krms.api.repository.language.NaturalLanguageTemplaterContract;
020    import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition;
021    import org.kuali.rice.krms.api.repository.proposition.PropositionParameter;
022    import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType;
023    import org.kuali.rice.krms.api.repository.proposition.PropositionType;
024    import org.kuali.rice.krms.api.repository.rule.RuleDefinition;
025    import org.kuali.rice.krms.api.repository.term.TermDefinition;
026    import org.kuali.rice.krms.api.repository.term.TermParameterDefinition;
027    import org.kuali.rice.krms.api.repository.term.TermRepositoryService;
028    
029    /**
030     * @author nwright
031     */
032    public class TranslationUtility implements TranslateBusinessMethods {
033    
034        private RuleManagementService ruleManagementService;
035        private NaturalLanguageTemplaterContract templater;
036    
037        public TranslationUtility(RuleManagementService ruleManagementService,
038                NaturalLanguageTemplaterContract templater) {
039            this.ruleManagementService = ruleManagementService;
040            this.templater = templater;
041        }
042    
043        public RuleManagementService getRuleManagementService() {
044            return ruleManagementService;
045        }
046    
047        public void setRuleManagementService(RuleManagementService ruleManagementService) {
048            this.ruleManagementService = ruleManagementService;
049        }
050    
051        public NaturalLanguageTemplaterContract getTemplater() {
052            return templater;
053        }
054    
055        public void setTemplater(NaturalLanguageTemplaterContract templater) {
056            this.templater = templater;
057        }
058    
059        @Override
060        public String translateNaturalLanguageForObject(String naturalLanguageUsageId, String typeId, String krmsObjectId, String languageCode)
061                throws RiceIllegalArgumentException {
062    
063            PropositionDefinition proposition = null;
064            // TODO: find out what RICE intended for this typeId? Was it supposed to be the Simple Class name?
065            if (typeId.equals("proposition")) {
066                proposition = this.ruleManagementService.getProposition(krmsObjectId);
067                if (proposition == null) {
068                    throw new RiceIllegalArgumentException(krmsObjectId + " is not an Id for a proposition");
069                }
070            } else if (typeId.equals("agenda")) {
071                AgendaDefinition agenda = this.ruleManagementService.getAgenda(krmsObjectId);
072                if (agenda == null) {
073                    throw new RiceIllegalArgumentException(krmsObjectId + " is not an Id for an agenda");
074                }
075                if (agenda.getFirstItemId() == null) {
076                    throw new RiceIllegalArgumentException("Agenda has no first item");
077                }
078                AgendaItemDefinition item = this.ruleManagementService.getAgendaItem(agenda.getFirstItemId());
079                if (item.getRuleId() == null) {
080                    throw new RiceIllegalArgumentException("Only simple agenda's composed of one item that holds a rule is supported at this time");
081                }
082                RuleDefinition rule = this.ruleManagementService.getRule(item.getRuleId());
083                proposition = rule.getProposition();
084                if (proposition == null) {
085                    throw new RiceIllegalArgumentException("The agenda's rule has a proposition that is null");
086                }
087            }
088            String propositionTypeId = proposition.getTypeId();
089            NaturalLanguageTemplate naturalLanguageTemplate =
090                    this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
091                    propositionTypeId,
092                    naturalLanguageUsageId);
093            if (naturalLanguageTemplate == null) {
094                throw new RiceIllegalArgumentException("no template found for " + languageCode
095                        + " " + typeId
096                        + " " + naturalLanguageUsageId);
097            }
098            return this.translateNaturalLanguageForProposition(naturalLanguageUsageId, proposition, languageCode);
099        }
100    
101        @Override
102        public String translateNaturalLanguageForProposition(String naturalLanguageUsageId,
103                PropositionDefinition proposition, String languageCode)
104                throws RiceIllegalArgumentException {
105            NaturalLanguageTemplate naturalLanguageTemplate =
106                    this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
107                    proposition.getTypeId(), naturalLanguageUsageId);
108            if (naturalLanguageTemplate == null) {
109                throw new RiceIllegalArgumentException(languageCode + "." + proposition.getTypeId() + "." + naturalLanguageUsageId);
110            }
111            Map<String, Object> contextMap;
112            if (proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
113                contextMap = this.buildSimplePropositionContextMap(proposition);
114            } else {
115                contextMap = this.buildCompoundPropositionContextMap(null, proposition, null);
116            }
117            return templater.translate(naturalLanguageTemplate, contextMap);
118        }
119    
120        @Override
121        public NaturalLanguageTree translateNaturalLanguageTreeForProposition(String naturalLanguageUsageId,
122                PropositionDefinition proposition,
123                String languageCode) throws RiceIllegalArgumentException {
124            NaturalLanguageTemplate naturalLanguageTemplate = null;
125            //Continue if typeid is null, some children may not be initialized yet.
126            if (proposition.getTypeId() != null) {
127                naturalLanguageTemplate = this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
128                        proposition.getTypeId(), naturalLanguageUsageId);
129                if (naturalLanguageTemplate == null) {
130                    throw new RiceIllegalArgumentException(languageCode + "." + proposition.getTypeId() + "." + naturalLanguageUsageId);
131                }
132            }
133    
134            if (proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
135                NaturalLanguageTree.Builder tree = NaturalLanguageTree.Builder.create();
136                Map<String, Object> contextMap = this.buildSimplePropositionContextMap(proposition);
137                String naturalLanguage = templater.translate(naturalLanguageTemplate, contextMap);
138                tree.setNaturalLanguage(naturalLanguage);
139                return tree.build();
140            }
141            if (proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
142                NaturalLanguageTree.Builder tree = NaturalLanguageTree.Builder.create();
143                Map<String, Object> contextMap = this.buildCompoundPropositionContextMap(naturalLanguageUsageId, proposition, languageCode);
144                String naturalLanguage = templater.translate(naturalLanguageTemplate, contextMap);
145                tree.setNaturalLanguage(naturalLanguage);
146    
147                //Null check because newly created compound propositions should also be translateable.
148                if(proposition.getCompoundComponents()!=null){
149                    List<NaturalLanguageTree> children = new ArrayList<NaturalLanguageTree>();
150                    for (PropositionDefinition child : proposition.getCompoundComponents()) {
151                        children.add(this.translateNaturalLanguageTreeForProposition(naturalLanguageUsageId, child, languageCode));
152                    }
153                    tree.setChildren(children);
154                }
155    
156                return tree.build();
157            }
158            throw new RiceIllegalArgumentException("Unknown proposition type: " + proposition.getPropositionTypeCode());
159        }
160    
161        protected Map<String, Object> buildSimplePropositionContextMap(PropositionDefinition proposition) {
162            if (!proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
163                throw new RiceIllegalArgumentException("proposition is not simple " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
164            }
165            Map<String, Object> contextMap = new LinkedHashMap<String, Object>();
166            for (PropositionParameter param : proposition.getParameters()) {
167                if (param.getParameterType().equals(PropositionParameterType.TERM.getCode())) {
168                    if (param.getTermValue() != null) {
169                        for (TermParameterDefinition termParam : param.getTermValue().getParameters()) {
170                            contextMap.put(termParam.getName(), termParam.getValue());
171                        }
172                    } else {
173                        contextMap.put(param.getParameterType(), param.getValue());
174                    }
175                } else {
176                    contextMap.put(param.getParameterType(), param.getValue());
177                }
178            }
179            return contextMap;
180        }
181        public static final String COMPOUND_COMPONENTS = "compoundComponent";
182    
183        protected Map<String, Object> buildCompoundPropositionContextMap(String naturalLanguageUsageId, PropositionDefinition proposition, String languageCode) {
184            if (!proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
185                throw new RiceIllegalArgumentException("proposition us not compound " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
186            }
187            Map<String, Object> contextMap = new LinkedHashMap<String, Object>();
188            /*List<String> children = new ArrayList<String>();
189             for (PropositionDefinition param : proposition.getCompoundComponents()) {
190             children.add(this.translateNaturalLanguageForProposition(naturalLanguageUsageId, proposition, languageCode));
191             }
192             contextMap.put(COMPOUND_COMPONENTS, children);*/
193            return contextMap;
194        }
195    
196        protected String translateCompoundProposition(PropositionDefinition proposition, String naturalLanguageUsageId, String languageCode)
197                throws RiceIllegalArgumentException {
198            if (!proposition.getPropositionTypeCode().equals(PropositionType.COMPOUND.getCode())) {
199                throw new RiceIllegalArgumentException("proposition us not compound " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
200            }
201            String compoundNaturalLanguageTypeId = this.calcCompoundNaturalLanguageTypeId(proposition.getCompoundOpCode());
202            // TODO: make sure we cache the AND and OR templates
203            NaturalLanguageTemplate template = this.ruleManagementService.findNaturalLanguageTemplateByLanguageCodeTypeIdAndNluId(languageCode,
204                    compoundNaturalLanguageTypeId, naturalLanguageUsageId);
205            Map<String, Object> contextMap = this.buildCompoundPropositionContextMap(naturalLanguageUsageId, proposition, languageCode);
206            return this.templater.translate(template, contextMap);
207    
208        }
209    
210        protected String calcCompoundNaturalLanguageTypeId(String compoundOpCode) throws RiceIllegalArgumentException {
211            if (compoundOpCode.equals("a")) {
212                return "kuali.compound.proposition.op.code." + "and";
213            }
214            if (compoundOpCode.equals("o")) {
215                return "kuali.compound.proposition.op.code." + "or";
216            }
217            throw new RiceIllegalArgumentException("unsupported compound op code " + compoundOpCode);
218        }
219    
220        protected String translateSimpleProposition(NaturalLanguageTemplate naturalLanguageTemplate,
221                PropositionDefinition proposition)
222                throws RiceIllegalArgumentException {
223            if (!proposition.getPropositionTypeCode().equals(PropositionType.SIMPLE.getCode())) {
224                throw new RiceIllegalArgumentException("proposition not simple " + proposition.getPropositionTypeCode() + " " + proposition.getId() + proposition.getDescription());
225            }
226            Map<String, Object> contextMap = this.buildSimplePropositionContextMap(proposition);
227            return templater.translate(naturalLanguageTemplate, contextMap);
228        }
229    }