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.function;
017
018import java.io.Serializable;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.List;
023
024import javax.xml.bind.annotation.XmlAccessType;
025import javax.xml.bind.annotation.XmlAccessorType;
026import javax.xml.bind.annotation.XmlAnyElement;
027import javax.xml.bind.annotation.XmlElement;
028import javax.xml.bind.annotation.XmlElementWrapper;
029import javax.xml.bind.annotation.XmlRootElement;
030import javax.xml.bind.annotation.XmlType;
031
032import org.apache.commons.lang.StringUtils;
033import org.kuali.rice.core.api.CoreConstants;
034import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
035import org.kuali.rice.core.api.mo.ModelBuilder;
036import org.kuali.rice.krms.api.repository.category.CategoryDefinition;
037import org.kuali.rice.krms.api.repository.category.CategoryDefinitionContract;
038import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
039import org.w3c.dom.Element;
040
041/**
042 * An immutable representation of a function definition.
043 * 
044 * @see FunctionDefinitionContract
045 * 
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 *
048 */
049@XmlRootElement(name = FunctionDefinition.Constants.ROOT_ELEMENT_NAME)
050@XmlAccessorType(XmlAccessType.NONE)
051@XmlType(name = FunctionDefinition.Constants.TYPE_NAME, propOrder = {
052                FunctionDefinition.Elements.ID,
053                FunctionDefinition.Elements.NAMESPACE,
054                FunctionDefinition.Elements.NAME,
055                FunctionParameterDefinition.Elements.DESCRIPTION,
056                FunctionDefinition.Elements.RETURN_TYPE,
057                FunctionDefinition.Elements.TYPE_ID,
058                FunctionDefinition.Elements.ACTIVE,
059        CoreConstants.CommonElements.VERSION_NUMBER,
060        FunctionDefinition.Elements.PARAMETERS,
061        FunctionDefinition.Elements.CATEGORIES,
062        CoreConstants.CommonElements.FUTURE_ELEMENTS
063})
064public class FunctionDefinition extends AbstractDataTransferObject implements FunctionDefinitionContract {
065
066        private static final long serialVersionUID = 1391030685309770560L;
067
068        @XmlElement(name = Elements.ID, required = false)
069        private final String id;
070        
071        @XmlElement(name = Elements.NAMESPACE, required = true)
072        private final String namespace;
073        
074        @XmlElement(name = Elements.NAME, required = true)
075        private final String name;
076        
077        @XmlElement(name = Elements.DESCRIPTION, required = false)
078        private final String description;
079        
080        @XmlElement(name = Elements.RETURN_TYPE, required = true)
081        private final String returnType;
082        
083        @XmlElement(name = Elements.TYPE_ID, required = true)
084        private final String typeId;
085        
086        @XmlElement(name = Elements.ACTIVE, required = true)
087        private final boolean active;
088        
089        @XmlElement(name = CoreConstants.CommonElements.VERSION_NUMBER, required = false)
090        private final Long versionNumber;
091        
092        @XmlElementWrapper(name = Elements.PARAMETERS, required = false)
093        @XmlElement(name = Elements.PARAMETER, required = false)
094        private final List<FunctionParameterDefinition> parameters;
095
096    @XmlElementWrapper(name = Elements.CATEGORIES, required = false)
097    @XmlElement(name = Elements.CATEGORY, required = false)
098    private final List<CategoryDefinition> categories;
099        
100        @SuppressWarnings("unused")
101    @XmlAnyElement
102    private final Collection<Element> _futureElements = null;
103        
104        /**
105     * Private constructor used only by JAXB.
106     */
107    private FunctionDefinition() {
108        this.id = null;
109        this.namespace = null;
110        this.name = null;
111        this.description = null;
112        this.returnType = null;
113        this.typeId = null;
114        this.active = true;
115        this.versionNumber = null;
116        this.parameters = null;
117        this.categories = null;
118    }
119
120    /**
121     * Constructs a FunctionDefinition from the given builder.  This constructor is private and should only
122     * ever be invoked from the builder.
123     *
124     * @param builder the Builder from which to construct the FunctionDefinition
125     */
126    private FunctionDefinition(Builder builder) {
127        this.id = builder.getId();
128        this.namespace = builder.getNamespace();
129        this.name = builder.getName();
130        this.description = builder.getDescription();
131        this.returnType = builder.getReturnType();
132        this.typeId = builder.getTypeId();
133        this.active = builder.isActive();
134        this.versionNumber = builder.getVersionNumber();
135        this.parameters = new ArrayList<FunctionParameterDefinition>();
136        for (FunctionParameterDefinition.Builder parameter : builder.getParameters()) {
137                this.parameters.add(parameter.build());
138        }
139        this.categories = new ArrayList<CategoryDefinition>();
140        for (CategoryDefinition.Builder category : builder.getCategories()) {
141            this.categories.add(category.build());
142        }
143    }
144    
145        @Override
146        public String getId() {
147                return id;
148        }
149
150        @Override
151        public String getNamespace() {
152                return namespace;
153        }
154
155        @Override
156        public String getName() {
157                return name;
158        }
159
160        @Override
161        public String getDescription() {
162                return description;
163        }
164        
165        @Override
166        public String getReturnType() {
167                return returnType;
168        }
169
170        @Override
171        public String getTypeId() {
172                return typeId;
173        }
174
175        @Override
176        public boolean isActive() {
177                return active;
178        }
179        
180        @Override
181        public Long getVersionNumber() {
182                return versionNumber;
183        }
184        
185        @Override
186        public List<FunctionParameterDefinition> getParameters() {
187                return Collections.unmodifiableList(parameters);
188        }
189
190    @Override
191    public List<CategoryDefinition> getCategories() {
192        return Collections.unmodifiableList(categories);
193    }
194
195        /**
196         * A builder which can be used to construct {@link FunctionDefinition}
197         * instances.  Enforces the constraints of the {@link FunctionDefinitionContract}.
198         * 
199         * @author Kuali Rice Team (rice.collab@kuali.org)
200         *
201         */
202        public static final class Builder implements FunctionDefinitionContract, ModelBuilder, Serializable  {
203                
204        private static final long serialVersionUID = -4470376239998290245L;
205        
206                private String id;
207        private String namespace;
208        private String name;
209        private String description;
210        private String returnType;
211        private String typeId;
212        private boolean active;
213        private Long versionNumber;
214        private List<FunctionParameterDefinition.Builder> parameters;
215        private List<CategoryDefinition.Builder> categories;
216
217        /**
218         * Private constructor, use create method
219         * @param namespace to use when building
220         * @param name to use when building
221         * @param returnType to use when building
222         * @param typeId to use when building
223         */
224        private Builder(String namespace, String name, String returnType, String typeId) {
225                setNamespace(namespace);
226                setName(name);
227                setReturnType(returnType);
228                setTypeId(typeId);
229                setActive(true);
230                setParameters(new ArrayList<FunctionParameterDefinition.Builder>());
231            setCategories(new ArrayList<CategoryDefinition.Builder>());
232        }
233        
234        /**
235         * Creates a function definition builder with the given required values.  This builder
236         * is the only means by which a {@link FunctionDefinition} object should be created.
237         * 
238         * <p>Will default the active flag to true.
239         * 
240         * @param namespace the namespace of the function definition to create, must not be null or blank
241         * @param name the name of the function definition to create, must not be null or blank
242         * @param returnType the return type of the function definition to create, must not be null or blank
243         * @param typeId the return type id of the function definition to create, must not be null or blank
244         * 
245         * @return a builder with the required values already initialized
246         * 
247         * @throws IllegalArgumentException if any of the given arguments is null or blank
248         */
249        public static Builder create(String namespace, String name, String returnType, String typeId) {
250                return new Builder(namespace, name, returnType, typeId);
251        }
252        
253        /**
254         * Creates and populates a builder with the data on the given {@link FunctionDefinitionContract}.
255         * This is similar in nature to a "copy constructor" for {@link FunctionDefinition}.
256         * 
257         * @param contract an object implementing the {@link FunctionDefinitionContract} from which
258         * to copy property values
259         *  
260         * @return a builder with the values from the contract already initialized
261         * 
262         * @throws IllegalArgumentException if the given contract is null
263         */
264        public static Builder create(FunctionDefinitionContract contract) {
265                if (contract == null) {
266                        throw new IllegalArgumentException("contract was null");
267                }
268                Builder builder = create(contract.getNamespace(), contract.getName(), contract.getReturnType(), contract.getTypeId());
269                builder.setId(contract.getId());
270                builder.setDescription(contract.getDescription());
271                builder.setActive(contract.isActive());
272                builder.setVersionNumber(contract.getVersionNumber());
273                for (FunctionParameterDefinitionContract parameter : contract.getParameters()) {
274                        builder.getParameters().add(FunctionParameterDefinition.Builder.create(parameter));
275                }
276            for (CategoryDefinitionContract category : contract.getCategories()) {
277                builder.getCategories().add(CategoryDefinition.Builder.create(category));
278            }
279                return builder;
280        }
281
282        @Override
283        public FunctionDefinition build() {
284                return new FunctionDefinition(this);
285        }
286        
287        @Override
288                public String getId() {
289                        return this.id;
290                }
291
292        /**
293         * Sets the id for the function definition that will be returned by this builder.
294         * 
295         * @param id the function definition id to set
296         */
297                public void setId(String id) {
298                        this.id = id;
299                }
300
301                @Override
302                public String getNamespace() {
303                        return this.namespace;
304                }
305
306        /**
307         * Sets the namespace code for the function definition that will be returned by this builder.
308         * The namespace must not be null or blank.
309         * 
310         * @param namespace the namespace code to set on this builder, must not be null or blank
311         * 
312         * @throws IllegalArgumentException if the given namespace is null or blank
313         */
314                public void setNamespace(String namespace) {
315                        if (StringUtils.isBlank(namespace)) {
316                                throw new IllegalArgumentException("namespace was blank");
317                        }
318                        this.namespace = namespace;
319                }
320
321                @Override
322                public String getName() {
323                        return this.name;
324                }
325
326                /**
327         * Sets the name for the function definition that will be returned by this builder.
328         * The name must not be null or blank.
329         * 
330         * @param name the name to set on this builder, must not be null or blank
331         * 
332         * @throws IllegalArgumentException if the given name is null or blank
333         */
334                public void setName(String name) {
335                        if (StringUtils.isBlank(name)) {
336                                throw new IllegalArgumentException("name was blank");
337                        }
338                        this.name = name;
339                }
340                
341                @Override
342                public String getDescription() {
343                        return this.description;
344                }
345
346        /**
347         * Sets the description for the function definition that will be returned by this builder.
348         * 
349         * @param description the description to set on this builder
350         */
351                public void setDescription(String description) {
352                        this.description = description;
353                }
354
355                @Override
356                public String getReturnType() {
357                        return this.returnType;
358                }
359
360                /**
361         * Sets the return type for the function definition that will be
362         * returned by this builder.  This can be one of a set of "built-in"
363         * data types or a custom datatype represented as a fully qualified
364         * java class name.  The returnType must not be null or blank.
365         * 
366         * @param returnType the returnType to set on this builder, must not be null or blank
367         * 
368         * @throws IllegalArgumentException if the given returnType is null or blank
369         */
370                public void setReturnType(String returnType) {
371                        if (StringUtils.isBlank(returnType)) {
372                                throw new IllegalArgumentException("returnType was blank");
373                        }
374                        this.returnType = returnType;
375                }
376
377                @Override
378                public String getTypeId() {
379                        return this.typeId;
380                }
381
382                /**
383         * Sets the id of the {@link KrmsTypeDefinition} which defines the
384         * actual implementation of this function.  The typeId must not be
385         * null or blank.
386         * 
387         * @param typeId the typeId to set on this builder, must not be null or blank
388         * 
389         * @throws IllegalArgumentException if the given typeId is null or blank
390         */
391                public void setTypeId(String typeId) {
392                        if (StringUtils.isBlank(typeId)) {
393                                throw new IllegalArgumentException("typeId was blank");
394                        }
395                        this.typeId = typeId;
396                }
397
398                @Override
399                public boolean isActive() {
400                        return this.active;
401                }
402
403                /**
404         * Sets the active flag for the function definition that will be
405         * returned by this builder.
406         * 
407         * @param active the active flag to set
408         */
409                public void setActive(boolean active) {
410                        this.active = active;
411                }
412
413                @Override
414                public Long getVersionNumber() {
415                        return this.versionNumber;
416                }
417
418                /**
419         * Sets the version number for the function definition that will be
420         * returned by this builder.
421         * 
422         * <p>In general, this value should not be manually set on the builder,
423         * but rather copied from an existing {@link FunctionDefinitionContract} when
424         * invoking {@link Builder#create(FunctionDefinitionContract)}.
425         * 
426         * @param versionNumber the version number to set
427         */
428                public void setVersionNumber(Long versionNumber) {
429                        this.versionNumber = versionNumber;
430                }
431                
432                @Override
433                public List<FunctionParameterDefinition.Builder> getParameters() {
434                        return this.parameters;
435                }
436
437                /**
438         * Sets the parameters for the function definition that will be returned by this builder.
439         * This list is a list of builders for each of the {@link FunctionParameterDefinition}
440         * instances that will form the parameters of this function definition.  The given list
441         * must not be null.
442         * 
443         * @param parameters a list of builders for the parameters which will be specified on this function definition
444         * 
445         * @throws IllegalArgumentException if the given parameters list is null 
446         */
447                public void setParameters(List<FunctionParameterDefinition.Builder> parameters) {
448                        if (parameters == null) {
449                                throw new IllegalArgumentException("parameters was null");
450                        }
451                        this.parameters = parameters;
452                }
453
454        @Override
455        public List<CategoryDefinition.Builder> getCategories() {
456            return this.categories;
457        }
458
459        /**
460         * Sets the category for the function definition that will be returned by this builder.
461         * This list is a list of builders for each of the {@link CategoryDefinition}
462         * instances that will form the categories of this function definition.  The given list
463         * must not be null.
464         *
465         * @param categories a list of builders for the categories which will be specified on this function definition
466         *
467         * @throws IllegalArgumentException if the given categories list is null
468         */
469        public void setCategories(List<CategoryDefinition.Builder> categories) {
470            if (categories == null) {
471                throw new IllegalArgumentException("categories was null");
472            }
473            this.categories = categories;
474        }
475
476        }
477        
478        /**
479     * Defines some internal constants used on this class.
480     */
481    static class Constants {
482        final static String ROOT_ELEMENT_NAME = "function";
483        final static String TYPE_NAME = "FunctionType";
484    }
485
486    /**
487     * A private class which exposes constants which define the XML element names to use
488     * when this object is marshalled to XML.
489     */
490    static class Elements {
491        final static String ID = "id";
492        final static String NAMESPACE = "namespace";
493        final static String NAME = "name";
494        final static String DESCRIPTION = "description";
495        final static String RETURN_TYPE = "returnType";
496        final static String TYPE_ID = "typeId";
497        final static String ACTIVE = "active";
498        final static String PARAMETERS = "parameters";
499        final static String PARAMETER = "parameter";
500        final static String CATEGORIES = "categories";
501        final static String CATEGORY = "category";
502    }
503    
504}