KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > jmi > xmi > XmiElement


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.lib.jmi.xmi;
20
21 import java.util.*;
22
23 import org.xml.sax.*;
24 import org.xml.sax.helpers.DefaultHandler JavaDoc;
25 import org.xml.sax.helpers.AttributesImpl JavaDoc;
26 import javax.xml.parsers.SAXParserFactory JavaDoc;
27 import javax.xml.parsers.ParserConfigurationException JavaDoc;
28 import javax.xml.parsers.SAXParser JavaDoc;
29
30 import org.netbeans.api.xmi.*;
31 import org.netbeans.lib.jmi.util.DebugException;
32
33 import javax.jmi.reflect.*;
34 import javax.jmi.model.*;
35 import org.netbeans.lib.jmi.util.Logger;
36
37 public abstract class XmiElement {
38
39     // context in which current elements are being processed
40
protected XmiContext context;
41     // parent element of this element
42
protected XmiElement parent;
43
44     public XmiElement (XmiElement parent, XmiContext context) {
45         this.parent = parent;
46         this.context = context;
47     }
48
49     public XmiElement (XmiContext context) {
50         this.context = context;
51     }
52
53     /**
54      * Handles startElement event generated by SAX parser. Usually creates sub-element and
55      * returns it or returns itself.
56      */

57     public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
58         return this;
59     }
60
61     /**
62      * Handles endElement event generated by SAX parser.
63      */

64     public XmiElement endElement (String JavaDoc qName) {
65         return parent;
66     }
67
68     /**
69      * Handles characters event generated by SAX parser.
70      */

71     public void characters (char buf[], int offset, int len) {
72         // default behaviour - ignore characters
73
return;
74     }
75
76     /**
77      * Method called by sub-elements to pass values resolved by them.
78      */

79     public void receiveValue (Object JavaDoc value) {
80         // should be called on instances that override it only
81
throw new DebugException ("Unexpected call of receiveValue () method.");
82     }
83
84 // ------------------------------------------------------------------------------
85
// inner classes
86
// ------------------------------------------------------------------------------
87

88     // **************************************************************************
89
// Document
90
// **************************************************************************
91
public static class Document extends XmiElement {
92
93         private String JavaDoc rootElementName;
94         private Content content = null;
95         private XmiElement xmiElement = null;
96         
97         public Document (XmiElement parent, XmiContext context, String JavaDoc rootName, Attributes attrs) {
98             super (parent, context);
99             rootElementName = rootName;
100             context.setVersion (attrs);
101             if (context.isXmi20) {
102                 content = new Content (this, context);
103                 if (!rootElementName.equals (context.xmiNsPrefix + XmiConstants.XMI_ROOT)) {
104                     AttributesImpl JavaDoc attrs2 = new AttributesImpl JavaDoc ();
105                     for (int x = 0; x < attrs.getLength (); x++) {
106                         String JavaDoc name = attrs.getQName (x);
107                         if (!(name.equals ("xmlns") || name.startsWith ("xmlns:") ||
108                             name.equals (context.xmiNsPrefix + XmiConstants.XMI20_VERSION))) {
109                             attrs2.addAttribute (null, null, name, null, attrs.getValue (x));
110                         } // if
111
} // for
112
xmiElement = content.startSubElement (rootElementName, attrs2);
113                 } // if
114
} // if
115
}
116
117         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
118             if (context.isXmi20) {
119                 // delegate startElement to content or xmiElement
120
if (xmiElement != null)
121                     return xmiElement.startSubElement (qName, attrs);
122                 else
123                     return content.startSubElement (qName, attrs);
124             } else {
125                 if (qName.equals (XmiConstants.XMI_CONTENT)) {
126                     return new XmiElement.Content (this, context);
127                 } else if (qName.equals (XmiConstants.XMI_DIFFERENCE)) {
128                     return new XmiElement.Difference (this, context, attrs);
129                 } else if (qName.equals (XmiConstants.XMI_HEADER)) {
130                     return new XmiElement.Header (this, context);
131                 } else {
132                     if (context.ignoreUnknownElements()) {
133                         return new XmiElement.Dummy(this, context, qName);
134                     } else {
135                         throw new DebugException("Invalid element name: " + qName);
136                     }
137                 }
138             }
139         }
140
141         public XmiElement endElement (String JavaDoc qName) {
142             if (qName.equals (rootElementName)) {
143                 if (context.isXmi20) {
144                     if (xmiElement != null)
145                         xmiElement.endElement (qName);
146                     content.endElement (qName);
147                 }
148                 context.finish ();
149                 return parent;
150             }
151             return this;
152         }
153
154     } // Document
155

156     
157     // **************************************************************************
158
// Header
159
// **************************************************************************
160

161     public static class Header extends XmiElement {
162     
163         private int level = 0;
164         private StringBuffer JavaDoc buffer = new StringBuffer JavaDoc ();
165         
166         public Header (XmiElement parent, XmiContext context) {
167             super (parent, context);
168         }
169         
170         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
171             level++;
172             buffer.append ('<' + qName);
173             int attrsLength = attrs.getLength ();
174             for (int index = 0; index < attrsLength; index++) {
175                 String JavaDoc attrName = attrs.getQName (index);
176                 String JavaDoc attrValue = attrs.getValue (index);
177                 buffer.append (" " + attrName + " = '" + attrValue + "'");
178             } // for
179
buffer.append ('>');
180             return this;
181         }
182
183         public XmiElement endElement (String JavaDoc qName) {
184             if (level == 0) {
185                 context.receiveHeader (buffer.toString ());
186                 return parent;
187             }
188             buffer.append ("</" + qName + '>');
189             level--;
190             return this;
191         }
192         
193         public void characters (char buf[], int offset, int len) {
194             buffer.append (buf, offset, len);
195         }
196         
197     } // Header
198

