001/**
002 * Copyright 2005-2015 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.api.rule;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.commons.lang.StringUtils;
020import org.joda.time.DateTime;
021import org.kuali.rice.core.api.CoreConstants;
022import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
023import org.kuali.rice.core.api.mo.ModelBuilder;
024import org.kuali.rice.core.api.util.jaxb.DateTimeAdapter;
025import org.kuali.rice.kew.api.KewApiConstants;
026import org.w3c.dom.Element;
027
028import javax.xml.bind.annotation.XmlAccessType;
029import javax.xml.bind.annotation.XmlAccessorType;
030import javax.xml.bind.annotation.XmlAnyElement;
031import javax.xml.bind.annotation.XmlElement;
032import javax.xml.bind.annotation.XmlElementWrapper;
033import javax.xml.bind.annotation.XmlRootElement;
034import javax.xml.bind.annotation.XmlType;
035import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
036import java.io.Serializable;
037import java.util.ArrayList;
038import java.util.Collection;
039import java.util.Collections;
040import java.util.HashMap;
041import java.util.List;
042import java.util.Map;
043
044@XmlRootElement(name = Rule.Constants.ROOT_ELEMENT_NAME)
045@XmlAccessorType(XmlAccessType.NONE)
046@XmlType(name = Rule.Constants.TYPE_NAME, propOrder = {
047    Rule.Elements.ID,
048    Rule.Elements.NAME,
049    Rule.Elements.RULE_TEMPLATE,
050    Rule.Elements.ACTIVE,
051    Rule.Elements.DESCRIPTION,
052    Rule.Elements.DOC_TYPE_NAME,
053    Rule.Elements.FROM_DATE,
054    Rule.Elements.TO_DATE,
055    Rule.Elements.FORCE_ACTION,
056    Rule.Elements.PREVIOUS_VERSION_ID,
057    Rule.Elements.RULE_RESPONSIBILITIES,
058    Rule.Elements.RULE_EXTENSIONS,
059    Rule.Elements.RULE_TEMPLATE_NAME,
060    Rule.Elements.RULE_EXPRESSION_DEF,
061    Rule.Elements.FROM_DATE_VALUE,
062    Rule.Elements.TO_DATE_VALUE,
063    CoreConstants.CommonElements.FUTURE_ELEMENTS
064})
065public final class Rule
066    extends AbstractDataTransferObject
067    implements RuleContract
068{
069    @XmlElement(name = Elements.ID, required = false)
070    private final String id;
071
072    @XmlElement(name = Elements.NAME, required = false)
073    private final String name;
074
075    @XmlElement(name = Elements.RULE_TEMPLATE, required = false)
076    private final RuleTemplate ruleTemplate;
077
078    @XmlElement(name = Elements.ACTIVE, required = false)
079    private final boolean active;
080
081    @XmlElement(name = Elements.DESCRIPTION, required = false)
082    private final String description;
083
084    @XmlElement(name = Elements.DOC_TYPE_NAME, required = false)
085    private final String docTypeName;
086
087    @Deprecated
088    @XmlElement(name = Elements.FROM_DATE, required = false)
089    private final DateTime fromDate;
090
091    @Deprecated
092    @XmlElement(name = Elements.TO_DATE, required = false)
093    private final DateTime toDate;
094
095    @XmlElement(name = Elements.FROM_DATE_VALUE, required = false)
096    @XmlJavaTypeAdapter(DateTimeAdapter.class)
097    private final DateTime fromDateValue;
098
099    @XmlElement(name = Elements.TO_DATE_VALUE, required = false)
100    @XmlJavaTypeAdapter(DateTimeAdapter.class)
101    private final DateTime toDateValue;
102
103    @XmlElement(name = Elements.FORCE_ACTION, required = false)
104    private final boolean forceAction;
105
106    @XmlElement(name = Elements.PREVIOUS_VERSION_ID, required = false)
107    private final String previousRuleId;
108
109    @XmlElementWrapper(name = Elements.RULE_RESPONSIBILITIES, required = false)
110    @XmlElement(name = Elements.RULE_RESPONSIBILITY, required = false)
111    private final List<RuleResponsibility> ruleResponsibilities;
112
113    @XmlElementWrapper(name = Elements.RULE_EXTENSIONS, required = false)
114    @XmlElement(name = Elements.RULE_EXTENSION, required = false)
115    private final List<RuleExtension> ruleExtensions;
116
117    @XmlElement(name = Elements.RULE_TEMPLATE_NAME, required = false)
118    private final String ruleTemplateName;
119
120    @XmlElement(name = Elements.RULE_EXPRESSION_DEF, required = false)
121    private final RuleExpression ruleExpressionDef;
122
123    @SuppressWarnings("unused")
124    @XmlAnyElement
125    private final Collection<Element> _futureElements = null;
126
127    /**
128     * Private constructor used only by JAXB.
129     * 
130     */
131    private Rule() {
132        this.id = null;
133        this.name = null;
134        this.ruleTemplate = null;
135        this.active = false;
136        this.description = null;
137        this.docTypeName = null;
138        this.fromDate = null;
139        this.toDate = null;
140        this.fromDateValue = null;
141        this.toDateValue = null;
142        this.forceAction = false;
143        this.ruleResponsibilities = null;
144        this.ruleExtensions = null;
145        this.ruleTemplateName = null;
146        this.ruleExpressionDef = null;
147        this.previousRuleId = null;
148    }
149
150    private Rule(Builder builder) {
151        this.id = builder.getId();
152        this.name = builder.getName();
153        this.ruleTemplate = builder.getRuleTemplate() == null ? null : builder.getRuleTemplate().build();
154        this.active = builder.isActive();
155        this.description = builder.getDescription();
156        this.docTypeName = builder.getDocTypeName();
157        this.fromDate = builder.getFromDate();
158        this.toDate = builder.getToDate();
159        this.fromDateValue = builder.getFromDate();
160        this.toDateValue = builder.getToDate();
161        this.forceAction = builder.isForceAction();
162        if (CollectionUtils.isNotEmpty(builder.getRuleResponsibilities())) {
163            List<RuleResponsibility> responsibilities = new ArrayList<RuleResponsibility>();
164            for (RuleResponsibility.Builder b : builder.getRuleResponsibilities()) {
165                responsibilities.add(b.build());
166            }
167            this.ruleResponsibilities = responsibilities;
168        } else {
169            this.ruleResponsibilities = Collections.emptyList();
170        }
171        if (CollectionUtils.isNotEmpty(builder.getRuleExtensions())) {
172            List<RuleExtension> extensions = new ArrayList<RuleExtension>();
173            for (RuleExtension.Builder b : builder.getRuleExtensions()) {
174                extensions.add(b.build());
175            }
176            this.ruleExtensions = extensions;
177        } else {
178            this.ruleExtensions = Collections.emptyList();
179        }
180        this.ruleTemplateName = builder.getRuleTemplateName();
181        this.ruleExpressionDef = builder.getRuleExpressionDef() == null ? null : builder.getRuleExpressionDef().build();
182        this.previousRuleId = builder.getPreviousRuleId();
183    }
184
185    @Override
186    public String getId() {
187        return this.id;
188    }
189
190    @Override
191    public String getName() {
192        return this.name;
193    }
194
195    @Override
196    public RuleTemplate getRuleTemplate() {
197        return this.ruleTemplate;
198    }
199
200    @Override
201    public boolean isActive() {
202        return this.active;
203    }
204
205    @Override
206    public String getDescription() {
207        return this.description;
208    }
209
210    @Override
211    public String getPreviousRuleId() {
212        return this.previousRuleId;
213    }
214
215    @Override
216    public String getDocTypeName() {
217        return this.docTypeName;
218    }
219
220    @Override
221    public DateTime getFromDate() {
222        return this.fromDateValue == null ? this.fromDate : this.fromDateValue;
223    }
224
225    @Override
226    public DateTime getToDate() {
227        return this.toDateValue == null ? this.toDate : this.toDateValue;
228    }
229
230    @Override
231    public boolean isForceAction() {
232        return this.forceAction;
233    }
234
235    @Override
236    public List<RuleResponsibility> getRuleResponsibilities() {
237        return this.ruleResponsibilities;
238    }
239
240    @Override
241    public List<RuleExtension> getRuleExtensions() {
242        return this.ruleExtensions;
243    }
244
245    public Map<String, String> getRuleExtensionMap() {
246        Map<String, String> extensions = new HashMap<String, String>();
247        for (RuleExtension ext : this.getRuleExtensions()) {
248            extensions.putAll(ext.getExtensionValuesMap());
249        }
250        return Collections.unmodifiableMap(extensions);
251    }
252
253    @Override
254    public String getRuleTemplateName() {
255        return this.ruleTemplateName;
256    }
257
258    @Override
259    public RuleExpression getRuleExpressionDef() {
260        return this.ruleExpressionDef;
261    }
262
263
264    /**
265     * A builder which can be used to construct {@link Rule} instances.  Enforces the constraints of the {@link RuleContract}.
266     * 
267     */
268    public final static class Builder
269        implements Serializable, ModelBuilder, RuleContract
270    {
271        private String id;
272        private String name;
273        private RuleTemplate.Builder ruleTemplate;
274        private boolean active;
275        private String description;
276        private String docTypeName;
277        private DateTime fromDate;
278        private DateTime toDate;
279        private boolean forceAction;
280        private List<RuleResponsibility.Builder> ruleResponsibilities = Collections.<RuleResponsibility.Builder>emptyList();
281        private List<RuleExtension.Builder> ruleExtensions = Collections.emptyList();
282        private String ruleTemplateName;
283        private String previousRuleId;
284        private RuleExpression.Builder ruleExpressionDef;
285
286        private Builder() {
287            setActive(true);
288        }
289
290        public static Builder create() {
291            return new Builder();
292        }
293
294        public static Builder create(RuleContract contract) {
295            if (contract == null) {
296                throw new IllegalArgumentException("contract was null");
297            }
298            Builder builder = create();
299            builder.setId(contract.getId());
300            builder.setName(contract.getName());
301            builder.setRuleTemplate(
302                    contract.getRuleTemplate() == null ? null : RuleTemplate.Builder.create(contract.getRuleTemplate()));
303            builder.setActive(contract.isActive());
304            builder.setDescription(contract.getDescription());
305            builder.setDocTypeName(contract.getDocTypeName());
306            builder.setFromDate(contract.getFromDate());
307            builder.setToDate(contract.getToDate());
308            builder.setForceAction(contract.isForceAction());
309            builder.setPreviousRuleId(contract.getPreviousRuleId());
310            if (CollectionUtils.isNotEmpty(contract.getRuleResponsibilities())) {
311                List<RuleResponsibility.Builder> responsibilityBuilders = new ArrayList<RuleResponsibility.Builder>();
312                for (RuleResponsibilityContract c : contract.getRuleResponsibilities()) {
313                    responsibilityBuilders.add(RuleResponsibility.Builder.create(c));
314                }
315                builder.setRuleResponsibilities(responsibilityBuilders);
316            } else {
317                builder.setRuleResponsibilities(Collections.<RuleResponsibility.Builder>emptyList());
318            }
319            if (CollectionUtils.isNotEmpty(contract.getRuleExtensions())) {
320                List<RuleExtension.Builder> extensionBuilders = new ArrayList<RuleExtension.Builder>();
321                for (RuleExtensionContract c : contract.getRuleExtensions()) {
322                    extensionBuilders.add(RuleExtension.Builder.create(c));
323                }
324                builder.setRuleExtensions(extensionBuilders);
325            } else {
326                builder.setRuleExtensions(Collections.<RuleExtension.Builder>emptyList());
327            }
328            builder.setRuleTemplateName(contract.getRuleTemplateName());
329            if (contract.getRuleExpressionDef() != null) {
330                builder.setRuleExpressionDef(RuleExpression.Builder.create(contract.getRuleExpressionDef()));
331        }
332            return builder;
333        }
334
335        public Rule build() {
336            return new Rule(this);
337        }
338
339        @Override
340        public String getId() {
341            return this.id;
342        }
343
344        @Override
345        public String getName() {
346            return this.name;
347        }
348
349        @Override
350        public RuleTemplate.Builder getRuleTemplate() {
351            return this.ruleTemplate;
352        }
353
354        @Override
355        public boolean isActive() {
356            return this.active;
357        }
358
359        @Override
360        public String getDescription() {
361            return this.description;
362        }
363
364        @Override
365        public String getDocTypeName() {
366            return this.docTypeName;
367        }
368
369        @Override
370        public DateTime getFromDate() {
371            return this.fromDate;
372        }
373
374        @Override
375        public DateTime getToDate() {
376            return this.toDate;
377        }
378
379        @Override
380        public boolean isForceAction() {
381            return this.forceAction;
382        }
383
384        @Override
385        public String getPreviousRuleId() {
386            return this.previousRuleId;
387        }
388
389        @Override
390        public List<RuleResponsibility.Builder> getRuleResponsibilities() {
391            return this.ruleResponsibilities;
392        }
393
394        @Override
395        public List<RuleExtension.Builder> getRuleExtensions() {
396            return this.ruleExtensions;
397        }
398
399        @Override
400        public String getRuleTemplateName() {
401            return this.ruleTemplateName;
402        }
403
404        @Override
405        public RuleExpression.Builder getRuleExpressionDef() {
406            return this.ruleExpressionDef;
407        }
408
409        public void setId(String id) {
410            if (StringUtils.isWhitespace(id)) {
411                throw new IllegalArgumentException("id is blank");
412            }
413            this.id  = id;
414        }
415
416        public void setName(String name) {
417            this.name = name;
418        }
419        public void setRuleTemplate(RuleTemplate.Builder ruleTemplate) {
420            this.ruleTemplate = ruleTemplate;
421        }
422
423        public void setActive(boolean active) {
424            this.active = active;
425        }
426
427        public void setDescription(String description) {
428            this.description = description;
429        }
430
431        public void setDocTypeName(String docTypeName) {
432            this.docTypeName = docTypeName;
433        }
434
435        public void setFromDate(DateTime fromDate) {
436            this.fromDate = fromDate;
437        }
438
439        public void setToDate(DateTime toDate) {
440            this.toDate = toDate;
441        }
442
443        public void setForceAction(boolean forceAction) {
444            this.forceAction = forceAction;
445        }
446
447        public void setPreviousRuleId(String previousRuleId) {
448            this.previousRuleId = previousRuleId;
449        }
450
451        public void setRuleResponsibilities(List<RuleResponsibility.Builder> ruleResponsibilities) {
452            this.ruleResponsibilities = Collections.unmodifiableList(ruleResponsibilities);
453        }
454
455        public void setRuleExtensions(List<RuleExtension.Builder> ruleExtensions) {
456            this.ruleExtensions = Collections.unmodifiableList(ruleExtensions);
457        }
458
459        public void setRuleTemplateName(String ruleTemplateName) {
460            this.ruleTemplateName = ruleTemplateName;
461        }
462
463        public void setRuleExpressionDef(RuleExpression.Builder ruleExpressionDef) {
464            this.ruleExpressionDef = ruleExpressionDef;
465        }
466
467    }
468
469
470    /**
471     * Defines some internal constants used on this class.
472     * 
473     */
474    static class Constants {
475
476        final static String ROOT_ELEMENT_NAME = "rule";
477        final static String TYPE_NAME = "RuleType";
478
479    }
480
481
482    /**
483     * A private class which exposes constants which define the XML element names to use when this object is marshalled to XML.
484     * 
485     */
486    static class Elements {
487        final static String ID = "id";
488        final static String NAME = "name";
489        final static String RULE_TEMPLATE = "ruleTemplate";
490        final static String ACTIVE = "active";
491        final static String DESCRIPTION = "description";
492        final static String DOC_TYPE_NAME = "docTypeName";
493        final static String FROM_DATE = "fromDate";
494        final static String TO_DATE = "toDate";
495        final static String FROM_DATE_VALUE = "fromDateValue";
496        final static String TO_DATE_VALUE = "toDateValue";
497        final static String FORCE_ACTION = "forceAction";
498        final static String RULE_RESPONSIBILITIES = "ruleResponsibilities";
499        final static String RULE_RESPONSIBILITY = "ruleResponsibility";
500        final static String RULE_EXTENSIONS = "ruleExtensions";
501        final static String RULE_EXTENSION = "ruleExtension";
502        final static String RULE_TEMPLATE_NAME = "ruleTemplateName";
503        final static String RULE_EXPRESSION_DEF = "ruleExpressionDef";
504        final static String PREVIOUS_VERSION_ID = "previousRuleId";
505    }
506
507    public static class Cache {
508        public static final String NAME = KewApiConstants.Namespaces.KEW_NAMESPACE_2_0 + "/" + Rule.Constants.TYPE_NAME;
509    }
510}