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.datadictionary.util;
017    
018    import java.io.File;
019    import java.io.FileNotFoundException;
020    import java.io.IOException;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.HashSet;
024    import java.util.LinkedHashMap;
025    import java.util.LinkedHashSet;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import org.apache.commons.io.FileUtils;
031    import org.apache.commons.lang.exception.ExceptionUtils;
032    import org.kuali.rice.krad.datadictionary.DataObjectEntry;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    import org.springframework.context.support.ClassPathXmlApplicationContext;
036    
037    public 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    }