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/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     */
016    package org.kuali.kfs.sys.spring.datadictionary;
017    
018    import java.util.ArrayList;
019    import java.util.HashMap;
020    import java.util.List;
021    import java.util.Map;
022    
023    import org.apache.commons.lang.StringUtils;
024    import org.kuali.rice.kns.datadictionary.DocumentCollectionPath;
025    import org.kuali.rice.kns.datadictionary.DocumentValuePathGroup;
026    import org.kuali.rice.kns.datadictionary.RoutingAttribute;
027    import org.kuali.rice.kns.datadictionary.RoutingTypeDefinition;
028    import org.kuali.rice.kns.datadictionary.SearchingAttribute;
029    import org.kuali.rice.kns.datadictionary.SearchingTypeDefinition;
030    import org.kuali.rice.kns.datadictionary.WorkflowAttributeMetadata;
031    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
032    import org.springframework.beans.factory.xml.ParserContext;
033    import org.w3c.dom.Element;
034    import org.w3c.dom.Node;
035    import org.w3c.dom.NodeList;
036    
037    public class WorkflowAttributesBeanDefinitionParser extends KualiBeanDefinitionParserBase {
038        private static final String SEARCHING_ATTRIBUTE = "searchingAttribute";
039        private static final String ROUTING_ATTRIBUTE = "routingAttribute";
040        private static final String DOCUMENT_VALUE_ATTRIBUTE = "documentValue";
041        private static final String SEARCHING_TYPES_ELEMENT = "searchingType";
042        private static final String ROUTING_TYPES_ELEMENT = "routingType";
043    
044        @Override
045        protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder bean) {
046            handleAbstractAttribute(element, bean);
047    
048            parseChildElements(element, bean);
049        }
050    
051        protected void parseChildElements(Element workflowAttributeElement, BeanDefinitionBuilder bean) {
052            NodeList children = workflowAttributeElement.getChildNodes();
053            List<SearchingTypeDefinition> searchingAttributesMap = parseSearchableAttributes(children);
054            bean.addPropertyValue("searchingTypeDefinitions", searchingAttributesMap);
055            
056            Map<String, RoutingTypeDefinition> routingTypesMap = parseRoutingTypes(children);
057            bean.addPropertyValue("routingTypeDefinitions", routingTypesMap);
058        }
059        
060        protected List<SearchingTypeDefinition> parseSearchableAttributes(NodeList workflowAttributesChildren) {
061            List<SearchingTypeDefinition> searchingAttributesMap = new ArrayList<SearchingTypeDefinition>();
062            for (int i = 0; i < workflowAttributesChildren.getLength(); i++) {
063                Node workflowAttributesChild = workflowAttributesChildren.item(i);
064                if (workflowAttributesChild.getNodeType() == Node.ELEMENT_NODE) {
065                    if (((Element) workflowAttributesChild).getLocalName().equals(SEARCHING_TYPES_ELEMENT)) {
066                        
067                        SearchingTypeDefinition searchingTypeDefinition = parseSearchingTypes(workflowAttributesChild.getChildNodes());
068                        
069                        searchingAttributesMap.add(searchingTypeDefinition);
070                    }
071                }
072            }
073            return searchingAttributesMap;
074        }
075        
076        protected List<Element> extractWorkflowAttributeElements(NodeList nodes, String attributeElementName) {
077            List<Element> results = new ArrayList<Element>();
078            
079            for (int i = 0; i < nodes.getLength(); i++) {
080                Node node = nodes.item(i);
081                if (node.getNodeType() == Node.ELEMENT_NODE) {
082                    if (StringUtils.isEmpty(attributeElementName) || ((Element) node).getLocalName().equals(attributeElementName)) {
083                        results.add((Element) node);
084                    }
085                }
086            }
087            return results;
088        }
089        
090        protected SearchingTypeDefinition parseSearchingTypes(NodeList workflowAttributesChildren) {
091            SearchingTypeDefinition  searchingTypeDefinition  = new SearchingTypeDefinition();
092            
093            for (int i = 0; i < workflowAttributesChildren.getLength(); i++) {
094                Node workflowAttributesChild = workflowAttributesChildren.item(i);
095                if (workflowAttributesChild.getNodeType() == Node.ELEMENT_NODE) {
096                    if (((Element) workflowAttributesChild).getLocalName().equals(SEARCHING_ATTRIBUTE)){
097                        searchingTypeDefinition.setSearchingAttribute((SearchingAttribute)parseAttributeDefinition((Element) workflowAttributesChild));
098                    }else if(((Element) workflowAttributesChild).getLocalName().equals(DOCUMENT_VALUE_ATTRIBUTE)){
099                        if(searchingTypeDefinition.getDocumentValues() == null){
100                            searchingTypeDefinition.setDocumentValues(new ArrayList<String>());
101                        }
102                        searchingTypeDefinition.getDocumentValues().addAll(parseDocumentValueAttributeDefinition((Element) workflowAttributesChild));
103                    }
104                }
105            }
106            
107            return searchingTypeDefinition;
108        }
109        protected WorkflowAttributeMetadata parseAttributeDefinition(Element workflowAttributeDefinitionElement) {
110            WorkflowAttributeMetadata workflowAttributeMetadata = null;
111            if(workflowAttributeDefinitionElement.getLocalName().equals(SEARCHING_ATTRIBUTE)){
112                return parseSearchingAttribute(workflowAttributeDefinitionElement);
113            }else if(workflowAttributeDefinitionElement.getLocalName().equals(ROUTING_ATTRIBUTE)){
114                return parseRoutingAttribute(workflowAttributeDefinitionElement);
115            }
116            return workflowAttributeMetadata;
117        }
118        
119        
120        protected WorkflowAttributeMetadata parseSearchingAttribute(Element workflowAttributeDefinitionElement) {
121            SearchingAttribute workflowAttributeMetadata = new SearchingAttribute();
122    
123            String businessObjectClassName = workflowAttributeDefinitionElement.getAttribute("businessObjectClassName");
124            if (StringUtils.isNotBlank(businessObjectClassName)) {
125                try {
126                    Class.forName(businessObjectClassName);
127                    workflowAttributeMetadata.setBusinessObjectClassName(businessObjectClassName);
128                }
129                catch (ClassNotFoundException e) {
130                    throw new RuntimeException("Unable to find class of name " + businessObjectClassName + " when parsing workflowAttribute");
131                }
132            }
133            String attributeName = workflowAttributeDefinitionElement.getAttribute("attributeName");
134            if (StringUtils.isNotBlank(attributeName)) {
135                workflowAttributeMetadata.setAttributeName(attributeName);
136            }
137            
138            return workflowAttributeMetadata;
139        }
140        
141        protected WorkflowAttributeMetadata parseRoutingAttribute(Element workflowAttributeDefinitionElement) {
142            RoutingAttribute workflowAttributeMetadata = new RoutingAttribute();
143    
144            String attributeName = workflowAttributeDefinitionElement.getAttribute("qualificationAttributeName");
145            if (StringUtils.isNotBlank(attributeName)) {
146                workflowAttributeMetadata.setQualificationAttributeName(attributeName);
147            }
148            
149            return workflowAttributeMetadata;
150        }
151        
152        protected List<String> parseDocumentValueAttributeDefinition(Element workflowAttributeDefinitionElement) {
153    
154            List<String>paths = new ArrayList<String>();
155            paths.add(workflowAttributeDefinitionElement.getAttribute("path"));
156           
157            return paths;
158        }
159        protected Map<String, RoutingTypeDefinition> parseRoutingTypes(NodeList workflowAttributesChildren) {
160            Map<String, RoutingTypeDefinition> routingTypesMap = new HashMap<String, RoutingTypeDefinition>();
161            
162            for (int i = 0; i < workflowAttributesChildren.getLength(); i++) {
163                Node workflowAttributesChild = workflowAttributesChildren.item(i);
164                if (workflowAttributesChild.getNodeType() == Node.ELEMENT_NODE) {
165                    if (((Element) workflowAttributesChild).getLocalName().equals(ROUTING_TYPES_ELEMENT)) {
166                        RoutingTypeDefinition routingTypeDefinition = new RoutingTypeDefinition();
167                        Element routingTypeElement = (Element) workflowAttributesChild;
168                        
169                        String name = routingTypeElement.getAttribute("nodeName");
170                        
171                        List<RoutingAttribute> routingAttributes = new ArrayList<RoutingAttribute>();
172                        List<DocumentValuePathGroup> documentValuePathGroups = new ArrayList<DocumentValuePathGroup>();
173                        List<Element> workflowAttributeList = extractWorkflowAttributeElements(routingTypeElement.getChildNodes(), "");
174                        for (int j = 0; j < workflowAttributeList.size(); j++) {
175                            Element workflowAttributeDefinitionElement = (Element) workflowAttributeList.get(j);
176                            if(workflowAttributeDefinitionElement.getLocalName().equals("routingAttributes")){
177                                List<Element> routingAttributeList = extractWorkflowAttributeElements(workflowAttributeDefinitionElement.getChildNodes(), "routingAttribute");
178                                for(Element routingAttribute:routingAttributeList){
179                                    routingAttributes.add((RoutingAttribute)parseAttributeDefinition(routingAttribute));
180                                }
181                            }
182                            else if(workflowAttributeDefinitionElement.getLocalName().equals("documentValuePathGroup")){
183                                documentValuePathGroups.add(parseDocumentValuesPathGroup(workflowAttributeDefinitionElement));
184                            }
185                        }
186                        routingTypeDefinition.setDocumentValuePathGroups(documentValuePathGroups);
187                        routingTypeDefinition.setRoutingAttributes(routingAttributes);
188                        routingTypesMap.put(name, routingTypeDefinition);
189                    }
190                }
191            }
192            
193            return routingTypesMap;
194        }
195        
196        protected DocumentCollectionPath parseDocumentCollectionPath(Element workflowAttributeDefinitionElement) {
197            DocumentCollectionPath documentCollectionPath = new DocumentCollectionPath();
198            for(Element element:extractWorkflowAttributeElements(workflowAttributeDefinitionElement.getChildNodes(), "documentCollectionPath")){
199                documentCollectionPath.setNestedCollection(parseDocumentCollectionPath(element));
200            }
201            List<String>paths = new ArrayList<String>();
202            for(Element element:extractWorkflowAttributeElements(workflowAttributeDefinitionElement.getChildNodes(), "documentValue")){
203                paths.addAll(parseDocumentValueAttributeDefinition(element));
204            }
205            documentCollectionPath.setDocumentValues(paths);
206            
207            String collectionName = workflowAttributeDefinitionElement.getAttribute("path");
208            documentCollectionPath.setCollectionPath(collectionName);
209            
210            return documentCollectionPath;
211        }
212        protected DocumentValuePathGroup parseDocumentValuesPathGroup(Element workflowAttributeDefinitionElement) {
213            DocumentValuePathGroup documentValuePathGroup = new DocumentValuePathGroup();
214            
215            List<Element> documentCollectionPathElements = extractWorkflowAttributeElements(workflowAttributeDefinitionElement.getChildNodes(), "documentCollectionPath");
216            if( documentCollectionPathElements.size() > 0){
217                documentValuePathGroup.setDocumentCollectionPath(parseDocumentCollectionPath(documentCollectionPathElements.get(0)));
218            }
219            List<String>paths = new ArrayList<String>();
220            for(Element element:extractWorkflowAttributeElements(workflowAttributeDefinitionElement.getChildNodes(), "documentValue")){
221                paths.addAll(parseDocumentValueAttributeDefinition(element));
222            }
223            documentValuePathGroup.setDocumentValues(paths);
224    
225            return documentValuePathGroup;
226        }
227        
228        @Override
229        protected String getBaseBeanTypeParent(Element element) {
230            return "WorkflowAttributes";
231        }
232    
233    }