199     // **************************************************************************
200
// Difference
201
// **************************************************************************
202
public static class Difference extends XmiElement {
203
204         //[PENDING] resolving of differences is not implemented yet
205

206         // link defining a targed the differences apply on
207
private String JavaDoc href;
208         // true if one of Add, Delete or Replace sub-elements is being currently read
209
private boolean diffReading;
210         // read sub-element
211
private Diff currentDiff;
212         // storage of all Add, Delete, Replace sub-elements
213
private HashMap diffs = new HashMap ();
214         private int timeStamp = 1;
215         
216         public Difference (XmiElement parent, XmiContext context, Attributes attrs) {
217             super (parent, context);
218             href = attrs.getValue (context.XMI_HREF);
219             if (href == null)
220                 throw new DebugException (
221                     "Differences referring to the document they are placed in are not supported."
222                 );
223             diffReading = false;
224         }
225
226         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
227             if (!diffReading) {
228                 if (qName.equals (XmiConstants.XMI_DIFFERENCE))
229                     throw new DebugException ("Nested differences are not supported.");
230                 int kind = Diff.ADD;
231                 if (qName.equals (XmiConstants.XMI_DELETE))
232                     kind = Diff.DELETE;
233                 else if (qName.equals (XmiConstants.XMI_REPLACE))
234                     kind = Diff.REPLACE;
235                 String JavaDoc localHref = attrs.getValue (context.XMI_HREF);
236                 int index = localHref.lastIndexOf ("|");
237                 if (index == -1)
238                     index = localHref.lastIndexOf ("#");
239                 String JavaDoc id = localHref.substring (index + 1, localHref.length ());
240                 String JavaDoc posString = attrs.getValue (XmiConstants.XMI_POSITION);
241                 int position = 1; // default value
242
if (posString != null) {
243                     try {
244                         position = Integer.parseInt (posString);
245                     } catch (NumberFormatException JavaDoc e) {
246                         throw new DebugException ("Differences - bad number format: " + posString);
247                     }
248                 } // if
249
if (position < 0)
250                     throw new DebugException ("Negative values of xmi.position parameters are not supported: " + posString);
251                 currentDiff = new Diff (kind, id, position, timeStamp);
252                 timeStamp++;
253                 diffReading = true;
254             } else { // diffReading == true
255
currentDiff.items.add (new Item (qName, attrs));
256             }
257             return this;
258         }
259         
260         public void characters (char buf[], int offset, int len) {
261             if (diffReading) {
262                 currentDiff.items.add (new String JavaDoc (buf, offset, len));
263             }
264         }
265
266         public XmiElement endElement (String JavaDoc qName) {
267             if (diffReading) {
268                 if ((qName.equals (XmiConstants.XMI_ADD)) ||
269                     (qName.equals (XmiConstants.XMI_DELETE)) ||
270                     (qName.equals (XmiConstants.XMI_REPLACE))) {
271                     diffReading = false;
272                     LinkedList list = (LinkedList) diffs.get (currentDiff.xmiId);
273                     if (list == null)
274                         diffs.put (currentDiff.xmiId, list = new LinkedList ());
275                     if (currentDiff.kind == Diff.DELETE)
276                         list.addFirst (currentDiff);
277                     else
278                         list.addLast (currentDiff);
279                 } else
280                     currentDiff.items.add (new Item (qName));
281                 return this;
282             }
283             //[TODO] take diffs and read referenced document
284
context.resolveDifferences (href, diffs);
285             return parent;
286         }
287         
288         // stores data related to one difference (add, delete or replace)
289
public static class Diff {
290             // constants for kind of difference
291
public static final int ADD = 0;
292             public static final int DELETE = 1;
293             public static final int REPLACE = 2;
294             
295             // kind of this difference
296
public int kind;
297             // optional position parameter, not relevant in case of Delete difference
298
public int position;
299             // xmi id of an elemenet the difference applays on
300
public String JavaDoc xmiId;
301             // content stored as a sequence of events represented by items or a String in case
302
// of a characters event
303
public LinkedList items = new LinkedList ();
304             public int timeStamp;
305             
306             public Diff (int kind, String JavaDoc xmiId, int position, int timeStamp) {
307                 this.kind = kind;
308                 this.xmiId = xmiId;
309                 this.position = position;
310                 this.timeStamp = timeStamp;
311             }
312             
313         }
314
315         // stores one start element or end element event
316
public static class Item {
317             // if true, represents start of an element
318
public boolean isStart;
319             // element name
320
public String JavaDoc qName;
321             // related attributes (in case of start of element)
322
public Attributes attrs;
323             
324             // end element event
325
public Item (String JavaDoc qName) {
326                 this.qName = qName;
327                 isStart = false;
328             }
329             
330             // start element event
331
public Item (String JavaDoc qName, Attributes attrs) {
332                 this.qName = qName;
333                 // attributes cannot be stored directly, they have to be copied
334
this.attrs = new AttributesImpl JavaDoc (attrs);
335                 isStart = true;
336             }
337         }
338         
339     } // Difference
340

341     // **************************************************************************
342
// Content
343
// **************************************************************************
344
public static class Content extends XmiElement {
345         // Since Content element encloses class-scoped attribute value elements,
346
// it handles collecting and setting them
347

348         // a class-scoped attribute whose (multi-)value is being currently read
349
private Attribute attr = null;
350         // class proxy related to the currently read class-scoped attribute
351
private RefClass refClass = null;
352         // stores currently read (multi-)value(s) of a class-scoped attribute
353
private List values;
354         
355         public Content (XmiElement parent, XmiContext context) {
356             super (parent, context);
357         }
358
359         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
360             Object JavaDoc ref = context.resolveElementName (qName);
361             if ((ref == null) && context.ignoreUnknownElements()) {
362                 return new XmiElement.Dummy(this, context, qName);
363             }
364             // [TODO] resolved 'ref' value can be passed to constructors of sub-elements
365
if (ref instanceof RefClass)
366                 return context.resolveInstanceOrReference (this, qName, attrs);
367             // class-scoped attribute ...........................................
368
if (ref instanceof Attribute) {
369                 RefClass readRefClass = (RefClass) context.resolveElementName (
370                     qName.substring (0, qName.lastIndexOf (XmiConstants.DOT_SEPARATOR))
371                 );
372                 if ((ref != attr) || (refClass != readRefClass)) {
373                     // the first value element related to the first or the next class-scoped attribute
374
if (attr != null) {
375                         // so, it is the next attribute, not the first one; set the previously obtained value ...
376
setAttributeValue ();
377                     }
378                     attr = (Attribute) ref;
379                     refClass = readRefClass;
380                     values = new LinkedList ();
381                 }
382                 // [PENDING] ClassLevelAttribute instance can be shared, similarly as, e.g., context.PRIMITIVE_VALUE
383
return new XmiElement.ClassLevelAttribute (this, context, attr, attrs);
384             }
385             // ..................................................................
386
if (ref instanceof Association)
387                 return new XmiElement.AssociationElement (this, context, (Association) ref);
388             // an unexpected element
389
throw new DebugException ("Unexpected element: " + qName);
390         }
391
392         public XmiElement endElement (String JavaDoc qName) {
393             if (attr != null) {
394                 // end of Content has been encountered and there is still previously
395
// collected (multi-)value of a class-scoped attribute that should be set
396
setAttributeValue ();
397             }
398             
399             // register all requests for objects in external documents
400
context.resolveExternalReferences ();
401             
402             if (context.isMain && !context.allReferencesResolved ()) {
403                 // (verification performed in case of main document only)
404
// some unresolved reference (i.e. related instance does not exist) or
405
// violation of Mof constraints, there is a cycle in the relation
406
// "an instance is a value of an attribute of another instance"
407
String JavaDoc badRef = context.getUnresolvedRefId ();
408                 Logger.getDefault ().log ("Unknown reference or circularity in instance dependences detected, bad reference: " + badRef);
409                 // throw new DebugException ("Unknown reference or circularity in instance dependences detected, bad reference: " + badRef);
410
}
411             return parent;
412         }
413         
414         public void receiveValue (Object JavaDoc value) {
415             // collects parts of (multi-)value of a class-scoped attribute
416
if (attr == null)
417                 throw new DebugException ("Unexpected call of Content.receiveValue ()");
418             if (value instanceof List)
419                 values.addAll ((List) value);
420             else
421                 values.add (value);
422         }
423
424         private void setAttributeValue () {
425             LinkedList list = new LinkedList ();
426             Iterator iter = values.iterator ();
427             Object JavaDoc value;
428             while (iter.hasNext ()) {
429                 value = iter.next ();
430                 if (value instanceof UnresolvedReference) {
431                     value = ((UnresolvedReference) value).getValue ();
432                     if (value == null) {
433                         throw new DebugException ("Class-scoped attribute value not resolved: " + attr.getName ());
434                     }
435                 }
436                 list.add (value);
437             }
438             if (XmiContext.isMultivalued (attr))
439                 value = list;
440             else {
441                 if (!(list.size () == 1))
442                     throw new DebugException ("Cannot set a multi-value to a non-multivalued attribute:" + attr.getName ());
443                 value = list.get (0);
444             }
445             refClass.refSetValue (attr, value);
446             attr = null;
447             refClass = null;
448             values = null;
449         }
450         
451     } // Content
452

