Sloan Digital Sky Survey
VO Enabled Mirage

Programming with the IVOA Client Package

There is Javadoc API documentation for the IVOA Client package here.

The following public classes are in the IVOA Client package.

The Main Components

Cone/SIAP and CAS Search

The WSRetrievalChooser class gives the programmer a dialog offering the user the option of "CONE" or "CAS" searches. CAS allows a query to be sent to the SDSS Skyserver. Cone queries the registry and offers a list of Cone and SIAP Services and the ability to put in the RA, Dec and SR parameters to send to the selected service(s). You can specify a different registry to be used by invoking the JRE with the optional flag
-Dregistry="http://some.registry.edu/registry"
where of course the value specified here is completely fictitious. You may also specify which VOTable parser to use (JAVOT or SAVOT) with the optional flag
-DVOTParser="javot"
where the default is to use SAVOT unless otherwise specified.

Task Management

The TaskManager class gives the programmer a frame which displays for the user the status of various tasks and gives the user the option to cancel tasks. To use the TaskManager, subclass the Task class and override the execute method to perform whatever logic you like, then add an instance of the subclassed Task to the TaskManager using its addTask method. See the API Documentation for more detailed class descriptions.

The VODownload Example

VODownload is a small, yet complete example showing how to use the IVOA Client package in a Java program. The source appears below. Note that it's really shorter than it looks; most of the space is taken up by graceful exception handling.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

import edu.jhu.pha.ivoa.*;


public class VODownload
{
  public static void main(String[] args)
  {
    new VODownload().begin(args);
  }

  protected void begin(String[] args)
  {
    _frame = new JFrame("VODownload");

    try
    {
      _chooser = new WSRetrievalChooser();
    }
    catch(java.rmi.RemoteException e)
    {
      ErrorPrompter.
        showErrorDialog(null, "Problem retrieving registry information", e);

      System.exit(1);
    }

    _tm = new TaskManager();

    JPanel controlPanel = new JPanel(new GridLayout(1, 2));
    controlPanel.add(new JButton(new AbstractAction("Retrieve...")
    {
      public void actionPerformed(ActionEvent e)
      {
        retrieve();
      }
    }));
    controlPanel.add(new JButton(new AbstractAction("Quit")
    {
      public void actionPerformed(ActionEvent e)
      {
        quit();
      }
    }));

    _frame.setContentPane(controlPanel);
    _frame.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        quit();
      }
    });

    _frame.pack();
    _frame.setVisible(true);
  }

  protected void retrieve()
  {
    int option = WSRetrievalChooser.ERROR_OPTION;

    try
    {
      option =
        _chooser.showRetrieveDialog((JComponent)_frame.getContentPane());
    }
    catch(Exception e)
    {
      ErrorPrompter.
        showErrorDialog(null, "Problem gathering search parameters.", e);
    }

    if(option == WSRetrievalChooser.APPROVE_OPTION)
    {
      retrieveData();
      retrieveImages();
    }
  }

  protected void retrieveImages()
  {
    // each of these is a URL to a SIAP service to query for images
    NameURLPair[] urls = _chooser.getSIAPNameURLPairs();
    final boolean fetchImages = _chooser.prefetchImages();

    for(int i = 0; i < urls.length; ++i)
    {
      final NameURLPair url = urls[i];

      // here we're declaring an anonymous inner class which provides the
      // implementation required to subclass Task.
      _tm.addTask(new Task("Downloading " + url.getName())
        {
          public void execute()
          {
            // if we're fetching images, fetch them
            if(fetchImages)
            {
              try
              {
                setMessage("Retrieving image URLs...");

                InputStream in = url.getURL().openStream();
                NameURLPair[] imageURLs =
                  _chooser.getImageNameURLPairs(in, url.getName());

                for(int i = 0; i < imageURLs.length; ++i)
                {
                  // don't tag a suffix on it, and don't treat it as a temp file
                  _tm.addTask(new DownloadTask(imageURLs[i], "", false));
                }
              }
              catch(MalformedURLException e)
              {
                ErrorPrompter.showErrorDialog(null, "Bad url.", e);
              }
              catch(IOException e)
              {
                ErrorPrompter.
                  showErrorDialog(null, "Problem retrieving SIAP data from " +
                                  url.getURL() + ".", e);
              }
              catch(Exception e)
              {
                ErrorPrompter.
                  showErrorDialog(null, "Problem parsing SIAP data from " +
                                  url.getURL() + ".", e);
              }
            }
            // otherwise just save the VOTable with the image URLs and let
            // the user pick them out by hand
            else
            {
              setMessage("Retrieving SIAP results...");

              // give it an xml suffix, and don't treat it as a temp file
              _tm.addTask(new DownloadTask(url, ".xml", false));
            }

            setMessage("Done.");
          }
        });
    }
  }

  protected void retrieveData()
  {
    NameURLPair[] urls = _chooser.getNameURLPairs();

    for(int i = 0; i < urls.length; ++i)
    {
      String name = urls[i].getName();
      // tack on an index to CAS searches,
      // which just come back with name "CAS".
      String suffix = name.startsWith("CAS") ?
        (nextCASIndex() + ".xml") : ".xml";

      // give it whatever suffix is, and don't treat it as a temp file
      _tm.addTask(new DownloadTask(urls[i], suffix, false));
    }
  }

  protected void quit()
  {
    System.exit(0);
  }

  protected int nextCASIndex()
  {
    return ++_nextCASIndex;
  }

  protected static int _nextCASIndex = 0;
  protected JFrame _frame;
  protected WSRetrievalChooser _chooser;
  protected TaskManager _tm;
}
If you copy this code into a file called VODownload.java, and put it in some directory along with the IVOA Client package jar file, you can compile and run it with the following commands:
javac -classpath .:ivoa-0.3.jar VODownload.java
java -classpath .:ivoa-0.3.jar [-Dregistry="http://some.registry.edu/registry"] [-DVOTParser="javot"] VODownload
The VODownload class is actually already in the jar, but if you put the current directory ahead of the jar in your classpath, you should be able to use your copy of the class. Alternatively, you could just rename the file and the class. Note that you will also have to have the Apache Axis 1.1 jar files in a directory called "lib" which is at the same level in the directory tree as the directory containing ivoa-0.3.jar and VODownload.java. Alternatively, you are free to edit the ant build file to point to the correct location of the Apache Axis 1.1 jar files.

Samuel Carliles
Last Modified :Friday, May 7, 2004 at 5:53:06 PM , $Revision 1.2 $