Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/bridge/BaseScriptingEnvironment.java


1   /*
2   
3      Copyright 2002-2004  The Apache Software Foundation 
4   
5      Licensed under the Apache License, Version 2.0 (the "License");
6      you may not use this file except in compliance with the License.
7      You may obtain a copy of the License at
8   
9          http://www.apache.org/licenses/LICENSE-2.0
10  
11     Unless required by applicable law or agreed to in writing, software
12     distributed under the License is distributed on an "AS IS" BASIS,
13     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14     See the License for the specific language governing permissions and
15     limitations under the License.
16  
17   */
18  package org.apache.batik.bridge;
19  
20  import java.io.IOException;
21  import java.io.InputStreamReader;
22  import java.io.Reader;
23  import java.io.StringReader;
24  import java.net.MalformedURLException;
25  import java.net.URL;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Set;
30  import java.util.jar.Manifest;
31  
32  import org.apache.batik.dom.svg.XMLBaseSupport;
33  import org.apache.batik.dom.util.XLinkSupport;
34  import org.apache.batik.script.Interpreter;
35  import org.apache.batik.script.InterpreterException;
36  import org.apache.batik.script.ScriptHandler;
37  import org.apache.batik.util.ParsedURL;
38  import org.apache.batik.util.SVGConstants;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  import org.w3c.dom.Node;
42  import org.w3c.dom.NodeList;
43  import org.w3c.dom.events.DocumentEvent;
44  import org.w3c.dom.events.Event;
45  import org.w3c.dom.events.EventListener;
46  import org.w3c.dom.events.EventTarget;
47  import org.w3c.dom.svg.SVGDocument;
48  import org.w3c.dom.svg.SVGSVGElement;
49  import org.w3c.dom.svg.EventListenerInitializer;
50  
51  /**
52   * This class is the base class for SVG scripting.
53   *
54   * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
55   * @version $Id: BaseScriptingEnvironment.java,v 1.35 2005/03/27 08:58:30 cam Exp $
56   */
57  public class BaseScriptingEnvironment {
58      /**
59       * Constant used to describe inline scripts.
60       * <pre>
61       * {0} - URL of document containing script.
62       * {1} - Element tag
63       * {2} - line number of element.
64       * </pre>
65       */
66      public static final String INLINE_SCRIPT_DESCRIPTION
67          = "BaseScriptingEnvironment.constant.inline.script.description";
68  
69      /**
70       * Constant used to describe inline scripts.
71       * <pre>
72       * {0} - URL of document containing script.
73       * {1} - Event attribute name
74       * {2} - line number of element.
75       * </pre>
76       */
77      public static final String EVENT_SCRIPT_DESCRIPTION
78          = "BaseScriptingEnvironment.constant.event.script.description";
79  
80      /**
81       * Tells whether the given SVG document is dynamic.
82       */
83      public static boolean isDynamicDocument(BridgeContext ctx, Document doc) {
84          Element elt = doc.getDocumentElement();
85          if ((elt != null) &&
86              SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI())) {
87              if (elt.getAttributeNS
88                  (null, SVGConstants.SVG_ONABORT_ATTRIBUTE).length() > 0) {
89                  return true;
90              }
91              if (elt.getAttributeNS
92                  (null, SVGConstants.SVG_ONERROR_ATTRIBUTE).length() > 0) {
93                  return true;
94              }
95              if (elt.getAttributeNS
96                  (null, SVGConstants.SVG_ONRESIZE_ATTRIBUTE).length() > 0) {
97                  return true;
98              }
99              if (elt.getAttributeNS
100                 (null, SVGConstants.SVG_ONUNLOAD_ATTRIBUTE).length() > 0) {
101                 return true;
102             }
103             if (elt.getAttributeNS
104                 (null, SVGConstants.SVG_ONSCROLL_ATTRIBUTE).length() > 0) {
105                 return true;
106             }
107             if (elt.getAttributeNS
108                 (null, SVGConstants.SVG_ONZOOM_ATTRIBUTE).length() > 0) {
109                 return true;
110             }
111             return isDynamicElement(ctx, doc.getDocumentElement());
112         }
113         return false;
114     }
115 
116     public static boolean isDynamicElement(BridgeContext ctx, Element elt) {
117         List bridgeExtensions = ctx.getBridgeExtensions(elt.getOwnerDocument());
118         return isDynamicElement(elt, ctx, bridgeExtensions);
119     }
120 
121     /**
122      * Tells whether the given SVG element is dynamic.
123      */
124     public static boolean isDynamicElement
125         (Element elt, BridgeContext ctx, List bridgeExtensions) {
126         Iterator i = bridgeExtensions.iterator();
127         while (i.hasNext()) {
128             BridgeExtension bridgeExtension = (BridgeExtension) i.next();
129             if (bridgeExtension.isDynamicElement(elt)) {
130                 return true;
131             }
132         }
133         if (SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI())) {
134             if (elt.getAttributeNS
135                 (null, SVGConstants.SVG_ONKEYUP_ATTRIBUTE).length() > 0) {
136                 return true;
137             }
138             if (elt.getAttributeNS
139                 (null, SVGConstants.SVG_ONKEYDOWN_ATTRIBUTE).length() > 0) {
140                 return true;
141             }
142             if (elt.getAttributeNS
143                 (null, SVGConstants.SVG_ONKEYPRESS_ATTRIBUTE).length() > 0) {
144                 return true;
145             }
146             if (elt.getAttributeNS
147                 (null, SVGConstants.SVG_ONLOAD_ATTRIBUTE).length() > 0) {
148                 return true;
149             }
150             if (elt.getAttributeNS
151                 (null, SVGConstants.SVG_ONERROR_ATTRIBUTE).length() > 0) {
152                 return true;
153             }
154             if (elt.getAttributeNS
155                 (null, SVGConstants.SVG_ONACTIVATE_ATTRIBUTE).length() > 0) {
156                 return true;
157             }
158             if (elt.getAttributeNS
159                 (null, SVGConstants.SVG_ONCLICK_ATTRIBUTE).length() > 0) {
160                 return true;
161             }
162             if (elt.getAttributeNS
163                 (null, SVGConstants.SVG_ONFOCUSIN_ATTRIBUTE).length() > 0) {
164                 return true;
165             }
166             if (elt.getAttributeNS
167                 (null, SVGConstants.SVG_ONFOCUSOUT_ATTRIBUTE).length() > 0) {
168                 return true;
169             }
170             if (elt.getAttributeNS
171                 (null, SVGConstants.SVG_ONMOUSEDOWN_ATTRIBUTE).length() > 0) {
172                 return true;
173             }
174             if (elt.getAttributeNS
175                 (null, SVGConstants.SVG_ONMOUSEMOVE_ATTRIBUTE).length() > 0) {
176                 return true;
177             }
178             if (elt.getAttributeNS
179                 (null, SVGConstants.SVG_ONMOUSEOUT_ATTRIBUTE).length() > 0) {
180                 return true;
181             }
182             if (elt.getAttributeNS
183                 (null, SVGConstants.SVG_ONMOUSEOVER_ATTRIBUTE).length() > 0) {
184                 return true;
185             }
186             if (elt.getAttributeNS
187                 (null, SVGConstants.SVG_ONMOUSEUP_ATTRIBUTE).length() > 0) {
188                 return true;
189             }
190         }
191 
192         for (Node n = elt.getFirstChild();
193              n != null;
194              n = n.getNextSibling()) {
195             if (n.getNodeType() == Node.ELEMENT_NODE) {
196                 if (isDynamicElement(ctx, (Element)n)) {
197                     return true;
198                 }
199             }
200         }
201         return false;
202     }
203 
204 
205     protected final static String EVENT_NAME = "event";
206     protected final static String ALTERNATE_EVENT_NAME = "evt";
207 
208     /**
209      * The bridge context.
210      */
211     protected BridgeContext bridgeContext;
212 
213     /**
214      * The user-agent.
215      */
216     protected UserAgent userAgent;
217 
218     /**
219      * The document to manage.
220      */
221     protected Document document;
222 
223     /**
224      * The URL of the document ot manage
225      */
226     protected ParsedURL docPURL;
227 
228     protected Set languages = new HashSet();
229 
230     /**
231      * The default Interpreter for the document
232      */
233     protected Interpreter interpreter;
234 
235     /**
236      * Creates a new BaseScriptingEnvironment.
237      * @param ctx the bridge context
238      */
239     public BaseScriptingEnvironment(BridgeContext ctx) {
240         bridgeContext = ctx;
241         document = ctx.getDocument();
242         docPURL = new ParsedURL(((SVGDocument)document).getURL());
243         userAgent     = bridgeContext.getUserAgent();
244     }
245 
246     /**
247      * Creates a new Window object.
248      */
249     public org.apache.batik.script.Window createWindow
250         (Interpreter interp, String lang) {
251         return new Window(interp, lang);
252     }
253 
254     /**
255      * Creates a new Window object.
256      */
257     public org.apache.batik.script.Window createWindow() {
258         return createWindow(null, null);
259     }
260 
261     /**
262      * Returns the default Interpreter for this document.
263      */
264     public Interpreter getInterpreter() {
265         if (interpreter != null)
266             return interpreter;
267 
268         SVGSVGElement root = (SVGSVGElement)document.getDocumentElement();
269         String lang = root.getContentScriptType();
270         return getInterpreter(lang);
271     }
272 
273     public Interpreter getInterpreter(String lang) {
274         interpreter = bridgeContext.getInterpreter(lang);
275         if (interpreter == null) {
276             if (languages.contains(lang)) {
277                 // Already issued warning so just return null;
278                 return null;
279             }
280 
281             // So we know we have processed this interpreter.
282             languages.add(lang);
283             return null;
284         }
285 
286         if (!languages.contains(lang)) {
287             languages.add(lang);
288             initializeEnvironment(interpreter, lang);
289         }
290         return interpreter;
291     }
292 
293     /**
294      * Initializes the environment of the given interpreter.
295      */
296     public void initializeEnvironment(Interpreter interp, String lang) {
297         interp.bindObject("window", createWindow(interp, lang));
298     }
299 
300     /**
301      * Loads the scripts contained in the <script> elements.
302      */
303     public void loadScripts() {
304         org.apache.batik.script.Window window = null;
305 
306         NodeList scripts = document.getElementsByTagNameNS
307             (SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_SCRIPT_TAG);
308         int len = scripts.getLength();
309 
310         if (len == 0) {
311             return;
312         }
313 
314         for (int i = 0; i < len; i++) {
315             Element script = (Element)scripts.item(i);
316             String type = script.getAttributeNS
317                 (null, SVGConstants.SVG_TYPE_ATTRIBUTE);
318 
319             if (type.length() == 0) {
320                 type = SVGConstants.SVG_SCRIPT_TYPE_DEFAULT_VALUE;
321             }
322 
323             //
324             // Java code invocation.
325             //
326             if (type.equals(SVGConstants.SVG_SCRIPT_TYPE_JAVA)) {
327                 try {
328                     String href = XLinkSupport.getXLinkHref(script);
329                     ParsedURL purl = new ParsedURL
330                         (XMLBaseSupport.getCascadedXMLBase(script), href);
331 
332                     checkCompatibleScriptURL(type, purl);
333 
334                     DocumentJarClassLoader cll;
335                     URL docURL = null;
336                     try {
337                         docURL = new URL(docPURL.toString());
338                     } catch (MalformedURLException mue) {
339                         /* nothing just let docURL be null */
340                     }
341                     cll = new DocumentJarClassLoader
342                         (new URL(purl.toString()), docURL);
343 
344                     // Get the 'Script-Handler' entry in the manifest.
345                     URL url = cll.findResource("META-INF/MANIFEST.MF");
346                     if (url == null) {
347                         continue;
348                     }
349                     Manifest man = new Manifest(url.openStream());
350 
351                     String sh;
352 
353                     sh = man.getMainAttributes().getValue("Script-Handler");
354                     if (sh != null) {
355                         // Run the script handler.
356                         ScriptHandler h;
357                         h = (ScriptHandler)cll.loadClass(sh).newInstance();
358 
359                         if (window == null) {
360                             window = createWindow();
361                         }
362 
363                         h.run(document, window);
364                     }
365 
366                     sh = man.getMainAttributes().getValue("SVG-Handler-Class");
367                     if (sh != null) {
368                         // Run the initializer
369                         EventListenerInitializer initializer;
370                         initializer =
371                             (EventListenerInitializer)cll.loadClass(sh).newInstance();
372 
373                         if (window == null) {
374                             window = createWindow();
375                         }
376 
377                         initializer.initializeEventListeners((SVGDocument)document);
378                     }
379                 } catch (Exception e) {
380                     if (userAgent != null) {
381                         userAgent.displayError(e);
382                     }
383                 }
384                 continue;
385             }
386 
387             //
388             // Scripting language invocation.
389             //
390             Interpreter interpreter = getInterpreter(type);
391             if (interpreter == null)
392                 // Can't find interpreter so just skip this script block.
393                 continue;
394 
395             try {
396                 String href = XLinkSupport.getXLinkHref(script);
397                 String desc = null;
398                 Reader reader;
399 
400                 if (href.length() > 0) {
401                     desc = href;
402 
403                     // External script.
404                     ParsedURL purl = new ParsedURL
405                         (XMLBaseSupport.getCascadedXMLBase(script), href);
406 
407                     checkCompatibleScriptURL(type, purl);
408                     reader = new InputStreamReader(purl.openStream());
409                 } else {
410                     checkCompatibleScriptURL(type, docPURL);
411                     DocumentLoader dl = bridgeContext.getDocumentLoader();
412                     Element e = script;
413                     SVGDocument d = (SVGDocument)e.getOwnerDocument();
414                     int line = dl.getLineNumber(script);
415                     desc = Messages.formatMessage
416                         (INLINE_SCRIPT_DESCRIPTION,
417                          new Object [] {d.getURL(),
418                                         "<"+script.getNodeName()+">", 
419                                         new Integer(line)});
420                     // Inline script.
421                     Node n = script.getFirstChild();
422                     if (n != null) {
423                         StringBuffer sb = new StringBuffer();
424                         while (n != null) {
425                             if (n.getNodeType() == Node.CDATA_SECTION_NODE
426                                 || n.getNodeType() == Node.TEXT_NODE)
427                                 sb.append(n.getNodeValue());
428                             n = n.getNextSibling();
429                         }
430                         reader = new StringReader(sb.toString());
431                     } else {
432                         continue;
433                     }
434                 }
435 
436                 interpreter.evaluate(reader, desc);
437 
438             } catch (IOException e) {
439                 if (userAgent != null) {
440                     userAgent.displayError(e);
441                 }
442                 return;
443             } catch (InterpreterException e) {
444                 System.err.println("InterpExcept: " + e);
445                 handleInterpreterException(e);
446                 return;
447             } catch (SecurityException e) {
448                 if (userAgent != null) {
449                     userAgent.displayError(e);
450                 }
451             }
452         }
453     }
454 
455     /**
456      * Checks that the script URLs and the document url are
457      * compatible. A SecurityException is thrown if loading
458      * the script is not allowed.
459      */
460     protected void checkCompatibleScriptURL(String scriptType,
461                                           ParsedURL scriptPURL){
462         userAgent.checkLoadScript(scriptType, scriptPURL, docPURL);
463     }
464 
465     /**
466      * Recursively dispatch the SVG 'onload' event.
467      */
468     public void dispatchSVGLoadEvent() {
469         SVGSVGElement root = (SVGSVGElement)document.getDocumentElement();
470         String lang = root.getContentScriptType();
471         dispatchSVGLoad(root, true, lang);
472     }
473 
474     /**
475      * Auxiliary method for dispatchSVGLoad.
476      */
477     protected void dispatchSVGLoad(Element elt,
478                                    boolean checkCanRun,
479                                    String lang) {
480         for (Node n = elt.getFirstChild();
481              n != null;
482              n = n.getNextSibling()) {
483             if (n.getNodeType() == Node.ELEMENT_NODE) {
484                 dispatchSVGLoad((Element)n, checkCanRun, lang);
485             }
486         }
487 
488         Event ev;
489         DocumentEvent de = (DocumentEvent)elt.getOwnerDocument();
490         ev = de.createEvent("SVGEvents");
491         ev.initEvent("SVGLoad", false, false);
492         EventTarget t = (EventTarget)elt;
493 
494         final String s =
495             elt.getAttributeNS(null, SVGConstants.SVG_ONLOAD_ATTRIBUTE);
496         if (s.length() == 0) {
497             // No script to run so just dispatch the event to DOM
498             // (For java presumably).
499             t.dispatchEvent(ev);
500             return;
501         }
502 
503         final Interpreter interp = getInterpreter();
504         if (interp == null) {
505             // Can't load interpreter so just dispatch normal event
506             // to the DOM (for java presumably).
507             t.dispatchEvent(ev);
508             return;
509         }
510 
511         if (checkCanRun) {
512             // Check that it is ok to run embeded scripts
513             checkCompatibleScriptURL(lang, docPURL);
514             checkCanRun = false; // we only check once for onload handlers
515         }
516 
517         DocumentLoader dl = bridgeContext.getDocumentLoader();
518         SVGDocument d = (SVGDocument)elt.getOwnerDocument();
519         int line = dl.getLineNumber(elt);
520         final String desc = Messages.formatMessage
521             (EVENT_SCRIPT_DESCRIPTION,
522              new Object [] {d.getURL(),
523                             SVGConstants.SVG_ONLOAD_ATTRIBUTE, 
524                             new Integer(line)});
525 
526         EventListener l = new EventListener() {
527                 public void handleEvent(Event evt) {
528                     try {
529                         interp.bindObject(EVENT_NAME, evt);
530                         interp.bindObject(ALTERNATE_EVENT_NAME, evt);
531                         interp.evaluate(new StringReader(s), desc);
532                     } catch (IOException io) {
533                     } catch (InterpreterException e) {
534                         handleInterpreterException(e);
535                     }
536                 }
537             };
538         t.addEventListener("SVGLoad", l, false);
539         t.dispatchEvent(ev);
540         t.removeEventListener("SVGLoad", l, false);
541     }
542 
543     /**
544      * Method to dispatch SVG Zoom event.
545      */
546     protected void dispatchSVGZoomEvent() {
547         dispatchSVGDocEvent("SVGZoom");
548     }
549 
550     /**
551      * Method to dispatch SVG Scroll event.
552      */
553     protected void dispatchSVGScrollEvent() {
554         dispatchSVGDocEvent("SVGScroll");
555     }
556 
557     /**
558      * Method to dispatch SVG Resize event.
559      */
560     protected void dispatchSVGResizeEvent() {
561         dispatchSVGDocEvent("SVGResize");
562     }
563 
564     protected void dispatchSVGDocEvent(String eventType) {
565         SVGSVGElement root =
566             (SVGSVGElement)document.getDocumentElement();
567         // Event is dispatched on outermost SVG element.
568         EventTarget t = root;
569 
570         DocumentEvent de = (DocumentEvent)document;
571         Event ev = de.createEvent("SVGEvents");
572         ev.initEvent(eventType, false, false);
573         t.dispatchEvent(ev);
574     }
575 
576     /**
577      * Handles the given exception.
578      */
579     protected void handleInterpreterException(InterpreterException ie) {
580         if (userAgent != null) {
581             Exception ex = ie.getException();
582             userAgent.displayError((ex == null) ? ie : ex);
583         }
584     }
585 
586     /**
587      * Handles the given exception.
588      */
589     protected void handleSecurityException(SecurityException se) {
590         if (userAgent != null) {
591             userAgent.displayError(se);
592         }
593     }
594 
595     /**
596      * Represents the window object of this environment.
597      */
598     protected class Window implements org.apache.batik.script.Window {
599 
600         /**
601          * The associated interpreter.
602          */
603         protected Interpreter interpreter;
604 
605         /**
606          * The associated language.
607          */
608         protected String language;
609 
610         /**
611          * Creates a new Window.
612          */
613         public Window(Interpreter interp, String lang) {
614             interpreter = interp;
615             language = lang;
616         }
617 
618         /**
619          * Implements {@link
620          * org.apache.batik.script.Window#setInterval(String,long)}.
621          */
622         public Object setInterval(final String script, long interval) {
623             return null;
624         }
625 
626         /**
627          * Implements {@link
628          * org.apache.batik.script.Window#setInterval(Runnable,long)}.
629          */
630         public Object setInterval(final Runnable r, long interval) {
631             return null;
632         }
633 
634         /**
635          * Implements {@link
636          * org.apache.batik.script.Window#clearInterval(Object)}.
637          */
638         public void clearInterval(Object interval) {
639         }
640 
641         /**
642          * Implements {@link
643          * org.apache.batik.script.Window#setTimeout(String,long)}.
644          */
645         public Object setTimeout(final String script, long timeout) {
646             return null;
647         }
648 
649         /**
650          * Implements {@link
651          * org.apache.batik.script.Window#setTimeout(Runnable,long)}.
652          */
653         public Object setTimeout(final Runnable r, long timeout) {
654             return null;
655         }
656 
657         /**
658          * Implements {@link
659          * org.apache.batik.script.Window#clearTimeout(Object)}.
660          */
661         public void clearTimeout(Object timeout) {
662         }
663 
664         /**
665          * Parses the given XML string into a DocumentFragment of the
666          * given document or a new document if 'doc' is null.
667          * The implementation in this class always returns 'null'
668          * @return The document/document fragment or null on error.
669          */
670         public Node parseXML(String text, Document doc) {
671             return null;
672         }
673 
674         /**
675          * Gets data from the given URI.
676          * @param uri The URI where the data is located.
677          * @param h A handler called when the data is available.
678          */
679         public void getURL(String uri, org.apache.batik.script.Window.URLResponseHandler h) {
680             getURL(uri, h, "UTF8");
681         }
682 
683         /**
684          * Gets data from the given URI.
685          * @param uri The URI where the data is located.
686          * @param h A handler called when the data is available.
687          * @param enc The character encoding of the data.
688          */
689         public void getURL(String uri,
690                            org.apache.batik.script.Window.URLResponseHandler h,
691                            String enc) {
692         }
693 
694         public void postURL(String uri, String content, 
695                             org.apache.batik.script.Window.URLResponseHandler h) {
696             postURL(uri, content, h, "text/plain", null);
697         }
698 
699         public void postURL(String uri, String content, 
700                             org.apache.batik.script.Window.URLResponseHandler h, 
701                      String mimeType) {
702             postURL(uri, content, h, mimeType, null);
703         }
704 
705         public void postURL(String uri, 
706                             String content, 
707                             org.apache.batik.script.Window.URLResponseHandler h, 
708                             String mimeType, 
709                             String fEnc) { 
710         }
711 
712 
713 
714         /**
715          * Displays an alert dialog box.
716          */
717         public void alert(String message) {
718         }
719 
720         /**
721          * Displays a confirm dialog box.
722          */
723         public boolean confirm(String message) {
724             return false;
725         }
726 
727         /**
728          * Displays an input dialog box.
729          */
730         public String prompt(String message) {
731             return null;
732         }
733 
734         /**
735          * Displays an input dialog box, given the default value.
736          */
737         public String prompt(String message, String defVal) {
738             return null;
739         }
740 
741         /**
742          * Returns the current BridgeContext.
743          */
744         public BridgeContext getBridgeContext() {
745             return bridgeContext;
746         }
747 
748         /**
749          * Returns the associated interpreter.
750          */
751         public Interpreter getInterpreter() {
752             return interpreter;
753         }
754 
755     }
756 }