453     // **************************************************************************
454
// Instance
455
// **************************************************************************
456
public static class Instance extends XmiElement implements ReferencesCounter {
457         // fully qualified name (possibly composed using a namespace prefix)
458
private String JavaDoc name;
459         // xmi.id value
460
private String JavaDoc xmiId = null;
461         // id of related document
462
private String JavaDoc docId;
463         // number of currently unresolved references preventing creation of this instance
464
private int unresolvedRefsCounter = 0;
465         // flag indicating if all sub-elements are already read, i.e. endElement () method has been called
466
private boolean endReached = false;
467         // holds an unresolved reference to this instance that should be set after the instance creation
468
private UnresolvedReference unresRef = null;
469         // currently processed attribute or reference
470
private StructuralFeature currentFeature;
471         // type of currently processed attribute
472
private Classifier currentType;
473
474         // RefClass resolved according to the name
475
private RefClass refClass;
476         // meta class corresponding to refClass
477
private MofClass metaClass;
478         // temporal storage for values of instance level attributes
479
private HashMap attributesValues = new HashMap ();
480         // temporal storage for values of instance level references
481
private HashMap referencesValues = new HashMap ();
482
483         public Instance (XmiElement parent, XmiContext context, String JavaDoc qName,
484             RefClass refClass, Attributes attrs) {
485                         
486             super (parent, context);
487             this.name = qName;
488             this.docId = context.getCurrentDocId ();
489             this.refClass = refClass;
490             metaClass = (MofClass) refClass.refMetaObject ();
491
492             int index; // index of currently processed attribute
493
String JavaDoc attrName, attrValue;
494             int attrsLength = attrs.getLength ();
495             // process all passed instance attributes and xmi id's
496
for (index = 0; index < attrsLength; index++) {
497                 attrName = attrs.getQName (index);
498                 attrValue = attrs.getValue (index);
499                 if (attrName.equals (context.XMI_ID)) {
500                     xmiId = attrValue;
501                 } else {
502                     resolveAttributeValue (attrName, attrValue);
503                 }
504             } // for
505
}
506
507         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
508             Object JavaDoc ref = context.resolveElementName (qName);
509             if (ref == null && context.ignoreUnknownElements()) {
510                 return new XmiElement.Dummy(this, context, qName);
511             }
512             
513             if (!(ref instanceof StructuralFeature)) {
514                 throw new DebugException ("Invalid sub-element: " + qName);
515             }
516             currentFeature = (StructuralFeature) ref;
517             if (currentFeature.getScope ().equals (ScopeKindEnum.CLASSIFIER_LEVEL) && !context.isXmi20) {
518                 throw new DebugException ("An instance serialization contains value of static attribute: " + currentFeature.getName ());
519             }
520             
521             if (currentFeature instanceof Attribute) {
522                 Classifier type = currentFeature.getType ();
523                 return context.resolveValue (this, type, attrs);
524             } else if (currentFeature instanceof Reference) {
525                 return new XmiElement.ObjectValues (this, context, null, false);
526             }
527             throw new DebugException ("Invalid sub-element: " + qName);
528         }
529
530         /**
531          * Creates an instance in repository. Called when all needed references
532          * related to attribute values have been resolved.
533          */

534         private RefObject createInstance () {
535             
536             List attributes = context.instanceAttributes (refClass);
537             List references = context.instanceReferences (refClass);
538
539             // obtain list of attributes values
540
List args = new LinkedList ();
541             Iterator iter = attributes.iterator ();
542             while (iter.hasNext ()) {
543                 Attribute attr = (Attribute) iter.next ();
544                 Object JavaDoc param = attributesValues.get (attr);
545                 if (param instanceof UnresolvedReference) {
546                     param = ((UnresolvedReference) param).getValue ();
547                 } else if (param instanceof List) {
548                     Iterator iter2 = ((List) param).iterator ();
549                     List temp = new LinkedList ();
550                     while (iter2.hasNext ()) {
551                         Object JavaDoc value = iter2.next ();
552                         if (value instanceof UnresolvedReference) {
553                             value = ((UnresolvedReference) value).getValue ();
554                             if (value instanceof CollectionWrapper)
555                                 value = ((CollectionWrapper) value).getCollection ();
556                         }
557                         temp.add (value);
558                     }
559                     param = temp;
560                 }
561                 if (param instanceof CollectionWrapper)
562                     param = ((CollectionWrapper) param).getCollection ();
563                 if (param == null)
564                     param = XmiContext.defaultValue (attr);
565                 args.add (param);
566             } // while
567
RefObject instance;
568             try {
569                 instance = refClass.refCreateInstance (args);
570             } catch (Exception JavaDoc e) {
571                 StringBuffer JavaDoc params = new StringBuffer JavaDoc(50);
572                 for (Iterator it = args.iterator(); it.hasNext();) {
573                     Object JavaDoc arg = it.next();
574                     params.append(" ");
575                     if (arg == null) {
576                         params.append("<null>");
577                     } else {
578                         params.append("(" + arg.getClass() + ") " + arg.toString());
579                     }
580                     params.append("\n");
581                 }
582                 /*
583                 DebugException ne = new DebugException("Instance of " + name + " cannot be created, bad parameters:\n" + params.toString() + "\n reason: " + e.toString());
584                 Logger.getDefault().annotate(ne, e);
585                 throw (DebugException) Logger.getDefault().annotate(ne, "Instance or " + name + " cannot be created, bad parameters:\n" + params.toString());
586                  */

587                 String JavaDoc msg = "Instance of " + name + " cannot be created, parameters:\n" + params.toString() + "\n reason: " + e.toString();
588                 Logger.getDefault ().log (msg);
589                 return null;
590             }
591             if (parent instanceof XmiElement.Content) {
592                 context.addOutermostObject (instance);
593             }
594
595             // if xmiId != null, store resolved reference
596
if (xmiId != null)
597                 context.putReference (docId, xmiId, instance);
598
599             // set resolved references, register unresolved
600
iter = references.iterator ();
601             while (iter.hasNext ()) {
602                 Reference ref = (Reference) iter.next ();
603                 List values = (List) referencesValues.get (ref);
604                 if (values != null)
605                     new ReferenceHandler (ref, instance, values, context);
606             } // while
607

608             context.countInstance ();
609             
610             if (context.isXmi20) {
611                 // check if there were some static attributes serialized, if so set these values
612
iter = context.staticAttributes (refClass).iterator ();
613                 while (iter.hasNext ()) {
614                     Attribute attr = (Attribute) iter.next ();
615                     Object JavaDoc value = attributesValues.get (attr);
616                     if (value != null) {
617                         refClass.refSetValue (attr, value);
618                     } // if
619
} // while
620
} // if
621

622             return instance;
623         }
624
625         public XmiElement endElement (String JavaDoc qName) {
626             // reading of instance object has been finished
627
// corresponding instance (initialized with read attributes values)
628
// can be created in repository if all needed references have been
629
// already resolved
630
endReached = true;
631             if (unresolvedRefsCounter == 0) {
632                 RefObject instance = createInstance ();
633                 if (!(parent instanceof XmiElement.Content)) {
634                     parent.receiveValue (instance);
635                 }
636             } else {
637                 if (!(parent instanceof XmiElement.Content)) {
638                     unresRef = new UnresolvedReference ();
639                     parent.receiveValue (unresRef);
640                 }
641             }
642             return parent;
643         }
644
645         /*
646          * Stores attribute value. It can be a single-value or a part of multi-value
647          * as well. Thus, in case of multi-values, the method can be called several
648          * times with the same attribute parameter.
649          */

650         // [PENDING] review setAttributeValue methods and storing of values
651
// (single-values vs. multi-values)
652
private void setAttributeValue (StructuralFeature attr, Object JavaDoc value) {
653             boolean isMultivalued = XmiContext.isMultivalued (attr);
654             Object JavaDoc tempValue = attributesValues.get (attr);
655             if (!isMultivalued) {
656                 if (tempValue != null)
657                     throw new DebugException ("Cannot set a multi-value to a non-multivalued attribute:" + attr.getName ());
658                 attributesValues.put (attr, value);
659
660                 /*
661                 if (value instanceof CollectionWrapper) {
662                     System.out.println("#: " + ((CollectionWrapper) value).getCollection ().size ());
663                 }
664                 */

665                 
666             } else {
667                 if (tempValue == null)
668                     attributesValues.put (attr, tempValue = new LinkedList ());
669                 ((List) tempValue).add (value);
670             } // else
671
}
672
673         /**
674          * Similar as @link #setAttributeValue, except that a list of values is passed
675          * rather than one value.
676          */

