KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > filesystems > XMLMIMEComponent


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
20 package org.netbeans.core.filesystems;
21
22 import java.lang.ref.WeakReference JavaDoc;
23 import java.util.logging.Level JavaDoc;
24 import java.util.logging.Logger JavaDoc;
25 import org.openide.filesystems.FileObject;
26 import org.openide.util.NbBundle;
27 import org.openide.xml.XMLUtil;
28 import org.xml.sax.Attributes JavaDoc;
29 import org.xml.sax.SAXException JavaDoc;
30 import org.xml.sax.SAXParseException JavaDoc;
31 import org.xml.sax.XMLReader JavaDoc;
32 import org.xml.sax.ext.LexicalHandler JavaDoc;
33
34 /**
35  * This source represents a <b>XML rules</b> core plugin to <tt>MIMEReolverImpl</tt>.
36  *
37  * @author Petr Kuzel
38  * @version
39  */

40 final class XMLMIMEComponent extends DefaultParser implements MIMEComponent {
41
42     private short parseState = INIT;
43     
44     // template obtained form parsed description
45
private final Smell template = new Smell();
46
47     // cached and reused parser used for sniffing
48
private static final LocalSniffingParser local = new LocalSniffingParser();
49
50     // FileObjectFilter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51

52     public boolean acceptFileObject(FileObject fo) {
53
54         // it may come from arbitrary thread
55
// retrive per thread instance
56

57         SniffingParser sniffer = local.getParser();
58         Smell print = sniffer.sniff(fo);
59 // System.err.println("Print of " + fo);
60
// System.err.println("print " + print);
61
// System.err.println("template " + template);
62
return template.match(print);
63     }
64
65     public String JavaDoc toString() {
66        return template.toString();
67     }
68
69     // XML description -> memory representation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
70

71
72     // pseudo validation states
73
private static final short INIT = 0;
74     private static final short IN_ROOT = 1;
75     private static final short IN_DOCTYPE = 2;
76     private static final short IN_ELEMENT = 3;
77
78     // grammar elements
79
private static final String JavaDoc ROOT = "xml-rule"; // NOI18N
80
private static final String JavaDoc PI = "pi"; // NOI18N
81
private static final String JavaDoc ELEMENT = "element"; // NOI18N
82
private static final String JavaDoc DOCTYPE = "doctype"; // NOI18N
83
private static final String JavaDoc PUBLIC_ID = "public-id"; // NOI18N
84
private static final String JavaDoc ID = "id"; // NOI18N
85
private static final String JavaDoc ATTR = "attr"; // NOI18N
86
private static final String JavaDoc NAME = "name"; // NOI18N
87
private static final String JavaDoc VALUE = "text"; // NOI18N
88
private static final String JavaDoc NS = "ns"; // NOI18N
89
private static final String JavaDoc TARGET = "target"; // NOI18N
90

91
92     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc atts) throws SAXException JavaDoc {
93
94         String JavaDoc s;
95
96         switch (parseState) {
97
98             case INIT:
99                 if (ROOT.equals(qName) == false) error();
100                 parseState = IN_ROOT;
101                 break;
102
103             case IN_ROOT:
104                 if (PI.equals(qName)) {
105                     s = atts.getValue(TARGET); if (s == null) error();
106                     template.addPI(s);
107
108                     //!!! TODO presudo atts
109

110                 } else if (DOCTYPE.equals(qName)) {
111                     s = atts.getValue(PUBLIC_ID);
112                     if (s == null) {
113                         parseState = IN_DOCTYPE;
114                         break;
115                     } else {
116                         template.addDoctype(s);
117                     }
118
119                 } else if (ELEMENT.equals(qName)) {
120
121                     s = atts.getValue(NAME);
122                     if (s == null) {
123                         s = atts.getValue(NS);
124                         if (s != null) template.addElementNS(s);
125                     } else {
126                         template.addElementName(s);
127                         s = atts.getValue(NS);
128                         if (s != null) template.addElementNS(s);
129                     }
130
131                     parseState = IN_ELEMENT;
132
133                 } else {
134                     error();
135                 }
136                 break;
137
138             case IN_DOCTYPE:
139                 if (PUBLIC_ID.equals(qName) == false) error();
140                 s = atts.getValue(ID); if (s == null) error();
141                 template.addDoctype(s);
142                 break;
143
144             case IN_ELEMENT:
145                 if (ATTR.equals(qName)) {
146                     s = atts.getValue(NAME); if (s == null) error();
147                     template.addElementAtt(s, atts.getValue(VALUE));
148
149                 } else if (NS.equals(qName)) {
150                     s = atts.getValue(NAME); if (s == null) error();
151                     template.addElementNS(s);
152
153                 } else {
154                     error();
155                 }
156
157         }
158     }
159
160     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName) {
161
162         switch (parseState) {
163             case IN_ELEMENT:
164                 if (ELEMENT.equals(qName)) parseState = IN_ROOT;
165                 break;
166
167             case IN_DOCTYPE:
168                 if (DOCTYPE.equals(qName)) parseState = IN_ROOT;
169                 break;
170         }
171     }
172     
173     // Sniffing parser ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174

