mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-07 21:37:34 +08:00
518 lines
12 KiB
Java
518 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();
|
|
}
|
|
}
|
|
}
|