677         private void setAttributeValues (StructuralFeature attr, List values) {
678             boolean isMultivalued = XmiContext.isMultivalued (attr);
679             if (!isMultivalued && (values.size () == 1)) {
680                 setAttributeValue (attr, values.get (0));
681                 return;
682             }
683
684             /*
685             System.out.println("passed");
686             */

687             
688             if (!isMultivalued) {
689                 throw new DebugException ("Cannot set a multi-value to a non-multivalued attribute:" + attr.getName ());
690             }
691             Object JavaDoc tempValue = attributesValues.get (attr);
692             if (tempValue == null)
693                 attributesValues.put (attr, tempValue = new LinkedList ());
694             ((List) tempValue).addAll (values);
695         }
696
697         /**
698          * Stores values of a reference.
699          */

700         private void setReferenceValues (Reference ref, List values) {
701             boolean isMultivalued = XmiContext.isMultivalued (ref);
702             Object JavaDoc tempValue = referencesValues.get (ref);
703             if (!isMultivalued) {
704                 if ((tempValue != null) || (values.size () > 1)) {
705                     throw new DebugException
706                         ("Cannot set a multi-value to a non-multivalued reference:" + ref.getName());
707                 }
708                 referencesValues.put (ref, values);
709                 return;
710             }
711             if (tempValue == null)
712                 referencesValues.put (ref, tempValue = new LinkedList ());
713             ((List) tempValue).addAll (values);
714         }
715
716         public void receiveValue (Object JavaDoc value) {
717             if (currentFeature instanceof Attribute) {
718                 if (value instanceof List)
719                     setAttributeValues (currentFeature, (List) value);
720                 else
721                     setAttributeValue (currentFeature, value);
722             } else { // Reference
723
// [PENDING] performance - change the following code !!
724
if (!(value instanceof List)) {
725                     List temp = new LinkedList ();
726                     temp.add (value);
727                     value = temp;
728                 }
729                 setReferenceValues ((Reference) currentFeature, (List) value);
730             }
731          }
732
733         /**
734          * Resolves attribute value stored as XMI element attribute
735          * (example: <Model:Class name='Person'/> ).
736          */

737         private void resolveAttributeValue (String JavaDoc attrName, String JavaDoc attrValue) {
738             StructuralFeature attr;
739             
740             attr = context.instanceElementByName (refClass, attrName);
741             if ((attr == null) && context.isXmi20) {
742                 attr = context.staticAttributeByName (refClass, attrName);
743             }
744             if (attr == null)
745                 return;
746
747             Classifier type = attr.getType ();
748             while (type instanceof AliasType)
749                 type = ((AliasType) type).getType ();
750             Object JavaDoc value = null;
751
752             if (type instanceof PrimitiveType) {
753                 value = XmiContext.resolvePrimitiveValue ((PrimitiveType) type, attrValue);
754                 setAttributeValue (attr, value);
755             } else if (type instanceof EnumerationType) {
756                 value = context.resolveEnumerationValue ((EnumerationType) type, attrValue);
757                 setAttributeValue (attr, value);
758             } else if (type instanceof MofClass) {
759                 boolean isReference = attr instanceof Reference;
760                 StringTokenizer tokenizer = new StringTokenizer (attrValue, " ");
761                 List list = new LinkedList ();
762                 while (tokenizer.hasMoreTokens ()) {
763                     // [PENDING] what about additional spaces in a string ???
764
// Is an empty token generated for them or not ?
765
String JavaDoc xmiId = tokenizer.nextToken ();
766                     Object JavaDoc obj = context.getReference (xmiId);
767                     if (obj == null) {
768                         // reference not known yet
769
if (isReference)
770                             obj = new UnresolvedReference ();
771                         else
772                             obj = new UnresolvedReference (this);
773                         context.registerUnresolvedRef (xmiId, (UnresolvedReference) obj);
774                     }
775                     list.add (obj);
776                 } // while
777
if (isReference)
778                     setReferenceValues ((Reference) attr, list);
779                 else
780                     setAttributeValues (attr, list);
781             } else {
782                 throw new DebugException ("type cannot be resolved: " + attr.getType ().getName ());
783             }
784         }
785
786         // ReferencesCounter interface .........................................
787

788         public void increaseUnresolvedRefs () {
789             unresolvedRefsCounter++;
790         }
791
792         public void decreaseUnresolvedRefs () {
793             unresolvedRefsCounter--;
794             if (endReached && (unresolvedRefsCounter == 0)) {
795                 RefObject instance = createInstance ();
796                 if (unresRef != null)
797                     unresRef.referenceResolved (instance);
798             }
799         }
800
801     } // Instance
802

803     // **************************************************************************
804
// DataTypeElement
805
// **************************************************************************
806
public static class DataTypeElement extends XmiElement {
807
808         // ==========================================
809
// MOF 1.3 compatibility
810
// ==========================================
811
/*
812          * Since DataType is an abstract class in MOF 1.4, its instances cannot be created,
813          * thus reading of DataType instances is handled using this special class that
814          * substitutes DataType by an equivalent legal type.
815          *
816          * How does it work: A complete tree composed of @link #DataTypeElement.Node
817          * instances having <XMI.CorbaTypeCode> element as its root is created and
818          * @link #XmiContext.resolveCorbaType is called on the tree.
819          */

820         
821         // idicates if typeCode attribute is currently processed
822
private boolean typeCodeReading = false;
823         // stores current node when tree structure of XMI elements is being created
824
private Node node = null;
825         // possibly stores xmi.id of this DataType value
826
private String JavaDoc xmiId;
827         // id of related document
828
private String JavaDoc docId;
829         
830         public DataTypeElement (XmiElement parent, XmiContext context,
831             String JavaDoc name, Attributes attrs) {
832             super (parent, context);
833             xmiId = attrs.getValue (context.XMI_ID);
834             docId = context.getCurrentDocId ();
835         }
836         
837         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
838             if (!typeCodeReading) {
839                 if (qName.endsWith ("typeCode"))
840                     typeCodeReading = true;
841                 return this;
842             }
843             if ((node == null) && (!qName.equals (XmiConstants.XMI_CORBA_TYPE_CODE)))
844                 throw new DebugException ("XMI.CorbaTypeCode element expected");
845             node = new Node (qName, attrs, node);
846             return this;
847         }
848
849         public XmiElement endElement (String JavaDoc qName) {
850             if (typeCodeReading) {
851                 if (node.parent != null)
852                     node = node.parent;
853                 else
854                     typeCodeReading = false;
855                 return this;
856             }
857             if (!qName.endsWith ("DataType"))
858                 return this;
859             // the end of DataTypeElement has been reached
860
RefObject typeEquivalent = context.resolveCorbaType (node, false);
861             if (xmiId != null)
862                 context.putReference (docId, xmiId, typeEquivalent);
863             if (!(parent instanceof XmiElement.Content))
864                 parent.receiveValue (typeEquivalent);
865             return parent;
866         }
867
868         // stores one XMI element
869
public static class Node {
870             // parent node of this node, null in case of a root
871
public Node parent;
872             // list of all direct sub-nodes
873
public List subnodes = new LinkedList ();
874             // name of this XMI element
875
public String JavaDoc name;
876             // value of xmi.tcName attribute (if present, otherwise null)
877
public String JavaDoc tcName;
878             
879             public Node (String JavaDoc name, Attributes attrs, Node parent) {
880                 this.parent = parent;
881                 this.name = name;
882                 tcName = attrs.getValue (XmiConstants.XMI_TCNAME);
883                 if (parent != null)
884                     parent.addSubNode (this);
885             }
886             
887             public void addSubNode (Node subNode) {
888                 subnodes.add (subNode);
889             }
890             
891             public Node firstSubNode () {
892                 return (Node) subnodes.get (0);
893             }
894             
895         } // Node
896

897     } // DataTypeElement
898

