View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.routeheader;
17  
18  import java.io.BufferedReader;
19  import java.io.IOException;
20  import java.io.ObjectInputStream;
21  import java.io.Serializable;
22  import java.io.StringReader;
23  
24  import javax.xml.parsers.DocumentBuilder;
25  import javax.xml.parsers.DocumentBuilderFactory;
26  import javax.xml.parsers.ParserConfigurationException;
27  
28  import org.kuali.rice.core.api.exception.RiceRuntimeException;
29  import org.kuali.rice.kew.api.document.InvalidDocumentContentException;
30  import org.kuali.rice.kew.engine.RouteContext;
31  import org.kuali.rice.kew.api.KewApiConstants;
32  import org.w3c.dom.Document;
33  import org.w3c.dom.Element;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.NodeList;
36  import org.xml.sax.InputSource;
37  import org.xml.sax.SAXException;
38  
39  
40  /**
41   * Standard implementation of {@link DocumentContent} which nows hows to parse a
42   * String that it's constructed with into content with the application,
43   * attribute, and searchable content sections.
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  public class StandardDocumentContent implements DocumentContent, Serializable {
48  
49  	private static final long serialVersionUID = -3189330007364191220L;
50  	
51  	private static final String LEGACY_FLEXDOC_ELEMENT = "flexdoc";
52  
53  	private String docContent;
54  
55  	private transient Document document;
56  
57  	private transient Element applicationContent;
58  
59  	private transient Element attributeContent;
60  
61  	private transient Element searchableContent;
62  
63  	private RouteContext routeContext;
64  
65  	public StandardDocumentContent(String docContent) {
66  		this(docContent, null);
67  	}
68  
69  	public StandardDocumentContent(String docContent, RouteContext routeContext) {
70  		this.routeContext = routeContext;
71  		initialize(docContent, routeContext);
72  	}
73  
74  	private void initialize(String docContent, RouteContext routeContext) {
75  		if (org.apache.commons.lang.StringUtils.isEmpty(docContent)) {
76  			this.docContent = "";
77  			this.document = null;
78  		} else {
79  			try {
80  				this.docContent = docContent;
81  				this.document = parseDocContent(docContent);
82  				extractElements(this.document);
83  			} catch (IOException e) {
84  				throw new InvalidDocumentContentException("I/O Error when attempting to parse document content.", e);
85  			} catch (SAXException e) {
86  				throw new InvalidDocumentContentException("XML parse error when attempting to parse document content.", e);
87  			} catch (ParserConfigurationException e) {
88  				throw new RiceRuntimeException("XML parser configuration error when attempting to parse document content.", e);
89  			}
90  		}
91  	}
92  
93  	private Document parseDocContent(String docContent) throws IOException, SAXException, ParserConfigurationException {
94  		DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
95  		return documentBuilder.parse(new InputSource(new BufferedReader(new StringReader(docContent))));
96  	}
97  
98  	private void extractElements(Document document) {
99  		// this handles backward compatibility in document content
100 		if (!document.getDocumentElement().getNodeName().equals(KewApiConstants.DOCUMENT_CONTENT_ELEMENT)) {
101 			// if the root element is the flexdoc element (pre Workflow 2.0)
102 			// then designate that as attribute content
103 			if (document.getDocumentElement().getNodeName().equals(LEGACY_FLEXDOC_ELEMENT)) {
104 				attributeContent = document.getDocumentElement();
105 			} else {
106 				applicationContent = document.getDocumentElement();
107 			}
108 		} else {
109 			NodeList nodes = document.getDocumentElement().getChildNodes();
110 			for (int index = 0; index < nodes.getLength(); index++) {
111 				Node node = nodes.item(index);
112 				if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(KewApiConstants.APPLICATION_CONTENT_ELEMENT)) {
113 					int numChildElements = 0;
114 					for (int childIndex = 0; childIndex < node.getChildNodes().getLength(); childIndex++) {
115 						Node child = (Node) node.getChildNodes().item(childIndex);
116 						if (child.getNodeType() == Node.ELEMENT_NODE) {
117 							applicationContent = (Element) child;
118 							numChildElements++;
119 						}
120 					}
121 					// TODO can we have application content without a root node?
122 					if (numChildElements > 1) {
123 						applicationContent = (Element) node;
124 					}
125 				} else if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(KewApiConstants.ATTRIBUTE_CONTENT_ELEMENT)) {
126 					attributeContent = (Element) node;
127 				} else if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(KewApiConstants.SEARCHABLE_CONTENT_ELEMENT)) {
128 					searchableContent = (Element) node;
129 				}
130 			}
131 		}
132 	}
133 
134 	public Element getApplicationContent() {
135 		return applicationContent;
136 	}
137 
138 	public Element getAttributeContent() {
139 		return attributeContent;
140 	}
141 
142 	public String getDocContent() {
143 		return docContent;
144 	}
145 
146 	public Document getDocument() {
147 		return document;
148 	}
149 
150 	public Element getSearchableContent() {
151 		return searchableContent;
152 	}
153 
154 	public RouteContext getRouteContext() {
155 		return this.routeContext;
156 	}
157 
158 	private void readObject(ObjectInputStream ais) throws IOException, ClassNotFoundException {
159 		ais.defaultReadObject();
160 		initialize(this.docContent, this.routeContext);
161 	}
162 
163 }