KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > schema > completion > util > CompletionContextImpl


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.schema.completion.util;
20
21 import java.net.URI JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Stack JavaDoc;
27 import javax.xml.XMLConstants JavaDoc;
28 import javax.xml.namespace.QName JavaDoc;
29 import org.w3c.dom.Attr JavaDoc;
30 import org.w3c.dom.NamedNodeMap JavaDoc;
31
32 import org.netbeans.editor.BaseDocument;
33 import org.netbeans.editor.TokenItem;
34 import org.openide.filesystems.FileObject;
35 import org.netbeans.modules.xml.text.syntax.dom.StartTag;
36 import org.netbeans.modules.xml.text.syntax.SyntaxElement;
37 import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport;
38 import org.netbeans.modules.xml.text.api.XMLDefaultTokenContext;
39 import org.netbeans.modules.xml.schema.completion.spi.CompletionContext;
40 import org.netbeans.modules.xml.schema.completion.spi.CompletionContext.CompletionType;
41 import org.netbeans.modules.xml.schema.completion.spi.CompletionModelProvider;
42 import org.netbeans.modules.xml.schema.completion.spi.CompletionModelProvider.CompletionModel;
43 import org.netbeans.modules.xml.text.syntax.dom.EmptyTag;
44 import org.netbeans.modules.xml.text.syntax.dom.EndTag;
45 import org.openide.util.Lookup;
46
47 /**
48  * Helps in populating the completion list.
49  *
50  * @author Samaresh (Samaresh.Panda@Sun.Com)
51  */