175
176     /**
177      * Create just one shared parser instance per thread.
178      * Consequently one instance cannot be run in paralel eliminating need for sync.
179      */

180     private static class LocalSniffingParser extends ThreadLocal JavaDoc<WeakReference JavaDoc<SniffingParser>> {
181         LocalSniffingParser() {}
182         
183         private WeakReference JavaDoc<SniffingParser> wref = null;
184         
185         protected WeakReference JavaDoc<SniffingParser> initialValue() {
186             SniffingParser parser = new SniffingParser();
187             wref = new WeakReference JavaDoc<SniffingParser>(parser);
188             return wref;
189         }
190         
191         public SniffingParser getParser() {
192             WeakReference JavaDoc<SniffingParser> cache = get();
193             SniffingParser cached = cache.get();
194             if (cached == null) {
195                 cached = new SniffingParser();
196                 wref = new WeakReference JavaDoc<SniffingParser>(cached);
197                 super.set(wref);
198             }
199             return cached;
200         }
201         
202         public void set(WeakReference JavaDoc<SniffingParser> data) {
203             // we are read only!
204
}
205     }
206
207         
208     /**
209      * Parser that test XML Document header.
210      */

211     private static class SniffingParser extends DefaultParser implements LexicalHandler JavaDoc {
212
213         SniffingParser() {
214             super(null);
215         }
216
217         // last succesfully sniffed fileobject
218
private FileObject lastFileObject = null;
219         
220         private Smell print = null;
221         
222         // the only way how to stop parser is throwing an exception
223
private static final SAXException JavaDoc STOP = new SAXException JavaDoc("STOP"); //NOI18N
224

225         /**
226          * Go ahead and retrieve a print or null
227          */

228         protected Smell sniff(FileObject fo) {
229
230             if (fo == null) return null;
231             
232             if (fo.equals(lastFileObject)) return print;
233             
234             if (fo.isValid() == false) return null;
235
236             if (fo.getSize() == 0) return null;
237             
238             print = new Smell();
239             parse(fo);
240             if (this.state == ERROR) {
241                 return null;
242             }
243             
244             lastFileObject = fo;
245             return print;
246         }
247         
248         protected XMLReader JavaDoc createXMLReader() {
249             XMLReader JavaDoc parser = null;
250             
251             try {
252                 parser = XMLUtil.createXMLReader(false, true);
253                 try {
254                     parser.setProperty("http://xml.org/sax/properties/lexical-handler", this); //NOI18N
255
} catch (SAXException JavaDoc sex) {
256                     Logger.getLogger(XMLMIMEComponent.class.getName()).fine(NbBundle.getMessage(XMLMIMEComponent.class, "W-003")); //NOI18N
257
}
258             } catch (SAXException JavaDoc ex) {
259                 Logger.getLogger(XMLMIMEComponent.class.getName()).log(Level.WARNING, null, ex);
260             }
261             return parser;
262         }
263         
264         protected boolean isStopException(Exception JavaDoc e) {
265             return STOP.getMessage().equals(e.getMessage());
266         }
267         
268         
269         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc atts) throws SAXException JavaDoc {
270             if (namespaceURI != null) {
271                 print.addElementNS(namespaceURI);
272             }
273             if ("".equals(localName)) localName = null; //#16484 //NOI18N
274
print.addElementName(localName != null ? localName : qName);
275             for (int i = 0; i<atts.getLength(); i++) {
276                 print.addElementAtt(atts.getQName(i), atts.getValue(i));
277             }
278             throw STOP;
279         }
280         
281         public void processingInstruction(String JavaDoc target, String JavaDoc data) throws SAXException JavaDoc {
282             print.addPI(target);
283         }
284         
285         // LexicalHandler
286

287         public void startDTD(String JavaDoc root, String JavaDoc pID, String JavaDoc sID) throws SAXException JavaDoc {
288             print.addDoctype(pID);
289         }
290
291         public void endDTD() {}
292
293         public void startEntity(String JavaDoc name) {}
294
295         public void endEntity(String JavaDoc name) {}
296
297         public void startCDATA() {}
298
299         public void endCDATA() {}
300
301         public void comment(char[] ch, int start, int length) {}
302         
303         public void error(SAXParseException JavaDoc exception) throws SAXException JavaDoc {
304             // we are not validating should not occure
305
Logger.getLogger(XMLMIMEComponent.class.getName()).warning(exception.getMessage());
306             this.state = ERROR;
307             throw STOP;
308         }
309
310         public void fatalError(SAXParseException JavaDoc exception) throws SAXException JavaDoc {
311
312             // it may be caused by wrong user XML documents, notify only in debug mode
313
// also see #16484 if the error message makes no sense
314
Logger JavaDoc emgr = Logger.getLogger("org.netbeans.core.filesystems.XMLMIMEComponent"); // NOI18N
315
if (emgr.isLoggable(Level.FINE)) {
316                 emgr.fine("[while parsing " + fo + "] " + exception.getSystemId() + ":" + exception.getLineNumber() + ":" + exception.getColumnNumber() + ": " + exception.getMessage()); // NOI18N
317
}
318
319             this.state = ERROR;
320             throw STOP;
321         }
322         
323         
324     }
325
326     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
327

