1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package org.exolab.castor.builder;
40
41 import java.io.File;
42 import java.io.FileInputStream;
43 import java.io.IOException;
44 import java.util.Enumeration;
45 import java.util.Properties;
46
47 import org.castor.core.constants.cpa.JDOConstants;
48 import org.exolab.castor.builder.conflictresolution.ClassNameCRStrategy;
49 import org.exolab.castor.builder.conflictresolution.ClassNameCRStrategyRegistry;
50 import org.exolab.castor.builder.descriptors.DescriptorSourceFactory;
51 import org.exolab.castor.builder.descriptors.JDOClassDescriptorFactory;
52 import org.exolab.castor.builder.factory.MappingFileSourceFactory;
53 import org.exolab.castor.builder.info.ClassInfo;
54 import org.exolab.castor.builder.info.nature.JDOClassInfoNature;
55 import org.exolab.castor.builder.info.nature.XMLInfoNature;
56 import org.exolab.castor.builder.printing.JClassPrinter;
57 import org.exolab.castor.builder.printing.JClassPrinterFactoryRegistry;
58 import org.exolab.castor.mapping.xml.MappingRoot;
59 import org.exolab.castor.util.dialog.ConsoleDialog;
60 import org.exolab.javasource.JClass;
61 import org.exolab.javasource.JComment;
62 import org.exolab.javasource.JNaming;
63
64
65
66
67
68
69
70
71
72
73 public final class SingleClassGenerator {
74
75
76
77
78 private static final String DEFAULT_HEADER = "This class was automatically generated with \n"
79 + "<a href=\"" + SourceGenerator.APP_URI + "\">" + SourceGenerator.APP_NAME + " "
80 + SourceGenerator.VERSION + "</a>, using an XML Schema.\n$" + "Id" + "$";
81
82
83 private static final String CDR_FILE = ".castor.cdr";
84
85 private boolean _promptForOverwrite = true;
86
87 private String _destDir;
88
89
90
91 private String _resourceDestinationDirectory;
92
93 private String _lineSeparator = null;
94
95 private boolean _createDescriptors = true;
96
97
98
99
100 private boolean _createJdoDescriptors = false;
101
102
103 private final JComment _header;
104
105 private final ConsoleDialog _dialog;
106
107
108
109
110 private final DescriptorSourceFactory _descriptorSourceFactory;
111
112
113
114
115 private JDOClassDescriptorFactory _jdoDescriptorSourceFactory;
116
117
118 private final MappingFileSourceFactory _mappingSourceFactory;
119
120 private final SourceGenerator _sourceGenerator;
121
122
123
124
125 private ClassNameCRStrategy _conflictStrategy;
126
127
128
129
130
131 private JClassPrinter _jClassPrinter;
132
133
134
135
136 private ClassNameCRStrategyRegistry _classNameConflictResolutionStrategyRegistry;
137
138
139
140
141
142
143
144
145
146
147 public SingleClassGenerator(final ConsoleDialog dialog, final SourceGenerator sourceGenerator,
148 final String conflictStrategyType, final String jClassPrinterType) {
149 this._dialog = dialog;
150 this._sourceGenerator = sourceGenerator;
151 this._header = new JComment(JComment.HEADER_STYLE);
152 this._descriptorSourceFactory = new DescriptorSourceFactory(_sourceGenerator);
153 this._jdoDescriptorSourceFactory = new JDOClassDescriptorFactory(_sourceGenerator);
154 this._mappingSourceFactory = new MappingFileSourceFactory(_sourceGenerator);
155
156 final String strategy =
157 sourceGenerator.getProperty(BuilderConfiguration.Property.NAME_CONFLICT_STRATEGIES, "");
158 this._classNameConflictResolutionStrategyRegistry = new ClassNameCRStrategyRegistry(strategy);
159 createNameConflictStrategy(conflictStrategyType);
160 createJClassPrinter(jClassPrinterType);
161 }
162
163
164
165
166
167
168 private void createJClassPrinter(final String classPrinterType) {
169 JClassPrinterFactoryRegistry registry = _sourceGenerator.getJClassPrinterFactoryRegistry();
170 this._jClassPrinter = registry.getJClassPrinterFactory(classPrinterType).getJClassPrinter();
171 }
172
173
174
175
176
177
178 public void setJClassPrinterType(final String jclassPrinterType) {
179 this.createJClassPrinter(jclassPrinterType);
180 }
181
182
183
184
185
186
187 public void setDestDir(final String destDir) {
188 _destDir = destDir;
189 if (_resourceDestinationDirectory == null) {
190 _resourceDestinationDirectory = destDir;
191 }
192 }
193
194
195
196
197
198
199 public void setResourceDestinationDirectory(final String destinationDirectory) {
200 _resourceDestinationDirectory = destinationDirectory;
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public void setLineSeparator(final String lineSeparator) {
218 _lineSeparator = lineSeparator;
219 }
220
221
222
223
224
225
226
227 public void setDescriptorCreation(final boolean createDescriptors) {
228 _createDescriptors = createDescriptors;
229 }
230
231
232
233
234
235
236
237
238 public void setJdoDescriptorCreation(final boolean createJdoDescriptors) {
239 _createJdoDescriptors = createJdoDescriptors;
240 }
241
242
243
244
245
246
247
248
249 public void setPromptForOverwrite(final boolean promptForOverwrite) {
250 this._promptForOverwrite = promptForOverwrite;
251 }
252
253
254
255
256
257
258
259
260
261
262
263 boolean processIfNotAlreadyProcessed(final Enumeration<?> classKeys, final SGStateInfo state)
264 throws IOException {
265 while (classKeys.hasMoreElements()) {
266 ClassInfo classInfo = state.resolve(classKeys.nextElement());
267 JClass jClass = classInfo.getJClass();
268 if (!state.processed(jClass)
269 && (inCurrentSchema(state, classInfo) || _sourceGenerator.getGenerateImportedSchemas())) {
270 process(jClass, state);
271 if (state.getStatusCode() == SGStateInfo.STOP_STATUS) {
272 return false;
273 }
274 }
275 }
276 return true;
277 }
278
279
280
281
282
283
284
285
286 private boolean inCurrentSchema(final SGStateInfo state, final ClassInfo classInfo) {
287 final String targetNamespace = state.getSchema().getTargetNamespace();
288 boolean inCurrentSchema = true;
289 if (targetNamespace != null) {
290 if (classInfo.hasNature(XMLInfoNature.class.getName())) {
291 XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
292 inCurrentSchema = targetNamespace.equals(xmlNature.getNamespaceURI());
293 }
294 }
295 return inCurrentSchema;
296 }
297
298
299
300
301
302
303
304
305
306
307
308 boolean process(final JClass[] classes, final SGStateInfo state) throws IOException {
309 for (JClass jClass : classes) {
310 process(jClass, state);
311 if (state.getStatusCode() == SGStateInfo.STOP_STATUS) {
312 return false;
313 }
314 }
315 return true;
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 boolean process(final JClass jClass, final SGStateInfo state) throws IOException {
332 if (state.getStatusCode() == SGStateInfo.STOP_STATUS) {
333 return false;
334 }
335
336 if (state.processed(jClass)) {
337 return true;
338 }
339
340
341 checkNameNotReserved(jClass.getName(), state);
342
343 ClassInfo classInfo = state.resolve(jClass);
344
345
346 JClass conflict = state.getProcessed(jClass.getName());
347 if (conflict != null && !state.getSuppressNonFatalWarnings()) {
348 SGStateInfo stateAfterResolution =
349 _conflictStrategy.dealWithClassNameConflict(state, classInfo, conflict);
350 return stateAfterResolution.getStatusCode() != SGStateInfo.STOP_STATUS;
351 }
352
353
354 state.markAsProcessed(jClass);
355
356
357 if (checkAllowPrinting(jClass)) {
358
359
360 jClass.removeImport("org.exolab.castor.types.Date");
361 jClass.setHeader(_header);
362 if (_lineSeparator == null) {
363 _lineSeparator = System.getProperty("line.separator");
364 }
365 _jClassPrinter.printClass(jClass, _destDir, _lineSeparator, DEFAULT_HEADER);
366 }
367
368
369 if (classInfo != null) {
370 processClassDescriptor(jClass, state, classInfo);
371 if (classInfo.hasNature(JDOClassInfoNature.class.getName())) {
372 processJDOClassDescriptor(jClass, state, classInfo);
373 }
374 }
375
376 return state.getStatusCode() != SGStateInfo.STOP_STATUS;
377 }
378
379
380
381
382
383
384
385
386
387 private void processClassDescriptor(final JClass jClass, final SGStateInfo state,
388 final ClassInfo classInfo) throws IOException {
389 if (_createDescriptors) {
390 JClass desc = _descriptorSourceFactory.createSource(classInfo);
391 if (checkAllowPrinting(desc)) {
392 updateCDRFile(jClass, desc, state, CDR_FILE);
393 desc.setHeader(_header);
394 if (_lineSeparator == null) {
395 _lineSeparator = System.getProperty("line.separator");
396 }
397 _jClassPrinter.printClass(desc, _destDir, _lineSeparator, DEFAULT_HEADER);
398 }
399 } else {
400
401
402 String pkg = state.getPackageName();
403 if (pkg == null) {
404 pkg = "";
405 }
406 MappingRoot mapping = state.getMapping(pkg);
407 if (mapping == null) {
408 mapping = new MappingRoot();
409 state.setMapping(pkg, mapping);
410 }
411 mapping.addClassMapping(_mappingSourceFactory.createMapping(classInfo));
412 }
413 }
414
415
416
417
418
419
420
421
422
423
424 private void processJDOClassDescriptor(final JClass jClass, final SGStateInfo state,
425 final ClassInfo classInfo) throws IOException {
426
427 if (_createJdoDescriptors) {
428 JClass desc = _jdoDescriptorSourceFactory.createSource(classInfo);
429 if (checkAllowPrinting(desc)) {
430 updateCDRFile(jClass, desc, state, JDOConstants.PKG_CDR_LIST_FILE);
431 desc.setHeader(_header);
432 if (_lineSeparator == null) {
433 _lineSeparator = System.getProperty("line.separator");
434 }
435 _jClassPrinter.printClass(desc, _destDir, _lineSeparator, DEFAULT_HEADER);
436 }
437 }
438 }
439
440
441
442
443
444
445
446
447
448
449
450 private boolean checkAllowPrinting(final JClass jClass) {
451 if (!_promptForOverwrite) {
452 return true;
453 }
454
455
456
457 String filename = jClass.getFilename(_destDir);
458 File file = new File(filename);
459
460 if (!file.exists()) {
461 return true;
462 }
463
464 return _conflictStrategy.dealWithFileOverwrite(filename);
465 }
466
467
468
469
470
471
472
473
474 private void checkNameNotReserved(final String elementName, final SGStateInfo sInfo) {
475 if (elementName == null) {
476 return;
477 }
478
479 String nameToCompare = elementName.substring(0, 1).toUpperCase() + elementName.substring(1);
480 if (JNaming.isInJavaLang(nameToCompare)) {
481 String err = "'" + nameToCompare
482 + "' conflicts with a class in java.lang.* and may cause a conflict during\n"
483 + " compilation. If you get this complaint during compilation, you need to\n"
484 + " use a mapping file or change the name of the schema element.";
485 sInfo.getDialog().notify(err);
486 }
487
488 if (JNaming.isReservedByCastor(nameToCompare)) {
489 String warn = "'" + nameToCompare + "' might conflict with a field name used"
490 + " by Castor. If you get a complaint\nabout a duplicate name, you will"
491 + " need to use a mapping file or change\nthe name of the conflicting"
492 + " schema element.";
493 sInfo.getDialog().notify(warn);
494 }
495
496 final String withoutPackage = nameToCompare.substring(nameToCompare.lastIndexOf('.') + 1);
497 if (JNaming.isReservedByWindows(nameToCompare) || JNaming.isReservedByWindows(withoutPackage)) {
498
499 String warn = "'" + nameToCompare + "' is reserved by the Windows filesystem and"
500 + " cannot be\nused as a class name. Windows will not allow you to create"
501 + " a file with this\nname. You will have to use a binding file or change"
502 + " the name of the conflicting\nschema element. For more information,"
503 + " see\nhttp://msdn.microsoft.com/library/default.asp?"
504 + "url=/library/en-us/fileio/fs/naming_a_file.asp";
505 sInfo.getDialog().notify(warn);
506 }
507 }
508
509
510
511
512
513
514
515
516
517
518 private void updateCDRFile(final JClass jClass, final JClass jDesc, final SGStateInfo sInfo,
519 final String cdrFileName) throws IOException {
520 String entityFilename = jClass.getFilename(_resourceDestinationDirectory);
521 File file = new File(entityFilename);
522 File parentDirectory = file.getParentFile();
523 File cdrFile = new File(parentDirectory, cdrFileName);
524 String cdrFilename = cdrFile.getAbsolutePath();
525
526 Properties props = sInfo.getCDRFile(cdrFilename);
527
528 if (props == null) {
529
530 props = new Properties();
531 if (cdrFile.exists()) {
532 try (FileInputStream fileStream = new FileInputStream(cdrFile)) {
533 props.load(fileStream);
534 }
535 }
536 sInfo.setCDRFile(cdrFilename, props);
537 }
538 props.setProperty(jClass.getName(), jDesc.getName());
539 }
540
541
542
543
544
545
546
547 public void setNameConflictStrategy(final String nameConflictStrategy) {
548 createNameConflictStrategy(nameConflictStrategy);
549 }
550
551
552
553
554
555
556
557 private void createNameConflictStrategy(final String nameConflictStrategy) {
558 this._conflictStrategy = _classNameConflictResolutionStrategyRegistry
559 .getClassNameConflictResolutionStrategy(nameConflictStrategy);
560 this._conflictStrategy.setConsoleDialog(_dialog);
561 this._conflictStrategy.setSingleClassGenerator(this);
562 }
563
564
565
566
567
568
569 public SourceGenerator getSourceGenerator() {
570 return _sourceGenerator;
571 }
572
573 }