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