52 public class CompletionContextImpl extends CompletionContext {
53         
54     /**
55      * Creates a new instance of CompletionQueryHelper
56      */

57     public CompletionContextImpl(FileObject primaryFile,
58             XMLSyntaxSupport support, int offset) {
59         try {
60             this.primaryFile = primaryFile;
61             this.document = support.getDocument();
62             this.element = support.getElementChain(offset);
63             this.token = support.getPreviousToken(offset);
64             this.docRoot = CompletionUtil.getRoot(element);
65             this.lastTypedChar = support.lastTypedChar();
66             populateNamespaces();
67         } catch(Exception JavaDoc ex) {
68             //in the worst case, there will not be
69
//any code completion help.
70
}
71     }
72     
73     ////////////////START CompletionContext Implementations////////////////
74
public CompletionType getCompletionType() {
75         return completionType;
76     }
77         
78     public String JavaDoc getDefaultNamespace() {
79         return defaultNamespace;
80     }
81     
82     public List JavaDoc<QName JavaDoc> getPathFromRoot() {
83         return pathFromRoot;
84     }
85     
86     public FileObject getPrimaryFile() {
87         return primaryFile;
88     }
89             
90     public BaseDocument getBaseDocument() {
91         return document;
92     }
93     
94     public HashMap JavaDoc<String JavaDoc, String JavaDoc> getDeclaredNamespaces() {
95         return declaredNamespaces;
96     }
97     
98     public String JavaDoc getTypedChars() {
99         return typedChars;
100     }
101     
102     public boolean isSchemaAwareCompletion() {
103         return schemaLocation != null;
104     }
105
106     public List JavaDoc<URI JavaDoc> getSchemas() {
107         List JavaDoc<URI JavaDoc> uris = new ArrayList JavaDoc<URI JavaDoc>();
108         if(schemaLocation != null)
109             CompletionUtil.loadSchemaURIs(schemaLocation, uris, false);
110         if(noNamespaceSchemaLocation != null)
111             CompletionUtil.loadSchemaURIs(noNamespaceSchemaLocation, uris, true);
112         return uris;
113     }
114     ////////////////END CompletionContext Implementations////////////////
115

116     /**
117      * Keeps all namespaces along with their prefixes in a HashMap.
118      * This is obtained from the root element's attributes, with
119      * the attribute value(namespace) as the key and name with prefix
120      * as the value.
121      * For example the hashmap may look like this
122      * KEY VALUE
123      * http://www.camera.com xmlns:c
124      * http://www.nikon.com xmlns:n
125      */

126     private void populateNamespaces() {
127         if(docRoot == null)
128             return;
129         //Check if the tag has any prefix. If yes, the defaultNamespace
130
//is the one with this prefix.
131
String JavaDoc tagName = docRoot.getTagName();
132         String JavaDoc defNS = XMLConstants.XMLNS_ATTRIBUTE;
133         String JavaDoc temp = CompletionUtil.getPrefixFromTag(tagName);
134         if(temp != null) defNS = defNS+":"+temp; //NOI18N
135
NamedNodeMap JavaDoc attributes = docRoot.getAttributes();
136         for(int index=0; index<attributes.getLength(); index++) {
137             Attr JavaDoc attr = (Attr JavaDoc)attributes.item(index);
138             String JavaDoc attrName = attr.getName();
139             if(CompletionUtil.getLocalNameFromTag(attrName).
140                     equals(XSI_SCHEMALOCATION)) {
141                 schemaLocation = attr.getValue().trim();
142                 continue;
143             }
144             if(CompletionUtil.getLocalNameFromTag(attrName).
145                     equals(XSI_NONS_SCHEMALOCATION)) {
146                 noNamespaceSchemaLocation = attr.getValue().trim();
147                 continue;
148             }
149             if(!attr.getName().startsWith(XMLConstants.XMLNS_ATTRIBUTE))
150                 continue;
151             if(attr.getName().equals(defNS))
152                 this.defaultNamespace = attr.getValue();
153             declaredNamespaces.put(attr.getName(), attr.getValue());
154         }
155     }
156             
157     /**
158      * At a given context, that is, at the current cursor location
159      * in the document, finds the type of query that needs to be
160      * carried out and finds the path from root.
161      */

162     public boolean initContext() {
163         try {
164             fromNoNamespace = false;
165             noNamespaceModel = null;
166             int id = token.getTokenID().getNumericID();
167             switch ( id) {
168                 //user enters < character
169
case XMLDefaultTokenContext.TEXT_ID:
170                     String JavaDoc chars = token.getImage().trim();
171                     if(chars != null && chars.equals("") &&
172                        token.getPrevious().getImage().trim().equals(">")) {
173                         completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
174                         break;
175                     }
176                     if(chars != null && !chars.equals("<") &&
177                        token.getPrevious().getImage().trim().equals(">")) {
178                         completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
179                         break;
180                     }
181                     completionType = CompletionType.COMPLETION_TYPE_ELEMENT;
182                     pathFromRoot = getPathFromRoot(element);
183                     break;
184
185                 //start tag of an element
186
case XMLDefaultTokenContext.TAG_ID:
187                     if(lastTypedChar == '>') {
188                         completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
189                         break;
190                     }
191                     if(element instanceof EmptyTag) {
192                         completionType = CompletionType.COMPLETION_TYPE_ATTRIBUTE;
193                         pathFromRoot = getPathFromRoot(element);
194                         break;
195                     }
196                     
197                     if(element instanceof StartTag) {
198                         StartTag tag = (StartTag)element;
199                         typedChars = tag.getTagName();
200                     }
201                     completionType = CompletionType.COMPLETION_TYPE_ELEMENT;
202                     pathFromRoot = getPathFromRoot(element.getPrevious());
203                     break;
204
205                 //user enters an attribute name
206
case XMLDefaultTokenContext.ARGUMENT_ID:
207                     completionType = CompletionType.COMPLETION_TYPE_ATTRIBUTE;
208                     typedChars = token.getImage();
209                     pathFromRoot = getPathFromRoot(element);
210                     break;
211
212                 //some random character
213
case XMLDefaultTokenContext.CHARACTER_ID:
214                 //user enters = character, we should ignore all other operators
215
case XMLDefaultTokenContext.OPERATOR_ID:
216                 //user enters either ' or "
217
case XMLDefaultTokenContext.VALUE_ID:
218                     completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
219                     break;
220
221                 //user enters white-space character
222
case XMLDefaultTokenContext.WS_ID:
223                     completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
224                     TokenItem prev = token.getPrevious();
225                     while( prev != null &&
226                            (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.WS_ID) ) {
227                             prev = prev.getPrevious();
228                     }
229                     if( (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.VALUE_ID) ||
230                         (prev.getTokenID().getNumericID() == XMLDefaultTokenContext.TAG_ID) ) {
231                         completionType = CompletionType.COMPLETION_TYPE_ATTRIBUTE;
232                         pathFromRoot = getPathFromRoot(element);
233                     }
234                     break;
235
236                 default:
237                     completionType = CompletionType.COMPLETION_TYPE_UNKNOWN;
238                     pathFromRoot = getPathFromRoot(element);
239                     break;
240             }
241         } catch (Exception JavaDoc ex) {
242             return false;
243         }
244         
245         return true;
246     }
247        
248     public NamedNodeMap JavaDoc getDocRootAttributes() {
249         return docRoot.getAttributes();
250     }
251     
252     public StartTag getDocRoot() {
253         return docRoot;
254     }
255     
256     private List JavaDoc<QName JavaDoc> getPathFromRoot(SyntaxElement se) {
257         assert(se != null);
258         Stack JavaDoc stack = new Stack JavaDoc();
259         while( se != null) {
260             if( (se instanceof EndTag) ||
261                 (se instanceof EmptyTag && stack.isEmpty()) ||
262                 (se instanceof StartTag && stack.isEmpty()) ) {
263                 stack.push(se);
264                 if( defaultNamespace == null &&
265                     (se instanceof StartTag || se instanceof EmptyTag) ) {
266                     String JavaDoc tagName = (se instanceof StartTag)?
267                         ((StartTag)se).getTagName():((EmptyTag)se).getTagName();
268                     if(isRootInNoNSModels(tagName))
269                         break;
270                 }
271                 se = se.getPrevious();
272                 continue;
273             }
274             if(se instanceof StartTag) {
275                 StartTag start = (StartTag)se;
276                 if(stack.peek() instanceof EndTag) {
277                     EndTag end = (EndTag)stack.peek();
278                     if(end.getTagName().equals(start.getTagName())) {
279                         stack.pop();
280                     }
281                 } else {
282                     SyntaxElement e = (SyntaxElement)stack.peek();
283                     String JavaDoc tagAtTop = (e instanceof StartTag)?
284                         ((StartTag)e).getTagName():((EmptyTag)e).getTagName();
285                     if(isRoot(tagAtTop))
286                         break;
287                     stack.push(se);
288                 }
289             }
290             se = se.getPrevious();
291         }
292         
293         return createPath(stack);
294     }
295         
296     private boolean fromSameNamespace(StartTag current, StartTag previous) {
297         String JavaDoc prevPrefix = CompletionUtil.getPrefixFromTag(previous.getTagName());
298         String JavaDoc thisPrefix = CompletionUtil.getPrefixFromTag(current.getTagName());
299         String JavaDoc thisNS = (thisPrefix == null) ? declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE) :
300             declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE+":"+thisPrefix);
301         String JavaDoc prevNS = (prevPrefix == null) ? declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE) :
302             declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE+":"+prevPrefix);
303         
304         return (thisNS == null && prevNS == null) ||
305                (thisNS != null && thisNS.equals(prevNS)) ||
306                (prevNS != null && prevNS.equals(thisNS));
307     }
308
309     private ArrayList JavaDoc<QName JavaDoc> createPath(Stack JavaDoc stack) {
310         ArrayList JavaDoc<QName JavaDoc> path = new ArrayList JavaDoc<QName JavaDoc>();
311         while(!stack.isEmpty()) {
312             Object JavaDoc top = stack.pop();
313             String JavaDoc tagName = (top instanceof StartTag)?
314                 ((StartTag)top).getTagName():((EmptyTag)top).getTagName();
315             String JavaDoc prefix = CompletionUtil.getPrefixFromTag(tagName);
316             String JavaDoc lName = CompletionUtil.getLocalNameFromTag(tagName);
317             if(fromNoNamespace) {
318                 path.add(new QName JavaDoc(lName));
319                 continue;
320             }
321             
322             QName JavaDoc qname = (prefix == null)?
323                 new QName JavaDoc(declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE), lName) :
324                 new QName JavaDoc(declaredNamespaces.get(XMLConstants.XMLNS_ATTRIBUTE+":"+prefix), lName, prefix); //NOI18N
325
path.add(qname);
326         }
327         //CompletionUtil.printPath(path);
328
return path;
329     }
330     
331     private boolean isRoot(String JavaDoc tag) {
332         //if no default namespace found, try the no namespace models
333
if(defaultNamespace == null) {
334             if(isRootInNoNSModels(tag))
335                 return true;
336         }
337         //now try all models, including no NS models
338
String JavaDoc prefix = CompletionUtil.getPrefixFromTag(tag);
339         if(prefix == null) {
340             //try default namespace first
341
CompletionModel cm = getCompletionModelMap().get(getDefaultNamespace());
342             if(CompletionUtil.isRoot(tag, cm))
343                 return true;
344             if(isRootInNoNSModels(tag))
345                 return true;
346             return false;
347         }
348         String JavaDoc tns = getDeclaredNamespaces().
349                 get(XMLConstants.XMLNS_ATTRIBUTE+":"+prefix);
350         CompletionModel cm = getCompletionModelMap().get(tns);
351         return CompletionUtil.isRoot(tag, cm);
352     }
353     
354     private boolean isRootInNoNSModels(String JavaDoc tag) {
355         for(CompletionModel m : noNSModels) {
356             if(CompletionUtil.isRoot(tag, m)) {
357                 fromNoNamespace = true;
358                 noNamespaceModel = m;
359                 return true;
360             }
361         }
362         return false;
363     }
364                 
365     /**
366      * Returns the active no namespace model.
367      */

