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.r1.common.dictionary.service.impl.old;
17  
18  import org.apache.log4j.Logger;
19  import org.kuali.student.r1.common.dictionary.old.dto.CaseConstraint;
20  import org.kuali.student.r1.common.dictionary.old.dto.ConstraintDescriptor;
21  import org.kuali.student.r1.common.dictionary.old.dto.ConstraintSelector;
22  import org.kuali.student.r1.common.dictionary.old.dto.Context;
23  import org.kuali.student.r1.common.dictionary.old.dto.Field;
24  import org.kuali.student.r1.common.dictionary.old.dto.FieldDescriptor;
25  import org.kuali.student.r1.common.dictionary.old.dto.LookupConstraint;
26  import org.kuali.student.r1.common.dictionary.old.dto.LookupKeyConstraint;
27  import org.kuali.student.r1.common.dictionary.old.dto.ObjectStructure;
28  import org.kuali.student.r1.common.dictionary.old.dto.OccursConstraint;
29  import org.kuali.student.r1.common.dictionary.old.dto.RequireConstraint;
30  import org.kuali.student.r1.common.dictionary.old.dto.SearchSelector;
31  import org.kuali.student.r1.common.dictionary.old.dto.State;
32  import org.kuali.student.r1.common.dictionary.old.dto.Type;
33  import org.kuali.student.r1.common.dictionary.old.dto.TypeStateCaseConstraint;
34  import org.kuali.student.r1.common.dictionary.old.dto.TypeStateWhenConstraint;
35  import org.kuali.student.r1.common.dictionary.old.dto.ValidCharsConstraint;
36  import org.kuali.student.r1.common.dictionary.old.dto.WhenConstraint;
37  import org.kuali.student.r2.common.util.date.DateFormatters;
38  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
39  import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
40  import org.springframework.beans.factory.xml.ParserContext;
41  import org.w3c.dom.Attr;
42  import org.w3c.dom.Document;
43  import org.w3c.dom.Element;
44  import org.w3c.dom.Node;
45  
46  import javax.xml.parsers.DocumentBuilder;
47  import javax.xml.parsers.DocumentBuilderFactory;
48  import java.util.HashMap;
49  import java.util.HashSet;
50  import java.util.List;
51  import java.util.Map;
52  
53  /**
54   * @author Daniel Epstein
55   *
56   */
57  @Deprecated
58  public class DictionaryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser{
59      
60      final Logger logger = Logger.getLogger(DictionaryBeanDefinitionParser.class);
61  
62  	//Resolves the tag name to an actual class
63      @Override
64      protected Class<?> getBeanClass(Element element) {
65  
66      	if (element.getLocalName().equals("case")){
67      		return CaseConstraint.class;
68  		}
69  		if (element.getLocalName().equals("constraintDescriptor")) {
70  			return ConstraintDescriptor.class;
71  		}
72  		if (element.getLocalName().equals("constraint")) {
73  			return ConstraintSelector.class;
74  		}
75  		if (element.getLocalName().equals("context")) {
76  			return Context.class;
77  		}
78  		if (element.getLocalName().equals("field")) {
79  			return Field.class;
80  		}
81  		if (element.getLocalName().equals("fieldDescriptor")) {
82  			return FieldDescriptor.class;
83  		}
84  		if (element.getLocalName().equals("lookup")) {
85  			return LookupConstraint.class;
86  		}
87  		if (element.getLocalName().equals("lookupKey")) {
88  			return LookupKeyConstraint.class;
89  		}
90  		if (element.getLocalName().equals("objectStructure")) {
91  			return ObjectStructure.class;
92  		}
93  		if (element.getLocalName().equals("occurs")) {
94  			return OccursConstraint.class;
95  		}
96  		if (element.getLocalName().equals("require")) {
97  			return RequireConstraint.class;
98  		}
99  		if (element.getLocalName().equals("search")) {
100 			return SearchSelector.class;
101 		}
102 		if (element.getLocalName().equals("state")) {
103 			return State.class;
104 		}
105 		if (element.getLocalName().equals("type")) {
106 			return Type.class;
107 		}
108 		if (element.getLocalName().equals("typeStateCase")) {
109 			return TypeStateCaseConstraint.class;
110 		}
111 		if (element.getLocalName().equals("typeStateWhen")) {
112 			return TypeStateWhenConstraint.class;
113 		}
114 		if (element.getLocalName().equals("when")) {
115 			return WhenConstraint.class;
116 		}
117 		if (element.getLocalName().equals("validChars")) {
118 			return ValidCharsConstraint.class;
119 		}
120     	
121 
122         return super.getBeanClass(element);
123     }
124 
125     @Override
126     protected void doParse(Element element, ParserContext pc, BeanDefinitionBuilder builder) {
127   	
128     	//Copy Attributes
129     	if(element.hasAttributes()){
130     		for(int i = 0;i<element.getAttributes().getLength();i++){
131         		Attr attr = (Attr) element.getAttributes().item(i);
132         		if("abstract".equals(attr.getName())){
133         			builder.setAbstract(true);
134         		}else if(!"id".equals(attr.getName())&&!"parent".equals(attr.getName())){
135         			builder.addPropertyValue(attr.getName(), attr.getValue());
136         		}
137     		}
138     	}
139     	
140 	    //Parse the children
141     	HashSet<String> visitedNodes = new HashSet<String>();
142         for(int i = 0;i<element.getChildNodes().getLength();i++){
143             Node node = element.getChildNodes().item(i);
144 
145             //We are only interested in child elements that have not been visited
146             if(Node.ELEMENT_NODE == node.getNodeType()){	              
147 	            
148             	//Get the local name minus the "Ref"
149             	String localName=node.getLocalName();
150             	if(localName.endsWith("Ref")){
151             		localName=localName.substring(0, localName.length()-"Ref".length());
152             	}
153             	if(!visitedNodes.contains(localName)){
154 	            	//Check if the child element belongs in a list
155 	            	if(isList(localName)){
156 	            		Element childList=getChildList(element,localName);
157 	                	visitedNodes.add(localName);
158 	                    List<?> refList = pc.getDelegate().parseListElement(childList, pc.getContainingBeanDefinition());
159 	                    if(refList!=null&&!refList.isEmpty()){
160 	                    	String fieldName=resolveFieldName(element.getLocalName(),localName);
161 	                    	builder.addPropertyValue(fieldName,refList);
162 	                    }
163 	                //Check if this is an attribute map
164 	            	}else if("attributes".equals(node.getLocalName())){
165 	            		Map<String,String> attributes = getAttributeMap((Element)node);
166 	            		builder.addPropertyValue(node.getLocalName(), attributes);
167 	                //Check if the child element is a Ref
168 	                }else if(node.getLocalName().endsWith("Ref")){
169 	                	if("objectStructureRef".equals(node.getLocalName())){
170 	                		builder.addPropertyValue("objectStructureRef", ((Element)node).getAttribute("bean"));
171 	                		//Add in the nested object too
172 	                		builder.addPropertyReference("objectStructure", ((Element)node).getAttribute("bean"));
173 	                	}else{
174 	                		builder.addPropertyReference(localName, ((Element)node).getAttribute("bean"));
175 	                	}
176 	               }else{
177 	            	    //Get the child of the child to see if we need to parse the nested node, or just set the text value
178 	                    Element childElement = getFirstChildElement(node);
179 	                    if(childElement!=null ||"search".equals(node.getLocalName())){
180 	                    	//Parse the nested Node
181 	                        Object childBean = pc.getDelegate().parsePropertySubElement((Element)node, pc.getContainingBeanDefinition());
182 	                        String fieldName=resolveFieldName(element.getLocalName(),node.getLocalName());
183 	                        builder.addPropertyValue(fieldName, childBean);
184 	                    }else{
185 	                    	
186 	                    	
187 	                   		//Set the text value
188 	                		String fieldName=resolveFieldName(element.getLocalName(),node.getLocalName());
189 
190 	                		if(Node.ELEMENT_NODE == node.getNodeType()&&"date".equals(((Element)node).getSchemaTypeInfo().getTypeName())){
191 	                			try {
192 									builder.addPropertyValue(fieldName, DateFormatters.DEFAULT_DATE_FORMATTER.parse(node.getTextContent()));
193 								} catch (Exception e) {
194 									logger.error("Cannot convert date, must be in format 'YYYY-MM-DD' :"+node.getTextContent(),e);
195 								}
196 	                		}else{
197 	                			builder.addPropertyValue(fieldName, node.getTextContent());
198 	                		}
199 	                    }
200 	                }
201 	            }
202 	        }
203         }
204     }
205 
206     
207     /**
208      * Parses attribute map from 
209      * &lt;attributes&gt;
210      * 	&lt;attribute key="attr1" value="attr2"/&gt;
211      * &lt;/attributes&gt;
212      * @param element
213      * @return map of attributes
214      */
215     private Map<String, String> getAttributeMap(Element element) {
216     	Map<String, String> attributes = new HashMap<String, String>();
217     	for(int i = 0;i<element.getChildNodes().getLength();i++){
218     		Node node = element.getChildNodes().item(i);
219     		if(Node.ELEMENT_NODE == node.getNodeType() && "attribute".equals(node.getLocalName())){
220     			String key = ((Element)node).getAttribute("key");
221     			String value = ((Element)node).getAttribute("value");
222     			attributes.put(key, value);
223     		}
224     	}
225 		return attributes;
226 	}
227 
228 	//This builds up a list of the child nodes so that the spring parseListElement can be used
229     //it also translates <fooRef> elements into straight spring <ref> elements
230     private Element getChildList(Element element, String localName) {
231     	try{
232     		//Create a new document to contain our list of elements
233 	    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
234 	    	DocumentBuilder builder = dbf.newDocumentBuilder();
235 	    	Document doc = builder.newDocument();
236 	
237 	    	Element root = doc.createElement("listRoot");
238 	    	
239 	        for(int i = 0;i<element.getChildNodes().getLength();i++){
240 	            Node node = element.getChildNodes().item(i);
241 	            if(Node.ELEMENT_NODE == node.getNodeType() && localName.equals(node.getLocalName())){
242 	            	
243 	            	//Copy the node from the spring config to our list
244 	            	Node copied = doc.importNode(node, true);
245 	            	root.appendChild(copied);
246 	            }
247 	            if(Node.ELEMENT_NODE == node.getNodeType() && (localName+"Ref").equals(node.getLocalName())){
248 	            	
249 	            	//Create a new spring ref element and copy the bean attribute
250 	            	Element ref = doc.createElement("ref");
251 	            	ref.setAttribute("bean", ((Element)node).getAttribute("bean"));
252 	            	root.appendChild(ref);
253 	            }
254 	        }
255 	        
256 	    	return root;
257     	}catch(Exception e){
258     		logger.error("Exception occured: ", e);
259     	}
260     	return null;
261 	}
262 
263     //This is called to resolve tag names to field names based on the element and parent element local names
264 	private String resolveFieldName(String parentName, String nodeName) {
265 		if("constraint".equals(parentName)&&"case".equals(nodeName)){
266 			return "caseConstraint";
267 		}
268 		if("constraint".equals(parentName)&&"typeStateCase".equals(nodeName)){
269 			return "typeStateCaseConstraint";
270 		}
271 		if("constraint".equals(parentName)&&"lookup".equals(nodeName)){
272 			return "lookupConstraint";
273 		}
274 		if("constraint".equals(parentName)&&"occurs".equals(nodeName)){
275 			return "occursConstraint";
276 		}
277 		if("constraint".equals(parentName)&&"require".equals(nodeName)){
278 			return "requireConstraint";
279 		}
280 		if("case".equals(parentName)&&"when".equals(nodeName)){
281 			return "whenConstraint";
282 		}
283 
284 		return nodeName;
285 	}
286 
287 	//Gets the first child element
288 	private Element getFirstChildElement(Node node) {
289         for(int i = 0;i<node.getChildNodes().getLength();i++){
290             Node childNode = node.getChildNodes().item(i);
291             if(Node.ELEMENT_NODE == childNode.getNodeType()){
292                 return (Element) childNode;
293             }
294         }
295         return null;
296     }
297 
298 	//Returns true if the element should be part of a list
299     private boolean isList(String localName) {
300 
301         return "field".equals(localName)||
302         	   "case".equals(localName)||
303         	   "when".equals(localName)||
304         	   "lookup".equals(localName)||
305         	   "lookupKey".equals(localName)||
306         	   "occurs".equals(localName)||
307         	   "constraint".equals(localName)||
308         	   "type".equals(localName)||
309         	   "state".equals(localName)||
310         	   "require".equals(localName);
311     }
312 
313     //This makes use of the spring parent="" functionality 
314 	@Override
315 	protected String getParentName(Element element) {
316 		if(element.hasAttribute("parent")){
317             return element.getAttribute("parent");
318 		}
319 		return super.getParentName(element);
320 	}
321 
322 	//This means any bean without an id attribute gets one auto generated for it
323 	@Override
324 	protected boolean shouldGenerateIdAsFallback() {
325 		return true;
326 	}
327 	
328 }