1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.ole.sys.context;
17  
18  import static org.kuali.ole.sys.OLEConstants.SchemaBuilder.DD_VALIDATION_PREFIX;
19  import static org.kuali.ole.sys.OLEConstants.SchemaBuilder.SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_BEGIN;
20  import static org.kuali.ole.sys.OLEConstants.SchemaBuilder.SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_END;
21  import static org.kuali.ole.sys.OLEConstants.SchemaBuilder.XSD_VALIDATION_PREFIX;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashSet;
28  import java.util.Iterator;
29  import java.util.Set;
30  
31  import org.apache.commons.io.FileUtils;
32  import org.apache.commons.lang.StringUtils;
33  import org.apache.log4j.BasicConfigurator;
34  import org.apache.log4j.Level;
35  import org.apache.log4j.Logger;
36  
37  
38  
39  
40  public class SchemaBuilder {
41      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SchemaBuilder.class);
42      private static Level logLevel = Level.INFO;
43  
44      
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62      public static void main(String[] args) {
63          if (args.length < 5) {
64              System.err.println("ERROR: You must pass the build directory, static directory, dd flag, external content url, and rebuild types flag as arguments");
65              System.exit(8);
66          }
67          try {
68              
69              BasicConfigurator.configure();
70              Logger.getRootLogger().setLevel(Level.WARN);
71              LOG.setLevel(logLevel);
72  
73              String buildDirectoryPath = args[0];
74              if (StringUtils.isBlank(buildDirectoryPath)) {
75                  logAndThrowException("Build directory must be passed as first argument");
76              }
77              if (LOG.isDebugEnabled()) {
78                  LOG.debug("Build directory set to " + buildDirectoryPath);
79              }
80  
81              String staticDirectoryPath = args[1];
82              if (StringUtils.isBlank(staticDirectoryPath)) {
83                  logAndThrowException("Static directory must be passed as second argument");
84              }
85              if (LOG.isDebugEnabled()) {
86                  LOG.debug("Static directory set to " + staticDirectoryPath);
87              }
88  
89              String dataDictionaryValidation = args[2];
90              if (StringUtils.isBlank(dataDictionaryValidation)) {
91                  logAndThrowException("Use data dictionary validation must be passed as third argument");
92              }
93  
94              String externalizableContentUrl = args[3];
95              if (StringUtils.isBlank(externalizableContentUrl)) {
96                  logAndThrowException("Externalizalbe static content URL must be passed as fourth argument");
97              }
98  
99              String rebuildDDTypesFlag = args[4];
100             if (StringUtils.isBlank(rebuildDDTypesFlag)) {
101                 logAndThrowException("Rebuild DD flags must be passed as fifth argument");
102             }
103 
104             boolean useDataDictionaryValidation = Boolean.parseBoolean(dataDictionaryValidation);
105             boolean rebuildDDTypes = Boolean.parseBoolean(rebuildDDTypesFlag);
106             if (LOG.isDebugEnabled()) {
107                 LOG.debug("Use data dictionary validation set to " + useDataDictionaryValidation);
108             }
109 
110             
111             if (useDataDictionaryValidation && rebuildDDTypes) {
112                 SpringContextForBatchRunner.initializeKfs();
113             }
114 
115             LOG.debug("Getting build schema files");
116             Collection buildSchemaFiles = getBuildSchemaFiles(buildDirectoryPath);
117 
118             LOG.debug("Building schema files");
119             try {
120                 buildSchemaFiles(buildSchemaFiles, staticDirectoryPath, buildDirectoryPath, useDataDictionaryValidation, externalizableContentUrl, rebuildDDTypes);
121             }
122             catch (IOException ex) {
123                 LOG.error("Error building schema files: " + ex.getMessage(), ex);
124                 throw new RuntimeException("Error building schema files: " + ex.getMessage(), ex);
125             }
126 
127             LOG.info("Finished building schema files.");
128             System.exit(0);
129         }
130         catch (Throwable t) {
131             System.err.println("ERROR: Exception caught: " + t.getMessage());
132             t.printStackTrace(System.err);
133             System.exit(8);
134         }
135     }
136 
137     
138 
139 
140 
141 
142 
143     protected static Collection getBuildSchemaFiles(String buildDirectoryPath) {
144         File buildDirectory = new File(buildDirectoryPath);
145 
146         return FileUtils.listFiles(buildDirectory, new String[] { "xsd" }, true);
147     }
148 
149     
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161     protected static void buildSchemaFiles(Collection buildSchemaFiles, String staticDirectoryPath, String buildDirectoryPath, boolean useDataDictionaryValidation, String externalizableContentUrl, boolean rebuildDDTypes) throws IOException {
162         
163         Collection typesSchemaLines = initalizeDataDictionaryTypesSchema();
164         Set<String> builtTypes = new HashSet<String>();
165 
166         
167         File staticDirectory = new File(staticDirectoryPath);
168         String staticPathName = staticDirectory.getAbsolutePath();
169 
170         for (Iterator iterator = buildSchemaFiles.iterator(); iterator.hasNext();) {
171             File buildSchemFile = (File) iterator.next();
172             if (LOG.isDebugEnabled()) {
173                 LOG.debug("Processing schema file: " + buildSchemFile.getName());
174             }
175 
176             String outSchemaFilePathName = staticPathName + getRelativeFilePathName(buildSchemFile, buildDirectoryPath);
177             LOG.info("Building schema file: " + outSchemaFilePathName);
178 
179             buildSchemaFile(buildSchemFile, outSchemaFilePathName, useDataDictionaryValidation, typesSchemaLines, externalizableContentUrl, builtTypes, rebuildDDTypes);
180         }
181 
182         
183         typesSchemaLines.addAll(finalizeDataDictionaryTypesSchema());
184 
185         if (rebuildDDTypes) {
186             LOG.debug("Writing ddTypes schema file");
187             File ddTypesFile = new File(staticPathName + File.separator + "xsd" + File.separator + "sys" + File.separator + "ddTypes.xsd");
188             File ddTypesFileBuild = new File(buildDirectoryPath + File.separator + "xsd" + File.separator + "sys" + File.separator + "ddTypes.xsd");
189             FileUtils.writeLines(ddTypesFile, typesSchemaLines);
190             FileUtils.copyFile(ddTypesFile, ddTypesFileBuild);
191         }
192     }
193 
194     
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207     protected static void buildSchemaFile(File buildSchemFile, String outSchemaFilePathName, boolean useDataDictionaryValidation, Collection typesSchemaLines, String externalizableContentUrl, Set<String> builtTypes, boolean rebuildDDTypes) throws IOException {
208         Collection buildSchemaLines = FileUtils.readLines(buildSchemFile);
209         Collection outSchemaLines = new ArrayList();
210         int lineCount = 1;
211         for (Iterator iterator = buildSchemaLines.iterator(); iterator.hasNext();) {
212             if (LOG.isDebugEnabled()) {
213                 LOG.debug("Processing line " + lineCount + "of file " + buildSchemFile.getAbsolutePath());
214             }
215             String buildLine = (String) iterator.next();
216             String outLine = buildLine;
217 
218             
219             if (StringUtils.contains(buildLine, "@externalizable.static.content.url@")) {
220                 outLine = StringUtils.replace(buildLine, "@externalizable.static.content.url@", externalizableContentUrl);
221             }
222 
223             
224             else if (StringUtils.contains(buildLine, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_BEGIN) && StringUtils.contains(buildLine, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_END)) {
225                 String validationPlaceholder = StringUtils.substringBetween(buildLine, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_BEGIN, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_END);
226                 if (StringUtils.isBlank(validationPlaceholder)) {
227                     logAndThrowException(String.format("File %s line %s: validation placeholder cannot be blank", buildSchemFile.getAbsolutePath(), lineCount));
228                 }
229 
230                 if (LOG.isDebugEnabled()) {
231                     LOG.debug("Found dd validation placeholder: " + validationPlaceholder);
232                 }
233                 if (!StringUtils.contains(validationPlaceholder, ",")) {
234                     logAndThrowException(String.format("File %s, line %s: Invalid format of placehoder value: %s, must contain a ',' seperating parts", buildSchemFile.getAbsolutePath(), lineCount, validationPlaceholder));
235                 }
236 
237                 outLine = processValidationPlaceholder(validationPlaceholder, buildLine, buildSchemFile.getAbsolutePath(), lineCount, useDataDictionaryValidation, typesSchemaLines, builtTypes, rebuildDDTypes);
238             }
239 
240             outSchemaLines.add(outLine);
241             lineCount++;
242         }
243 
244         LOG.debug("Writing schema file to static directory");
245         File schemaFile = new File(outSchemaFilePathName);
246         FileUtils.writeLines(schemaFile, outSchemaLines);
247     }
248 
249     
250 
251 
252 
253 
254 
255 
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270     protected static String processValidationPlaceholder(String validationPlaceholder, String buildLine, String fileName, int lineCount, boolean useDataDictionaryValidation, Collection typesSchemaLines, Set<String> builtTypes, boolean rebuildDDTypes) {
271         String orignalPlaceholderValue = validationPlaceholder;
272 
273         
274         validationPlaceholder = StringUtils.deleteWhitespace(validationPlaceholder);
275 
276         
277         String[] validationParts = StringUtils.split(validationPlaceholder, ",");
278         String xsdValidation = validationParts[0];
279         if (StringUtils.isBlank(xsdValidation) || !xsdValidation.startsWith(XSD_VALIDATION_PREFIX)) {
280             logAndThrowException(String.format("File %s, line %s: specified xsd validation is invalid, must start with %s", fileName, lineCount, XSD_VALIDATION_PREFIX));
281         }
282 
283         String ddAttributeName = validationParts[1];
284         if (StringUtils.isBlank(ddAttributeName) || !ddAttributeName.startsWith(DD_VALIDATION_PREFIX)) {
285             logAndThrowException(String.format("File %s, line %s: specified dd validation is invalid, must start with %s", fileName, lineCount, DD_VALIDATION_PREFIX));
286         }
287 
288         String outLine = buildLine;
289         if (useDataDictionaryValidation) {
290             if (LOG.isDebugEnabled()) {
291                 LOG.debug("Setting validation to use type: " + ddAttributeName);
292             }
293             outLine = StringUtils.replace(outLine, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_BEGIN + orignalPlaceholderValue + SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_END, ddAttributeName);
294 
295             if (rebuildDDTypes) {
296                 buildDataDictionarySchemaValidationType(ddAttributeName, typesSchemaLines, builtTypes);
297             }
298         }
299         else {
300             if (LOG.isDebugEnabled()) {
301                 LOG.debug("Setting validation to use type: " + xsdValidation);
302             }
303             outLine = StringUtils.replace(outLine, SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_BEGIN + orignalPlaceholderValue + SCHEMA_FILE_DD_VALIDATION_PLACEHOLDER_END, xsdValidation);
304         }
305 
306         return outLine;
307     }
308 
309     
310 
311 
312 
313 
314 
315 
316 
317 
318     protected static void buildDataDictionarySchemaValidationType(String ddAttributeName, Collection typesSchemaLines, Set<String> builtTypes) {
319         
320         String attributeEntryName = StringUtils.removeStart(ddAttributeName, DD_VALIDATION_PREFIX);
321         if (LOG.isDebugEnabled()) {
322             LOG.debug("Retrieving entry from data dictionary for attribute: " + attributeEntryName);
323         }
324 
325         
326         if (!builtTypes.contains(attributeEntryName)) {
327             AttributeSchemaValidationBuilder schemaBuilder = new AttributeSchemaValidationBuilder(attributeEntryName);
328             typesSchemaLines.addAll(schemaBuilder.toSchemaType());
329             typesSchemaLines.add(" ");
330 
331             builtTypes.add(attributeEntryName);
332         }
333     }
334 
335     
336 
337 
338 
339 
340     protected static Collection initalizeDataDictionaryTypesSchema() {
341         LOG.debug("Initializing dd types schema");
342         Collection typesSchemaLines = new ArrayList();
343 
344         typesSchemaLines.add("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
345         typesSchemaLines.add("<xsd:schema elementFormDefault=\"qualified\"");
346         typesSchemaLines.add("    targetNamespace=\"http://www.kuali.org/ole/sys/ddTypes\"");
347         typesSchemaLines.add("    xmlns:dd=\"http://www.kuali.org/ole/sys/ddTypes\"");
348         typesSchemaLines.add("    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
349         typesSchemaLines.add("");
350 
351         return typesSchemaLines;
352     }
353 
354     
355 
356 
357 
358 
359     protected static Collection finalizeDataDictionaryTypesSchema() {
360         LOG.debug("Finalizing dd types schema");
361         Collection typesSchemaLines = new ArrayList();
362 
363         typesSchemaLines.add("</xsd:schema>");
364 
365         return typesSchemaLines;
366     }
367 
368     
369 
370 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380     protected static String getRelativeFilePathName(File file, String parentPath) {
381         
382         File parentDirectory = new File(parentPath);
383 
384         String fullParentPathName = parentDirectory.getAbsolutePath();
385         String fullFilePathName = file.getAbsolutePath();
386 
387         String relativeFilePathName = StringUtils.substringAfter(fullFilePathName, fullParentPathName);
388         if (LOG.isDebugEnabled()) {
389             LOG.debug("sub-directory for schema: " + relativeFilePathName);
390         }
391 
392         if (StringUtils.isBlank(relativeFilePathName)) {
393             String msg = String.format("Cannot find relative path for file name %s from parent directory %s", fullFilePathName, fullParentPathName);
394             LOG.error(msg);
395             throw new RuntimeException(msg);
396         }
397 
398         return relativeFilePathName;
399     }
400 
401     
402 
403 
404 
405 
406     protected static void logAndThrowException(String msg) {
407         LOG.error(msg);
408         throw new RuntimeException(msg);
409     }
410 
411 }