Domanda

I've met a problem and I've been struggling last 2 days. I have a compiled program that runs some simulations and visualizes the results in an SVG file. The file is replaced every 2 seconds with a new one, until the simulation is done.

Wanting to visualize the results, I made a java swing program which uses batik and JSVGCanvas to display the svg file and update it every 2 seconds.

The code I use is:

// In the main part of my code
svgCanvas = new JSVGCanvas();
oneLineInnerPanel.add("Center", svgCanvas);
(new Thread() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                File f = new File("file_that_shows_simulation_still_running");
                while (f.exists()) {
                    svgReloadButtonActionPerformed(null);
                    Thread.sleep(2000);
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }).start();
// -----------------------------------------------

private void svgReloadButtonActionPerformed(java.awt.event.ActionEvent evt) {                                                
    try {
        svgCanvas.loadSVGDocument(SVGFile.toURL().toString());

    } catch (MalformedURLException ex) {
        Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
    }
}

It works fine with the exception that every 30-40 updates, it happens that the loadSVGDocument tries to read the document while it's being written by the simulator and thus I get a jdialog error:

XML document structures must start and end within the same entity. org.apache.batik.dom.util.SAXIOException: XML document structures must start and end within the same entity. at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:437) at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:349) at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:200) at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createSVGDocument(SAXSVGDocumentFactory.java:124) at org.apache.batik.bridge.DocumentLoader.loadDocument(DocumentLoader.java:106) at org.apache.batik.swing.svg.SVGDocumentLoader.run(SVGDocumentLoader.java:84)

Caused by: org.xml.sax.SAXParseException; systemId: file:/tmp/tempDir9189341730639722289/svgOut.svg; lineNumber: 272; columnNumber: 2; XML document structures must start and end within the same entity. at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:431) ... 5 more

This doesn't affect the whole procedure, but it's ugly. I get 2-3 of these jdialogs throughout the simulation. I cannot lock the file I/O, because I don't have access to the simulator code. If I lock from java only, the simulator crashes saying it cannot access the file.

What I want is that if there is an error while loading the svg file to somehow catch it internally and not have a jdialog. I can accept missing an update every 30-40 times (60-80 secs).

Now, JSVGCanvas gives you the option to provide a useragent and overwrite the displayError() method to do as you like. I tried that but the dialogs still occur. The problem is that the dialogs are not produced by the svgUserAgent I provide but by an internal BridgeUserAgent:

public JSVGComponent(SVGUserAgent ua, boolean eventsEnabled,
                     boolean selectableText) {
    super(eventsEnabled, selectableText);

    svgUserAgent = ua;

    userAgent = new BridgeUserAgentWrapper(createUserAgent());

    addSVGDocumentLoaderListener((SVGListener)listener);
    addGVTTreeBuilderListener((SVGListener)listener);
    addSVGLoadEventDispatcherListener((SVGListener)listener);
    if (updateOverlay != null) 
        getOverlays().add(updateOverlay);
}
public void loadSVGDocument(String url) {
    String oldURI = null;
    if (svgDocument != null) {
        oldURI = svgDocument.getURL();
    }
    final ParsedURL newURI = new ParsedURL(oldURI, url);

    stopThenRun(new Runnable() {
            public void run() {
                String url = newURI.toString();
                fragmentIdentifier = newURI.getRef();

                loader = new DocumentLoader(userAgent);
                nextDocumentLoader = new SVGDocumentLoader(url, loader);
                nextDocumentLoader.setPriority(Thread.MIN_PRIORITY);

                Iterator it = svgDocumentLoaderListeners.iterator();
                while (it.hasNext()) {
                    nextDocumentLoader.addSVGDocumentLoaderListener
                        ((SVGDocumentLoaderListener)it.next());
                }
                startDocumentLoader();
            }
        });
}

Can anyone help me get out of this mess, please?

Thanks in advance!

È stato utile?

Soluzione

Finally solved the issue. Extended JSVGCanvas, override the createUserAgent() method to provide a bridgeuseragent of my own. This useragent extends the JSVGCanvas user agent but overrides the displayError methods. Here's the code:

import org.apache.batik.bridge.UserAgent;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.XMLConstants;

/**
 *
 * @author
 */
public class myJSVGCanvas extends JSVGCanvas{

@Override
protected UserAgent createUserAgent() {
    return new myCanvasUserAgent();
}

protected class myCanvasUserAgent extends CanvasUserAgent

    implements XMLConstants {

    /**
     * Displays an error message in the User Agent interface.
     */
    @Override
    public void displayError(String message) {
        if (svgUserAgent != null) {
            super.displayError(message);
        } else {
            System.out.println(message);
//            JOptionPane pane =
//                new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
//            JDialog dialog =
//                pane.createDialog(myJSVGCanvas.this, "ERROR");
//            dialog.setModal(false);
//            dialog.setVisible(true); // Safe to be called from any thread
        }
    }

    /**
     * Displays an error resulting from the specified Exception.
     */
    @Override
    public void displayError(Exception ex) {
        if (svgUserAgent != null) {
            super.displayError(ex);
        } else {
            ex.printStackTrace();
//            JErrorPane pane =
//                new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
//            JDialog dialog = pane.createDialog(myJSVGCanvas.this, "ERROR");
//            dialog.setModal(false);
//            dialog.setVisible(true); // Safe to be called from any thread
        }
    }
}    
}

Hope it helps somebody. If anyone has a better idea for dealing with the problem, than just hiding it, I'd be glad to hear it!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top