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 }