2626 * It's only if you use the non jdbc facilities, do you have to take this into
2727 * account.
2828 *
29+ * Note: For PostgreSQL 6.4, the driver is now Thread safe, so this example
30+ * application has been updated to use multiple threads, especially in the
31+ * image storing and retrieving methods.
2932 */
3033
3134public class ImageViewer implements ItemListener
@@ -42,8 +45,15 @@ public class ImageViewer implements ItemListener
4245// This is a simple component to display our image
4346public class imageCanvas extends Canvas
4447 {
48+ // holds the image
4549private Image image ;
4650
51+ // holds the background buffer
52+ private Image bkg ;
53+
54+ // the size of the buffer
55+ private Dimension size ;
56+
4757public imageCanvas ()
4858 {
4959image =null ;
@@ -71,14 +81,35 @@ public void update(Graphics g)
7181paint (g );
7282 }
7383
74- public void paint (Graphics g )
84+ /**
85+ * Paints the image, using double buffering to prevent screen flicker
86+ */
87+ public void paint (Graphics gr )
7588 {
89+ Dimension s =getSize ();
90+
91+ if (size ==null ||bkg ==null || !s .equals (size )) {
92+ size =s ;
93+ bkg =createImage (size .width ,size .height );
94+ }
95+
96+ // now set the background
97+ Graphics g =bkg .getGraphics ();
7698g .setColor (Color .gray );
77- g .fillRect (0 ,0 ,getSize () .width ,getSize () .height );
99+ g .fillRect (0 ,0 ,s .width ,s .height );
78100
101+ // now paint the image over the background
79102if (image !=null )
80103g .drawImage (image ,0 ,0 ,this );
104+
105+ // dispose the graphics instance
106+ g .dispose ();
107+
108+ // paint the image onto the component
109+ gr .drawImage (bkg ,0 ,0 ,this );
110+
81111 }
112+
82113 }
83114
84115public ImageViewer (Frame f ,String url ,String user ,String password )throws ClassNotFoundException ,FileNotFoundException ,IOException ,SQLException
@@ -197,9 +228,8 @@ public void close()
197228 }
198229
199230/**
200- * This imports an image into the database.
201- *
202- * This is the most efficient method, using the large object extension.
231+ * This imports an image into the database, using a Thread to do this in the
232+ * background.
203233 */
204234public void importImage ()
205235 {
@@ -209,51 +239,92 @@ public void importImage()
209239String dir =d .getDirectory ();
210240d .dispose ();
211241
212- // Now the real import stuff
213- if (name !=null &&dir !=null ) {
214- try {
215- System .out .println ("Importing file" );
216- // A temporary buffer - this can be as large as you like
217- byte buf [] =new byte [2048 ];
218-
219- // Open the file
220- System .out .println ("Opening file " +dir +"/" +name );
221- FileInputStream fis =new FileInputStream (new File (dir ,name ));
222-
223- // Gain access to large objects
224- System .out .println ("Gaining LOAPI" );
225-
226- // Now create the large object
227- System .out .println ("creating blob" );
228- int oid =lom .create ();
229-
230- System .out .println ("Opening " +oid );
231- LargeObject blob =lom .open (oid );
242+ // now start the true importer
243+ Thread t =new importer (db ,name ,dir );
244+ //t.setPriority(Thread.MAX_PRIORITY);
245+ t .start ();
246+ }
247+
248+ /**
249+ * This is an example of using a thread to import a file into a Large Object.
250+ * It uses the Large Object extension, to write blocks of the file to the
251+ * database.
252+ */
253+ class importer extends Thread
254+ {
255+ String name ,dir ;
256+ Connection db ;
257+
258+ public importer (Connection db ,String name ,String dir ) {
259+ this .db =db ;
260+ this .name =name ;
261+ this .dir =dir ;
262+ }
263+
264+ public void run () {
265+
266+ // Now the real import stuff
267+ if (name !=null &&dir !=null ) {
268+ Statement stat =null ;
232269
233- // Now copy the file into the object.
234- //
235- // Note: we dont use write(buf), as the last block is rarely the same
236- // size as our buffer, so we have to use the amount read.
237- System .out .println ("Importing file" );
238- int s ,t =0 ;
239- while ((s =fis .read (buf ,0 ,buf .length ))>0 ) {
240- System .out .println ("Block s=" +s +" t=" +t );t +=s ;
241- blob .write (buf ,0 ,s );
270+ try {
271+ // fetch the large object manager
272+ LargeObjectManager lom = ((postgresql .Connection )db ).getLargeObjectAPI ();
273+
274+ System .out .println ("Importing file" );
275+ // A temporary buffer - this can be as large as you like
276+ byte buf [] =new byte [2048 ];
277+
278+ // Open the file
279+ System .out .println ("Opening file " +dir +"/" +name );
280+ FileInputStream fis =new FileInputStream (new File (dir ,name ));
281+
282+ // Gain access to large objects
283+ System .out .println ("Gaining LOAPI" );
284+
285+ // Now create the large object
286+ System .out .println ("creating blob" );
287+ int oid =lom .create ();
288+
289+ System .out .println ("Opening " +oid );
290+ LargeObject blob =lom .open (oid );
291+
292+ // Now copy the file into the object.
293+ //
294+ // Note: we dont use write(buf), as the last block is rarely the same
295+ // size as our buffer, so we have to use the amount read.
296+ System .out .println ("Importing file" );
297+ int s ,t =0 ;
298+ while ((s =fis .read (buf ,0 ,buf .length ))>0 ) {
299+ System .out .println ("Block s=" +s +" t=" +t );t +=s ;
300+ blob .write (buf ,0 ,s );
301+ }
302+
303+ // Close the object
304+ System .out .println ("Closing blob" );
305+ blob .close ();
306+
307+ // Now store the entry into the table
308+
309+ // As we are a different thread to the other window, we must use
310+ // our own thread
311+ stat =db .createStatement ();
312+ stat .executeUpdate ("insert into images values ('" +name +"'," +oid +")" );
313+
314+ // Finally refresh the names list, and display the current image
315+ ImageViewer .this .refreshList ();
316+ ImageViewer .this .displayImage (name );
317+ }catch (Exception ex ) {
318+ label .setText (ex .toString ());
319+ }finally {
320+ // ensure the statement is closed after us
321+ try {
322+ if (stat !=null )
323+ stat .close ();
324+ }catch (SQLException se ) {
325+ System .err .println ("closing of Statement failed" );
326+ }
242327}
243-
244- // Close the object
245- System .out .println ("Closing blob" );
246- blob .close ();
247-
248- // Now store the entry into the table
249- stat .executeUpdate ("insert into images values ('" +name +"'," +oid +")" );
250- stat .close ();
251-
252- // Finally refresh the names list, and display the current image
253- refreshList ();
254- displayImage (name );
255- }catch (Exception ex ) {
256- label .setText (ex .toString ());
257328 }
258329 }
259330 }
@@ -364,7 +435,7 @@ public static void main(String args[])
364435 }
365436
366437try {
367- Frame frame =new Frame ("PostgreSQL ImageViewer v6.3 rev 1" );
438+ Frame frame =new Frame ("PostgreSQL ImageViewer v6.4 rev 1" );
368439frame .setLayout (new BorderLayout ());
369440ImageViewer viewer =new ImageViewer (frame ,args [0 ],args [1 ],args [2 ]);
370441frame .pack ();