View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.r2.common.class1.search;
17  
18  import org.apache.log4j.Logger;
19  import org.kuali.student.r1.common.dictionary.old.dto.FieldDescriptor;
20  import org.kuali.student.r2.core.search.dto.*;
21  import org.kuali.student.r2.core.search.dto.CrossSearchTypeInfo;
22  import org.kuali.student.r2.core.search.dto.QueryParamInfo;
23  import org.kuali.student.r2.core.search.dto.SearchCriteriaTypeInfo;
24  import org.kuali.student.r2.core.search.dto.SearchResultTypeInfo;
25  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
26  import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
27  import org.springframework.beans.factory.xml.ParserContext;
28  import org.w3c.dom.Attr;
29  import org.w3c.dom.Document;
30  import org.w3c.dom.Element;
31  import org.w3c.dom.Node;
32  
33  import javax.xml.parsers.DocumentBuilder;
34  import javax.xml.parsers.DocumentBuilderFactory;
35  import java.util.HashSet;
36  import java.util.List;
37  
38  public class SearchBeanDefinitionParser extends
39  		AbstractSingleBeanDefinitionParser {
40      private static final Logger logger = Logger.getLogger(SearchBeanDefinitionParser.class);
41  
42  	@Override
43  	protected Class<?> getBeanClass(Element element) {
44  
45  		if (element.getLocalName().equals("fieldDescriptor")) {
46  			return FieldDescriptor.class;
47  		}
48  		if (element.getLocalName().equals("searchCriteriaTypeInfo")) {
49  			return SearchCriteriaTypeInfo.class;
50  		}
51  		if (element.getLocalName().equals("queryParam")) {
52  			return QueryParamInfo.class;
53  		}
54  		if (element.getLocalName().equals("searchType")) {
55  			return SearchTypeInfo.class;
56  		}
57  		if (element.getLocalName().equals("resultColumn")) {
58  			return ResultColumnInfo.class;
59  		}
60  		if (element.getLocalName().equals("searchResultTypeInfo")) {
61  			return SearchResultTypeInfo.class;
62  		}
63  		
64  		
65  		if (element.getLocalName().equals("crossSearchType")) {
66  			return CrossSearchTypeInfo.class;
67  		}
68  		if (element.getLocalName().equals("subSearch")) {
69  			return SubSearchInfo.class;
70  		}
71  		if (element.getLocalName().equals("subSearchParamMappings")) {
72  			return SubSearchParamMappingInfo.class;
73  		}
74  		if (element.getLocalName().equals("joinCriteria")) {
75  			return JoinCriteriaInfo.class;
76  		}
77  		if (element.getLocalName().equals("comparison")) {
78  			return JoinComparisonInfo.class;
79  		}
80  		if (element.getLocalName().equals("leftHandSide")) {
81  			return ComparisonParamInfo.class;
82  		}
83  		if (element.getLocalName().equals("rightHandSide")) {
84  			return ComparisonParamInfo.class;
85  		}
86  		if (element.getLocalName().equals("joinResultMapping")) {
87  			return JoinResultMappingInfo.class;
88  		}
89  
90  		return super.getBeanClass(element);
91  	}
92  
93  	@Override
94  	protected void doParse(Element element, ParserContext pc, BeanDefinitionBuilder builder) {
95  		//Set the key
96  		if(!"fieldDescriptor".equals(element.getLocalName())&&element.hasAttribute("id")){
97  			builder.addPropertyValue("key", element.getAttributes().getNamedItem("id").getTextContent());
98  		}
99  		
100 		if("fieldDescriptor".equals(element.getLocalName())&&element.hasAttribute("parent")){
101 			builder.setParentName(element.getAttributes().getNamedItem("parent").getTextContent());
102 		}
103 		
104 		//Set optional if its a queryParam
105 		if("queryParam".equals(element.getLocalName())&&element.hasAttribute("optional")){
106 			builder.addPropertyValue("optional", "true".equals(element.getAttribute("optional"))?true:false);
107 		}
108 		
109     	//Copy Attributes
110     	if(element.hasAttributes()){
111     		for(int i = 0;i<element.getAttributes().getLength();i++){
112         		Attr attr = (Attr) element.getAttributes().item(i);
113         		if("abstract".equals(attr.getName())){
114         			builder.setAbstract(true);
115         		}else if(!"id".equals(attr.getName())&&!"parent".equals(attr.getName())){
116         			String fieldName = resolveFieldName(element.getLocalName(),attr.getName());
117         			builder.addPropertyValue(fieldName, attr.getValue());
118         		}
119     		}
120     	}
121 		
122 	
123 		HashSet<String> visitedNodes = new HashSet<String>();
124 		//Parse the children
125 		for(int i = 0;i<element.getChildNodes().getLength();i++){
126 			Node node = element.getChildNodes().item(i);
127 
128 			if(Node.ELEMENT_NODE == node.getNodeType()){
129             	String localName=node.getLocalName();
130             	if(!visitedNodes.contains(localName)){
131 					if(isWrappedList(node.getLocalName())){
132 						List<?> refList = pc.getDelegate().parseListElement((Element) node, pc.getContainingBeanDefinition());
133 						builder.addPropertyValue(node.getLocalName(),refList);
134 					}else if(isUnwrappedList(node.getLocalName())){
135 	            		Element childList=getChildList(element,node.getLocalName());
136 	                	visitedNodes.add(node.getLocalName());
137 	                    List<?> refList = pc.getDelegate().parseListElement(childList, pc.getContainingBeanDefinition());
138 	                    if(refList!=null&&!refList.isEmpty()){
139 	                    	String fieldName=resolveFieldName(element.getLocalName(),node.getLocalName());
140 	                    	builder.addPropertyValue(fieldName,refList);
141 	                    }
142 					}else{
143 						Element childElement = getFirstChildElement(node); 
144 						if(childElement!=null){
145 							if("ref".equals(childElement.getLocalName())){
146 								Object childBean = pc.getDelegate().parsePropertySubElement(childElement, pc.getContainingBeanDefinition());
147 								builder.addPropertyValue(node.getLocalName(), childBean);
148 							}else{
149 								Object childBean = pc.getDelegate().parsePropertySubElement((Element)node, pc.getContainingBeanDefinition());
150 								builder.addPropertyValue(node.getLocalName(), childBean);
151 							}
152 						}else{
153 							if(("ref".equals(node.getLocalName())&&"queryParam".equals(element.getLocalName()))){
154 								Object childBean = pc.getDelegate().parsePropertySubElement((Element)node, pc.getContainingBeanDefinition());
155 								builder.addPropertyValue("fieldDescriptor", childBean);
156 							}else if("leftHandSide".equals(node.getLocalName())
157 									||"rightHandSide".equals(node.getLocalName())
158 									||"joinCriteria".equals(node.getLocalName())){
159 								Object childBean = pc.getDelegate().parsePropertySubElement((Element)node, pc.getContainingBeanDefinition());
160 								builder.addPropertyValue(node.getLocalName(), childBean);
161 							}else{
162 								builder.addPropertyValue(node.getLocalName(), node.getTextContent());
163 							}
164 						}
165 					}
166             	}
167 			}
168 		}
169 	}
170 
171 	private boolean isUnwrappedList(String localName) {
172 		return localName.equals("subSearchParamMappings")||
173                localName.equals("comparison")||
174                localName.equals("subSearch")||
175                localName.equals("joinResultMapping");
176 	}
177 	
178     //This is called to resolve tag names to field names based on the element and parent element local names
179 	private String resolveFieldName(String parentName, String nodeName) {
180 		if("comparison".equals(nodeName)){
181 			return "comparisons";
182 		}
183 		if("subSearch".equals(nodeName)){
184 			return "subSearches";
185 		}
186 		if("joinResultMapping".equals(nodeName)){
187 			return "joinResultMappings";
188 		}
189 		if("joinCriteria".equals(parentName)&&"type".equals(nodeName)){
190 			return "joinType";
191 		}
192 
193 		return nodeName;
194 	}
195 	
196     //This builds up a list of the child nodes so that the spring parseListElement can be used
197     //it also translates <fooRef> elements into straight spring <ref> elements
198     private Element getChildList(Element element, String localName) {
199     	try{
200     		//Create a new document to contain our list of elements
201 	    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
202 	    	DocumentBuilder builder = dbf.newDocumentBuilder();
203 	    	Document doc = builder.newDocument();
204 	
205 	    	Element root = doc.createElement("listRoot");
206 	    	
207 	        for(int i = 0;i<element.getChildNodes().getLength();i++){
208 	            Node node = element.getChildNodes().item(i);
209 	            if(Node.ELEMENT_NODE == node.getNodeType() && localName.equals(node.getLocalName())){
210 	            	
211 	            	//Copy the node from the spring config to our list
212 	            	Node copied = doc.importNode(node, true);
213 	            	root.appendChild(copied);
214 	            }
215 	            if(Node.ELEMENT_NODE == node.getNodeType() && (localName+"Ref").equals(node.getLocalName())){
216 	            	
217 	            	//Create a new spring ref element and copy the bean attribute
218 	            	Element ref = doc.createElement("ref");
219 	            	ref.setAttribute("bean", ((Element)node).getAttribute("bean"));
220 	            	root.appendChild(ref);
221 	            }
222 	        }
223 	        
224 	    	return root;
225     	}catch(Exception e){
226     		logger.error("Exception occured: ", e);
227     	}
228     	return null;
229 	}
230     
231 	private Element getFirstChildElement(Node node) {
232 		for(int i = 0;i<node.getChildNodes().getLength();i++){
233 			Node childNode = node.getChildNodes().item(i);
234 			if(Node.ELEMENT_NODE == childNode.getNodeType()){
235 				return (Element) childNode;
236 			}
237 		}
238 		
239 		return null;
240 	}
241 
242 	private boolean isWrappedList(String localName) {
243 		return localName.equals("queryParams")||
244 			   localName.equals("resultColumns");
245 	}
246 	
247 	@Override
248 	protected String getParentName(Element element) {
249 		if(element.hasAttribute("parent")){
250             return element.getAttribute("parent");
251 		}
252 		return super.getParentName(element);
253 	}
254 	
255 	@Override
256 	protected boolean shouldGenerateIdAsFallback() {
257 		return true;
258 	}
259 }