Here are some explanations for developers who need to write a driver to read/write a new file format.
import java.io.<b style="color:black;background-color:#99ff99">File</b>;
import java.util.Map;
import java.util.HashMap;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JComboBox;
import com.vividsolutions.jump.workbench.datasource.*;
import com.vividsolutions.jump.util.Blackboard;
import com.vividsolutions.jump.workbench.plugin.PlugInContext;
/**
* PlugIn installing a driver to <b style="color:black;background-color:#ffff66">read</b> <b style="color:black;background-color:#a0ffff">XYZ</b> data files.
* @author Michaƫl Michaud
* @version 0.1 (2007-04-29)
*/
public class InstallXYZDataSourceQueryChooserPlugIn extends
InstallStandardDataSourceQueryChoosersPlugIn {
public static final String INDEX = "INDEX";
/**
* PlugIn initialization.
*/
public void initialize(final PlugInContext context) throws Exception {
Blackboard blackboard = context.getWorkbenchContext().getWorkbench().getBlackboard();
final String description = "<b style="color:black;background-color:#a0ffff">XYZ</b> (plain text)";
final JComboBox jcb = new JComboBox(new Object[]{"1","2","3","4","5","6"});
DataSourceQueryChooserManager.get(blackboard).addLoadDataSourceQueryChooser(
new LoadFileDataSourceQueryChooser(XYZDataSource.class,
description,
new String[] { "", "<b style="color:black;background-color:#a0ffff">xyz</b>", "txt", "asc" },
context.getWorkbenchContext()) {
// Put the x column index in the properties map
protected Map toProperties(<b style="color:black;background-color:#99ff99">File</b> <b style="color:black;background-color:#99ff99">file</b>) {
Map properties = new HashMap(super.toProperties(<b style="color:black;background-color:#99ff99">file</b>));
JPanel panel = getSouthComponent1();
properties.put(INDEX, ((JComboBox)panel.getComponent(1)).getSelectedItem().toString());
return properties;
}
// Create a component to select the comlumn index of <b style="color:black;background-color:#a0ffff">xyz</b> data
protected JPanel getSouthComponent1() {
JPanel southComponent = new JPanel();
southComponent.add(new JLabel("Index of X column"));
southComponent.add(jcb);
return southComponent;
}
}
);
}
}
This class extends InstallStandardDataSourceQueryChoosersPlugIn, which is used to install shapefile driver, gml driver…
InstallXYZDataSourceQueryChooserPlugIn adds a special widget to the interface to select the index of the X column (the Y and Z columns are supposed to be just after the X column).
The widget is a final JComboBox initialized during the installer initialization, and is made visible in the southComponent of the file chooser dialog.
The toProperties method of the LoadFileDataSourceQueryChooser put this column index in the properties Map used by the special XYZDataSource.
For a read-only driver as our XYZ driver, the Connection method to averload is : public FeatureCollection executeQuery(String query, Collection exceptions, TaskMonitor monitor)
Here is the piece of code which will return a Connection able to parse the XYZ file :
import java.io.<b style="color:black;background-color:#99ff99">File</b>;
import java.util.ArrayList;
import java.util.Collection;
import java.io.BufferedReader;
import java.io.FileReader;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jump.feature.*;
import com.vividsolutions.jump.io.datasource.*;
import com.vividsolutions.jump.task.TaskMonitor;
import org.apache.log4j.Logger;
/**
* <b style="color:black;background-color:#a0ffff">XYZ</b> Data Source
* @author Michael MICHAUD
* @version 0.1 (2007-04-29)
*/
public class XYZDataSource extends DataSource {
private static final Logger LOG = Logger.getLogger(XYZDataSource.class);
/**
* Creates a new Connection to this DataSource.
*/
public Connection getConnection() {
try {
return new Connection() {
public FeatureCollection executeQuery(String query, Collection exceptions, TaskMonitor monitor) {
BufferedReader br = null;
try {
<b style="color:black;background-color:#99ff99">File</b> <b style="color:black;background-color:#99ff99">file</b> = new <b style="color:black;background-color:#99ff99">File</b>(getProperties().get(FILE_KEY).toString());
int index = new Integer(getProperties().get(InstallXYZDataSourceQueryChooserPlugIn.INDEX).toString()).intValue();
br = new BufferedReader(new FileReader(<b style="color:black;background-color:#99ff99">file</b>));
String line;
FeatureSchema fs = new FeatureSchema();
fs.addAttribute("GEOMETRY", AttributeType.GEOMETRY);
for (int i = 0 ; i < index ; i++) {
fs.addAttribute("Attribute_"+i, AttributeType.STRING);
}
GeometryFactory gf = new GeometryFactory();
FeatureCollection coll = new FeatureDataset(fs);
while(null != (line = br.readLine())) {
if (line.trim().length()==0) continue;
String[] ss = line.split("(\\s|,|;|\\|)");
try {
double x = Double.parseDouble(ss[index-1]);
double y = Double.parseDouble(ss[index]);
double z = ss.length > (index+1) ? Double.parseDouble(ss[index+1]) : Double.NaN;
BasicFeature bf = new BasicFeature(fs);
bf.setGeometry(gf.createPoint(new Coordinate(x,y,z)));
for (int i = 0 ; i < index ; i++) {
bf.setAttribute("Attribute_"+i, ss[i]);
}
coll.add(bf);
}
catch(Exception e) {
LOG.debug("Error reading <b style="color:black;background-color:#a0ffff">XYZ</b> <b style="color:black;background-color:#99ff99">file</b> : " + line, e);
}
}
br.close();
return coll;
} catch (Exception e) {
LOG.warn("Error executing query \"" + query + "\"", e);
exceptions.add(e);
return null;
}
}
public void executeUpdate(String update,
FeatureCollection featureCollection,
TaskMonitor monitor) throws Exception {
throw new Exception("Update is not authorized for this DataSource");
}
public void close() {}
public FeatureCollection executeQuery(String query, TaskMonitor monitor) throws Exception {
ArrayList exceptions = new ArrayList();
FeatureCollection featureCollection = executeQuery(query, exceptions, monitor);
if (!exceptions.isEmpty()) {
throw (Exception) exceptions.iterator().next();
}
return featureCollection;
}
};
}
catch(Exception e) {
LOG.warn("Error trying to connect to a GeoConcept Data Source", e);
return null;
}
}
public boolean isWritable() {
return false;
}
}
If you want to add a ‘save as’ driver, you’ll have to implement the executeUpdate method of the Connection
For more complex drivers, it may be useful to create special classes as JUMPReaders and/or JUMPWriters.
import com.vividsolutions.jump.workbench.plugin.Extension;
import com.vividsolutions.jump.workbench.plugin.PlugInContext;
/**
* Configuration <b style="color:black;background-color:#99ff99">file</b> for <b style="color:black;background-color:#a0ffff">xyz</b> driver extension.
* @version 0.1 (2007-04-29)
*/
public class XYZDriverConfiguration extends Extension {
public void configure(PlugInContext context) throws Exception {
new InstallXYZDataSourceQueryChooserPlugIn().initialize(context);
}
public String getName() {return "<b style="color:black;background-color:#a0ffff">XYZ</b> driver (<b style="color:black;background-color:#ffff66">read</b>-only)";}
public String getVersion() {return "0.1 (2007-04-29)";}
}
Hope that example will help you to write your own driver. I wrote this small tutorial because it gave me headache to understand the api and write a driver for the GeoConcept format.
If you find errors or want to improve this tutorial, please, feel free to do it.