899     // **************************************************************************
900
// ClassLevelAttribute
901
// **************************************************************************
902
public static class ClassLevelAttribute extends XmiElement {
903         
904         private Classifier type;
905         
906         public ClassLevelAttribute (XmiElement parent, XmiContext context, Attribute attr,
907             Attributes attrs) {
908             super (parent, context);
909             type = attr.getType ();
910         }
911
912         public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
913             return context.resolveValue (this, type, attrs);
914         }
915         
916         public void receiveValue (Object JavaDoc value) {
917             // post value to Content element
918
parent.receiveValue (value);
919         }
920
921     } // ClassLevelAttribute
922

923     // **************************************************************************
924
// AssociationElement
925
// **************************************************************************
926
public static class AssociationElement extends XmiElement implements ReferencesCounter {
927         
928         // related association
929
private Association assoc;
930         // flag indicating if the first object of a link has been read
931
private boolean oddNumberOfElementsRead = false;
932         // unresolved references counter
933
private int counter = 0;
934         // flag indicating if the whole association element (including sub-elements) has been read
935
private boolean endReached = false;
936         // list of read elements forming ends of links
937
private List elements = new LinkedList ();
938         
939         public AssociationElement (XmiElement parent, XmiContext context, Association assoc) {
940             super (parent, context);
941             this.assoc = assoc;
942     }
943
944     public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
945             return context.resolveInstanceOrReference (this, qName, attrs);
946     }
947
948         public void receiveValue (Object JavaDoc obj) {
949             if (obj instanceof UnresolvedReference) {
950                 ((UnresolvedReference) obj).setOwner (this);
951             }
952             elements.add (obj);
953             oddNumberOfElementsRead = !oddNumberOfElementsRead;
954         }
955         
956     public XmiElement endElement (String JavaDoc qName) {
957             if (oddNumberOfElementsRead) {
958                 throw new DebugException ("Odd number of association ends serialized: " + assoc.getName ());
959             }
960             endReached = true;
961             if (counter == 0)
962                 createLinks ();
963             return parent;
964     }
965
966         private void createLinks () {
967             RefAssociation refAssoc = ((RefPackage) context.findProxy (assoc)).refAssociation (assoc);
968             Iterator iter = elements.iterator ();
969             while (iter.hasNext ()) {
970                 Object JavaDoc firstObject = iter.next ();
971                 Object JavaDoc secondObject = iter.next ();
972                 if (firstObject instanceof UnresolvedReference)
973                     firstObject = ((UnresolvedReference) firstObject).getValue ();
974                 if (secondObject instanceof UnresolvedReference)
975                     secondObject = ((UnresolvedReference) secondObject).getValue ();
976                 if (!refAssoc.refLinkExists ((RefObject) firstObject, (RefObject) secondObject)) {
977                     refAssoc.refAddLink ((RefObject) firstObject, (RefObject) secondObject);
978                 }
979             } // while
980
}
981         
982         // ReferencesCounter implementation .....................................
983

984         public void increaseUnresolvedRefs() {
985             counter++;
986         }
987         
988         public void decreaseUnresolvedRefs() {
989             counter--;
990             if (endReached && (counter == 0))
991                 createLinks ();
992         }
993         
994     } // AssociationElement
995

996     // **************************************************************************
997
// PrimitiveValue
998
// **************************************************************************
999
public static class PrimitiveValue extends XmiElement {
1000
1001        // value of xmi.value attribute (if present - XMI 1.1 compatibility)
1002
private String JavaDoc xmiValue;
1003        // buffer for value of characters event
1004
private String JavaDoc valueAsText = "";
1005        // type of this primitive value
1006
private PrimitiveType type;
1007        // flag indicating if <xmi.any> value is read
1008
private boolean xmiAnyValueEndExpected = false;
1009        // flag that is set as true when </xmi.any> is encountered
1010
private boolean stopCharsReading = false;
1011
1012        public PrimitiveValue (XmiElement parent, XmiContext context,
1013            PrimitiveType type, Attributes attrs) {
1014            super (parent, context);
1015            this.type = type;
1016            xmiValue = attrs.getValue (XmiConstants.XMI_VALUE);
1017        }
1018
1019        /**
1020         * Constructor used to create shared instance of PrimitiveValue.
1021         * (shared instance is stored in context, see @link #XmiContext.PRIMITIVE_VALUE,
1022         * every time a new instance of PrimitiveValue is needed shared instance is taken
1023         * and inited by @link #init )
1024         */

1025        public PrimitiveValue (XmiContext context) {
1026            super (context);
1027        }
1028
1029        public void init (XmiElement parent, PrimitiveType type, Attributes attrs) {
1030            this.parent = parent;
1031            this.type = type;
1032            xmiValue = attrs.getValue (XmiConstants.XMI_VALUE);
1033            valueAsText = "";
1034            xmiAnyValueEndExpected = false;
1035            stopCharsReading = false;
1036        }
1037
1038        public void characters (char buf[], int offset, int len) {
1039            if (!stopCharsReading)
1040                valueAsText = valueAsText + new String JavaDoc (buf, offset, len);
1041        }
1042
1043    public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1044            // =======================================
1045
// XMI 1.1 compatibility
1046
// =======================================
1047
if (!qName.equals (XmiConstants.XMI_ANY_TYPE))
1048                throw new DebugException ("Unexpected element: " + qName);
1049            xmiAnyValueEndExpected = true;
1050            valueAsText = "";
1051            return this;
1052    }
1053        
1054        public XmiElement endElement (String JavaDoc qName) {
1055            if (xmiAnyValueEndExpected) {
1056                stopCharsReading = true;
1057                xmiAnyValueEndExpected = false;
1058                return this;
1059            }
1060            // =======================================
1061
// XMI 1.1 compatibility
1062
// =======================================
1063
if (xmiValue != null)
1064                valueAsText = xmiValue;
1065            // =======================================
1066
parent.receiveValue
1067                (XmiContext.resolvePrimitiveValue ((PrimitiveType) type, valueAsText));
1068            return parent;
1069        }
1070
1071    } // PrimitiveValue
1072

1073    // **************************************************************************
1074
// EnumerationValue
1075
// **************************************************************************
1076
public static class EnumerationValue extends XmiElement {
1077
1078        public EnumerationValue (XmiElement parent, XmiContext context,
1079            EnumerationType type, Attributes attributes) {
1080            super (parent, context);
1081            init (parent, type, attributes);
1082        }
1083
1084        /**
1085         * Constructor used to create shared instance of EnumerationValue.
1086         * (shared instance is stored in context, see @link #XmiContext.ENUMERATION_VALUE,
1087         * every time a new instance of EnumerationValue is needed shared instance is taken
1088         * and inited by @link #init )
1089         */

1090        public EnumerationValue (XmiContext context) {
1091            super (context);
1092        }
1093
1094        public void init (XmiElement parent, EnumerationType type,
1095            Attributes attrs) {
1096            this.parent = parent;
1097            String JavaDoc enumValue = attrs.getValue (XmiConstants.XMI_VALUE);
1098            if (enumValue == null)
1099                throw new DebugException ("xmi.value attribute expected in Enum element");
1100            parent.receiveValue
1101                (context.resolveEnumerationValue (type, enumValue));
1102        }
1103
1104    } // EnumerationValue
1105

