KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > axi > impl > AXIModelUpdater


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.xml.axi.impl;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.List JavaDoc;
23 import org.netbeans.modules.xml.axi.AXIComponent;
24 import org.netbeans.modules.xml.axi.AXIComponent.ComponentType;
25 import org.netbeans.modules.xml.axi.AXIDocument;
26 import org.netbeans.modules.xml.axi.AXIType;
27 import org.netbeans.modules.xml.axi.AnyAttribute;
28 import org.netbeans.modules.xml.axi.AnyElement;
29 import org.netbeans.modules.xml.axi.Attribute;
30 import org.netbeans.modules.xml.axi.Compositor;
31 import org.netbeans.modules.xml.axi.Element;
32 import org.netbeans.modules.xml.axi.visitor.DeepAXITreeVisitor;
33 import org.netbeans.modules.xml.schema.model.AttributeReference;
34 import org.netbeans.modules.xml.schema.model.ElementReference;
35 import org.netbeans.modules.xml.schema.model.GlobalAttribute;
36 import org.netbeans.modules.xml.schema.model.GlobalElement;
37 import org.netbeans.modules.xml.schema.model.LocalAttribute;
38 import org.netbeans.modules.xml.schema.model.LocalElement;
39 import org.netbeans.modules.xml.schema.model.SchemaComponent;
40 import org.netbeans.modules.xml.axi.ContentModel;
41
42 /**
43  * AXIModelUpdater updates the AXIModel to keep it in sync
44  * with the SchemaModel. The sync alogirithm works as follows:
45  *
46  * For every component X it creates another component X' by using
47  * the peer in X.
48  * 1. For each child in X, checks its existence in X'.
49  * If not found, deleted from X.
50  * 2. For each child in X', checks its existence in X.
51  * If not found, added to X.
52  * 3. Repeat the steps for for all remaining child in X after step 1.
53  *
54  * @author Samaresh (Samaresh.Panda@Sun.Com)
55  */

