001    /**
002     * Copyright 2004-2014 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.student.contract.model.util;
017    
018    import org.kuali.student.contract.exception.DictionaryExecutionException;
019    import org.kuali.student.contract.model.*;
020    
021    import java.util.ArrayList;
022    import java.util.LinkedHashSet;
023    import java.util.List;
024    import java.util.Set;
025    
026    /**
027     * Utility that implements searches of the spreadsheet model that are needed
028     * TODO: refactor all the *Writer to use this instead of their own finds.
029     * @author nwright
030     */
031    public class ModelFinder {
032    
033        private SearchModel searchModel;
034        private ServiceContractModel serviceContractModel;
035        private DictionaryModel dictionaryModel;
036    
037        public ModelFinder(DictionaryModel model) {
038            this.dictionaryModel = model;
039            this.searchModel = model;
040            this.serviceContractModel = model;
041        }
042    
043        public ModelFinder(SearchModel model) {
044            this.searchModel = model;
045        }
046    
047        public ModelFinder(ServiceContractModel model) {
048            this.serviceContractModel = model;
049        }
050    
051        public XmlType findXmlType(String xmlTypeName) {
052            for (XmlType xmlType : serviceContractModel.getXmlTypes()) {
053                if (xmlTypeName.equalsIgnoreCase(xmlType.getName())) {
054                    return xmlType;
055                }
056            }
057            return null;
058        }
059    
060        public List<State> findStates(String xmlObject) {
061            List<State> list = new ArrayList();
062            for (State state : dictionaryModel.getStates()) {
063                if (state.getXmlObject().equalsIgnoreCase(xmlObject)) {
064                    list.add(state);
065                }
066            }
067            return list;
068        }
069    
070        public List<Type> findTypes(String xmlObject) {
071            List<Type> list = new ArrayList();
072            for (Type type : dictionaryModel.getTypes()) {
073                if (type.getXmlObject().equalsIgnoreCase(xmlObject)) {
074                    list.add(type);
075                }
076            }
077            return list;
078        }
079    
080        public Type findType(String xmlObject, String typeName) {
081            if (typeName.equalsIgnoreCase(State.DEFAULT)) {
082                return this.getDefaultType();
083            }
084            for (Type type : dictionaryModel.getTypes()) {
085                if (type.getXmlObject().equalsIgnoreCase(xmlObject)) {
086                    if (type.getName().equalsIgnoreCase(typeName)) {
087                        return type;
088                    }
089                }
090            }
091            return null;
092        }
093    
094        public Type findType(String typeKey) {
095            for (Type type : dictionaryModel.getTypes()) {
096                if (type.getTypeKey().equalsIgnoreCase(typeKey)) {
097                    return type;
098                }
099            }
100            return null;
101        }
102    
103        public State findState(String xmlObject, String stateName) {
104            if (stateName.equalsIgnoreCase(State.DEFAULT)) {
105                return this.getDefaultState();
106            }
107            for (State state : dictionaryModel.getStates()) {
108                if (state.getXmlObject().equalsIgnoreCase(xmlObject)) {
109                    if (state.getName().equalsIgnoreCase(stateName)) {
110                        return state;
111                    }
112                }
113            }
114            return null;
115        }
116    
117        public State findState(String stateKey) {
118            for (State state : dictionaryModel.getStates()) {
119                if (state.getStateKey().equalsIgnoreCase(stateKey)) {
120                    return state;
121                }
122            }
123            return null;
124        }
125    
126        public Dictionary findRoot(Dictionary dict) {
127            if (dict.getParent() == null) {
128                return dict;
129            }
130            return findRoot(dict.getParent());
131        }
132    
133        /**
134         * get dictionary entry for the id
135         * @return
136         */
137        public Dictionary findDictionaryEntry(String dictId) {
138            for (Dictionary d : dictionaryModel.getDictionary()) {
139                if (d.getId().equalsIgnoreCase(dictId)) {
140                    return d;
141                }
142            }
143            return null;
144        }
145    
146        /**
147         * get dictionary entries for the state overries
148         * @return
149         */
150        public List<Dictionary> findChildDictionaryEntries(Dictionary parent) {
151            List<Dictionary> list = new ArrayList();
152            for (Dictionary d : dictionaryModel.getDictionary()) {
153                if (d.getParent() == null) {
154                    continue;
155                }
156                if (d.getParent().equals(parent)) {
157                    list.add(d);
158                }
159            }
160            return list;
161        }
162    
163        /**
164         * get dictionary entries for the state overries
165         * @return
166         */
167        public List<Dictionary> findDefaultDictionary() {
168            List<Dictionary> list = new ArrayList(dictionaryModel.getDictionary().size());
169            for (Dictionary d : dictionaryModel.getDictionary()) {
170                if (d.getState().equalsIgnoreCase(State.DEFAULT)) {
171                    list.add(d);
172                }
173            }
174            return list;
175        }
176    
177        public List<Dictionary> findDictionaryEntriees(String xmlTypeName) {
178            List<Dictionary> list = new ArrayList();
179            for (Dictionary dict : dictionaryModel.getDictionary()) {
180                if (dict.getXmlObject().equalsIgnoreCase(xmlTypeName)) {
181                    list.add(dict);
182                }
183            }
184            return list;
185        }
186    
187        public List<Dictionary> findDefaultDictionaryEntriees(String xmlTypeName) {
188            List<Dictionary> list = new ArrayList();
189            for (Dictionary dict : this.findDefaultDictionary()) {
190                if (dict.getXmlObject().equalsIgnoreCase(xmlTypeName)) {
191                    list.add(dict);
192                }
193            }
194            return list;
195        }
196    
197        /**
198         * get dictionary entries for the state overries
199         * @return
200         */
201        public List<Dictionary> findStateOverrideDictionary() {
202            List<Dictionary> list = new ArrayList(dictionaryModel.getDictionary().size());
203            for (Dictionary d : dictionaryModel.getDictionary()) {
204                if (!d.getState().equalsIgnoreCase(State.DEFAULT)) {
205                    list.add(d);
206                }
207            }
208            return list;
209        }
210    
211        /**
212         * Expands a type that has a status of Type.GROUPING.
213         * A group can contain another group
214         * @param state
215         * @return
216         */
217        public Set<Type> expandType(Type type) {
218            Set<Type> types = new LinkedHashSet();
219            if (!type.getStatus().equalsIgnoreCase(Type.GROUPING)) {
220                types.add(type);
221                return types;
222            }
223            String pattern = type.getTypeKey();
224            GroupTypeStatePatternMatcher matcher =
225                    new GroupTypeStatePatternMatcher(pattern);
226            for (Type t : dictionaryModel.getTypes()) {
227                // can't match yourself
228                if (t == type) {
229                    //System.out.println ("skipping itself " + type.getName ());
230                    continue;
231                }
232                if (!t.getInclude()) {
233                    continue;
234                }
235    
236                // must match the same type of object
237                if (type.getXmlObject().equalsIgnoreCase(t.getXmlObject())) {
238                    if (matcher.matches(t.getTypeKey())) {
239                        if (t.getStatus().equalsIgnoreCase(Type.GROUPING)) {
240                            //TODO: Worry about self-recursion
241                            types.addAll(expandType(t));
242                        } else {
243                            types.add(t);
244                        }
245                    }
246                }
247            }
248            return types;
249        }
250    
251        /**
252         * Expands a type that has a status of Type.GROUPING.
253         * A group can contain another group
254         * @param state
255         * @return
256         */
257        public Set<State> expandState(State state) {
258            Set<State> states = new LinkedHashSet();
259            if (!state.getStatus().equalsIgnoreCase(State.GROUPING)) {
260                states.add(state);
261                return states;
262            }
263            String pattern = state.getStateKey();
264            GroupTypeStatePatternMatcher matcher =
265                    new GroupTypeStatePatternMatcher(pattern);
266            for (State s : dictionaryModel.getStates()) {
267                // can't match yourself
268                if (s == state) {
269                    //System.out.println ("skipping itself " + state.getName ());
270                    continue;
271                }
272                if (!s.getInclude()) {
273                    continue;
274                }
275    
276                // must match the same type of object
277                if (state.getXmlObject().equalsIgnoreCase(s.getXmlObject())) {
278                    if (matcher.matches(s.getStateKey())) {
279                        if (s.getStatus().equalsIgnoreCase(Type.GROUPING)) {
280                            //TODO: Worry about self-recursion
281                            states.addAll(expandState(s));
282                        } else {
283                            states.add(s);
284                        }
285                    }
286                }
287            }
288            return states;
289        }
290    
291        public Constraint findConstraint(String id) {
292            for (Constraint cons : dictionaryModel.getConstraints()) {
293                if (cons.getId().equalsIgnoreCase(id)) {
294                    return cons;
295                }
296            }
297            return null;
298        }
299    
300        private static String stripListFromType(String type) {
301            if (type.endsWith("List")) {
302                return type.substring(0, type.length() - "List".length());
303            }
304            return type;
305        }
306    
307        private void loadAllComplexSubTypes(Set<XmlType> types, String xmlTypeName) {
308            for (MessageStructure ms : this.findMessageStructures(xmlTypeName)) {
309                XmlType type = this.findXmlType(stripListFromType(ms.getType()));
310                if (type != null) {
311                    if (type.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
312                        if (types.add(type)) {
313    //                        System.out.println("debug: " + xmlTypeName + "." + ms.getShortName() + " " + type.getName());
314                            loadAllComplexSubTypes(types, type.getName());
315                        }
316                    }
317                }
318            }
319        }
320    
321        public Set<XmlType> findAllComplexSubTypes(String xmlTypeName) {
322            Set<XmlType> types = new LinkedHashSet();
323            this.loadAllComplexSubTypes(types, xmlTypeName);
324            return types;
325        }
326    
327        public Set<XmlType> findAllComplexTypesInService(String service) {
328            Set<XmlType> allTypes = findMainXmlTypesInService(service);
329            for (XmlType type : findMainXmlTypesInService(service)) {
330                this.loadAllComplexSubTypes(allTypes, type.getName());
331            }
332            return allTypes;
333        }
334    
335        public Set<XmlType> findMainXmlTypesInService(String service) {
336            Set<XmlType> types = new LinkedHashSet();
337            for (ServiceMethod method : this.findServiceMethods(service)) {
338                XmlType type = this.findXmlType(stripListFromType(method.getReturnValue().getType()));
339                if (type != null) {
340                    if (type.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
341                        types.add(type);
342                    }
343                }
344    
345                for (ServiceMethodParameter param : method.getParameters()) {
346                    type = this.findXmlType(stripListFromType(param.getType()));
347                    if (type != null) {
348                        if (type.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
349                            types.add(type);
350                        }
351                    }
352                    break;
353                }
354            }
355            return types;
356        }
357    
358        public Field findField(String id) {
359            for (Field field : dictionaryModel.getFields()) {
360                if (field.getId().equalsIgnoreCase(id)) {
361                    return field;
362                }
363            }
364            return null;
365        }
366    
367        public Field findField(String xmlTypeName, String shortName) {
368            return findField(xmlTypeName + "." + shortName);
369        }
370    
371        public Field findField(Dictionary dict) {
372            if (dict.isDynamic()) {
373                return findField(dict.getXmlObject(), "attributes");
374            }
375            return findField(dict.getXmlObject(), dict.getShortName());
376        }
377    
378        public List<Field> findFields(String xmlTypeName) {
379            List<Field> list = new ArrayList();
380            for (Field field : dictionaryModel.getFields()) {
381                if (field.getXmlObject().equalsIgnoreCase(xmlTypeName)) {
382                    list.add(field);
383                }
384            }
385            return list;
386        }
387    
388        public Service findService(String key) {
389            for (Service serv : serviceContractModel.getServices()) {
390                if (serv.getKey().equalsIgnoreCase(key)) {
391                    return serv;
392                }
393            }
394            return null;
395        }
396    
397        public Project findProject(String key) {
398            for (Project proj : dictionaryModel.getProjects()) {
399                if (proj.getKey().equalsIgnoreCase(key)) {
400                    return proj;
401                }
402            }
403            return null;
404        }
405    
406        public SearchType findSearchType(String key) {
407            for (SearchType st : searchModel.getSearchTypes()) {
408                if (st.getKey().equalsIgnoreCase(key)) {
409                    return st;
410                }
411            }
412            return null;
413        }
414    
415        public List<ServiceMethod> findServiceMethods(String service) {
416            List<ServiceMethod> methods = new ArrayList<ServiceMethod>();
417            for (ServiceMethod method : serviceContractModel.getServiceMethods()) {
418                if (method.getService().equalsIgnoreCase(service)) {
419                    methods.add(method);
420                }
421            }
422            return methods;
423        }
424    
425        public ServiceMethod findServiceMethod(String service, String name) {
426            for (ServiceMethod method : serviceContractModel.getServiceMethods()) {
427                if (method.getService().equalsIgnoreCase(service)) {
428                    if (method.getName().equalsIgnoreCase(name)) {
429                        return method;
430                    }
431                }
432            }
433            return null;
434        }
435    
436        public List<ServiceMethod> getServiceMethodsInService(String service) {
437            List<ServiceMethod> list = new ArrayList();
438            for (ServiceMethod method : serviceContractModel.getServiceMethods()) {
439                if (method.getService().equalsIgnoreCase(service)) {
440                    list.add(method);
441                }
442            }
443            return list;
444        }
445    
446        public List<MessageStructure> findMessageStructures(String xmlType) {
447            List<MessageStructure> list = new ArrayList();
448            for (MessageStructure ms : serviceContractModel.getMessageStructures()) {
449                if (ms.getXmlObject().equalsIgnoreCase(xmlType)) {
450                    list.add(ms);
451                }
452            }
453            return list;
454        }
455    
456        public MessageStructure findMessageStructure(String xmlType, String shortName) {
457            for (MessageStructure ms : serviceContractModel.getMessageStructures()) {
458                if (ms.getXmlObject().equalsIgnoreCase(xmlType)) {
459                    if (ms.getShortName().equalsIgnoreCase(shortName)) {
460                        return ms;
461                    }
462                }
463            }
464            return null;
465        }
466        private Type defaultType = null;
467    
468        public Type getDefaultType() {
469            if (defaultType != null) {
470                return defaultType;
471            }
472            List<Type> list = findTypes(Type.DEFAULT);
473            if (list.size() == 0) {
474                throw new DictionaryExecutionException("No default Type found");
475            }
476            if (list.size() > 1) {
477                throw new DictionaryExecutionException("More than one default Type found");
478            }
479            defaultType = list.get(0);
480            return defaultType;
481        }
482        private State defaultState = null;
483    
484        public State getDefaultState() {
485            if (defaultState != null) {
486                return defaultState;
487            }
488            List<State> list = findStates(State.DEFAULT);
489            if (list.size() == 0) {
490                throw new DictionaryExecutionException("No default State found");
491            }
492            if (list.size() > 1) {
493                throw new DictionaryExecutionException("More than one default State found");
494            }
495            defaultState = list.get(0);
496            return defaultState;
497        }
498    }