1106    // **************************************************************************
1107
// StructureValue
1108
// **************************************************************************
1109
public static class StructureValue extends XmiElement
1110        implements ReferencesCounter {
1111
1112        // type of this structure value
1113
private StructureType type;
1114        // structure's fields, i.e. a list of StructureFields
1115
private List fields;
1116        /* this iterator is used if oldFormat == true, it iterates trough all elements in
1117         * @link #fields
1118         * current field in iterator corresponds to currently read field value */

1119        private Iterator fieldsIterator;
1120        // field related to the currently read value
1121
private StructureField currentField;
1122        // storage for already read fields' values
1123
private HashMap fieldsValues = new HashMap ();
1124        // if true, the structure is serialized using <xmi.field> elements
1125
private boolean oldFormat;
1126
1127        // number of currently unresolved references preventing creation of this structure
1128
private int counter = 0;
1129        // flag indicating if all sub-elements are already read, i.e. endElement () method has been called
1130
private boolean endReached = false;
1131        // holds an unresolved reference to this structure that should be set after the instance creation
1132
private UnresolvedReference unresRef = null;
1133
1134        public StructureValue (XmiElement parent, XmiContext context,
1135            StructureType type, Attributes attrs, boolean oldFormat) {
1136            super (parent, context);
1137            this.type = type;
1138            this.oldFormat = oldFormat;
1139
1140            int attrsLength = attrs.getLength ();
1141            fields = context.structureFields (type);
1142                        
1143            if (oldFormat)
1144                fieldsIterator = fields.iterator ();
1145            else {
1146                boolean isMultiplicityType =
1147                    XmiContext.getQualifiedName (type).equals ("Model.MultiplicityType");
1148                String JavaDoc fieldName, fieldValue;
1149                for (int index = 0; index < attrsLength; index++) {
1150                    fieldName = attrs.getQName (index);
1151                    // MOF 1.3 COMPATIBILITY PATCH ===========
1152
if (isMultiplicityType) {
1153                        if (fieldName.equals ("is_ordered"))
1154                            fieldName = "isOrdered";
1155                        else if (fieldName.equals ("is_unique"))
1156                            fieldName = "isUnique";
1157                    }
1158                    // =======================================
1159
fieldValue = attrs.getValue (index);
1160                    resolveFieldValue (fieldName, fieldValue);
1161                } // for
1162
} // else
1163
}
1164
1165        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1166            if (oldFormat) {
1167                // the structure value is serialized using <xmi.field> elements
1168
if (!fieldsIterator.hasNext ()) {
1169                    finishElement ();
1170                    return parent.startSubElement (qName, attrs);
1171                }
1172                currentField = (StructureField) fieldsIterator.next ();
1173            } else {
1174                currentField = (StructureField) context.resolveElementName (qName);
1175            }
1176
1177            Classifier type = currentField.getType ();
1178            return context.resolveValue (this, type, attrs);
1179        }
1180
1181        public void receiveValue (Object JavaDoc value) {
1182            if (value instanceof List) {
1183                if (((List) value).size () != 1)
1184                    throw new DebugException ("Multi-valued structure field: " + currentField.getName ());
1185                value = ((List) value).get (0);
1186            }
1187            if (value instanceof UnresolvedReference)
1188                ((UnresolvedReference) value).setOwner (this);
1189            setFieldValue (currentField, value);
1190        }
1191
1192        private void setFieldValue (TypedElement field, Object JavaDoc value) {
1193            if (fieldsValues.get (field) != null)
1194                throw new DebugException ("Multi-valued structure field: " + field.getName ());
1195            fieldsValues.put (field, value);
1196        }
1197
1198        private void resolveFieldValue (String JavaDoc fieldName, String JavaDoc fieldValue) {
1199            StructureField field;
1200            try {
1201                field = (StructureField) type.lookupElement (fieldName);
1202            } catch (NameNotFoundException e) {
1203                throw new DebugException ("Field name cannot be resolved: " + type.getName () + "." + fieldName);
1204            }
1205
1206            Classifier type = field.getType ();
1207            while (type instanceof AliasType)
1208                type = ((AliasType) type).getType ();
1209            Object JavaDoc value = null;
1210
1211            if (type instanceof PrimitiveType) {
1212                value = XmiContext.resolvePrimitiveValue ((PrimitiveType) type, fieldValue);
1213            } else if (type instanceof EnumerationType) {
1214                value = context.resolveEnumerationValue ((EnumerationType) type, fieldValue);
1215            } else if (type instanceof MofClass) {
1216                String JavaDoc xmiId = fieldValue.trim ();
1217                Object JavaDoc obj = context.getReference (xmiId);
1218                if (obj == null) {
1219                    // reference not known yet
1220
obj = new UnresolvedReference (this);
1221                    context.registerUnresolvedRef (xmiId, (UnresolvedReference) obj);
1222                    value = obj;
1223                }
1224            } else {
1225                throw new DebugException ("Field cannot be resolved, invalid type: " + type.getName ());
1226            }
1227            setFieldValue (field, value);
1228        }
1229
1230        private RefStruct createInstance () {
1231            // obtain list of fields values
1232
List args = new LinkedList ();
1233            Iterator iter = fields.iterator ();
1234            while (iter.hasNext ()) {
1235                StructureField field = (StructureField) iter.next ();
1236                Object JavaDoc param = fieldsValues.get (field);
1237                if (param instanceof UnresolvedReference) {
1238                    param = ((UnresolvedReference) param).getValue ();
1239                }
1240                if (param instanceof CollectionWrapper) {
1241                    param = ((CollectionWrapper) param).getCollection ();
1242                }
1243                if (param == null)
1244                    param = XmiContext.defaultValue (field.getType ());
1245                args.add (param);
1246            } // while
1247

1248            RefStruct struct = null;
1249            RefBaseObject proxy = context.findProxy (type);
1250            if (proxy == null)
1251                throw new DebugException ("Proxy not found: " + type.getName ());
1252            if (proxy instanceof RefClass)
1253                struct = ((RefClass) proxy).refCreateStruct (type, args);
1254            else
1255                struct = ((RefPackage) proxy).refCreateStruct (type, args);
1256            return struct;
1257        }
1258
1259        private void finishElement () {
1260            endReached = true;
1261            if (counter == 0) {
1262                RefStruct instance = createInstance ();
1263                if (!(parent instanceof XmiElement.Content)) {
1264                    parent.receiveValue (instance);
1265                }
1266            } else {
1267                if (!(parent instanceof XmiElement.Content)) {
1268                    unresRef = new UnresolvedReference ();
1269                    parent.receiveValue (unresRef);
1270                }
1271            }
1272        }
1273        
1274        public XmiElement endElement (String JavaDoc qName) {
1275            if (oldFormat) {
1276                if (fieldsIterator.hasNext ())
1277                    throw new DebugException ("Structure value serialization not complete: " + type.getName ());
1278                finishElement ();
1279                // A PATCH - see comment in StructureValues.startSubElement () method.
1280
return parent.endElement (qName);
1281            } else {
1282                finishElement ();
1283                return parent;
1284            }
1285        }
1286
1287        // ReferencesCounter interface ..........................................
1288

1289        public void increaseUnresolvedRefs () {
1290            counter++;
1291        }
1292
1293        public void decreaseUnresolvedRefs () {
1294            counter--;
1295            if (endReached && (counter == 0)) {
1296                RefStruct instance = createInstance ();
1297                if (unresRef != null)
1298                    unresRef.referenceResolved (instance);
1299            }
1300        }
1301
1302    } // StructureValue
1303

1304    // **************************************************************************
1305
// CollectionValues
1306
// **************************************************************************
1307
public static class CollectionValues extends XmiElement {
1308
1309        // storage of (multi-)value(s)
1310
private List values = new LinkedList ();
1311        // type of serialized structure value(s)
1312
private CollectionType type;
1313
1314        public CollectionValues (XmiElement parent, XmiContext context, CollectionType type) {
1315            super (parent, context);
1316            this.type = type;
1317        }
1318
1319        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1320            return new CollectionValue (this, context, type);
1321        }
1322
1323        public void receiveValue (Object JavaDoc value) {
1324            values.add (value);
1325        }
1326
1327        public XmiElement endElement (String JavaDoc qName) {
1328            parent.receiveValue (values);
1329            return parent;
1330        }
1331
1332    } // CollectionValues
1333

