001/**
002 * Copyright 2005-2012 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;
033import org.kuali.rice.krms.impl.repository.PropositionParameterBo;
034
035/**
036 * Concrete model object implementation of KRMS Proposition Parameter 
037 * immutable. 
038 * Instances of PropositionParameter can be (un)marshalled to and from XML.
039 *
040 * @see PropositionParameterContract
041 */
042@XmlRootElement(name = PropositionParameter.Constants.ROOT_ELEMENT_NAME)
043@XmlAccessorType(XmlAccessType.NONE)
044@XmlType(name = PropositionParameter.Constants.TYPE_NAME, propOrder = {
045                PropositionParameter.Elements.ID,
046                PropositionParameter.Elements.PROP_ID,
047                PropositionParameter.Elements.VALUE,
048                PropositionParameter.Elements.TERM_VALUE,
049                PropositionParameter.Elements.PARM_TYPE,
050                PropositionParameter.Elements.SEQUENCE,
051        CoreConstants.CommonElements.VERSION_NUMBER,
052                CoreConstants.CommonElements.FUTURE_ELEMENTS
053})
054public final class PropositionParameter extends AbstractDataTransferObject implements PropositionParameterContract {
055        private static final long serialVersionUID = 2783959459503209577L;
056
057        @XmlElement(name = PropositionParameter.Elements.ID, required=true)
058        private String id;
059        @XmlElement(name = PropositionParameter.Elements.PROP_ID, required=true)
060        private String propId;
061        @XmlElement(name = PropositionParameter.Elements.VALUE, required=true)
062        private String value;
063        @XmlElement(name = PropositionParameter.Elements.TERM_VALUE, required=true)
064        private TermDefinition termValue;
065        @XmlElement(name = PropositionParameter.Elements.PARM_TYPE, required=true)
066        private String parameterType;
067        @XmlElement(name = PropositionParameter.Elements.SEQUENCE, required=true)
068        private Integer sequenceNumber;
069    @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
070    private final Long versionNumber;
071        
072        @SuppressWarnings("unused")
073    @XmlAnyElement
074    private final Collection<org.w3c.dom.Element> _futureElements = null;
075        
076         /** 
077     * This constructor should never be called.  
078     * It is only present for use during JAXB unmarshalling. 
079     */
080    private PropositionParameter() {
081        this.id = null;
082        this.propId = null;
083        this.value = null;
084        this.termValue = null;
085        this.parameterType = null;
086        this.sequenceNumber = null;
087        this.versionNumber = null;
088    }
089    
090    /**
091         * Constructs a PropositionParameter from the given builder.  
092         * This constructor is private and should only ever be invoked from the builder.
093         * 
094         * @param builder the Builder from which to construct the PropositionParameter
095         */
096    private PropositionParameter(PropositionParameter.Builder builder) {
097        this.id = builder.getId();
098        this.propId = builder.getPropId();
099        this.value = builder.getValue();
100        this.termValue = builder.getTermValue();
101        this.parameterType = builder.getParameterType();
102        this.sequenceNumber = builder.getSequenceNumber();
103        this.versionNumber = builder.getVersionNumber();
104    }
105    
106        @Override
107        public String getId() {
108                return this.id;
109        }
110        
111        @Override
112        public String getPropId() {
113                return this.propId;
114        }
115
116        @Override
117        public String getValue() {
118                return this.value;
119        }
120        
121        public TermDefinition getTermValue() {
122                return this.termValue;
123        }
124
125        @Override
126        public String getParameterType() {
127                return this.parameterType;
128        }
129        @Override
130        public Integer getSequenceNumber() {
131                return this.sequenceNumber; 
132        }
133
134    @Override
135    public Long getVersionNumber() {
136        return versionNumber;
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            this.value = value;
167            setTermValue(null);
168            setParameterType(parameterType);
169                        setSequenceNumber(sequenceNumber);
170        }
171
172        /**
173         * Create a builder using the given values
174         * @param id the id value to set, must not be null or blank
175         * @param propId the propId value to set, must not be null or blank
176         * @param value the value value to set, must not be null or blank
177         * @param parameterType the value parameterType to set, must not be null or blank
178         * @param sequenceNumber the value sequenceNumber to set, must not be null or blank
179         * @return Builder with the given values set
180         */
181        public static PropositionParameter.Builder create(String id, String propId, String value, String parameterType, Integer sequenceNumber) {
182                return new PropositionParameter.Builder(id, propId, value, parameterType, sequenceNumber);
183        }
184
185        /**
186         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
187         * 
188         * @param contract the contract from which to populate this builder
189         * @return an instance of the builder populated with data from the contract
190         */
191        public static PropositionParameter.Builder create(PropositionParameterContract contract) {
192                if (contract == null) {
193                throw new IllegalArgumentException("contract is null");
194            }
195            PropositionParameter.Builder builder =  new PropositionParameter.Builder(contract.getId(), contract.getPropId(), contract.getValue(), contract.getParameterType(), contract.getSequenceNumber());
196            builder.setVersionNumber(contract.getVersionNumber());
197
198            //TODO: this if statement should be removed once propositionparameterbo also implements the new interface.
199            if (!(contract instanceof PropositionParameterBo)){
200                builder.setTermValue(contract.getTermValue());
201            }
202            return builder;
203        }
204
205        /**
206         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
207         * 
208         * @param propositionParameter the contract from which to populate this builder
209         * @return an instance of the builder populated with data from the contract
210         */
211        public static PropositionParameter.Builder create(PropositionParameter propositionParameter) {
212                if (propositionParameter == null) {
213                throw new IllegalArgumentException("parameter is null");
214            }
215            PropositionParameter.Builder builder =  new PropositionParameter.Builder(propositionParameter.getId(), propositionParameter.getPropId(), propositionParameter.getValue(), propositionParameter.getParameterType(), propositionParameter.getSequenceNumber());
216            builder.setVersionNumber(propositionParameter.getVersionNumber());
217            builder.setTermValue(propositionParameter.getTermValue());
218            return builder;
219        }
220
221
222        /**
223         * Creates a builder by populating it with data from the given {@link PropositionParameterContract}.
224         * 
225         * @param inputBuilder the contract from which to populate this builder
226         * @return an instance of the builder populated with data from the contract
227         */
228        public static PropositionParameter.Builder create(PropositionParameter.Builder inputBuilder) {
229                if (inputBuilder == null) {
230                throw new IllegalArgumentException("inputBuilder is null");
231            }
232            PropositionParameter.Builder builder =  new PropositionParameter.Builder(inputBuilder.getId(), inputBuilder.getPropId(), inputBuilder.getValue(), inputBuilder.getParameterType(), inputBuilder.getSequenceNumber());
233            builder.setVersionNumber(inputBuilder.getVersionNumber());
234            builder.setTermValue(inputBuilder.getTermValue());
235            return builder;
236        }
237
238                /**
239                 * Sets the value of the id on this builder to the given value.
240                 * 
241                 * @param id the id value to set, must not be null or blank
242                 * @throws IllegalArgumentException if the id is null or blank
243                 */
244        public void setId(String id) {
245            if (id != null && StringUtils.isBlank(id)) {
246                throw new IllegalArgumentException("id must not be null or blank");
247            }
248            this.id = id;
249        }
250
251        /**
252         * Sets the value of the propId on this builder to the given value.
253         *
254         * @param propId the propId value to set, must not be null or blank
255         * @throws IllegalArgumentException if the propId is null or blank
256         */
257                public void setPropId(String propId) {
258                    // have to be able to create it with a null propId for chicken/egg reasons.
259            if (null != propId && StringUtils.isBlank(propId)) {
260                throw new IllegalArgumentException("propId must be not be null or blank");
261            }
262                        this.propId = propId;
263                }
264
265        /**
266         * Sets the value of the value on this builder to the given value.
267         *
268         * @param value the value value to set, may be null, otherwise must contain non-whitespace
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}