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 */
016package org.kuali.student.datadictionary.util;
017
018import java.io.File;
019import java.io.FileNotFoundException;
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.HashSet;
024import java.util.LinkedHashMap;
025import java.util.LinkedHashSet;
026import java.util.List;
027import java.util.Map;
028import java.util.Set;
029
030import org.apache.commons.io.FileUtils;
031import org.apache.commons.lang.exception.ExceptionUtils;
032import org.kuali.rice.krad.datadictionary.DataObjectEntry;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035import org.springframework.context.support.ClassPathXmlApplicationContext;
036
037public class DictionaryTesterHelper {
038
039        private static final Logger log = LoggerFactory.getLogger(DictionaryTesterHelper.class);
040        
041        private String outputDir;
042        private Collection<String> inputFiles;
043        private List<String> supportFiles;
044        
045        private Map<String, List<String>>inputFileToBeanNameMap = new LinkedHashMap<String, List<String>>();
046
047        private Set<String> missingDictionaryFiles;
048
049        private Set<String> invalidDictionaryFiles;
050        
051        
052
053        public DictionaryTesterHelper(String outputDir, Collection<String> inputFiles,
054                        List<String> supportFiles) {
055                this.outputDir = outputDir;
056                this.inputFiles = inputFiles;
057                this.supportFiles = supportFiles;
058        }
059
060        // public void loadApplicationContext() {
061        // System.out.println
062        // ("DictionaryTesterHelper: begin loading application context");
063        //
064        // ac = new PathValidatingClassPathXmlApplicationContext();
065        //
066        // for (String candidateConfigFile : this.configFiles) {
067        // ac.addContextFile(candidateConfigFile);
068        // }
069        //
070        // ac.buildApplicationContext();
071        // System.out.println
072        // ("DictionaryTesterHelper: end loading application context");
073        // }
074        //
075        // public Map<String, DataObjectEntry> getDataObjectEntryBeans () {
076        // return (Map<String, DataObjectEntry>)
077        // ac.getBeansOfType(DataObjectEntry.class);
078        // }
079
080        public void doTest(String projectVersion, String formattedDate) {
081
082                missingDictionaryFiles = new LinkedHashSet<String>();
083                
084                invalidDictionaryFiles = new LinkedHashSet<String>();
085                
086                for (String inputFile : inputFiles) {
087
088                        List<String> contextFiles = new ArrayList<String>();
089
090                        contextFiles.add(inputFile);
091                        contextFiles.addAll(supportFiles);
092
093                        ClassPathXmlApplicationContext ac;
094                        try {
095                                log.info("Starting on inputFile: " + inputFile);
096                                
097                                ac = new ClassPathXmlApplicationContext(
098                                                contextFiles.toArray(new String[0]));
099                        } catch (Exception e) {
100                                log.warn ("FAILED to valildate file: " + inputFile, e);
101                                
102                                Throwable cause = e.getCause();
103                                if (cause != null && cause instanceof FileNotFoundException) {
104                                        missingDictionaryFiles.add(inputFile);
105                                }
106                                else {
107                                        // In this case we should create a place holder page 
108                                        writePlaceholderPage(inputFile, cause);
109                                        invalidDictionaryFiles.add(inputFile);
110                                }
111                                continue; // skip over this file.
112                        }
113
114                        ArrayList<String> associatedBeanNameList  = new ArrayList<String>();
115                        
116                        Map<String, DataObjectEntry> beansOfType = ac
117                                        .getBeansOfType(DataObjectEntry.class);
118
119                        for (String beanId : beansOfType.keySet()) {
120                                
121                                try {
122                                DataObjectEntry doe = beansOfType.get(beanId);
123                                if ("org.kuali.rice.krad.bo.AttributeReferenceDummy".equals(doe
124                                                .getFullClassName())) {
125                                        continue;
126                                }
127                                
128                                associatedBeanNameList.add(beanId);
129                                
130                                log.info("Processing data object entry: "
131                                                + doe.getDataObjectClass().getName());
132                                DictionaryValidator validator = new DictionaryValidator(doe,
133                                                new HashSet<DataObjectEntry>());
134                                List<String> errors = validator.validate();
135                                if (errors != null) {
136                                        if (!errors.isEmpty()) {
137                                                throw new IllegalArgumentException(
138                                                                "Errors validating bean " + beanId + "\n"
139                                                                                + this.formatAsString(errors));
140                                        }
141                                }
142                                String outputFileName = beanId + ".html";
143                                String fullOutputFileName = this.outputDir + "/"
144                                                + outputFileName;
145                                DictionaryFormatter formatter = new DictionaryFormatter(doe,
146                                                beansOfType, beanId, fullOutputFileName);
147                                
148                                        formatter.formatForHtml(projectVersion, formattedDate);
149                                        
150                                        
151                                } catch (Exception e) {
152                                        
153                                        log.warn("FAILED to format dictionary page for: " + beanId, e);
154                                        invalidDictionaryFiles.add(inputFile);
155                                        continue;
156                                }
157                                
158                        }
159                        
160                        if (associatedBeanNameList.size() > 0) {
161                                inputFileToBeanNameMap.put(inputFile, associatedBeanNameList);
162                        }
163                        
164                        log.info("Finished processing inputFile: " + inputFile);
165                }
166        }
167
168        /*
169         * In some cases like where spring fails to parse the input file we will want to write a place holder with the cause.
170         * 
171         */
172        private void writePlaceholderPage(String inputFile, Throwable cause) {
173                
174                String[] parts = inputFile.split ("-");
175                
176                String beanId = parts[1];
177                
178                        String outputFileName = beanId + ".html";
179                        String fullOutputFileName = this.outputDir + "/"
180                                        + outputFileName;
181                
182                        try {
183                                FileUtils.writeStringToFile(new File (fullOutputFileName), "<html><body><h1>Failed To Generate Page due to Error in Dictionary File: "+inputFile+"</h1>" +ExceptionUtils.getFullStackTrace(cause) + "</body></html>", false);
184                        } catch (IOException e) {
185                                log.warn("failed to write placeholder page: " + inputFile, e);
186                }
187        }
188
189        private String formatAsString(List<String> errors) {
190                int i = 0;
191                StringBuilder builder = new StringBuilder();
192                for (String error : errors) {
193                        i++;
194                        builder.append(i).append(". ").append(error).append("\n");
195                }
196                return builder.toString();
197        }
198
199        /**
200         * @return the inputFileToBeanNameMap
201         */
202        public Map<String, List<String>> getInputFileToBeanNameMap() {
203                return inputFileToBeanNameMap;
204        }
205
206        /**
207         * @return the missingDictionaryFiles
208         */
209        public Set<String> getMissingDictionaryFiles() {
210                return missingDictionaryFiles;
211        }
212
213        /**
214         * @return the invalidDictionaryFiles
215         */
216        public Set<String> getInvalidDictionaryFiles() {
217                return invalidDictionaryFiles;
218        }
219        
220        
221        
222}