001    /**
002     * Copyright 2005-2014 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     */
016    package org.kuali.rice.krms.api.repository.function;
017    
018    import java.io.Serializable;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.List;
023    
024    import javax.xml.bind.annotation.XmlAccessType;
025    import javax.xml.bind.annotation.XmlAccessorType;
026    import javax.xml.bind.annotation.XmlAnyElement;
027    import javax.xml.bind.annotation.XmlElement;
028    import javax.xml.bind.annotation.XmlElementWrapper;
029    import javax.xml.bind.annotation.XmlRootElement;
030    import javax.xml.bind.annotation.XmlType;
031    
032    import org.apache.commons.lang.StringUtils;
033    import org.kuali.rice.core.api.CoreConstants;
034    import org.kuali.rice.core.api.mo.AbstractDataTransferObject;
035    import org.kuali.rice.core.api.mo.ModelBuilder;
036    import org.kuali.rice.krms.api.repository.category.CategoryDefinition;
037    import org.kuali.rice.krms.api.repository.category.CategoryDefinitionContract;
038    import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
039    import 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    })
064    public 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    }