001/**
002 * Copyright 2005-2017 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.ui;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.kuali.rice.core.api.criteria.QueryByCriteria;
021import org.kuali.rice.core.api.criteria.QueryResults;
022import org.kuali.rice.core.api.util.ConcreteKeyValue;
023import org.kuali.rice.core.api.util.KeyValue;
024import org.kuali.rice.krad.service.KRADServiceLocator;
025import org.kuali.rice.krad.uif.control.UifKeyValuesFinderBase;
026import org.kuali.rice.krad.uif.view.ViewModel;
027import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
028import org.kuali.rice.krms.impl.repository.CategoryBo;
029import org.kuali.rice.krms.impl.repository.ContextValidTermBo;
030import org.kuali.rice.krms.impl.repository.PropositionBo;
031import org.kuali.rice.krms.impl.repository.TermBo;
032import org.kuali.rice.krms.impl.repository.TermResolverBo;
033import org.kuali.rice.krms.impl.repository.TermSpecificationBo;
034import org.kuali.rice.krms.impl.util.KrmsImplConstants;
035
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.HashMap;
039import java.util.List;
040import java.util.Map;
041
042/**
043 * ValuesFinder used to populate the list of available Terms when creating/editing a proposition in a
044 * KRMS Rule.
045 *
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 */
048public class ValidTermsValuesFinder extends UifKeyValuesFinderBase {
049
050    /**
051     * get the value list for the Term dropdown in the KRMS rule editing UI
052     * @param model
053     * @return
054     */
055    @Override
056    public List<KeyValue> getKeyValues(ViewModel model) {
057        List<KeyValue> keyValues = new ArrayList<KeyValue>();
058
059        MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model;
060        AgendaEditor agendaEditor = ((AgendaEditor) maintenanceForm.getDocument().getNewMaintainableObject().getDataObject());
061        String contextId = agendaEditor.getAgenda().getContextId();
062
063        String selectedPropId = agendaEditor.getSelectedPropositionId();
064
065        PropositionBo rootProposition = agendaEditor.getAgendaItemLine().getRule().getProposition();
066        PropositionBo editModeProposition = findPropositionUnderEdit(rootProposition);
067        String selectedCategoryId = (editModeProposition != null) ? editModeProposition.getCategoryId() : null;
068
069        // Get all valid terms
070
071        QueryByCriteria criteria = QueryByCriteria.Builder.forAttribute("contextId", contextId).build();
072
073        Collection<ContextValidTermBo> contextValidTerms =
074                KRADServiceLocator.getDataObjectService().findMatching(ContextValidTermBo.class, criteria).getResults();
075
076        List<String> termSpecIds = new ArrayList();
077        for (ContextValidTermBo validTerm : contextValidTerms) {
078            termSpecIds.add(validTerm.getTermSpecificationId());
079        }
080
081        if (termSpecIds.size() > 0) { // if we don't have any valid terms, skip it
082            QueryResults<TermBo> terms = null;
083            Map<String,Object> critMap = new HashMap<String,Object>();
084            critMap.put("specificationId", termSpecIds);
085            QueryByCriteria.Builder critBuilder = QueryByCriteria.Builder.forAttribute("specificationId", termSpecIds);
086            critBuilder.setOrderByAscending("description");
087
088            terms = KRADServiceLocator.getDataObjectService().findMatching(TermBo.class, critBuilder.build());
089
090            // add all terms that are in the selected category (or else add 'em all if no category is selected)
091            if (!CollectionUtils.isEmpty(terms.getResults())) for (TermBo term : terms.getResults()) {
092                String selectName = term.getDescription();
093
094                if (StringUtils.isBlank(selectName) || "null".equals(selectName)) {
095                    selectName = term.getSpecification().getName();
096                }
097
098                if (!StringUtils.isBlank(selectedCategoryId)) {
099                    // only add if the term has the selected category
100                    if (isTermSpecificationInCategory(term.getSpecification(), selectedCategoryId)) {
101                        keyValues.add(new ConcreteKeyValue(term.getId(), selectName));
102                    }
103                } else {
104                    keyValues.add(new ConcreteKeyValue(term.getId(), selectName));
105                }
106            }
107
108            //
109            // Add Parameterized Term Specs
110            //
111
112            // get term resolvers for the given term specs
113            QueryByCriteria.Builder termResolverCritBuilder = QueryByCriteria.Builder.forAttribute("outputId", termSpecIds);
114            termResolverCritBuilder.setOrderByAscending("name");
115            QueryResults<TermResolverBo> termResolvers =
116                    KRADServiceLocator.getDataObjectService().findMatching(TermResolverBo.class, termResolverCritBuilder.build());
117
118            // TODO: what if there is more than one resolver for a given term specification?
119
120            if (termResolvers.getResults() != null) for (TermResolverBo termResolver : termResolvers.getResults()) {
121                if (!CollectionUtils.isEmpty(termResolver.getParameterSpecifications())) {
122                    TermSpecificationBo output = termResolver.getOutput();
123
124                    // filter by category
125                    if (StringUtils.isBlank(selectedCategoryId) ||
126                            isTermSpecificationInCategory(output, selectedCategoryId)) {
127                        String outputDescription = StringUtils.isBlank(output.getDescription())?output.getName():
128                                                                                                                                                                        output.getDescription();
129                        // we use a special prefix to differentiate these, as they are term spec ids instead of term ids.
130                        keyValues.add(new ConcreteKeyValue(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX
131                                + output.getId(), outputDescription
132                                // build a string that indicates the number of parameters
133                                + "(" + StringUtils.repeat("_", ",", termResolver.getParameterSpecifications().size()) +")"));
134                    }
135                }
136            }
137        }
138
139        return keyValues;
140    }
141
142    /**
143     * @return true if the term specification is in the given category
144     */
145    private boolean isTermSpecificationInCategory(TermSpecificationBo termSpec, String categoryId) {
146        if (termSpec.getCategories() != null) {
147            for (CategoryBo category : termSpec.getCategories()) {
148                if (categoryId.equals(category.getId())) {
149                    return true;
150                }
151            }
152        }
153
154        return false;
155    }
156
157    /**
158     * helper method to find the proposition under edit
159     */
160    private PropositionBo findPropositionUnderEdit(PropositionBo currentProposition) {
161        PropositionBo result = null;
162        if (currentProposition.getEditMode()) {
163            result = currentProposition;
164        } else {
165            if (currentProposition.getCompoundComponents() != null) {
166                for (PropositionBo child : currentProposition.getCompoundComponents()) {
167                    result = findPropositionUnderEdit(child);
168                    if (result != null) break;
169                }
170            }
171        }
172
173        return result;
174    }
175
176}