1998-01-12 21:19:56 -05:00
package example ;
import java.awt.* ;
import java.awt.event.* ;
import java.io.* ;
import java.sql.* ;
2000-04-26 01:32:01 -04:00
import org.postgresql.largeobject.* ;
1998-01-12 21:19:56 -05:00
2001-11-19 17:43:13 -05:00
/ *
1998-01-12 21:19:56 -05:00
* 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 .
*
2000-04-26 01:32:01 -04:00
* 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
1998-01-12 21:19:56 -05:00
* that importing postgresql can confuse javac ( we have conflicting class names
2000-04-26 01:32:01 -04:00
* in org . postgresql . * and java . sql . * ) . This doesn ' t cause any problems , as
* long as no code imports org . postgresql .
1998-01-12 21:19:56 -05:00
*
* 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 .
*
1998-10-11 22:45:45 -04:00
* 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 .
1998-01-12 21:19:56 -05:00
* /
public class ImageViewer implements ItemListener
{
2001-10-25 02:00:05 -04:00
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 ) ;
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ( ) ;
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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());
//}
1998-01-12 21:19:56 -05:00
}
2001-10-25 02:00:05 -04:00
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ) ;
1998-01-12 21:19:56 -05:00
}
2001-10-25 02:00:05 -04:00
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ( ) ;
1998-01-12 21:19:56 -05:00
}
2001-10-25 02:00:05 -04:00
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 " ) ;
}
}
}
}
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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? " ) ;
}
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ( ) ) ;
}
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ( ) ) ) ;
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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. " ) ;
}
2001-11-19 17:43:13 -05:00
/ *
2001-10-25 02:00:05 -04:00
* 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 ( ) ;
}
2000-05-05 03:35:29 -04:00
}
1998-01-12 21:19:56 -05:00
}