1334    // **************************************************************************
1335
// CollectionValue
1336
// **************************************************************************
1337
public static class CollectionValue extends XmiElement implements ReferencesCounter {
1338
1339        private Classifier type;
1340        private List values = new LinkedList ();
1341        private String JavaDoc collName;
1342                
1343        private int counter = 0;
1344        private boolean endReached = false;
1345        private UnresolvedReference unresRef = null;
1346        
1347        public CollectionValue (XmiElement parent, XmiContext context, CollectionType collType) {
1348            super (parent, context);
1349            type = collType.getType ();
1350            collName = collType.getName ();
1351        }
1352        
1353        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1354            if (type instanceof MofClass) {
1355                return context.resolveInstanceOrReference (this, qName, attrs);
1356            }
1357            if (type instanceof CollectionType) {
1358                return new XmiElement.CollectionValue (this, context, (CollectionType) type);
1359            }
1360            return context.resolveValue (this, type, attrs);
1361        }
1362
1363        public void receiveValue (Object JavaDoc value) {
1364            if (value instanceof List) {
1365                Iterator iter = ((List) value).iterator ();
1366                while (iter.hasNext ()) {
1367                    Object JavaDoc obj = iter.next ();
1368                    if (obj instanceof UnresolvedReference)
1369                        ((UnresolvedReference) obj).setOwner (this);
1370                    values.add (obj);
1371                }
1372            } else {
1373                if (value instanceof UnresolvedReference)
1374                    ((UnresolvedReference) value).setOwner (this);
1375                values.add (value);
1376            }
1377        }
1378
1379        public XmiElement endElement (String JavaDoc qName) {
1380            finishElement ();
1381            return parent;
1382        }
1383
1384        private void finishElement () {
1385            endReached = true;
1386            if (counter == 0) {
1387                CollectionWrapper val = createValue ();
1388                if (!(parent instanceof XmiElement.Content)) {
1389                    parent.receiveValue (val);
1390                }
1391            } else {
1392                if (!(parent instanceof XmiElement.Content)) {
1393                    unresRef = new UnresolvedReference ();
1394                    parent.receiveValue (unresRef);
1395                }
1396            }
1397        }
1398        
1399        public CollectionWrapper createValue () {
1400            List list = new LinkedList ();
1401            Iterator iter = values.iterator ();
1402            while (iter.hasNext ()) {
1403                Object JavaDoc obj = iter.next ();
1404                if (obj instanceof UnresolvedReference) {
1405                    obj = ((UnresolvedReference) obj).getValue ();
1406                }
1407                if (obj instanceof CollectionWrapper) {
1408                    obj = ((CollectionWrapper) obj).getCollection ();
1409                }
1410                list.add (obj);
1411            }
1412            return new CollectionWrapper (list);
1413        }
1414        
1415        // ReferencesCounter interface ..........................................
1416

1417        public void increaseUnresolvedRefs () {
1418            counter++;
1419        }
1420
1421        public void decreaseUnresolvedRefs () {
1422            counter--;
1423            if (endReached && (counter == 0)) {
1424                CollectionWrapper value = createValue ();
1425                if (unresRef != null)
1426                    unresRef.referenceResolved (value);
1427            }
1428        }
1429        
1430    } // CollectionValue
1431

1432    // **************************************************************************
1433
// ObjectValues
1434
// **************************************************************************
1435
public static class ObjectValues extends XmiElement {
1436        /* ObjectValues represents an element that consists of a sequence of
1437         * ObjectValue elements.
1438         * If an attribute of Class type or a reference is encountered,
1439         * this element is created to handle resolving its (multi-)value.
1440         */

1441
1442        // storage of (multi-)value(s)
1443
private List values = new LinkedList ();
1444        // stores correspondent value passed in the constructor, see the comment there
1445
private ReferencesCounter target;
1446        // XMI 2.0, if true then "nil=true" attribute is present
1447
private boolean isNull;
1448
1449        /**
1450         * @param target an auxiliar parameter;
1451         * If target is not of <code>null</code> value and some of sub-values is
1452         * resolved as UnresolvedReference, target is set as an owner of this
1453         * @link #UnresolvedReference,
1454         * see @link #UnresolvedReference.setOwner
1455         * (target is <code>null</code> iff value of reference is read - in this
1456         * case an owner cannot be set till it is created, see creation of
1457         * @link #ReferenceHandler in #Instance.createInstance )
1458         */

1459        public ObjectValues (XmiElement parent, XmiContext context, ReferencesCounter target, boolean isNull) {
1460            super (parent, context);
1461            this.target = target;
1462            this.isNull = isNull;
1463        }
1464
1465        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1466            return context.resolveInstanceOrReference (this, qName, attrs);
1467        }
1468
1469        public void receiveValue (Object JavaDoc value) {
1470            values.add (value);
1471            if ((value instanceof UnresolvedReference) && (target != null))
1472                ((UnresolvedReference) value).setOwner (target);
1473        }
1474
1475        public XmiElement endElement (String JavaDoc qName) {
1476            parent.receiveValue (isNull ? null : values);
1477            return parent;
1478        }
1479
1480    } // ObjectValues
1481

1482    // **************************************************************************
1483
// StructureValues
1484
// **************************************************************************
1485
public static class StructureValues extends XmiElement {
1486        /* The purpose of this element is similar to the purpose of
1487         * @link #ObjectValues
1488         * A sequence of structures is expected. */

1489
1490        // storage of (multi-)value(s)
1491
private List values = new LinkedList ();
1492        // type of serialized structure value(s)
1493
private StructureType type;
1494        // if true, structure values are serialized using <xmi.field> elements
1495
private boolean oldFormat = false;
1496
1497        public StructureValues (XmiElement parent, XmiContext context, StructureType type) {
1498            super (parent, context);
1499            this.type = type;
1500        }
1501
1502        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1503            if (qName.equals (XmiConstants.XMI_FIELD))
1504                oldFormat = true;
1505            StructureValue struct = new StructureValue (this, context, type, attrs, oldFormat);
1506            if (oldFormat) {
1507                /* A PATCH - we need to call startSubElement method, because items of the structure
1508                 * (that will be read) are encapsulated directly by StructureValues element
1509                 * (compare to "class style" serialization, where items are encapsulated by
1510                 * StructureValue element rather than StructureValues.
1511                 * There is pairwise call of this.endElement () in StructureValue.endElemnet ()
1512                 * method. */

1513                return struct.startSubElement (qName, attrs);
1514            }
1515            return struct;
1516        }
1517
1518        public void receiveValue (Object JavaDoc value) {
1519            values.add (value);
1520        }
1521
1522        public XmiElement endElement (String JavaDoc qName) {
1523            parent.receiveValue (values);
1524            return parent;
1525        }
1526
1527    } // StructureValues
1528

1529    // **************************************************************************
1530
// ReferenceValue
1531
// **************************************************************************
1532
public static class ReferenceValue extends XmiElement {
1533        /* This element reads an object value stored as reference,
1534         * example: <Model:Class id.ref='a1'/>
1535         */

1536
1537        public ReferenceValue (XmiElement parent, XmiContext context, String JavaDoc xmiId) {
1538            super (parent, context);
1539            init (parent, xmiId);
1540        }
1541
1542        /**
1543         * Constructor used to create shared instance of ReferenceValue.
1544         * (shared instance is stored in context, see @link #XmiContext.REFERENCE_VALUE,
1545         * every time a new instance of ReferenceValue is needed shared instance is taken
1546         * and inited by @link #init )
1547         */

1548        public ReferenceValue (XmiContext context) {
1549            super (context);
1550        }
1551
1552        public void init (XmiElement parent, String JavaDoc xmiId) {
1553            this.parent = parent;
1554            Object JavaDoc obj = context.getReference (xmiId);
1555            if (obj == null) {
1556                obj = new UnresolvedReference ();
1557                context.registerUnresolvedRef (xmiId, (UnresolvedReference) obj);
1558            }
1559            parent.receiveValue (obj);
1560        }
1561        
1562        public void initExternal (XmiElement parent, String JavaDoc hRef) {
1563            this.parent = parent;
1564            Object JavaDoc obj;
1565            
1566            XMIReferenceProvider.XMIReference ref = context.toXMIReference (hRef);
1567            
1568            String JavaDoc docId = ref.getSystemId ();
1569            String JavaDoc xmiId = ref.getXmiId ();
1570            obj = context.getReference (docId, xmiId);
1571            if (obj == null) {
1572                obj = new UnresolvedReference ();
1573                context.registerUnresolvedExternalRef (docId, xmiId, (UnresolvedReference) obj);
1574            }
1575            parent.receiveValue (obj);
1576        }
1577
1578    } // ReferenceValue
1579

