001    /*
002     * Copyright 2011 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/ecl1.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.kew.api.document;
017    
018    import java.io.Serializable;
019    import java.util.Collection;
020    import java.util.Collections;
021    import java.util.HashMap;
022    import java.util.Map;
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.XmlRootElement;
029    import javax.xml.bind.annotation.XmlType;
030    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
031    
032    import org.apache.commons.lang.StringUtils;
033    import org.apache.commons.lang.builder.EqualsBuilder;
034    import org.apache.commons.lang.builder.HashCodeBuilder;
035    import org.apache.commons.lang.builder.ToStringBuilder;
036    import org.kuali.rice.core.api.CoreConstants;
037    import org.kuali.rice.core.api.mo.ModelBuilder;
038    import org.kuali.rice.core.util.jaxb.MapStringStringAdapter;
039    import org.kuali.rice.kew.api.KewApiConstants;
040    import org.w3c.dom.Element;
041    
042    /**
043     * Defines an update to document content on a particular workflow document.
044     * Contains general application content as well as a list of attribute
045     * definitions and searchable definitions.  When passed to the appropriate
046     * workflow services to perform an update on document content, if any of the
047     * internal content or definitions on this object have not been set then they
048     * will not be updated.  This allows for this data structure to be used to only
049     * update the portion of the document content that is desired to be updated.
050     * 
051     * @author Kuali Rice Team (rice.collab@kuali.org)
052     * 
053     */
054    @XmlRootElement(name = DocumentUpdate.Constants.ROOT_ELEMENT_NAME)
055    @XmlAccessorType(XmlAccessType.NONE)
056    @XmlType(name = DocumentUpdate.Constants.TYPE_NAME, propOrder = {
057            DocumentUpdate.Elements.TITLE,
058        DocumentUpdate.Elements.APPLICATION_DOCUMENT_ID,
059        DocumentUpdate.Elements.APPLICATION_DOCUMENT_STATUS,
060        DocumentUpdate.Elements.VARIABLES,
061        CoreConstants.CommonElements.FUTURE_ELEMENTS
062    })
063    public final class DocumentUpdate implements Serializable {
064    
065            private static final long serialVersionUID = 608839901744771499L;
066    
067            @XmlElement(name = Elements.TITLE, required = false)
068            private final String title;
069    
070            @XmlElement(name = Elements.APPLICATION_DOCUMENT_ID, required = false)
071            private final String applicationDocumentId;
072                    
073            @XmlElement(name = Elements.APPLICATION_DOCUMENT_STATUS, required = false)
074            private final String applicationDocumentStatus;
075            
076            @XmlElement(name = Elements.VARIABLES, required = false)
077            @XmlJavaTypeAdapter(MapStringStringAdapter.class)
078            private final Map<String, String> variables;
079        
080            @SuppressWarnings("unused")
081        @XmlAnyElement
082        private final Collection<Element> _futureElements = null;
083        
084            private DocumentUpdate() {
085                    this.title = null;
086                    this.applicationDocumentId = null;
087                    this.applicationDocumentStatus = null;
088                    this.variables = null;
089            }
090            
091        private DocumentUpdate(Builder builder) {
092            this.title = builder.getTitle();
093            this.applicationDocumentId = builder.getApplicationDocumentId();
094            this.applicationDocumentStatus = builder.getApplicationDocumentStatus();
095            this.variables = builder.getVariables();
096        }
097    
098            public String getTitle() {
099                    return title;
100            }
101    
102            public String getApplicationDocumentId() {
103                    return applicationDocumentId;
104            }
105            
106            public String getApplicationDocumentStatus() {
107                    return applicationDocumentStatus;
108            }
109            
110            public Map<String, String> getVariables() {
111                    if (variables == null) {
112                            return Collections.emptyMap();
113                    }
114                    return Collections.unmodifiableMap(variables);
115            }
116            
117            @Override
118        public int hashCode() {
119            return HashCodeBuilder.reflectionHashCode(this, Constants.HASH_CODE_EQUALS_EXCLUDE);
120        }
121    
122        @Override
123        public boolean equals(Object object) {
124            return EqualsBuilder.reflectionEquals(object, this, Constants.HASH_CODE_EQUALS_EXCLUDE);
125        }
126    
127        @Override
128        public String toString() {
129            return ToStringBuilder.reflectionToString(this);
130        }
131                    
132            /**
133             * A builder which can be used to construct {@link DocumentUpdate} instances.
134             */
135            public final static class Builder implements Serializable, ModelBuilder {
136    
137                    private static final long serialVersionUID = 2220000561051177421L;
138    
139                    private String title;
140                    private String applicationDocumentId;
141                    private String applicationDocumentStatus;
142                    private Map<String, String> variables;
143    
144    
145                    private Builder() {
146                            this.title = "";
147                            this.variables = new HashMap<String, String>();
148                    }
149    
150                    public static Builder create() {
151                            return new Builder();
152                    }
153    
154                    public static Builder create(Document document) {
155                            if (document == null) {
156                                    throw new IllegalArgumentException("document was null");
157                            }
158                            Builder builder = create();
159                            builder.setTitle(document.getTitle());
160                            builder.setApplicationDocumentId(document.getApplicationDocumentId());
161                            builder.setApplicationDocumentStatus(document.getApplicationDocumentStatus());
162                            builder.setVariables(document.getVariables());
163                            return builder;
164                    }
165    
166                    public DocumentUpdate build() {
167                            return new DocumentUpdate(this);
168                    }
169    
170                    public String getTitle() {
171                            return title;
172                    }
173    
174                    /**
175                     * TODO: document the fact that this will auto-truncate the title...
176                     */
177                    public void setTitle(String title) {
178                            if (title == null) {
179                                    title = "";
180                            }
181                    if (title.length() > KewApiConstants.TITLE_MAX_LENGTH) {
182                        title = title.substring(0, KewApiConstants.TITLE_MAX_LENGTH);
183                    }
184                            this.title = title;
185                    }
186    
187                    public String getApplicationDocumentId() {
188                            return applicationDocumentId;
189                    }
190    
191                    public void setApplicationDocumentId(String applicationDocumentId) {
192                            this.applicationDocumentId = applicationDocumentId;
193                    }
194    
195                    public String getApplicationDocumentStatus() {
196                            return applicationDocumentStatus;
197                    }
198    
199                    public void setApplicationDocumentStatus(String applicationDocumentStatus) {
200                            this.applicationDocumentStatus = applicationDocumentStatus;
201                    }
202    
203                    public void setVariables(Map<String, String> variables) {
204                            if (variables == null) {
205                                    this.variables = new HashMap<String, String>();
206                            } else {
207                                    this.variables = new HashMap<String, String>(variables);
208                            }
209                    }
210                    
211                    public Map<String, String> getVariables() {
212                            return variables;
213                    }
214                    
215                    public String getVariableValue(String name) {
216                            return variables.get(name);
217                }
218    
219                public void setVariable(String name, String value) {
220                    if (StringUtils.isBlank(name)) {
221                            throw new IllegalArgumentException("name was null or blank");
222                    }
223                    variables.put(name, value);
224                }
225                
226            }
227            
228        /**
229         * Defines some internal constants used on this class.
230         */
231        static class Constants {
232            final static String ROOT_ELEMENT_NAME = "documentUpdate";
233            final static String TYPE_NAME = "DocumentUpdateType";
234            final static String[] HASH_CODE_EQUALS_EXCLUDE = new String[] { CoreConstants.CommonElements.FUTURE_ELEMENTS };
235        }
236    
237        /**
238         * A private class which exposes constants which define the XML element names to use when this object is marshalled to XML.
239         */
240        static class Elements {
241            final static String TITLE = "title";
242            final static String APPLICATION_DOCUMENT_ID = "applicationDocumentId";
243            final static String APPLICATION_DOCUMENT_STATUS = "applicationDocumentStatus";
244            final static String VARIABLES = "variables";
245        }
246    
247    }