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.kew.api.document.search; 017 018import org.kuali.rice.core.api.CoreConstants; 019import org.kuali.rice.core.api.mo.AbstractDataTransferObject; 020import org.kuali.rice.core.api.mo.ModelBuilder; 021import org.kuali.rice.kew.api.document.Document; 022import org.kuali.rice.kew.api.document.attribute.DocumentAttribute; 023import org.kuali.rice.kew.api.document.attribute.DocumentAttributeContract; 024import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory; 025import org.w3c.dom.Element; 026 027import javax.xml.bind.annotation.XmlAccessType; 028import javax.xml.bind.annotation.XmlAccessorType; 029import javax.xml.bind.annotation.XmlAnyElement; 030import javax.xml.bind.annotation.XmlElement; 031import javax.xml.bind.annotation.XmlElementWrapper; 032import javax.xml.bind.annotation.XmlRootElement; 033import javax.xml.bind.annotation.XmlType; 034import java.io.Serializable; 035import java.util.ArrayList; 036import java.util.Collection; 037import java.util.Collections; 038import java.util.List; 039 040/** 041 * An immutable data transfer object implementation of the {@link DocumentSearchResultContract}. Instances of this 042 * class should be constructed using the nested {@link Builder} class. 043 * 044 * @author Kuali Rice Team (rice.collab@kuali.org) 045 */ 046@XmlRootElement(name = DocumentSearchResult.Constants.ROOT_ELEMENT_NAME) 047@XmlAccessorType(XmlAccessType.NONE) 048@XmlType(name = DocumentSearchResult.Constants.TYPE_NAME, propOrder = { 049 DocumentSearchResult.Elements.DOCUMENT, 050 DocumentSearchResult.Elements.DOCUMENT_ATTRIBUTES, 051 CoreConstants.CommonElements.FUTURE_ELEMENTS 052}) 053public final class DocumentSearchResult extends AbstractDataTransferObject implements DocumentSearchResultContract { 054 055 @XmlElement(name = Elements.DOCUMENT, required = false) 056 private final Document document; 057 058 @XmlElementWrapper(name = Elements.DOCUMENT_ATTRIBUTES, required = true) 059 @XmlElement(name = Elements.DOCUMENT_ATTRIBUTE, required = false) 060 private final List<DocumentAttribute> documentAttributes; 061 062 @SuppressWarnings("unused") 063 @XmlAnyElement 064 private final Collection<Element> _futureElements = null; 065 066 /** 067 * Private constructor used only by JAXB. 068 */ 069 @SuppressWarnings("unused") 070 private DocumentSearchResult() { 071 this.document = null; 072 this.documentAttributes = null; 073 } 074 075 private DocumentSearchResult(Builder builder) { 076 this.document = builder.getDocument().build(); 077 List<DocumentAttribute> documentAttributes = new ArrayList<DocumentAttribute>(); 078 for (DocumentAttribute.AbstractBuilder<?> documentAttribute : builder.getDocumentAttributes()) { 079 documentAttributes.add(documentAttribute.build()); 080 } 081 this.documentAttributes = Collections.unmodifiableList(documentAttributes); 082 } 083 084 @Override 085 public Document getDocument() { 086 return this.document; 087 } 088 089 @Override 090 public List<DocumentAttribute> getDocumentAttributes() { 091 return this.documentAttributes; 092 } 093 094 /** 095 * Returns an unmodifiable list of all document attributes on this result which have the given name. It is legal 096 * for a result to contain more than one attribute of the same name. In these cases, this represents a document 097 * attribute which has more than one value. 098 * 099 * @param attributeName the attribute name of document attributes to retrieve 100 * @return an unmodifiable list of document attributes with the given name, will never be null but may be empty 101 */ 102 public List<DocumentAttribute> getDocumentAttributeByName(String attributeName) { 103 List<DocumentAttribute> namedAttributes = new ArrayList<DocumentAttribute>(); 104 for (DocumentAttribute attribute : getDocumentAttributes()) { 105 if (attribute.getName().equals(attributeName)) { 106 namedAttributes.add(attribute); 107 } 108 } 109 return Collections.unmodifiableList(namedAttributes); 110 } 111 112 /** 113 * Returns a single document attribute from this result which has the given name. If there is more than one 114 * document attribute on this result with the given name, only a single one will be returned (though it is 115 * undeterministic which one will this will be). If there are no attributes on this result with the given name 116 * then this method will return null. 117 * 118 * @param attributeName the attribute name of the document attribute to retrieve 119 * @return a single document attribute with the given name, or null if one does not exist 120 */ 121 public DocumentAttribute getSingleDocumentAttributeByName(String attributeName) { 122 List<DocumentAttribute> namedAttributes = getDocumentAttributeByName(attributeName); 123 if (namedAttributes.isEmpty()) { 124 return null; 125 } 126 return namedAttributes.get(0); 127 } 128 129 /** 130 * A builder which can be used to construct {@link DocumentSearchResult} instances. Enforces the constraints of the 131 * {@link DocumentSearchResultContract}. 132 */ 133 public final static class Builder implements Serializable, ModelBuilder, DocumentSearchResultContract { 134 135 private Document.Builder document; 136 private List<DocumentAttribute.AbstractBuilder<?>> documentAttributes; 137 138 private Builder(Document.Builder document) { 139 setDocument(document); 140 setDocumentAttributes(new ArrayList<DocumentAttribute.AbstractBuilder<?>>()); 141 } 142 143 /** 144 * Create a builder for the document search result and initialize it with the given document builder. 145 * Additionally initializes the list of document attribute builders on the new instance to an empty list. 146 * 147 * @param document the document builder with which to initialize the returned builder instance 148 * 149 * @return a builder instance initialized with the given document builder 150 * 151 * @throws IllegalArgumentException if the given document builder is null 152 */ 153 public static Builder create(Document.Builder document) { 154 return new Builder(document); 155 } 156 157 /** 158 * Creates a new builder instance initialized with copies of the properties from the given contract. 159 * 160 * @param contract the contract from which to copy properties 161 * 162 * @return a builder instance initialized with properties from the given contract 163 * 164 * @throws IllegalArgumentException if the given contract is null 165 */ 166 public static Builder create(DocumentSearchResultContract contract) { 167 if (contract == null) { 168 throw new IllegalArgumentException("contract was null"); 169 } 170 Document.Builder documentBuilder = Document.Builder.create(contract.getDocument()); 171 Builder builder = create(documentBuilder); 172 List<DocumentAttribute.AbstractBuilder<?>> documentAttributes = new ArrayList<DocumentAttribute.AbstractBuilder<?>>(); 173 for (DocumentAttributeContract documentAttributeContract : contract.getDocumentAttributes()) { 174 documentAttributes.add(DocumentAttributeFactory.loadContractIntoBuilder(documentAttributeContract)); 175 } 176 builder.setDocumentAttributes(documentAttributes); 177 return builder; 178 } 179 180 public DocumentSearchResult build() { 181 return new DocumentSearchResult(this); 182 } 183 184 @Override 185 public Document.Builder getDocument() { 186 return this.document; 187 } 188 189 @Override 190 public List<DocumentAttribute.AbstractBuilder<?>> getDocumentAttributes() { 191 return this.documentAttributes; 192 } 193 194 public void setDocument(Document.Builder document) { 195 if (document == null) { 196 throw new IllegalArgumentException("document was null"); 197 } 198 this.document = document; 199 } 200 201 public void setDocumentAttributes(List<DocumentAttribute.AbstractBuilder<?>> documentAttributes) { 202 this.documentAttributes = documentAttributes; 203 } 204 205 } 206 207 /** 208 * Defines some internal constants used on this class. 209 */ 210 static class Constants { 211 final static String ROOT_ELEMENT_NAME = "documentSearchResult"; 212 final static String TYPE_NAME = "DocumentSearchResultType"; 213 } 214 215 /** 216 * A private class which exposes constants which define the XML element names to use when this object is marshalled to XML. 217 */ 218 static class Elements { 219 final static String DOCUMENT = "document"; 220 final static String DOCUMENT_ATTRIBUTES = "documentAttributes"; 221 final static String DOCUMENT_ATTRIBUTE = "documentAttribute"; 222 } 223 224}