1580    // **************************************************************************
1581
// Dummy
1582
// **************************************************************************
1583
public static class Dummy extends XmiElement {
1584
1585        private int level = 0;
1586        
1587        public Dummy (XmiElement parent, XmiContext context, String JavaDoc qName) {
1588            super (parent, null);
1589            context.unknownElementFound(qName);
1590        }
1591    
1592        public XmiElement startSubElement (String JavaDoc qName, Attributes attrs) {
1593            level++;
1594            return this;
1595        }
1596
1597        public XmiElement endElement (String JavaDoc qName) {
1598            if (level == 0) {
1599                return parent;
1600            } else {
1601                level--;
1602                return this;
1603            }
1604        }
1605        
1606    }
1607        
1608    // **************************************************************************
1609
// ReferencesCounter
1610
// **************************************************************************
1611
public static interface ReferencesCounter {
1612        /**
1613         * Increments counter counting the number of unresolved references preventing
1614         * given object to be created.
1615         */

1616        public void increaseUnresolvedRefs ();
1617
1618        /** Decrements counter. */
1619        public void decreaseUnresolvedRefs ();
1620
1621    }
1622    
1623    // **************************************************************************
1624
// UnresolvedReference
1625
// **************************************************************************
1626
public static class UnresolvedReference {
1627        /**
1628         * Unresolved reference represents *link* to a not yet created instance.
1629         * It can be registered in context, see @link #XmiContext.registerUnresolvedRef,
1630         * then, if the desired instance is created and put into context by
1631         * @link #XmiContext.putRefrence, @link #referenceResolved is called -
1632         * it decreases owner's counter of unresolved references preventing instance
1633         * creation.
1634         */

1635        
1636        // when resolved, stores the resolved value
1637
private Object JavaDoc value = null;
1638        // owner of this unresolved reference
1639
private ReferencesCounter owner;
1640
1641        /**
1642         * Creates UnresolvedReference with no owner (owner can be set later by
1643         * @link #setOwner ).
1644         */

1645        public UnresolvedReference () {
1646        }
1647
1648        public UnresolvedReference (ReferencesCounter owner) {
1649            this.owner = owner;
1650            owner.increaseUnresolvedRefs ();
1651        }
1652
1653        public void referenceResolved (Object JavaDoc value) {
1654            this.value = value;
1655            if (owner != null)
1656                owner.decreaseUnresolvedRefs ();
1657        }
1658
1659        public Object JavaDoc getValue () {
1660            return value;
1661        }
1662
1663        public void setOwner (ReferencesCounter owner) {
1664            this.owner = owner;
1665            owner.increaseUnresolvedRefs ();
1666        }
1667
1668    } // UnresolvedReference
1669

1670    // **************************************************************************
1671
// ReferenceHandler
1672
// **************************************************************************
1673
public static class ReferenceHandler implements ReferencesCounter {
1674        /**
1675         * ReferenceHandler is used to set value of a reference later, when all needed
1676         * references are resolved (it implements @link #ReferenceCounter, so it is
1677         * notified when the situation occurs).
1678         */

1679        
1680        // object that contains this reference
1681
private RefObject obj;
1682        // related reference
1683
private Reference ref;
1684        // reference values
1685
private List values = new LinkedList ();
1686        // counter of unresolved references
1687
private int unresolvedRefsCounter = 0;
1688        // context
1689
private XmiContext context;
1690
1691        public ReferenceHandler (Reference ref, RefObject obj, List args, XmiContext context) {
1692            this.obj = obj;
1693            this.ref = ref;
1694            this.context = context;
1695            Iterator iter = args.iterator ();
1696            while (iter.hasNext ()) {
1697                Object JavaDoc value = iter.next ();
1698                if (value instanceof UnresolvedReference) {
1699                    Object JavaDoc val = ((UnresolvedReference) value).getValue ();
1700                    if (val != null)
1701                        value = val;
1702                    else
1703                        ((UnresolvedReference) value).setOwner (this);
1704                } // if
1705
values.add (value);
1706            } // while
1707
if (unresolvedRefsCounter == 0) {
1708                setReference ();
1709            }
1710        }
1711
1712        public void increaseUnresolvedRefs () {
1713            unresolvedRefsCounter++;
1714        }
1715
1716        public void decreaseUnresolvedRefs () {
1717            unresolvedRefsCounter--;
1718            if (unresolvedRefsCounter == 0)
1719                setReference ();
1720        }
1721
1722        private void setReference () {
1723            Iterator iter;
1724            AssociationEnd end = ref.getReferencedEnd ();
1725            boolean isOrdered = end.getMultiplicity ().isOrdered ();
1726            Association association = (Association) end.getContainer ();
1727
1728            /*
1729            boolean debug = "Assoc".equals (association.getName ());
1730            if (debug) {
1731                System.out.println("setReference: " + ref.getName () + " " + end.getName ());
1732            }
1733            */

1734            
1735            boolean isFirst = false;
1736            for (iter = association.getContents ().iterator (); iter.hasNext ();) {
1737                ModelElement me = (ModelElement) iter.next ();
1738                if (me instanceof AssociationEnd) {
1739                    isFirst = me.equals (end);
1740                    break;
1741                }
1742            }
1743            
1744            RefPackage refPackage = (RefPackage) context.findProxy (association);
1745            if (refPackage == null)
1746                throw new DebugException ("Proxy not found: " + association.getName ());
1747            RefAssociation refAssoc = refPackage.refAssociation (association);
1748            if (refAssoc == null)
1749                throw new DebugException ("Proxy not found: " + association.getName ());
1750            iter = values.iterator ();
1751            while (iter.hasNext ()) {
1752                Object JavaDoc value = iter.next ();
1753                RefObject endValue;
1754                if (value instanceof UnresolvedReference)
1755                    endValue = (RefObject) ((UnresolvedReference) value).getValue ();
1756                else
1757                    endValue = (RefObject) value;
1758                RefObject firstObj = isFirst ? endValue : obj;
1759                RefObject secondObj = isFirst ? obj : endValue;
1760                if ((firstObj != null) && (secondObj != null)) {
1761                    if (!refAssoc.refLinkExists (firstObj, secondObj)) {
1762                        refAssoc.refAddLink (firstObj, secondObj);
1763
1764                        /*
1765                        if (debug)
1766                            System.out.println("add");
1767                        */

1768                        
1769                    } else if (isOrdered) {
1770                        refAssoc.refRemoveLink (firstObj, secondObj);
1771                        refAssoc.refAddLink (firstObj, secondObj);
1772
1773                        /*
1774                        if (debug)
1775                            System.out.println("remove, add");
1776                        */

1777                        
1778                    } else {
1779                        /*
1780                        if (debug)
1781                            System.out.println("skip");
1782                        */

1783                        
1784                    }
1785                        
1786                }
1787            } // while
1788

1789            /*
1790            if (debug) {
1791                iter = refAssoc.refAllLinks ().iterator ();
1792                while (iter.hasNext ()) {
1793                    RefAssociationLink link = (RefAssociationLink) iter.next ();
1794                    String n_1 = (String) link.refFirstEnd ().refGetValue ("name");
1795                    String n_2 = (String) link.refSecondEnd ().refGetValue ("name");
1796                    System.out.println("link: " + n_1 + " " + n_2);
1797                }
1798            }
1799            */

1800            
1801        }
1802        
1803    } // ReferenceHandler
1804

1805    // **************************************************************************
1806
// CollectionWrapper
1807
// **************************************************************************
1808
public static class CollectionWrapper {
1809        
1810        private Collection coll;
1811        
1812        public CollectionWrapper (Collection coll) {
1813            this.coll = coll;
1814        }
1815        
1816        public Collection getCollection () {
1817            return coll;
1818        }
1819                
1820    } // CollectionWrapper
1821

1822}
1823
Popular Tags