328     /**
329      * Template smell per resolver and print data per FileObject.
330      */

331     private static class Smell {
332         Smell() {}
333         
334         private String JavaDoc[] doctypes = null;
335         private String JavaDoc[] pis = null;
336         
337         private String JavaDoc root = null;
338         private String JavaDoc[] nss = null;
339         
340         private String JavaDoc[] attns = null;
341         private String JavaDoc[] attvs = null;
342
343         public String JavaDoc toString() {
344             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
345             int i = 0;
346             buf.append("xml-check(");
347             
348             if (doctypes != null) {
349                 buf.append("doctypes:");
350                 for (i = 0; i<doctypes.length; i++)
351                     buf.append(doctypes[i]).append(", ");
352             }
353
354             if (pis != null) {
355                 buf.append("PIs:");
356                 for (i = 0; i<pis.length; i++)
357                     buf.append(pis[i]).append(", ");
358             }
359
360             if (root != null) {
361                buf.append("root:").append(root);
362             }
363
364             if (nss != null) {
365                 buf.append("root-namespaces:");
366                 for (i = 0; i<nss.length; i++)
367                     buf.append(nss[i]).append(", ");
368             }
369
370             if (attns != null) {
371                 buf.append("attributes:");
372                 for (i = 0; i<attns.length; i++)
373                     buf.append(attns[i]).append("='").append(attvs[i]).append("'");
374             }
375
376             buf.append(')');
377             return buf.toString();
378
379         }
380
381         private void addDoctype(String JavaDoc s) {
382             if (doctypes == null) {
383                 doctypes = new String JavaDoc[] { s };
384             } else {
385                 doctypes = Util.addString(doctypes, s);
386             }
387         }
388         
389         private void addPI(String JavaDoc s) {
390             if (pis == null) {
391                 pis = new String JavaDoc[] { s };
392             } else {
393                 pis = Util.addString(pis, s);
394             }
395         }
396         
397         private void addElementNS(String JavaDoc s) {
398             if (nss == null) {
399                 nss = new String JavaDoc[] { s };
400             } else {
401                 nss = Util.addString(nss, s);
402             }
403         }
404         
405         private void addElementName(String JavaDoc name) {
406             root = name;
407         }
408         
409         private void addElementAtt(String JavaDoc name, String JavaDoc value) {
410             if (attns == null) {
411                 attns = new String JavaDoc[] {name};
412                 attvs = new String JavaDoc[] {value};
413             } else {
414                 attns = Util.addString(attns, name);
415                 attvs = Util.addString(attvs, value);
416             }
417             
418         }
419
420         /**
421          * Matches passed data this template?
422          * Any of constructs must match.
423          */

424         public boolean match(Smell t) {
425
426             if (t == null) return false;
427             
428             // try if a doctype public-id matches
429

430             if (doctypes != null && t.doctypes != null) {
431                 if (Util.contains(doctypes, t.doctypes[0])) return true;
432             }
433             
434             // try root element match
435

436             if (root != null && root.equals(t.root)) {
437                 if (nss == null) {
438                     if (attMatch(t)) return true;
439                 } else {
440                     if (t.nss != null && Util.contains(nss, t.nss[0])) {
441                         if (attMatch(t)) return true;
442                     }
443                 }
444             } else {
445                 if (root == null && nss != null && t.nss != null && Util.contains(nss, t.nss[0])) {
446                     if (attMatch(t)) return true;
447                 }
448             }
449             
450             // try if a PI matches
451

452             if (pis != null && t.pis!=null) {
453                 for (int i = 0; i<pis.length; i++) {
454                     for (int j = 0; j<t.pis.length; j++) {
455                         if (pis[i].equals(t.pis[j])) return true;
456                     }
457                 }
458             }
459             
460             return false;
461         }
462         
463         
464         private boolean attMatch(Smell t) {
465
466             if (attns == null) return true;
467             if (t.attns == null) return false;
468             
469             // all attributes must match by name ...
470
for (int i = 0 ; i<attns.length; i++) {
471                 int match = Util.indexOf(t.attns, attns[i]);
472                 if (match == -1) {
473                     return false;
474                 }
475
476                 // ... and value if specified in template
477

478                 if (attvs[i] != null && (!attvs[i].equals(t.attvs[match]))) {
479                     return false;
480                 }
481             }
482             
483             return true;
484             
485         }
486
487     }
488 }
489
Popular Tags