views:

37

answers:

2

I wrote an application that uses GraphViz to generate some graphs as .gif's according to the DOT syntax. When I run from Eclipse the images are generated fine but when I export it as a jar the images are created but there is no data in them. When I view them in Microsoft Picture Viewer its just the red X.

It was working as an exported jar until I put the picture generation in its own thread. I can't seem to figure out whats going on here. Are there any problems exporting multi-threaded projects? Any one have any ideas?

Thanks

Here is some of the code. Its hard to pin point what is going wrong.

/**
* Writes the graph's image in a file.
* @param img   A byte array containing the image of the graph.
* @param to    A File object to where we want to write.
* @return Success: 1, Failure: -1
*/

public int writeGraphToFile(byte[] img, File to)
   {
      try {
         FileOutputStream fos = new FileOutputStream(to);
         fos.write(img);
         fos.close();
      } catch (java.io.IOException ioe) { return -1; }
      return 1;
   }

The above function is called from an alternate thread by this call.

public void generateMainGraph() {
        //create the graph and put it to file name mainGraphCount.gif
        GraphViz gv = new GraphViz();
        System.out.println("Generating MAIN graph...");

        //add the ending } to mainDot
        mainDot += "}";

        File newGraph = new File("graphs\\main" + Integer.toString(mainGraphCount) + ".gif");
        gv.writeGraphToFile(gv.getGraph(mainDot), newGraph);
}

Here is the thread that calls the function which makes the call to generateMainGraph(...).

graphGeneratingThread = new Runnable() {
            //This method will run in the timer thread
            public void run() {
                try {
                    //Generate the graphs
                    if (iData.importDataSet()) {
                        int timeout = 0;
                        Scanner scan = new Scanner(graphGen.logSource);
                        while(timeout < 10) {
                            if(!scan.hasNextLine()) {
                                Thread.sleep(1000);
                                timeout++;
                            } else {
                                timeout = 0;
                                graphGen.generateGraph(scan.nextLine());   //This function calls generateMainGraph(...)
                                if(!beginningButton.isEnabled()) {
                                    enableTivoButtons();
                                }
                            }
                        }
                    }
                } catch(Exception exc) {
                    System.err.println("GraphGenerationThread Runnable Error: " + exc.getMessage() + "\n");
                    exc.printStackTrace();
                    System.exit(1);
                }
            }
        };
+1  A: 

Check the classpath in Eclipse. You are likely missing a jar in your path outside of Eclipse. You can list the required jars in the Manifest of your jar.

BillThor
There are no external jars that need to be included. The GraphViz "api" I am using is really just a .java file that defines a class. It uses an external program located in my Program Files directory but that program is there. The project wouldn't have worked in eclipse without it.
Mike
Check the ENV that is being used to run inside Eclipse. There may be something added or removed there.
BillThor
+1  A: 

It does not make a difference if a project is multithreaded or not when you export it. Differences are cause by how the threads are being scheduled by the VM (which may be effected by running inside of eclipse).

Since your problem is with the threaded version my guess is you have internal object state that is being corrupted in the middle of the operation of one thread by another thread. For example:

  1. Thread A generates the image data
  2. Thread B replaces the data array with an empty one
  3. Thread A writes data (which is now empty from step 2)

this would be an explanation for a 0 byte image. Another scenario:

  1. Thread A starts generating image data
  2. Thread B starts generating image data
  3. Thread A completes generating data.
  4. Thread A writes image data (which now contains part of thread B's data)

This would be a cause of a corrupt image file. Debugging concurrent code can be tricky. My suggestion is:

  1. Find any code that can be invoked by more than thread at once.
  2. Add logging statements including Thread.currentThread().getName() if it is not already part of a logging API you are using.
  3. Look at the interleaving of the two threads this should give you ideas of where data may becoming corrupt.

If you are looking for a "simple solution" after you find code that can be run by more than thread at once and effect your data simply make that method synchronized, however that will likely defeat what you are trying to achieve in adding the Threads.

M. Jessup