PostgreSQL/src/interfaces/jdbc/example/ImageViewer.java
2000-05-05 07:35:29 +00:00

465 lines
12 KiB
Java

package example;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.sql.*;
import org.postgresql.largeobject.*;
/**
* This example is a small application that stores and displays images
* held on a postgresql database.
*
* Before running this application, you need to create a database, and
* on the first time you run it, select "Initialise" in the "PostgreSQL"
* menu.
*
* Important note: You will notice we import the org.postgresql.largeobject
* package, but don't import the org.postgresql package. The reason for this is
* that importing postgresql can confuse javac (we have conflicting class names
* in org.postgresql.* and java.sql.*). This doesn't cause any problems, as
* long as no code imports org.postgresql.
*
* Under normal circumstances, code using any jdbc driver only needs to import
* java.sql, so this isn't a problem.
*
* It's only if you use the non jdbc facilities, do you have to take this into
* account.
*
* Note: For PostgreSQL 6.4, the driver is now Thread safe, so this example
* application has been updated to use multiple threads, especially in the
* image storing and retrieving methods.
*/
public class ImageViewer implements ItemListener
{
Connection db;
Statement stat;
LargeObjectManager lom;
Frame frame;
Label label; // Label used to display the current name
List list; // The list of available images
imageCanvas canvas; // Canvas used to display the image
String currentImage; // The current images name
// This is a simple component to display our image
public class imageCanvas extends Canvas
{
// holds the image
private Image image;
// holds the background buffer
private Image bkg;
// the size of the buffer
private Dimension size;
public imageCanvas()
{
image=null;
}
public void setImage(Image img)
{
image=img;
repaint();
}
// This defines our minimum size
public Dimension getMinimumSize()
{
return new Dimension(400,400);
}
public Dimension getPreferedSize()
{
return getMinimumSize();
}
public void update(Graphics g)
{
paint(g);
}
/**
* Paints the image, using double buffering to prevent screen flicker
*/
public void paint(Graphics gr)
{
Dimension s = getSize();
if(size==null || bkg==null || !s.equals(size)) {
size = s;
bkg = createImage(size.width,size.height);
}
// now set the background
Graphics g = bkg.getGraphics();
g.setColor(Color.gray);
g.fillRect(0,0,s.width,s.height);
// now paint the image over the background
if(image!=null)
g.drawImage(image,0,0,this);
// dispose the graphics instance
g.dispose();
// paint the image onto the component
gr.drawImage(bkg,0,0,this);
}
}
public ImageViewer(Frame f,String url,String user,String password) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
frame = f;
MenuBar mb = new MenuBar();
Menu m;
MenuItem i;
f.setMenuBar(mb);
mb.add(m = new Menu("PostgreSQL"));
m.add(i= new MenuItem("Initialise"));
i.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.init();
}
});
m.add(i= new MenuItem("Exit"));
ActionListener exitListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.close();
}
};
m.addActionListener(exitListener);
mb.add(m = new Menu("Image"));
m.add(i= new MenuItem("Import"));
ActionListener importListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.importImage();
}
};
i.addActionListener(importListener);
m.add(i= new MenuItem("Remove"));
ActionListener removeListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.removeImage();
}
};
i.addActionListener(removeListener);
// To the north is a label used to display the current images name
f.add("North",label = new Label());
// We have a panel to the south of the frame containing the controls
Panel p = new Panel();
p.setLayout(new FlowLayout());
Button b;
p.add(b=new Button("Refresh List"));
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageViewer.this.refreshList();
}
});
p.add(b=new Button("Import new image"));
b.addActionListener(importListener);
p.add(b=new Button("Remove image"));
b.addActionListener(removeListener);
p.add(b=new Button("Quit"));
b.addActionListener(exitListener);
f.add("South",p);
// And a panel to the west containing the list of available images
f.add("West",list=new List());
list.addItemListener(this);
// Finally the centre contains our image
f.add("Center",canvas = new imageCanvas());
// Load the driver
Class.forName("org.postgresql.Driver");
// Connect to database
db = DriverManager.getConnection(url, user, password);
// Create a statement
stat = db.createStatement();
// Also, get the LargeObjectManager for this connection
lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
// Now refresh the image selection list
refreshList();
}
/**
* This method initialises the database by creating a table that contains
* the image names, and Large Object OID's
*/
public void init()
{
try {
//db.setAutoCommit(true);
stat.executeUpdate("create table images (imgname name,imgoid oid)");
label.setText("Initialised database");
db.commit();
} catch(SQLException ex) {
label.setText(ex.toString());
}
// This must run outside the previous try{} catch{} segment
//try {
//db.setAutoCommit(true);
//} catch(SQLException ex) {
//label.setText(ex.toString());
//}
}
/**
* This closes the connection, and ends the application
*/
public void close()
{
try {
db.close();
} catch(SQLException ex) {
System.err.println(ex.toString());
}
System.exit(0);
}
/**
* This imports an image into the database, using a Thread to do this in the
* background.
*/
public void importImage()
{
FileDialog d = new FileDialog(frame,"Import Image",FileDialog.LOAD);
d.setVisible(true);
String name = d.getFile();
String dir = d.getDirectory();
d.dispose();
// now start the true importer
Thread t = new importer(db,name,dir);
//t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
/**
* This is an example of using a thread to import a file into a Large Object.
* It uses the Large Object extension, to write blocks of the file to the
* database.
*/
class importer extends Thread
{
String name,dir;
Connection db;
public importer(Connection db,String name,String dir) {
this.db = db;
this.name = name;
this.dir = dir;
}
public void run() {
// Now the real import stuff
if(name!=null && dir!=null) {
Statement stat = null;
try {
// fetch the large object manager
LargeObjectManager lom = ((org.postgresql.Connection)db).getLargeObjectAPI();
db.setAutoCommit(false);
// A temporary buffer - this can be as large as you like
byte buf[] = new byte[2048];
// Open the file
FileInputStream fis = new FileInputStream(new File(dir,name));
// Now create the large object
int oid = lom.create();
LargeObject blob = lom.open(oid);
// Now copy the file into the object.
//
// Note: we dont use write(buf), as the last block is rarely the same
// size as our buffer, so we have to use the amount read.
int s,t=0;
while((s=fis.read(buf,0,buf.length))>0) {
t+=s;
blob.write(buf,0,s);
}
// Close the object
blob.close();
// Now store the entry into the table
// As we are a different thread to the other window, we must use
// our own thread
stat = db.createStatement();
stat.executeUpdate("insert into images values ('"+name+"',"+oid+")");
db.commit();
db.setAutoCommit(false);
// Finally refresh the names list, and display the current image
ImageViewer.this.refreshList();
ImageViewer.this.displayImage(name);
} catch(Exception ex) {
label.setText(ex.toString());
} finally {
// ensure the statement is closed after us
try {
if(stat != null)
stat.close();
} catch(SQLException se) {
System.err.println("closing of Statement failed");
}
}
}
}
}
/**
* This refreshes the list of available images
*/
public void refreshList()
{
try {
// First, we'll run a query, retrieving all of the image names
ResultSet rs = stat.executeQuery("select imgname from images order by imgname");
if(rs!=null) {
list.removeAll();
while(rs.next())
list.addItem(rs.getString(1));
rs.close();
}
} catch(SQLException ex) {
label.setText(ex.toString()+" Have you initialised the database?");
}
}
/**
* This removes an image from the database
*
* Note: With postgresql, this is the only way of deleting a large object
* using Java.
*/
public void removeImage()
{
try {
//
// Delete any large objects for the current name
//
// Note: We don't need to worry about being in a transaction
// here, because we are not opening any blobs, only deleting
// them
//
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='"+currentImage+"'");
if(rs!=null) {
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while(rs.next()) {
lom.delete(rs.getInt(1));
}
}
rs.close();
// Finally delete any entries for that name
stat.executeUpdate("delete from images where imgname='"+currentImage+"'");
label.setText(currentImage+" deleted");
currentImage=null;
refreshList();
} catch(SQLException ex) {
label.setText(ex.toString());
}
}
/**
* This displays an image from the database.
*
* For images, this is the easiest method.
*/
public void displayImage(String name)
{
try {
//
// Now as we are opening and reading a large object we must
// turn on Transactions. This includes the ResultSet.getBytes()
// method when it's used on a field of type oid!
//
db.setAutoCommit(false);
ResultSet rs = stat.executeQuery("select imgoid from images where imgname='"+name+"'");
if(rs!=null) {
// Even though there should only be one image, we still have to
// cycle through the ResultSet
while(rs.next()) {
canvas.setImage(canvas.getToolkit().createImage(rs.getBytes(1)));
label.setText(currentImage = name);
}
}
rs.close();
} catch(SQLException ex) {
label.setText(ex.toString());
} finally {
try {
db.setAutoCommit(true);
} catch(SQLException ex2) {
}
}
}
public void itemStateChanged(ItemEvent e) {
displayImage(list.getItem(((Integer)e.getItem()).intValue()));
}
/**
* This is the command line instructions
*/
public static void instructions()
{
System.err.println("java example.ImageViewer jdbc-url user password");
System.err.println("\nExamples:\n");
System.err.println("java -Djdbc.driver=org.postgresql.Driver example.ImageViewer jdbc:postgresql:test postgres password\n");
System.err.println("This example tests the binary large object api of the driver.\nBasically, it will allow you to store and view images held in the database.");
System.err.println("Note: If you are running this for the first time on a particular database,\nyou have to select \"Initialise\" in the \"PostgreSQL\" menu.\nThis will create a table used to store image names.");
}
/**
* This is the application entry point
*/
public static void main(String args[])
{
if(args.length!=3) {
instructions();
System.exit(1);
}
try {
Frame frame = new Frame("PostgreSQL ImageViewer v7.0 rev 1");
frame.setLayout(new BorderLayout());
ImageViewer viewer = new ImageViewer(frame,args[0],args[1],args[2]);
frame.pack();
frame.setLocation(0,50);
frame.setVisible(true);
} catch(Exception ex) {
System.err.println("Exception caught.\n"+ex);
ex.printStackTrace();
}
}
}