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 package org.exolab.castor.tools;
46
47 import java.io.File;
48 import java.io.FileWriter;
49 import java.io.PrintWriter;
50 import java.io.Writer;
51 import java.util.Enumeration;
52 import java.util.Hashtable;
53 import java.util.Properties;
54
55 import org.castor.xml.BackwardCompatibilityContext;
56 import org.castor.xml.InternalContext;
57 import org.exolab.castor.mapping.FieldDescriptor;
58 import org.exolab.castor.mapping.MappingException;
59 import org.exolab.castor.mapping.loader.CollectionHandlers;
60 import org.exolab.castor.mapping.loader.Types;
61 import org.exolab.castor.mapping.xml.BindXml;
62 import org.exolab.castor.mapping.xml.ClassChoice;
63 import org.exolab.castor.mapping.xml.ClassMapping;
64 import org.exolab.castor.mapping.xml.FieldMapping;
65 import org.exolab.castor.mapping.xml.MapTo;
66 import org.exolab.castor.mapping.xml.MappingRoot;
67 import org.exolab.castor.mapping.xml.types.BindXmlNodeType;
68 import org.exolab.castor.mapping.xml.types.FieldMappingCollectionType;
69 import org.exolab.castor.util.CommandLineOptions;
70 import org.exolab.castor.util.dialog.ConsoleDialog;
71 import org.exolab.castor.xml.Marshaller;
72 import org.exolab.castor.xml.XMLClassDescriptor;
73 import org.exolab.castor.xml.XMLContext;
74 import org.exolab.castor.xml.XMLFieldDescriptor;
75
76
77
78
79
80
81
82
83
84 public class MappingTool {
85
86 private static final String UNDERSCORE = "_";
87
88
89 private Hashtable _mappings;
90
91
92
93
94
95 private MappingToolMappingLoader _mappingLoader;
96
97
98
99
100
101 private boolean _forceIntrospection = false;
102
103
104
105
106 private InternalContext _internalContext;
107
108
109
110
111 public MappingTool() {
112 super();
113 }
114
115
116
117
118
119
120
121 public static void main(final String[] args) {
122 CommandLineOptions allOptions = new CommandLineOptions();
123
124
125 allOptions.addFlag("i", "classname", "Sets the input class");
126
127
128 String desc = "Sets the output mapping filename";
129 allOptions.addFlag("o", "filename", desc, true);
130
131
132 desc = "Force overwriting of files.";
133 allOptions.addFlag("f", "", desc, true);
134
135
136 desc = "Displays this help screen.";
137 allOptions.addFlag("h", "", desc, true);
138
139
140 Properties options = allOptions.getOptions(args);
141
142
143 if (options.getProperty("h") != null) {
144 PrintWriter pw = new PrintWriter(System.out, true);
145 allOptions.printHelp(pw);
146 pw.flush();
147 return;
148 }
149
150 String classname = options.getProperty("i");
151 String mappingName = options.getProperty("o");
152 boolean force = (options.getProperty("f") != null);
153
154 if (classname == null) {
155 PrintWriter pw = new PrintWriter(System.out, true);
156 allOptions.printUsage(pw);
157 pw.flush();
158 return;
159 }
160
161 MappingTool tool;
162
163 try {
164 XMLContext xmlContext = new XMLContext();
165 tool = xmlContext.createMappingTool();
166 tool.addClass(classname);
167
168 Writer writer = null;
169
170 if ((mappingName == null) || (mappingName.length() == 0)) {
171 writer = new PrintWriter(System.out, true);
172 } else {
173 File file = new File(mappingName);
174 if (file.exists() && (!force)) {
175 ConsoleDialog dialog = new ConsoleDialog();
176 String message = "The file already exists. Do you wish " + "to overwrite '"
177 + mappingName + "'?";
178 if (!dialog.confirm(message)) {
179 return;
180 }
181 }
182 writer = new FileWriter(file);
183 }
184
185 tool.write(writer);
186 } catch (Exception except) {
187 System.out.println(except);
188 except.printStackTrace();
189 }
190 }
191
192
193
194
195
196
197
198
199
200 public void addClass(final String name) throws MappingException {
201 addClass(name, true);
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216 public void addClass(final String name, final boolean deep) throws MappingException {
217 if (name == null) {
218 throw new MappingException("Cannot introspect a null class.");
219 }
220
221 try {
222 addClass(Class.forName(name), deep);
223 } catch (ClassNotFoundException except) {
224 throw new MappingException(except);
225 }
226 }
227
228
229
230
231
232
233
234
235
236 public void addClass(final Class cls) throws MappingException {
237 addClass(cls, true);
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254 public void addClass(final Class cls, final boolean deep) throws MappingException {
255 if (cls == null) {
256 throw new MappingException("Cannot introspect a null class.");
257 }
258
259 if (_mappings.get(cls) != null) {
260 return;
261 }
262
263 if (cls.isArray()) {
264 Class cType = cls.getComponentType();
265 if (_mappings.get(cType) != null) {
266 return;
267 }
268 if (Types.isSimpleType(cType)) {
269 return;
270 }
271
272 addClass(cType);
273 }
274
275 if (_forceIntrospection && (!Types.isConstructable(cls))) {
276 throw new MappingException("mapping.classNotConstructable", cls.getName());
277 }
278
279 XMLClassDescriptor xmlClass;
280 FieldDescriptor[] fields;
281 ClassMapping classMap;
282 FieldMapping fieldMap;
283
284 boolean introspected = false;
285 try {
286 if (_forceIntrospection) {
287 xmlClass = _internalContext.getIntrospector().generateClassDescriptor(cls);
288 introspected = true;
289 } else {
290 xmlClass = (XMLClassDescriptor) _internalContext.getXMLClassDescriptorResolver().resolve(cls);
291 introspected = _internalContext.getIntrospector().introspected(xmlClass);
292 }
293 } catch (Exception except) {
294 throw new MappingException(except);
295 }
296 classMap = new ClassMapping();
297 classMap.setName(cls.getName());
298 classMap.setDescription("Default mapping for class " + cls.getName());
299
300
301 classMap.setAccess(null);
302
303
304 MapTo mapTo = new MapTo();
305 mapTo.setXml(xmlClass.getXMLName());
306 mapTo.setNsUri(xmlClass.getNameSpaceURI());
307 mapTo.setNsPrefix(xmlClass.getNameSpacePrefix());
308 classMap.setMapTo(mapTo);
309
310
311
312 _mappings.put(cls, classMap);
313
314 fields = xmlClass.getFields();
315 for (int i = 0; i < fields.length; ++i) {
316 FieldDescriptor fdesc = fields[i];
317
318 String fieldName = fdesc.getFieldName();
319
320 boolean isContainer = false;
321
322 if (introspected && fieldName.startsWith("##container")) {
323 fdesc = fdesc.getClassDescriptor().getFields()[0];
324 fieldName = fdesc.getFieldName();
325 isContainer = true;
326 }
327
328 Class fieldType = fdesc.getFieldType();
329
330
331
332
333
334
335 if ((!introspected) && fieldName.startsWith(UNDERSCORE)) {
336
337 if (!_mappingLoader.canFindAccessors(cls, fieldName, fieldType)) {
338 fieldName = fieldName.substring(1);
339 }
340
341
342
343 if (!_mappingLoader.canFindAccessors(cls, fieldName, fieldType)) {
344 if (fieldName.endsWith("List")) {
345 int len = fieldName.length() - 4;
346 String tmpName = fieldName.substring(0, len);
347 if (_mappingLoader.canFindAccessors(cls, tmpName, fieldType)) {
348 fieldName = tmpName;
349 }
350 }
351 }
352 }
353
354 fieldMap = new FieldMapping();
355 fieldMap.setName(fieldName);
356
357
358 boolean isArray = fieldType.isArray();
359 while (fieldType.isArray()) {
360 fieldType = fieldType.getComponentType();
361 }
362
363
364
365 if (fdesc.isRequired()) {
366 fieldMap.setRequired(true);
367 }
368 if (fdesc.isTransient()) {
369 fieldMap.setTransient(true);
370 }
371 if (fdesc.isMultivalued()) {
372
373 if (isContainer) {
374
375
376
377
378 fieldMap.setContainer(false);
379 }
380
381
382 if (isArray) {
383 fieldMap.setCollection(FieldMappingCollectionType.ARRAY);
384 } else {
385
386
387
388 String colName = CollectionHandlers.getCollectionName(fieldType);
389 if (colName != null) {
390 fieldMap.setCollection(FieldMappingCollectionType.valueOf(colName));
391 fieldType = Object.class;
392 } else if (_mappingLoader.returnsArray(cls, fieldName, fieldType)) {
393
394
395 fieldMap.setCollection(FieldMappingCollectionType.ARRAY);
396 } else {
397 fieldMap.setCollection(FieldMappingCollectionType.ENUMERATE);
398 }
399 }
400 }
401
402
403 fieldMap.setType(fieldType.getName());
404
405
406 fieldMap.setBindXml(new BindXml());
407 fieldMap.getBindXml().setName(((XMLFieldDescriptor) fdesc).getXMLName());
408 fieldMap.getBindXml().setNode(
409 BindXmlNodeType.valueOf(((XMLFieldDescriptor) fields[i]).getNodeType()
410 .toString()));
411 if (classMap.getClassChoice() == null) {
412 classMap.setClassChoice(new ClassChoice());
413 }
414 classMap.getClassChoice().addFieldMapping(fieldMap);
415
416 if (deep) {
417 if (_mappings.get(fieldType) != null) {
418 continue;
419 }
420 if (Types.isSimpleType(fieldType)) {
421 continue;
422 }
423
424 addClass(fieldType);
425 }
426 }
427 }
428
429
430
431
432
433
434
435
436
437
438 public void setForceIntrospection(final boolean force) {
439 _forceIntrospection = force;
440 }
441
442
443
444
445
446
447
448
449 public void write(final Writer writer) throws MappingException {
450 Marshaller marshal;
451 MappingRoot mapping;
452 Enumeration enumeration;
453
454 try {
455 mapping = new MappingRoot();
456 mapping.setDescription("Castor generated mapping file");
457 enumeration = _mappings.elements();
458 while (enumeration.hasMoreElements()) {
459 mapping.addClassMapping((ClassMapping) enumeration.nextElement());
460 }
461 marshal = new Marshaller(writer);
462 marshal.setNamespaceMapping(null, "http://castor.exolab.org/");
463 marshal.setNamespaceMapping("cst", "http://castor.exolab.org/");
464 marshal.marshal(mapping);
465 } catch (Exception except) {
466 throw new MappingException(except);
467 }
468 }
469
470
471
472
473
474 public void setInternalContext(final InternalContext internalContext) {
475 _internalContext = internalContext;
476 _mappings = new Hashtable();
477 _mappingLoader = new MappingToolMappingLoader(_internalContext.getJavaNaming());
478 }
479 }