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.kew.impl.rule;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.apache.log4j.Logger;
021import org.joda.time.DateTime;
022import org.kuali.rice.core.api.criteria.CriteriaLookupService;
023import org.kuali.rice.core.api.criteria.GenericQueryResults;
024import org.kuali.rice.core.api.criteria.LookupCustomizer;
025import org.kuali.rice.core.api.criteria.Predicate;
026import org.kuali.rice.core.api.criteria.QueryByCriteria;
027import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
028import org.kuali.rice.core.api.exception.RiceIllegalStateException;
029import org.kuali.rice.core.api.util.jaxb.DateTimeAdapter;
030import org.kuali.rice.kew.api.KewApiServiceLocator;
031import org.kuali.rice.kew.api.doctype.DocumentTypeService;
032import org.kuali.rice.kew.api.rule.Rule;
033import org.kuali.rice.kew.api.rule.RuleDelegation;
034import org.kuali.rice.kew.api.rule.RuleQueryResults;
035import org.kuali.rice.kew.api.rule.RuleReportCriteria;
036import org.kuali.rice.kew.api.rule.RuleResponsibility;
037import org.kuali.rice.kew.api.rule.RuleService;
038import org.kuali.rice.kew.api.rule.RuleTemplate;
039import org.kuali.rice.kew.api.rule.RuleTemplateQueryResults;
040import org.kuali.rice.kew.doctype.bo.DocumentType;
041import org.kuali.rice.kew.rule.RuleBaseValues;
042import org.kuali.rice.kew.rule.RuleDelegationBo;
043import org.kuali.rice.kew.rule.RuleResponsibilityBo;
044import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
045import org.kuali.rice.kew.service.KEWServiceLocator;
046import org.kuali.rice.kim.impl.common.attribute.AttributeTransform;
047import org.kuali.rice.krad.service.BusinessObjectService;
048
049import javax.jws.WebParam;
050import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
051import java.sql.Timestamp;
052import java.util.ArrayList;
053import java.util.Calendar;
054import java.util.Collection;
055import java.util.Collections;
056import java.util.HashMap;
057import java.util.List;
058import java.util.Map;
059
060import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
061import static org.kuali.rice.core.api.criteria.PredicateFactory.and;
062
063/**
064 *
065 * @author Kuali Rice Team (rice.collab@kuali.org)
066 *
067 */
068public class RuleServiceImpl implements RuleService {
069    private static final Logger LOG = Logger.getLogger(RuleServiceImpl.class);
070    //private RuleDAO ruleDAO;
071    private BusinessObjectService businessObjectService;
072    private CriteriaLookupService criteriaLookupService;
073
074    @Override
075    public Rule getRule(String id) throws RiceIllegalArgumentException, RiceIllegalStateException{
076        incomingParamCheck("id", id);
077        Map<String, String> criteria = Collections.singletonMap("id", id);
078        RuleBaseValues rbv = this.businessObjectService.findByPrimaryKey(RuleBaseValues.class, criteria);
079        if (rbv == null) {
080            throw new RiceIllegalStateException("Rule with specified id: " + id + " does not exist");
081        }
082        return RuleBaseValues.to(rbv);
083    }
084
085    @Override
086    public Rule getRuleByName(String name) {
087        incomingParamCheck("name", name);
088        Map<String, Object> criteria = new HashMap<String, Object>(2);
089        criteria.put("name", name);
090        criteria.put("currentInd", Boolean.TRUE);
091        RuleBaseValues rbv = this.businessObjectService.findByPrimaryKey(RuleBaseValues.class, criteria);
092        if (rbv == null) {
093            throw new RiceIllegalStateException("Rule with specified name: " + name + " does not exist");
094        }
095        return RuleBaseValues.to(rbv);
096    }
097
098    @Override
099    public List<Rule> getRulesByTemplateId(
100            @WebParam(name = "templateId") String templateId) throws RiceIllegalArgumentException {
101        incomingParamCheck("templateId", templateId);
102        Map<String, Object> criteria = new HashMap<String, Object>();
103        criteria.put("ruleTemplateId", templateId);
104        criteria.put("currentInd", Boolean.TRUE);
105        Collection<RuleBaseValues> ruleValues = this.businessObjectService.findMatching(RuleBaseValues.class, criteria);
106
107        final List<Rule> rules = new ArrayList<Rule>();
108        for (RuleBaseValues bo : ruleValues) {
109            rules.add(Rule.Builder.create(bo).build());
110        }
111        return rules;
112    }
113
114    @Override
115    public List<Rule> getRulesByTemplateNameAndDocumentTypeName(String templateName, String documentTypeName) {
116        return getRulesByTemplateNameAndDocumentTypeNameAndEffectiveDate(templateName, documentTypeName, null);
117    }
118
119    @Override
120    public List<Rule> getRulesByTemplateNameAndDocumentTypeNameAndEffectiveDate(String templateName, String documentTypeName,
121            DateTime effectiveDate)
122            throws RiceIllegalArgumentException {
123        QueryByCriteria.Builder query = QueryByCriteria.Builder.create();
124        List<Predicate> predicates = new ArrayList<Predicate>();
125        predicates.add(equal("ruleTemplate.name", templateName));
126
127        // Check all document types in ancestry
128        DocumentTypeService documentTypeService = KewApiServiceLocator.getDocumentTypeService();
129        org.kuali.rice.kew.api.doctype.DocumentType dt = documentTypeService.getDocumentTypeByName(documentTypeName);
130        List<String> documentTypeAncestryNames = new ArrayList<String>();
131        while (dt != null) {
132            documentTypeAncestryNames.add(dt.getName());
133            dt = dt.getParentId() == null ? null : documentTypeService.getDocumentTypeById(dt.getParentId());
134        }
135        predicates.add(in("docTypeName", documentTypeAncestryNames.toArray(
136                new String[documentTypeAncestryNames.size()])));
137        DateTime currentTime = new DateTime();
138        predicates.add(and(
139                           or(isNull("fromDateValue"), lessThanOrEqual("fromDateValue", currentTime)),
140                           or(isNull("toDateValue"), greaterThan("toDateValue", currentTime))
141                      ));
142        predicates.add(equal("active", new Integer(1))); //true
143        predicates.add(equal("delegateRule", new Integer(0)));  //false
144        predicates.add(equal("templateRuleInd", new Integer(0))); //false
145        if (effectiveDate != null) {
146            predicates.add(
147                    and(
148                        or(isNull("activationDate"), lessThanOrEqual("activationDate", effectiveDate)),
149                        or(isNull("deactivationDate"), greaterThan("deactivationDate", effectiveDate))
150                    ));
151        } else {
152            predicates.add(equal("currentInd", new Integer(1))); //true
153        }
154        Predicate p = and(predicates.toArray(new Predicate[]{}));
155        query.setPredicates(p);
156        return KewApiServiceLocator.getRuleService().findRules(query.build()).getResults();
157    }
158
159    @Override
160    public RuleQueryResults findRules(QueryByCriteria queryByCriteria) {
161        if (queryByCriteria == null) {
162            throw new RiceIllegalArgumentException("queryByCriteria is null");
163        }
164
165        LookupCustomizer.Builder<RuleBaseValues> lc = LookupCustomizer.Builder.create();
166        lc.setPredicateTransform(AttributeTransform.getInstance());
167
168        GenericQueryResults<RuleBaseValues> results = criteriaLookupService.lookup(RuleBaseValues.class, queryByCriteria, lc.build());
169
170        RuleQueryResults.Builder builder = RuleQueryResults.Builder.create();
171        builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
172        builder.setTotalRowCount(results.getTotalRowCount());
173
174        final List<Rule.Builder> ims = new ArrayList<Rule.Builder>();
175        for (RuleBaseValues bo : results.getResults()) {
176            ims.add(Rule.Builder.create(RuleBaseValues.to(bo)));
177        }
178
179        builder.setResults(ims);
180        return builder.build();
181    }
182
183    @Override
184    public List<Rule> ruleReport(RuleReportCriteria ruleReportCriteria) {
185        incomingParamCheck(ruleReportCriteria, "ruleReportCriteria");
186        if ( LOG.isDebugEnabled() ) {
187                LOG.debug("Executing rule report [responsibleUser=" + ruleReportCriteria.getResponsiblePrincipalId() + ", responsibleWorkgroup=" +
188                    ruleReportCriteria.getResponsibleGroupId() + "]");
189        }
190        Collection<RuleBaseValues> rulesFound = KEWServiceLocator.getRuleService().searchByTemplate(
191                ruleReportCriteria.getDocumentTypeName(), ruleReportCriteria.getRuleTemplateName(),
192                ruleReportCriteria.getRuleDescription(), ruleReportCriteria.getResponsibleGroupId(),
193                ruleReportCriteria.getResponsiblePrincipalId(), Boolean.valueOf(ruleReportCriteria.isConsiderGroupMembership()),
194                Boolean.valueOf(ruleReportCriteria.isIncludeDelegations()), Boolean.valueOf(ruleReportCriteria.isActive()), ruleReportCriteria.getRuleExtensions(),
195                ruleReportCriteria.getActionRequestCodes());
196        List<org.kuali.rice.kew.api.rule.Rule> returnableRules = new ArrayList<Rule>(rulesFound.size());
197        for (RuleBaseValues rule : rulesFound) {
198            returnableRules.add(RuleBaseValues.to(rule));
199        }
200        return returnableRules;
201    }
202
203    @Override
204    public RuleTemplate getRuleTemplate(@WebParam(name = "id") String id) {
205        incomingParamCheck("id", id);
206        Map<String, String> criteria = Collections.singletonMap("id", id);
207        RuleTemplateBo template = this.businessObjectService.findByPrimaryKey(RuleTemplateBo.class, criteria);
208        if (template == null) {
209            throw new RiceIllegalStateException("RuleTemplate with specified id: " + id + " does not exist");
210        }
211        return RuleTemplateBo.to(template);
212    }
213
214    @Override
215    public RuleTemplate getRuleTemplateByName(@WebParam(name = "name") String name) {
216        incomingParamCheck("name", name);
217        Map<String, Object> criteria = new HashMap<String, Object>(2);
218        criteria.put("name", name);
219        RuleTemplateBo template = this.businessObjectService.findByPrimaryKey(RuleTemplateBo.class, criteria);
220        if (template == null) {
221            throw new RiceIllegalStateException("RuleTemplate with specified name: " + name + " does not exist");
222        }
223        return RuleTemplateBo.to(template);
224    }
225
226    @Override
227    public RuleTemplateQueryResults findRuleTemplates(
228            @WebParam(name = "query") QueryByCriteria queryByCriteria) throws RiceIllegalArgumentException {
229        if (queryByCriteria == null) {
230            throw new RiceIllegalArgumentException("queryByCriteria is null");
231        }
232
233        LookupCustomizer.Builder<RuleTemplateBo> lc = LookupCustomizer.Builder.create();
234        lc.setPredicateTransform(AttributeTransform.getInstance());
235
236        GenericQueryResults<RuleTemplateBo> results = criteriaLookupService.lookup(RuleTemplateBo.class, queryByCriteria, lc.build());
237
238        RuleTemplateQueryResults.Builder builder = RuleTemplateQueryResults.Builder.create();
239        builder.setMoreResultsAvailable(results.isMoreResultsAvailable());
240        builder.setTotalRowCount(results.getTotalRowCount());
241
242        final List<RuleTemplate.Builder> ims = new ArrayList<RuleTemplate.Builder>();
243        for (RuleTemplateBo bo : results.getResults()) {
244            ims.add(RuleTemplate.Builder.create(RuleTemplateBo.to(bo)));
245        }
246
247        builder.setResults(ims);
248        return builder.build();
249    }
250
251    @Override
252    public RuleResponsibility getRuleResponsibility(String responsibilityId) {
253        incomingParamCheck("responsibilityId", responsibilityId);
254        Map<String, String> criteria = Collections.singletonMap("responsibilityId", responsibilityId);
255        RuleResponsibilityBo responsibility = this.businessObjectService.findByPrimaryKey(RuleResponsibilityBo.class, criteria);
256        if (responsibility == null) {
257            throw new RiceIllegalStateException("RuleResponsibility with specified id: " + responsibilityId + " does not exist");
258        }
259        return RuleResponsibilityBo.to(responsibility);
260    }
261
262    @Override
263    public List<RuleDelegation> getRuleDelegationsByResponsibiltityId(
264            @WebParam(name = "id") String id) throws RiceIllegalArgumentException, RiceIllegalStateException {
265        incomingParamCheck("id", id);
266        Map<String, Object> criteria = new HashMap<String, Object>(2);
267        criteria.put("responsibilityId", id);
268        criteria.put("delegationRule.currentInd", Boolean.TRUE);
269        Collection<RuleDelegationBo> delegations = this.businessObjectService.findMatching(RuleDelegationBo.class,
270                criteria);
271        List<RuleDelegation> ruleDelegations = new ArrayList<RuleDelegation>();
272        if (CollectionUtils.isNotEmpty(delegations)) {
273            for (RuleDelegationBo bo : delegations) {
274                ruleDelegations.add(RuleDelegationBo.to(bo));
275            }
276        }
277
278        return ruleDelegations;
279
280    }
281
282    private void incomingParamCheck(Object object, String name) {
283        if (object == null) {
284            throw new RiceIllegalArgumentException(name + " was null");
285        } else if (object instanceof String
286                && StringUtils.isBlank((String) object)) {
287            throw new RiceIllegalArgumentException(name + " was blank");
288        }
289    }
290
291    public BusinessObjectService getBusinessObjectService() {
292        return this.businessObjectService;
293    }
294
295    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
296        this.businessObjectService = businessObjectService;
297    }
298
299    public CriteriaLookupService getCriteriaLookupService() {
300        return this.criteriaLookupService;
301    }
302
303    public void setCriteriaLookupService(CriteriaLookupService criteriaLookupService) {
304        this.criteriaLookupService = criteriaLookupService;
305    }
306}