368     public CompletionModel getActiveNoNSModel() {
369         return noNamespaceModel;
370     }
371     
372     /**
373      * Returns the CompletionModel map.
374      * Maps target namespaces to the CompletionModels
375      */

376     public HashMap JavaDoc<String JavaDoc, CompletionModel> getCompletionModelMap() {
377         return nsModelMap;
378     }
379     
380     /**
381      * Returns the list of no namespace CompletionModels.
382      */

383     public List JavaDoc<CompletionModel> getNoNamespaceModels() {
384         return noNSModels;
385     }
386     
387     /**
388      * Returns the combined list of CompletionModels.
389      */

390     public List JavaDoc<CompletionModel> getCompletionModels() {
391         List JavaDoc<CompletionModel> models = new ArrayList JavaDoc<CompletionModel>();
392         models.addAll(nsModelMap.values());
393         models.addAll(noNSModels);
394         return models;
395     }
396     
397     /**
398      * Finds all CompletionModelProviders and builds a model map for schemas having TNS
399      * and builds a list for all no namespace models.
400      */

401     public boolean initModels() {
402         Lookup.Template templ = new Lookup.Template(CompletionModelProvider.class);
403         Lookup.Result result = Lookup.getDefault().lookup(templ);
404         Collection JavaDoc impls = result.allInstances();
405         if(impls == null || impls.size() == 0)
406             return false;
407         for(Object JavaDoc obj: impls) {
408             CompletionModelProvider modelProvider = (CompletionModelProvider)obj;
409             List JavaDoc<CompletionModel> models = modelProvider.getModels(this);
410             if(models == null || models.size() == 0)
411                 continue;
412             for(CompletionModel m: models) {
413                 String JavaDoc tns = m.getSchemaModel().getSchema().getTargetNamespace();
414                 if(tns == null) {
415                     noNSModels.add(m); //no namespace models
416
continue;
417                 }
418                 //models with namespaces
419
nsModelMap.put(tns, m);
420             }
421         }
422         
423         return !(nsModelMap.size() == 0 && noNSModels.size() == 0);
424     }
425     
426     /**
427      * Lets first try with "xmlns:ns1". If not used, use it. If used, we
428      * keep trying with ns2, ns3 etc.
429      */

