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.api.repository.proposition;
017
018import java.io.Serializable;
019import java.util.Collection;
020
021import javax.xml.bind.annotation.XmlAccessType;
022import javax.xml.bind.annotation.XmlAccessorType;
023import javax.xml.bind.annotation.XmlAnyElement;
024import javax.xml.bind.annotation.XmlElement;
025import javax.xml.bind.annotation.XmlRootElement;
026import javax.xml.bind.annotation.XmlType;
027
028import org.apache.commons.lang.StringUtils;
029import org.kuali.rice.core.api.CoreConstants;
030import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
031import org.kuali.rice.core.api.mo.ModelBuilder;
032import org.kuali.rice.krms.api.repository.term.TermDefinition;
033
034/**
035 * Concrete model object implementation of KRMS Proposition Parameter 
036 * immutable. 
037 * Instances of PropositionParameter can be (un)marshalled to and from XML.
038 *
039 * @see PropositionParameterContract
040 */
041@XmlRootElement(name = PropositionParameter.Constants.ROOT_ELEMENT_NAME)
042@XmlAccessorType(XmlAccessType.NONE)
043@XmlType(name = PropositionParameter.Constants.TYPE_NAME, propOrder = {
044                PropositionParameter.Elements.ID,
045                PropositionParameter.Elements.PROP_ID,
046                PropositionParameter.Elements.VALUE,
047                PropositionParameter.Elements.PARM_TYPE,
048                PropositionParameter.Elements.SEQUENCE,
049        CoreConstants.CommonElements.VERSION_NUMBER,
050        PropositionParameter.Elements.TERM_VALUE,
051                CoreConstants.CommonElements.FUTURE_ELEMENTS
052})
053public final class PropositionParameter extends AbstractDataTransferObject implements PropositionParameterContract {
054        private static final long serialVersionUID = 2783959459503209577L;
055
056        @XmlElement(name = Elements.ID, required=true)
057        private String id;
058        @XmlElement(name = Elements.PROP_ID, required=true)
059        private String propId;
060        @XmlElement(name = Elements.VALUE, required=true)
061        private String value;
062        @XmlElement(name = Elements.PARM_TYPE, required=true)
063        private String parameterType;
064        @XmlElement(name = Elements.SEQUENCE, required=true)
065        private Integer sequenceNumber;
066    @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
067    private final Long versionNumber;
068    @XmlElement(name = Elements.TERM_VALUE, required=false)
069    private TermDefinition termValue;
070
071        @SuppressWarnings("unused")
072    @XmlAnyElement
073    private final Collection<org.w3c.dom.Element> _futureElements = null;
074        
075         /** 
076     * This constructor should never be called.  
077     * It is only present for use during JAXB unmarshalling. 
078     */
079    private PropositionParameter() {
080        this.id = null;
081        this.propId = null;
082        this.value = null;
083        this.termValue = null;
084        this.parameterType = null;
085        this.sequenceNumber = null;
086        this.versionNumber = null;
087    }
088    
089    /**
090         * Constructs a PropositionParameter from the given builder.  
091         * This constructor is private and should only ever be invoked from the builder.
092         * 
093         * @param builder the Builder from which to construct the PropositionParameter
094         */
095    private PropositionParameter(Builder builder) {
096        this.id = builder.getId();
097        this.propId = builder.getPropId();
098        this.value = builder.getValue();
099        this.termValue = builder.getTermValue();
100        this.parameterType = builder.getParameterType();
101        this.sequenceNumber = builder.getSequenceNumber();
102        this.versionNumber = builder.getVersionNumber();
103    }
104    
105        @Override
106        public String getId() {
107                return this.id;
108        }
109        
110        @Override
111        public String getPropId() {
112                return this.propId;
113        }
114
115        @Override
116        public String getValue() {
117                return this.value;
118        }
119        
120        @Override
121        public String getParameterType() {
122                return this.parameterType;
123        }
124        @Override
125        public Integer getSequenceNumber() {
126                return this.sequenceNumber; 
127        }
128
129    @Override
130    public Long getVersionNumber() {
131        return versionNumber;
132    }
133
134    @Override
135    public TermDefinition getTermValue() {
136        return this.termValue;
137    }
138
139    /**
140     * This builder is used to construct instances of PropositionParameter.  
141     * It enforces the constraints of the {@link PropositionParameterContract}.
142     */
143    public static class Builder implements PropositionParameterContract, ModelBuilder, Serializable {
144        private static final long serialVersionUID = -6889320709850568900L;
145                
146                private String id;
147        private String propId;
148        private String value;
149        private TermDefinition termValue;
150        private String parameterType;
151        private Integer sequenceNumber;
152        private Long versionNumber;
153        private PropositionDefinition.Builder proposition;
154
155        /**
156         * Private constructor for creating a builder with all of it's required attributes.
157         * @param id the id value to set, must not be null or blank
158         * @param propId the propId value to set, must not be null or blank
159         * @param value the value value to set, must not be null or blank
160         * @param parameterType the value parameterType to set, must not be null or blank
161         * @param sequenceNumber the value sequenceNumber to set, must not be null or blank
162         */
163        private Builder(String id, String propId, String value, String parameterType, Integer sequenceNumber) {
164            setId(id);
165            setPropId(propId);
166            setValue(value);
167            setParameterType(parameterType);
168                        setSequenceNumber(sequenceNumber);
169        }
170
171        /**
172         * Create a builder using the given values
173         * @param id the id value to set, must not be null or blank
174         * @param propId the propId value to set, must not be null or blank
175         * @param value the value value to set, must not be null or blank
176         * @param parameterType the value parameterType to set, must not be null or blank
177         * @param sequenceNumber the value sequenceNumber to set, must not be null or blank
178         * @return Builder with the given values set
179         */
180        public static Builder create(String id, String propId, String value, String parameterType, Integer sequenceNumber) {
181                return new Builder(id, propId, value, parameterType, sequenceNumber);
182        }
183
184        /**
185         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
186         * 
187         * @param contract the contract from which to populate this builder
188         * @return an instance of the builder populated with data from the contract
189         */
190        public static Builder create(PropositionParameterContract contract) {
191                if (contract == null) {
192                throw new IllegalArgumentException("contract is null");
193            }
194
195            Builder builder =  new Builder(contract.getId(), contract.getPropId(), contract.getValue(), contract.getParameterType(), contract.getSequenceNumber());
196            builder.setVersionNumber(contract.getVersionNumber());
197            builder.setTermValue(contract.getTermValue());
198
199            return builder;
200        }
201
202        /**
203         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
204         * 
205         * @param propositionParameter the contract from which to populate this builder
206         * @return an instance of the builder populated with data from the contract
207         */
208        public static PropositionParameter.Builder create(PropositionParameter propositionParameter) {
209                if (propositionParameter == null) {
210                throw new IllegalArgumentException("parameter is null");
211            }
212
213            Builder builder =  new Builder(propositionParameter.getId(), propositionParameter.getPropId(), propositionParameter.getValue(), propositionParameter.getParameterType(), propositionParameter.getSequenceNumber());
214            builder.setVersionNumber(propositionParameter.getVersionNumber());
215            builder.setTermValue(propositionParameter.getTermValue());
216
217            return builder;
218        }
219
220
221        /**
222         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
223         * 
224         * @param inputBuilder the contract from which to populate this builder
225         * @return an instance of the builder populated with data from the contract
226         */
227        public static PropositionParameter.Builder create(Builder inputBuilder) {
228                if (inputBuilder == null) {
229                throw new IllegalArgumentException("inputBuilder is null");
230            }
231            Builder builder =  new Builder(inputBuilder.getId(), inputBuilder.getPropId(), inputBuilder.getValue(), inputBuilder.getParameterType(), inputBuilder.getSequenceNumber());
232            builder.setVersionNumber(inputBuilder.getVersionNumber());
233            builder.setTermValue(inputBuilder.getTermValue());
234            return builder;
235        }
236
237                /**
238                 * Sets the value of the id on this builder to the given value.
239                 * 
240                 * @param id the id value to set, must not be null or blank
241                 * @throws IllegalArgumentException if the id is null or blank
242                 */
243        public void setId(String id) {
244            if (id != null && StringUtils.isBlank(id)) {
245                throw new IllegalArgumentException("id must not be null or blank");
246            }
247            this.id = id;
248        }
249
250        /**
251         * Sets the value of the propId on this builder to the given value.
252         *
253         * @param propId the propId value to set, must not be null or blank
254         * @throws IllegalArgumentException if the propId is null or blank
255         */
256                public void setPropId(String propId) {
257                    // have to be able to create it with a null propId for chicken/egg reasons.
258            if (null != propId && StringUtils.isBlank(propId)) {
259                throw new IllegalArgumentException("propId must be not be null or blank");
260            }
261                        this.propId = propId;
262                }
263
264        /**
265         * Sets the value of the value on this builder to the given value.
266         *
267         * @param value the value value to set, may be null, otherwise must contain non-whitespace
268         * @throws IllegalArgumentException if the value is all whitespace characters
269         */
270                public void setValue(String value) {
271            if (value != null && "".equals(value.trim())) {
272                throw new IllegalArgumentException("value must contain non-whitespace characters");
273            }
274                        this.value = value;
275                }
276                        
277        /**
278         * Sets the value of the termValue on this builder to the given value.
279         * 
280         * @param termValue the termValue value to set, may be null
281         */
282                public void setTermValue(TermDefinition termValue) {
283                        this.termValue = termValue;
284                }
285
286        /**
287         * Sets the value of the parameterType on this builder to the given value.
288         *
289         * @param parameterType the value parameterType to set, must not be null or blank
290         * @throws IllegalArgumentException if the parameterType is null, blank, or invalid
291         */
292                public void setParameterType(String parameterType) {
293                        if (StringUtils.isBlank(parameterType)){
294                        throw new IllegalArgumentException("parameter type is null or blank");
295                        }
296                        if (!PropositionParameterType.VALID_TYPE_CODES.contains(parameterType)){
297                throw new IllegalArgumentException("parameter type is invalid");                                
298                        }
299                        // TODO: check against valid values
300                        this.parameterType = parameterType;
301                }
302
303        /**
304         * Sets the value of the sequenceNumber on this builder to the given value.
305         *
306         * @param sequenceNumber the value sequenceNumber to set, must not be null or blank
307         * @throws IllegalArgumentException if the sequenceNumber is null, blank, or invalid
308         */
309                public void setSequenceNumber(Integer sequenceNumber) {
310                        if (sequenceNumber == null) {
311                throw new IllegalArgumentException("sequenceNumber type is blank");
312                        }
313                        this.sequenceNumber = sequenceNumber;
314                }
315
316        /**
317         * Sets the value of the proposition on this builder to the given value.
318         *
319         * @param proposition the value proposition to set
320         */
321                public void setProposition(PropositionDefinition.Builder proposition) {
322                    if (proposition != null && !StringUtils.isBlank(proposition.getId())) {
323                        setPropId(proposition.getId());
324                    }
325                    this.proposition = proposition;
326                }
327
328        /**
329         * Sets the value of the versionNumber on this builder to the given value.
330         *
331         * @param versionNumber the value versionNumber to set
332         */
333        public void setVersionNumber(Long versionNumber){
334            this.versionNumber = versionNumber;
335        }
336        
337                @Override
338                public String getId() {
339                        return id;
340                }
341
342                @Override
343                public String getPropId() {
344                        return propId;
345                }
346
347                @Override
348                public String getValue() {
349                        return value;
350                }
351
352                @Override
353                public TermDefinition getTermValue() {
354                        return termValue;
355                }
356
357                @Override
358                public String getParameterType() {
359                        return parameterType;
360                }
361
362                @Override
363                public Integer getSequenceNumber() {
364                        return sequenceNumber;
365                }
366
367        @Override
368        public Long getVersionNumber() {
369            return versionNumber;
370        }
371
372                /**
373                 * Builds an instance of a PropositionParameter based on the current state of the builder.
374                 * 
375                 * @return the fully-constructed PropositionParameter
376                 */
377        @Override
378        public PropositionParameter build() {
379            if (proposition == null && StringUtils.isBlank(propId)) {
380                throw new IllegalStateException("either proposition must be non-null or propId must be non-blank");
381            }
382            return new PropositionParameter(this);
383        }
384                
385    }
386        
387        /**
388         * Defines some internal constants used on this class.
389         */
390        static class Constants {
391                final static String ROOT_ELEMENT_NAME = "PropositionParameter";
392                final static String TYPE_NAME = "PropositionParameterType";
393        }
394        
395        /**
396         * A private class which exposes constants which define the XML element names to use
397         * when this object is marshalled to XML.
398         */
399        public static class Elements {
400                final static String ID = "id";
401                final static String PROP_ID = "propId";
402                final static String VALUE = "value";
403                final static String TERM_VALUE = "termValue";
404                final static String PARM_TYPE = "parameterType";
405                final static String SEQUENCE = "sequenceNumber";
406        }
407
408}