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