430     String JavaDoc suggestPrefix(String JavaDoc tns) {
431         if(tns == null)
432             return null;
433         //if the tns is already present in declared namespaces,
434
//return the prefix
435
for(String JavaDoc key : getDeclaredNamespaces().keySet()) {
436             String JavaDoc ns = getDeclaredNamespaces().get(key);
437             if(ns.equals(tns))
438                 return key;
439         }
440         
441         int index = suggestedNamespaces.size() + 1;
442         String JavaDoc prefix = PREFIX + index;
443         String JavaDoc nsDecl = XMLConstants.XMLNS_ATTRIBUTE+":"+prefix;
444         while(getDeclaredNamespaces().get(nsDecl) != null) {
445             prefix = PREFIX + index++;
446             nsDecl = XMLConstants.XMLNS_ATTRIBUTE+":" + prefix;
447         }
448         suggestedNamespaces.put(prefix, tns);
449         return prefix;
450     }
451     
452     public boolean isPrefixBeingUsed(String JavaDoc prefix) {
453         return getDeclaredNamespaces().
454                 get(XMLConstants.XMLNS_ATTRIBUTE+":"+prefix) != null;
455     }
456     
457     /**
458      * Returns target namespace for a given prefix.
459      */

460     public String JavaDoc getTargetNamespaceByPrefix(String JavaDoc prefix) {
461         for(CompletionModel cm : getCompletionModelMap().values()) {
462             if(prefix.equals(cm.getSuggestedPrefix()))
463                 return cm.getTargetNamespace();
464         }
465         
466         return null;
467     }
468         
469     private FileObject primaryFile;
470     private String JavaDoc typedChars;
471     private TokenItem token;
472     private SyntaxElement element;
473     private StartTag docRoot;
474     private char lastTypedChar;
475     private CompletionType completionType;
476     private List JavaDoc<QName JavaDoc> pathFromRoot;
477     private String JavaDoc schemaLocation;
478     private String JavaDoc noNamespaceSchemaLocation;
479     private String JavaDoc defaultNamespace;
480     private BaseDocument document;
481     private HashMap JavaDoc<String JavaDoc, CompletionModel> nsModelMap =
482             new HashMap JavaDoc<String JavaDoc, CompletionModel>();
483     private List JavaDoc<CompletionModel> noNSModels =
484             new ArrayList JavaDoc<CompletionModel>();
485     private HashMap JavaDoc<String JavaDoc, String JavaDoc> declaredNamespaces =
486             new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
487     private HashMap JavaDoc<String JavaDoc, String JavaDoc> suggestedNamespaces =
488             new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
489     private boolean fromNoNamespace = false;
490     private CompletionModel noNamespaceModel;
491     
492     public static final String JavaDoc PREFIX = "ns"; //NOI18N
493
public static final String JavaDoc XSI_SCHEMALOCATION = "schemaLocation"; //NOI18N
494
public static final String JavaDoc XSI_NONS_SCHEMALOCATION = "noNamespaceSchemaLocation"; //NOI18N
495
}
496
Popular Tags