001// XmlApplet.java: base class for Æfred applet demos.
002// NO WARRANTY! See README, and copyright below.
003// $Id$
004// Modified 11/8/98 to add package statement.
005package com.microstar.xml.demo;
006
007import java.applet.Applet;
008import java.awt.BorderLayout;
009import java.awt.Button;
010import java.awt.Event;
011import java.awt.FlowLayout;
012import java.awt.Panel;
013import java.awt.TextArea;
014import java.net.MalformedURLException;
015import java.net.URL;
016
017import com.microstar.xml.XmlHandler;
018import com.microstar.xml.XmlParser;
019
020/**
021 * Base class for Ælfred demonstration applications.
022 * <p>This class fills in the basic interface, and provides
023 * an I/O infrastructure for simple applications and applets.
024 * @author Copyright (c) 1997, 1998 by Microstar Software Ltd.;
025 * @author written by David Megginson &lt;dmeggins@microstar.com&gt;
026 * @version 1.1
027 * @since Ptolemy II 0.2
028 * @see com.microstar.xml.XmlParser
029 * @see com.microstar.xml.XmlHandler
030 * @see EventDemo
031 * @see TimerDemo
032 * @see DtdDemo
033 * @see StreamDemo
034 */
035@SuppressWarnings("serial")
036public class XmlApplet extends Applet implements XmlHandler {
037    /**
038     * Flag to show whether we're running as an applet or application.
039     */
040    public boolean isApplet = false;
041
042    public XmlParser parser;
043
044    //////////////////////////////////////////////////////////////////////
045    // Implementation of XmlParser interface.
046    //
047    // The following methods provide a full skeleton implementation of the
048    // XmlHandler interface, so that subclasses can override only
049    // the methods they need.
050    //////////////////////////////////////////////////////////////////////
051
052    /**
053     * Resolve an external entity.
054     * <p>This method could generate a new URL by looking up the
055     * public identifier in a hash table, or it could replace the
056     * URL supplied with a different, local one; for now, however,
057     * just return the URL supplied.
058     * @see com.microstar.xml.XmlHandler#resolveEntity
059     */
060    @Override
061    public Object resolveEntity(String publicId, String systemId) {
062        return null;
063    }
064
065    @Override
066    public void startExternalEntity(String systemId) {
067    }
068
069    @Override
070    public void endExternalEntity(String systemId) {
071    }
072
073    /**
074     * Handle the start of the document.
075     * <p>Do nothing for now.  Subclasses can override this method
076     * if they want to take a specific action.
077     * <p>This method will always be called first.
078     * @see com.microstar.xml.XmlHandler#startDocument
079     */
080    @Override
081    public void startDocument() {
082    }
083
084    /**
085     * Handle the end the document.
086     * <p>Do nothing for now.  Subclasses can override this method
087     * if they want to take a specific action.
088     * <p>This method will always be called last.
089     * @see com.microstar.xml.XmlHandler#endDocument
090     */
091    @Override
092    public void endDocument() {
093    }
094
095    /**
096     * Handle a DOCTYPE declaration.
097     * <p>Do nothing for now.  Subclasses can override this method
098     * if they want to take a specific action.
099     * <p>Well-formed XML documents might not have one of these.
100     * <p>The query methods in XmlParser will return useful
101     * values only after this callback.
102     * @see com.microstar.xml.XmlHandler#doctypeDecl
103     */
104    @Override
105    public void doctypeDecl(String name, String pubid, String sysid) {
106    }
107
108    /**
109     * Handle an attribute value specification.
110     * <p>Do nothing for now.  Subclasses can override this method
111     * if they want to take a specific action.
112     * @see com.microstar.xml.XmlHandler#attribute
113     */
114    @Override
115    public void attribute(String name, String value, boolean isSpecified) {
116    }
117
118    /**
119     * Handle the start of an element.
120     * <p>Do nothing for now.  Subclasses can override this method
121     * if they want to take a specific action.
122     * @see com.microstar.xml.XmlHandler#startElement
123     */
124    @Override
125    public void startElement(String name) {
126    }
127
128    /**
129     * Handle the end of an element.
130     * <p>Do nothing for now.  Subclasses can override this method
131     * if they want to take a specific action.
132     * @see com.microstar.xml.XmlHandler#endElement
133     */
134    @Override
135    public void endElement(String name) {
136    }
137
138    /**
139     * Handle character data.
140     * <p>Do nothing for now.  Subclasses can override this method
141     * if they want to take a specific action.
142     * @see com.microstar.xml.XmlHandler#charData
143     */
144    @Override
145    public void charData(char[] ch, int start, int length) {
146    }
147
148    /**
149     * Handle ignorable whitespace.
150     * <p>Do nothing for now.  Subclasses can override this method
151     * if they want to take a specific action.
152     * @see com.microstar.xml.XmlHandler#ignorableWhitespace
153     */
154    @Override
155    public void ignorableWhitespace(char[] ch, int start, int length) {
156    }
157
158    /**
159     * Handle a processing instruction.
160     * <p>Do nothing for now.  Subclasses can override this method
161     * if they want to take a specific action.
162     * @see com.microstar.xml.XmlHandler#processingInstruction
163     */
164    @Override
165    public void processingInstruction(String target, String data) {
166    }
167
168    /**
169     * Handle a parsing error.
170     * <p>By default, print a message and throw an Error.
171     * <p>Subclasses can override this method if they want to do something
172     * different.
173     * @see com.microstar.xml.XmlHandler#error
174     */
175    @Override
176    public void error(String message, String url, int line, int column) {
177        displayText("FATAL ERROR: " + message);
178        displayText("  at " + url + ": line " + line + " column " + column);
179        throw new Error(message);
180    }
181
182    //////////////////////////////////////////////////////////////////////
183    // General utility methods.
184    //////////////////////////////////////////////////////////////////////
185
186    /**
187     * Start a parse in application mode.
188     * <p>Output will go to STDOUT.
189     * @see #displayText(String)
190     * @see com.microstar.xml.XmlParser#parse(String, String, String)
191     */
192    void doParse(String url) throws java.lang.Exception {
193        /* String docURL =*/makeAbsoluteURL(url);
194
195        // create the parser
196        parser = new XmlParser();
197        parser.setHandler(this);
198        parser.parse(makeAbsoluteURL(url), null, (String) null);
199    }
200
201    static String makeAbsoluteURL(String url) throws MalformedURLException {
202        URL baseURL;
203
204        String currentDirectory = System.getProperty("user.dir");
205
206        String fileSep = System.getProperty("file.separator");
207        String file = currentDirectory.replace(fileSep.charAt(0), '/') + '/';
208
209        if (file.charAt(0) != '/') {
210            file = "/" + file;
211        }
212
213        baseURL = new URL("file", null, file);
214        return new URL(baseURL, url).toString();
215    }
216
217    /**
218     * Display text on STDOUT or in an applet TextArea.
219     */
220    void displayText(String text) {
221        if (isApplet) {
222            textArea.append(text + '\n');
223        } else {
224            System.out.println(text);
225        }
226    }
227
228    /**
229     * Escape a string for printing.
230     */
231    String escape(char[] ch, int length) {
232        StringBuffer out = new StringBuffer();
233
234        for (int i = 0; i < length; i++) {
235            switch (ch[i]) {
236            case '\\':
237                out.append("\\\\");
238                break;
239
240            case '\n':
241                out.append("\\n");
242                break;
243
244            case '\t':
245                out.append("\\t");
246                break;
247
248            case '\r':
249                out.append("\\r");
250                break;
251
252            case '\f':
253                out.append("\\f");
254                break;
255
256            default:
257                out.append(ch[i]);
258                break;
259            }
260        }
261
262        return out.toString();
263    }
264
265    //////////////////////////////////////////////////////////////////////
266    // Applet support.
267    //
268    // These methods and variables are used only if we are running as an
269    // applet.
270    //////////////////////////////////////////////////////////////////////
271    TextArea textArea;
272
273    Panel buttonPanel;
274
275    Button startButton;
276
277    /**
278     * Initialise the applet the first time it runs.
279     */
280    @Override
281    public void init() {
282        startButton = new Button("Parse " + getParameter("url"));
283        isApplet = true;
284        textArea = new TextArea();
285        buttonPanel = new Panel();
286        buttonPanel.setLayout(new FlowLayout());
287        setLayout(new BorderLayout());
288        buttonPanel.add("Center", startButton);
289        add("Center", textArea);
290        add("South", buttonPanel);
291    }
292
293    /**
294     * React to a button press.
295     * <p>This uses the old event model, so that it will work with
296     * existing browsers.  It will cause a 'deprecated' warning
297     * when you compile.
298     */
299    @Override
300    public boolean action(Event ev, Object target) {
301        if (target == startButton.getLabel()) {
302            try {
303                startParse();
304            } catch (Exception e) {
305                System.err.println(e.getMessage());
306            }
307
308            return true;
309        } else {
310            return false;
311        }
312    }
313
314    /**
315     * Start a parse (in response to a button press).
316     * <p>Erase the text area, then start the parser running, using
317     * the value of the "url" parameter.
318     * @exception Exception If thrown by the parser.
319     */
320    public void startParse() throws java.lang.Exception {
321        textArea.setText("");
322
323        try {
324            XmlParser parser = new XmlParser();
325            parser.setHandler(this);
326            ;
327            parser.parse(
328                    new URL(getDocumentBase(), getParameter("url")).toString(),
329                    null, (String) null);
330        } catch (Exception e) {
331            displayText("Caught exception (" + e.getClass().toString() + "): "
332                    + e.getMessage());
333        }
334    }
335}
336
337// end of XmlApplet.java