KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > model > BindingElement


1 /*
2 Copyright (c) 2004-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding.model;
30
31 //import java.io.File;
32
//import java.io.FileInputStream;
33
//import java.io.FileOutputStream;
34
//import java.io.FileReader;
35
import java.io.InputStream JavaDoc;
36 import java.net.URL JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.Iterator JavaDoc;
40
41 import org.jibx.binding.classes.ClassCache;
42 //import org.jibx.binding.classes.ClassFile;
43
import org.jibx.binding.util.StringArray;
44 //import org.jibx.extras.DocumentComparator;
45
import org.jibx.runtime.BindingDirectory;
46 import org.jibx.runtime.EnumSet;
47 import org.jibx.runtime.IBindingFactory;
48 //import org.jibx.runtime.IMarshallingContext;
49
import org.jibx.runtime.IUnmarshallingContext;
50 import org.jibx.runtime.JiBXException;
51
52 /**
53  * Model component for <b>binding</b> element.
54  *
55  * @author Dennis M. Sosnoski
56  * @version 1.0
57  */

58  
59 public class BindingElement extends NestingElementBase
60 {
61     /** Enumeration of allowed attribute names */
62     public static final StringArray s_allowedAttributes =
63         new StringArray(new String JavaDoc[] { "direction", "forwards", "name",
64         "package", "track-source" }, NestingElementBase.s_allowedAttributes);
65     
66     //
67
// Value set information
68

69     public static final int IN_BINDING = 0;
70     public static final int OUT_BINDING = 1;
71     public static final int BOTH_BINDING = 2;
72     
73     /*package*/ static final EnumSet s_directionEnum = new EnumSet(IN_BINDING,
74         new String JavaDoc[] { "input", "output", "both" });
75     
76     //
77
// Instance data
78

79     /** Binding name. */
80     private String JavaDoc m_name;
81     
82     /** Binding direction. */
83     private String JavaDoc m_direction;
84
85     /** Input binding flag. */
86     private boolean m_isInput;
87
88     /** Output binding flag. */
89     private boolean m_isOutput;
90
91     /** Support forward references to IDs flag. */
92     private boolean m_isForward;
93
94     /** Generate souce tracking interface flag. */
95     private boolean m_isTrackSource;
96
97     /** Package for generated context factory. */
98     private String JavaDoc m_targetPackage;
99     
100     /** Base URL for use with relative include paths. */
101     private URL JavaDoc m_baseUrl;
102     
103     /** Set of paths for includes. */
104     private HashSet JavaDoc m_includePaths;
105     
106     /** List of child elements. */
107     private ArrayList JavaDoc m_children;
108     
109     /** Set of class names which can be referenced by ID. */
110     private HashSet JavaDoc m_idClassSet;
111     
112     /**
113      * Default constructor.
114      */

115     public BindingElement() {
116         super(BINDING_ELEMENT);
117         m_includePaths = new HashSet JavaDoc();
118         m_children = new ArrayList JavaDoc();
119     }
120     
121     /**
122      * Set binding name.
123      *
124      * @param name binding definition name
125      */

126     public void setName(String JavaDoc name) {
127         m_name = name;
128     }
129     
130     /**
131      * Get binding name.
132      *
133      * @return binding definition name
134      */

135     public String JavaDoc getName() {
136         return m_name;
137     }
138     
139     /**
140      * Set forward references to IDs be supported in XML.
141      *
142      * @param forward <code>true</code> if forward references supported,
143      * <code>false</code> if not
144      */

145     public void setForward(boolean forward) {
146         m_isForward = forward;
147     }
148     
149     /**
150      * Check if forward references to IDs must be supported in XML.
151      *
152      * @return <code>true</code> if forward references required,
153      * <code>false</code> if not
154      */

155     public boolean isForward() {
156         return m_isForward;
157     }
158     
159     /**
160      * Set source position tracking for unmarshalling.
161      *
162      * @param track <code>true</code> if source position tracking enabled,
163      * <code>false</code> if not
164      */

165     public void setTrackSource(boolean track) {
166         m_isTrackSource = track;
167     }
168     
169     /**
170      * Check if source position tracking enabled for unmarshalling.
171      *
172      * @return <code>true</code> if source position tracking enabled,
173      * <code>false</code> if not
174      */

175     public boolean isTrackSource() {
176         return m_isTrackSource;
177     }
178     
179     /**
180      * Set package for generated context factory class.
181      *
182      * @param pack generated context factory package
183      */

184     public void setTargetPackage(String JavaDoc pack) {
185         m_targetPackage = pack;
186     }
187     
188     /**
189      * Get package for generated context factory class.
190      *
191      * @return package for generated context factory
192      */

193     public String JavaDoc getTargetPackage() {
194         return m_targetPackage;
195     }
196     
197     /**
198      * Set base URL for relative include paths.
199      *
200      * @param base
201      */

202     public void setBaseUrl(URL JavaDoc base) {
203         m_baseUrl = base;
204     }
205     
206     /**
207      * Get base URL for relative include paths.
208      *
209      * @return
210      */

211     public URL JavaDoc getBaseUrl() {
212         return m_baseUrl;
213     }
214     
215     /**
216      * Set binding component applies for marshalling XML.
217      *
218      * @param out <code>true</code> if binding supports output,
219      * <code>false</code> if not
220      */

221     public void setOutBinding(boolean out) {
222         m_isOutput = out;
223     }
224     
225     /**
226      * Check if this binding component applies for marshalling XML.
227      *
228      * @return <code>true</code> if binding supports output, <code>false</code>
229      * if not
230      */

231     public boolean isOutBinding() {
232         return m_isOutput;
233     }
234     
235     /**
236      * Set binding component applies for unmarshalling XML.
237      *
238      * @param in <code>true</code> if binding supports input,
239      * <code>false</code> if not
240      */

241     public void setInBinding(boolean in) {
242         m_isInput = in;
243     }
244     
245     /**
246      * Check if this binding component applies for unmarshalling XML.
247      *
248      * @return <code>true</code> if binding supports input, <code>false</code>
249      * if not
250      */

251     public boolean isInBinding() {
252         return m_isInput;
253     }
254     
255     /**
256      * Add include path to set processed.
257      *
258      * @return <code>true</code> if new path, <code>false</code> if duplicate
259      */

260     public boolean addIncludePath(String JavaDoc path) {
261         return m_includePaths.add(path);
262     }
263     
264     /**
265      * Add a class defined with a ID value. This is used to track the classes
266      * with ID values for validating ID references in the binding. If the
267      * binding uses global IDs, the actual ID class is added to the table along
268      * with all interfaces implemented by the class and all superclasses, since
269      * instances of the ID class can be referenced in any of those forms. If the
270      * binding does not use global IDs, only the actual ID class is added, since
271      * references must be type-specific.
272      *
273      * @param clas information for class with ID value
274      */

275     public void addIdClass(IClass clas) {
276         
277         // create the set if not already present
278
if (m_idClassSet == null) {
279             m_idClassSet = new HashSet JavaDoc();
280         }
281         
282         // add the class if not already present
283
if (m_idClassSet.add(clas.getName())) {
284             
285             // new class, add all interfaces if not previously defined
286
String JavaDoc[] inames = clas.getInterfaces();
287             for (int i = 0; i < inames.length; i++) {
288                 m_idClassSet.add(inames[i]);
289             }
290             while (clas != null && m_idClassSet.add(clas.getName())) {
291                 clas = clas.getSuperClass();
292             }
293         }
294     }
295     
296     /**
297      * Check if a class can be referenced by ID. This just checks if any classes
298      * compatible with the reference type are bound with ID values.
299      *
300      * @param name fully qualified name of class
301      * @return <code>true</code> if class is bound with an ID,
302      * <code>false</code> if not
303      */

304     public boolean isIdClass(String JavaDoc name) {
305         if (m_idClassSet == null) {
306             return false;
307         } else {
308             return m_idClassSet.contains(name);
309         }
310     }
311     
312     /**
313      * Add top-level child element.
314      * TODO: should be ElementBase argument, but JiBX doesn't allow yet
315      *
316      * @param child element to be added as child of this element
317      */

318     public void addTopChild(Object JavaDoc child) {
319         m_children.add(child);
320     }
321     
322     /**
323      * Get list of top-level child elements.
324      *
325      * @return list of child elements, or <code>null</code> if none
326      */

327     public ArrayList JavaDoc topChildren() {
328         return m_children;
329     }
330     
331     /**
332      * Get iterator for top-level child elements.
333      *
334      * @return iterator for child elements
335      */

336     public Iterator JavaDoc topChildIterator() {
337         return m_children.iterator();
338     }
339     
340     //
341
// Overrides of base class methods.
342

343     /* (non-Javadoc)
344      * @see org.jibx.binding.model.ElementBase#hasAttribute()
345      */

346     public boolean hasAttribute() {
347         throw new IllegalStateException JavaDoc
348             ("Internal error: method should never be called");
349     }
350
351     /* (non-Javadoc)
352      * @see org.jibx.binding.model.ElementBase#hasContent()
353      */

354     public boolean hasContent() {
355         throw new IllegalStateException JavaDoc
356             ("Internal error: method should never be called");
357     }
358
359     /* (non-Javadoc)
360      * @see org.jibx.binding.model.ElementBase#isOptional()
361      */

362     public boolean isOptional() {
363         throw new IllegalStateException JavaDoc
364             ("Internal error: method should never be called");
365     }
366     
367     /**
368      * Get default style value for child components. This call is only
369      * meaningful after validation.
370      *
371      * @return default style value for child components
372      */

373     public int getDefaultStyle() {
374         int style = super.getDefaultStyle();
375         if (style < 0) {
376             style = NestingAttributes.s_styleEnum.getValue("element");
377         }
378         return style;
379     }
380     
381     //
382
// Validation methods
383

384     /**
385      * Make sure all attributes are defined.
386      *
387      * @param uctx unmarshalling context
388      * @exception JiBXException on unmarshalling error
389      */

390     private void preSet(IUnmarshallingContext uctx) throws JiBXException {
391         validateAttributes(uctx, s_allowedAttributes);
392     }
393     
394     /**
395      * Prevalidate all attributes of element in isolation.
396      *
397      * @param vctx validation context
398      */

399     public void prevalidate(ValidationContext vctx) {
400         
401         // set the direction flags
402
int index = -1;
403         if (m_direction != null) {
404             index = s_directionEnum.getValue(m_direction);
405             if (index < 0) {
406                 vctx.addError("Value \"" + m_direction +
407                     "\" is not a valid choice for direction");
408             }
409         } else {
410             index = BOTH_BINDING;
411         }
412         m_isInput = index == IN_BINDING || index == BOTH_BINDING;
413         m_isOutput = index == OUT_BINDING || index == BOTH_BINDING;
414         super.prevalidate(vctx);
415     }
416     
417     private static FormatElement buildFormat(String JavaDoc name, String JavaDoc type,
418         boolean use, String JavaDoc sname, String JavaDoc dname, String JavaDoc dflt) {
419         FormatElement format = new FormatElement();
420         format.setLabel(name);
421         format.setTypeName(type);
422         format.setDefaultFormat(use);
423         format.setSerializerName(sname);
424         format.setDeserializerName(dname);
425         format.setDefaultText(dflt);
426         return format;
427     }
428     
429     private void defineBaseFormat(FormatElement format,
430         DefinitionContext dctx, ValidationContext vctx) {
431         format.prevalidate(vctx);
432         format.validate(vctx);
433         dctx.addFormat(format, vctx);
434     }
435     
436
437     /**
438      * Run the actual validation of a binding model.
439      *
440      * @param vctx context for controlling validation
441      */

442     public void runValidation(ValidationContext vctx) {
443         
444         // initially enable both directions for format setup
445
m_isInput = true;
446         m_isOutput = true;
447         
448         // create outer definition context
449
DefinitionContext dctx = new DefinitionContext(null);
450         vctx.setGlobalDefinitions(dctx);
451         defineBaseFormat(buildFormat("byte:default", "byte", true,
452             "org.jibx.runtime.Utility.serializeByte",
453             "org.jibx.runtime.Utility.parseByte", "0"), dctx, vctx);
454         defineBaseFormat(buildFormat("char:default", "char", true,
455             "org.jibx.runtime.Utility.serializeChar",
456             "org.jibx.runtime.Utility.parseChar", "0"), dctx, vctx);
457         defineBaseFormat(buildFormat("double:default", "double", true,
458             "org.jibx.runtime.Utility.serializeDouble",
459             "org.jibx.runtime.Utility.parseDouble", "0.0"), dctx, vctx);
460         defineBaseFormat(buildFormat("float:default", "float", true,
461             "org.jibx.runtime.Utility.serializeFloat",
462             "org.jibx.runtime.Utility.parseFloat", "0.0"), dctx, vctx);
463         defineBaseFormat(buildFormat("int:default", "int", true,
464             "org.jibx.runtime.Utility.serializeInt",
465             "org.jibx.runtime.Utility.parseInt", "0"), dctx, vctx);
466         defineBaseFormat(buildFormat("long:default", "long", true,
467             "org.jibx.runtime.Utility.serializeLong",
468             "org.jibx.runtime.Utility.parseLong", "0"), dctx, vctx);
469         defineBaseFormat(buildFormat("short:default", "short", true,
470             "org.jibx.runtime.Utility.serializeShort",
471             "org.jibx.runtime.Utility.parseShort", "0"), dctx, vctx);
472         defineBaseFormat(buildFormat("boolean:default", "boolean", true,
473             "org.jibx.runtime.Utility.serializeBoolean",
474             "org.jibx.runtime.Utility.parseBoolean", "false"), dctx, vctx);
475         defineBaseFormat(buildFormat("Date:default", "java.util.Date", true,
476             "org.jibx.runtime.Utility.serializeDateTime",
477             "org.jibx.runtime.Utility.deserializeDateTime", null), dctx, vctx);
478         defineBaseFormat(buildFormat("SqlDate:default", "java.sql.Date",
479             true, "org.jibx.runtime.Utility.serializeSqlDate",
480             "org.jibx.runtime.Utility.deserializeSqlDate", null), dctx, vctx);
481         defineBaseFormat(buildFormat("byte[]:default", "byte[]", true,
482             "org.jibx.runtime.Utility.serializeBase64",
483             "org.jibx.runtime.Utility.deserializeBase64", null), dctx, vctx);
484         defineBaseFormat(buildFormat("String:default", "java.lang.String",
485             true, null, null, null), dctx, vctx);
486         defineBaseFormat(buildFormat("Object:default", "java.lang.Object",
487             true, null, null, null), dctx, vctx);
488         FormatElement format = buildFormat("char:string", "char", false,
489             "org.jibx.runtime.Utility.serializeCharString",
490             "org.jibx.runtime.Utility.deserializeCharString", "0");
491         format.setDefaultFormat(false);
492         format.prevalidate(vctx);
493         format.validate(vctx);
494         dctx.addFormat(format, vctx);
495         NamespaceElement ns = new NamespaceElement();
496         ns.setDefaultName("all");
497         ns.prevalidate(vctx);
498         dctx.addNamespace(ns);
499         // TODO: check for errors in basic configuration
500

501         // create a definition context for the binding
502
setDefinitions(new DefinitionContext(dctx));
503         
504         // run the actual validation
505
vctx.prevalidate(this);
506         RegistrationVisitor rvisitor = new RegistrationVisitor(vctx);
507         rvisitor.visitTree(this);
508         vctx.validate(this);
509     }
510
511     /**
512      * Read a binding definition to construct binding model.
513      *
514      * @param is input stream for reading binding
515      * @param fname name of input file (<code>null</code> if unknown)
516      * @param vctx validation context used during unmarshalling
517      * @return root of binding definition model
518      * @throws JiBXException on error in reading binding
519      */

520     public static BindingElement readBinding(InputStream JavaDoc is, String JavaDoc fname,
521         ValidationContext vctx) throws JiBXException {
522         
523         // look up the binding factory
524
IBindingFactory bfact =
525             BindingDirectory.getFactory(BindingElement.class);
526         
527         // unmarshal document to construct objects
528
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
529         uctx.setDocument(is, fname, null);
530         uctx.pushObject(new UnmarshalWrapper(vctx));
531         BindingElement binding = (BindingElement)uctx.unmarshalElement();
532         uctx.popObject();
533         return binding;
534     }
535     
536     /**
537      * Validate a binding definition.
538      *
539      * @param name binding definition name
540      * @param is input stream for reading binding
541      * @param vctx validation context to record problems
542      * @return root of binding definition model, or <code>null</code> if error
543      * in unmarshalling
544      * @throws JiBXException on error in binding XML structure
545      */

546     public static BindingElement validateBinding(String JavaDoc name, URL JavaDoc path,
547         InputStream JavaDoc is, ValidationContext vctx) throws JiBXException {
548         
549         // construct object model for binding
550
BindingElement binding = readBinding(is, name, vctx);
551         binding.setBaseUrl(path);
552         vctx.setBindingRoot(binding);
553         
554         // validate the binding definition
555
binding.runValidation(vctx);
556         
557         // list validation errors
558
ArrayList JavaDoc probs = vctx.getProblems();
559         if (probs.size() > 0) {
560             for (int i = 0; i < probs.size(); i++) {
561                 ValidationProblem prob = (ValidationProblem)probs.get(i);
562                 System.out.print(prob.getSeverity() >=
563                     ValidationProblem.ERROR_LEVEL ? "Error: " : "Warning: ");
564                 System.out.println(prob.getDescription());
565             }
566         }
567         return binding;
568     }
569
570     /**
571      * Create a default validation context.
572      *
573      * @return new validation context
574      */

575     public static ValidationContext newValidationContext() {
576         IClassLocator locate = new IClassLocator() {
577             public IClass getClassInfo(String JavaDoc name) {
578                 try {
579                     return new ClassWrapper(ClassCache.getClassFile(name));
580                 } catch (JiBXException e) {
581                     return null;
582                 }
583             }
584         };
585         return new ValidationContext(locate);
586     }
587     
588 /* // test runner
589     // This code only used in testing, to roundtrip binding definitions
590     public static void test(String ipath, String opath, ValidationContext vctx)
591         throws Exception {
592         
593         // validate the binding definition
594         FileInputStream is = new FileInputStream(ipath);
595         URL url = new URL("file://" + ipath);
596         BindingElement binding = validateBinding(ipath, url, is, vctx);
597         
598         // marshal back out for comparison purposes
599         IBindingFactory bfact =
600             BindingDirectory.getFactory(BindingElement.class);
601         IMarshallingContext mctx = bfact.createMarshallingContext();
602         mctx.setIndent(2);
603         mctx.marshalDocument(binding, null, null, new FileOutputStream(opath));
604         System.out.println("Wrote output binding " + opath);
605         
606         // compare input document with output document
607         DocumentComparator comp = new DocumentComparator(System.err);
608         boolean match = comp.compare(new FileReader(ipath),
609             new FileReader(opath));
610         if (!match) {
611             System.err.println("Mismatch from input " + ipath +
612                 " to output " + opath);
613         }
614     }
615     
616     // test runner
617     public static void main(String[] args) throws Exception {
618         
619         // configure class loading
620         String[] paths = new String[] { "." };
621         ClassCache.setPaths(paths);
622         ClassFile.setPaths(paths);
623         ValidationContext vctx = newValidationContext();
624         
625         // process all bindings listed on command line
626         for (int i = 0; i < args.length; i++) {
627             try {
628                 String ipath = args[i];
629                 int split = ipath.lastIndexOf(File.separatorChar);
630                 String opath = "x" + ipath.substring(split+1);
631                 test(ipath, opath, vctx);
632             } catch (Exception e) {
633                 System.err.println("Error handling binding " + args[i]);
634                 e.printStackTrace();
635             }
636         }
637     } */

638     
639     /**
640      * Inner class as wrapper for binding element on unmarshalling. This
641      * provides a handle for passing the validation context, allowing elements
642      * to check for problems during unmarshalling.
643      */

644     public static class UnmarshalWrapper
645     {
646         private final ValidationContext m_validationContext;
647         
648         private UnmarshalWrapper(ValidationContext vctx) {
649             m_validationContext = vctx;
650         }
651         
652         public ValidationContext getValidation() {
653             return m_validationContext;
654         }
655     }
656 }
Popular Tags