56 public class AXIModelUpdater extends DeepAXITreeVisitor {
57
58     /**
59      * Creates a new instance of AXIModelUpdater
60      */

61     public AXIModelUpdater(AXIModelImpl model) {
62         this.model = model;
63     }
64         
65     /**
66      * Keeps the AXIModel in sync with schema model.
67      * Returns true if success, false if failed.
68      */

69     public boolean doSync() {
70         try {
71             syncCompleted = false;
72             //first sync the document
73
model.getRoot().accept(this);
74             
75             //sync all global elements and attributes
76
for(AXIComponent child : model.getRoot().getChildren()) {
77                 if(child instanceof ContentModel)
78                     continue;
79                 
80                 child.accept(this);
81             }
82             
83             //finally sync all the content models
84
for(ContentModel contentModel : model.getRoot().getContentModels()) {
85                 contentModel.accept(this);
86             }
87             syncCompleted = true;
88         } catch(Exception JavaDoc ex) {
89             //bad things happened
90
}
91         return syncCompleted;
92     }
93     
94     
95     /**
96      * Syncs only the specified component.
97      */

98     public void syncOne(AXIComponent component) {
99         component.accept(this);
100     }
101         
102     /**
103      * Syncs one component at a time. For each component, it creates
104      * the same component as if it was created from scratch and then merges
105      * the difference to the original one and then visits the modified list
106      * of children.
107      */

108     protected void visitChildren(AXIComponent original) {
109         if(!original.canVisitChildren())
110             return;
111         
112         //skip proxies if the original is from the same model
113
if(original.getComponentType() == ComponentType.PROXY &&
114            original.getModel() == original.getOriginal().getModel()) {
115             return;
116         }
117         
118         AXIComponentCreator creator = new AXIComponentCreator(model);
119         AXIComponent altered = getAltered(original);
120         assert(altered != null);
121         
122         List JavaDoc<AXIComponent> modifiedChildren = synchronize(original, altered);
123         if( (modifiedChildren == null) ||
124             (original instanceof AXIDocument) ) {
125             return;
126         }
127         
128         //visit the children that were nethier removed nor added
129
for(AXIComponent child : modifiedChildren) {
130             child.accept(this);
131         }
132     }
133
134     /**
135      * We do not sync proxies, unless they represent items from other files.
136      * Hence, for a proxy, get the original, else create a new one.
137      */

138     private AXIComponent getAltered(AXIComponent original) {
139         if(original.getComponentType() == ComponentType.PROXY) {
140             return original.getOriginal();
141         }
142         
143         //create the same component from the original's peer
144
AXIComponentCreator creator = new AXIComponentCreator(model);
145         return creator.createNew(original.getPeer());
146     }
147     
148     /**
149      * Step 1: From the original tree, delete the children that no longer
150      * exist in new tree. Remaining ones exist and we must sync them.
151      * Step 2: From the new tree, add the children that are new w.r.t. the
152      * original.
153      */

154     private List JavaDoc<AXIComponent> synchronize(AXIComponent original, AXIComponent altered) {
155         //first remove the removed children
156
List JavaDoc<AXIComponent> modifiedChildren = removeRemovedChildren(original, altered);
157         
158         //add new children
159
addNewChildren(original, altered);
160         
161         return modifiedChildren;
162     }
163     
164     /**
165      * Removes the list of children, that no longer exists in the altered tree.
166      */

167     private List JavaDoc<AXIComponent> removeRemovedChildren(AXIComponent original, AXIComponent altered) {
168         List JavaDoc<AXIComponent> removedChildren = new ArrayList JavaDoc<AXIComponent>();
169         List JavaDoc<AXIComponent> dirtyChildren = new ArrayList JavaDoc<AXIComponent>();
170         for(AXIComponent oChild : original.getChildren()) {
171             int index = childExists(oChild, altered, true);
172             if( (index == -1) ||
173                 oChild.getPeer().getParent() == null ||
174                 oChild.getPeer().getModel() == null) {
175                 removedChildren.add(oChild);
176                 continue;
177             }
178             dirtyChildren.add(oChild);
179         }
180         for(AXIComponent child : removedChildren) {
181             original.removeChild(child);
182         }
183         
184         return dirtyChildren;
185     }
186     
187     /**
188      * Finds all newly added children and surgically inserts
189      * them into the original component at appropriate position.
190      */

191     private void addNewChildren(AXIComponent original, AXIComponent altered) {
192         int size = altered.getChildren().size();
193         for(int index=0; index<size; index++) {
194             AXIComponent aChild = altered.getChildren().get(index);
195             int indexInOriginalTree = childExists(aChild, original, false);
196             //this is a new child, add it to the original tree
197
if(indexInOriginalTree == -1) {
198                 if(original.getComponentType() == ComponentType.PROXY) {
199                     AXIComponent proxy = model.getComponentFactory().createProxy(aChild);
200                     original.addChildAtIndex(proxy, index); //items from other model/file.
201
} else {
202                     original.addChildAtIndex(aChild, index); //same model/file.
203
}
204                 continue;
205             }
206             //if found, remove these transient objects as listeners.
207
if(aChild.getComponentType() == ComponentType.PROXY) {
208                 aChild.getSharedComponent().removeListener(aChild);
209             }
210         }
211     }
212     
213     /**
214      * Checks if the specified component exists as a child of the given parent.
215      * Returns a non negative index if found, -1 otherwise.
216      */

217     private int childExists(AXIComponent child, AXIComponent parent, boolean checkOriginal) {
218         int size = parent.getChildren().size();
219         for(int index=0; index<size; index++) {
220             AXIComponent c = parent.getChildren().get(index);
221             if(c.getPeer() == child.getPeer()) {
222                 if(checkOriginal) {
223                     if(!validateOriginal(child, c))
224                         return -1;
225                 }
226                 return index;
227             }
228         }
229         
230         return -1;
231     }
232     
233     /**
234      * Validates the original. First, it checks for a valid peer.
235      * Then some more sanity checks.
236      */

237     private boolean validateOriginal(AXIComponent original, AXIComponent altered) {
238         //first pass: validate the peer
239
PeerValidator validator = new PeerValidator();
240         if(!validator.validate(original))
241             return false;
242         
243         //altered child is a proxy where as original is not.
244
//possible that codegen creates a GCT(SEQ(LE))) and sets
245
//the peer of SEQ and LE to arbitrary AXI components.
246
//These components should be removed and then be added as proxies.
247
if(altered.getComponentType() == ComponentType.PROXY &&
248            original.getComponentType() != ComponentType.PROXY) {
249             return false;
250         }
251         
252         return true;
253     }
254         
255     /**
256      * Visit the AXIDocument.
257      */

258     public void visit(AXIDocument document) {
259         Util.updateAXIDocument(document);
260         visitChildren(document);
261     }
262     
263     /**
264      * Visit an element.
265      */

266     public void visit(Element element) {
267         if(element instanceof ElementImpl)
268             visit((ElementImpl)element);
269         if(element instanceof ElementRef)
270             visit((ElementRef)element);
271         if(element instanceof ElementProxy)
272             ((ElementProxy)element).forceFireEvent();
273     }
274         
275     /**
276      * For an ElementImpl, add and remove child means that type
277      * changed, in which case we should recreate children,
278      * Same if the type changed.
279      */

280     public void visit(ElementImpl element) {
281         SchemaComponent schemaComponent = element.getPeer();
282         if(schemaComponent instanceof LocalElement)
283             Util.updateLocalElement(element);
284         if(schemaComponent instanceof GlobalElement)
285             Util.updateGlobalElement(element);
286                 
287         //if type changed, update children
288
SchemaComponent newType = Util.getSchemaType(model, element.getPeer());
289         AXIType axiType = Util.getAXIType(element, newType);
290         if(element.getType() != axiType)
291             element.setType(axiType);
292         
293         //sync children.
294
visitChildren(element);
295     }
296                 
297     public void visit(ElementRef elementRef) {
298         ElementReference ref = (ElementReference)elementRef.getPeer();
299         GlobalElement newGE = ref.getRef().get();
300         SchemaComponent originalGE = elementRef.getReferent().getPeer();
301         if(originalGE == newGE) {
302             Util.updateElementReference(elementRef);
303             elementRef.forceFireEvent();
304             visitChildren(elementRef);
305             return;
306         }
307         //the element ref now points to a different global element
308
AXIComponent newElement = Util.lookup(elementRef.getModel(), newGE);
309         if(newElement != null && newElement instanceof Element) {
310             elementRef.setRef((Element)newElement);
311             elementRef.forceFireEvent();
312         }
313     }
314
315     public void visit(Attribute attribute) {
316         if(attribute instanceof AttributeImpl)
317             visit((AttributeImpl)attribute);
318         if(attribute instanceof AttributeRef)
319             visit((AttributeRef)attribute);
320         if(attribute instanceof AttributeProxy)
321             ((AttributeProxy)attribute).forceFireEvent();
322     }
323     
324     public void visit(AttributeImpl attribute) {
325         SchemaComponent schemaComponent = attribute.getPeer();
326         if(schemaComponent instanceof LocalAttribute) {
327             Util.updateLocalAttribute(attribute);
328             AXIType type = Util.getDatatype(attribute.getModel(), (LocalAttribute)schemaComponent);
329             if(type != null)
330                 attribute.setType(type);
331         }
332         if(schemaComponent instanceof GlobalAttribute) {
333             Util.updateGlobalAttribute(attribute);
334             AXIType type = Util.getDatatype(attribute.getModel(), (GlobalAttribute)schemaComponent);
335             if(type != null)
336                 attribute.setType(type);
337         }
338     }
339     
340     public void visit(AttributeRef attributeRef) {
341         AttributeReference ref = (AttributeReference)attributeRef.getPeer();
342         SchemaComponent originalGA = attributeRef.getReferent().getPeer();
343         GlobalAttribute newGA = ref.getRef().get();
344         if(originalGA == newGA) {
345             Util.updateAttributeReference(attributeRef);
346             attributeRef.forceFireEvent();
347             return;
348         }
349         
350         //the attribute ref now points to a different global attribute
351
AXIComponent newAttr = Util.lookup(attributeRef.getModel(), newGA);
352         if(newAttr != null && newAttr instanceof Attribute) {
353             attributeRef.setRef((Attribute)newAttr);
354             attributeRef.forceFireEvent();
355         }
356     }
357     
358     public void visit(Compositor compositor) {
359         Util.updateCompositor(compositor);
360         visitChildren(compositor);
361     }
362     
363     public void visit(ContentModel contentModel) {
364         Util.updateContentModel(contentModel);
365         visitChildren(contentModel);
366     }
367     
368     public void visit(AnyAttribute attribute) {
369         Util.updateAnyAttribute(attribute);
370     }
371     
372     public void visit(AnyElement element) {
373         Util.updateAnyElement(element);
374     }
375
376     ////////////////////////////////////////////////////////////////////
377
////////////////////////// member variables ////////////////////////
378
////////////////////////////////////////////////////////////////////
379
private AXIModelImpl model;
380     private boolean syncCompleted;
381 }
382
Popular Tags