Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Easy Learn Java: Programming Articles, Examples and Tips - Page 437


Previous 1060 Stories (530 Pages, 2 Per Page) Next

Inner-class Listeners

Go to all tips in Java Notes by Fred Swartz

Named inner class

Defining an inner class listener to handle events is a very popular style.

  • Access. Use an inner class rather than an outer class to access instance variables of the enclosing class. In the example below, the myGreetingField can be referenced by the listener class. Because simple program listeners typically get or set values of other widgets in the interface, it is very convenient to use an inner class.
  • Reuse. Unlike anonymous inner class listeners, it's easy to reuse the same listener for more than one control, eg, the click of a button might perform the same action as the equivalent menu item, and might be the same as hitting the enter key in a text field.
  • Organization. It's easier to group all the listeners together with inner classes than with anonymous inner class listeners.

Examples

See Lesson 7 - DogYears - Listeners

Partial source code to share one inner class listener

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
// File:  : events/SomePanel.java
// Purpose: Show use of named inner class listener.
// Author : Fred Swartz
// Date   : 2005-09-05

import javax.swing.*;
import java.awt.event.*;

class SomePanel extends JPanel {

    private JButton    myGreetingButton = new JButton("Hello");
    private JTextField myGreetingField  = new JTextField(20);

    //=== Constructor
    public SomePanel() {
        ActionListener doGreeting = new GreetingListener();
        myGreetingButton.addActionListener(doGreeting);
        myGreetingField.addActionListener(doGreeting);
        // . . . Layout the panel.
    }


    /////////////////////////// Define inner class as listener.
    private class GreetingListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            myGreetingField.setText("Guten Tag");
        }
    }
}

Getting the name or actionCommand from a button

If you have a listener for a button, you might wonder why you need to get the text that labels the button. A common reason is that you have a number of buttons (eg, the numeric keypad on a calculator) that do almost the same thing. You can create one listener for all the keys, then use the text from the button as the value.

getActionCommand(). By default the getActionCommand() method of an ActionEvent will return the text on a button. However, if you internationalize your buttons so that the show different text depending on the user locale, then you can explicitly set the "actionCommmand" text to something else.

Let's say that you want to put the button value at the end of the inField field as you might want to do for a calculator. You could do something like below (altho checking for overflow).

 JTextField inField = new JTextField(10);
 . . .
// Create an action listener that adds the key name to a field
ActionListener keyIn = new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Get the name of the button
        String keyNum = e.getActionCommand(); // "1", "2", ...
        inField.setText(inField.getText() + keyNum);
    }
};

// Create many buttons with the same listener
JButton key1 = new JButton("1");
key1.addActionListener(keyIn);
JButton key2 = new JButton("2");
key2.addActionListener(keyIn);
JButton key3 = new JButton("3");
key3.addActionListener(keyIn);
 . . .


comments? | Printer Friendly Page  Send to a Friend | Score: 0
Posted by jalex on Tuesday, February 21, 2006 (21:00:00) (2592 reads)

Counting bytes on Sockets

Go to all tips in Story by Dr. Kabutz

The Java Specialists' Newsletter [Issue 058]

Author: Dr. Heinz M. Kabutz

JDK version:

Category: Performance

If you are reading this, and have not subscribed, please consider doing it now by going to our subscribe page [http://www.javaspecialists.co.za/archive/subscribe.jsp]. You can subscribe either via email or RSS.


Welcome to the 58th edition of The Java(tm) Specialists' Newsletter sent to 4814 Java Specialists in 86 countries [http://www.javaspecialists.co.za/countries.jsp] .

Counting bytes on Sockets

Background

At the end of 2001, William Grosso [http://www.wgrosso.com] , author of Java RMI, offered to send me a copy of his newly published book. William is a keen reader of our newsletter, and wanted to thank me for publishing it. (I am not hinting that I expect gifts from my readers Wink Being a technical bookworm, I was quite excited to get my hands on the book, although I was not too excited about the title. How interesting could a book about RMI be?!?

The book arrived, and I started reading it here and there, and I quickly noticed that it was far more than the typical Java books that only contain a beautified view of the Java APIs. It is actually a book about distributed computing, and includes chapters on threads, serialization, and such topics. Infact, only half the book is about RMI, the rest is about writing distributed applications.

I did not have the time to finish reading the book before I went to Germany during March and April 2002. Having two little children to take with, we were pressed for space, so the Java RMI book stayed in South Africa. One of my tasks in Germany was to improve the performance of an application server and naturally, one of the hotspots we looked at was the RMI communication. Remembering Bill's book, I promptly went to a local bookshop and bought another copy (that's how useful I found it!).

One of the things we wanted to look at was the number of bytes transferred over the network from and to the application server. This is where the book came in. It showed me how to specify my own socket factory for RMI and how to link in my own counting stream.

This newsletter is therefore based on ideas gleaned from Java RMI. Some parts of the book are not very advanced, and it has parts of Java in there that do not seem to fit into a book on "Java RMI". Perhaps a different title would have been better. However, there are things in the book that have really helped me improved RMI communication when I did not know where to turn. I therefore recommend the book to both beginners in RMI and those who have already used RMI a bit.


The actual code

When I used these tricks in Germany, I hacked the java.net.Socket class and added support for counting bytes. I did that because it was the easiest way, however, you can get into trouble legally if you ship such a hacked class by mistake. For this newsletter, I wanted to go the "right" way by providing an RMISocketFactory.

The first thing we need if we want to count the bytes is to have two decorators for the input and output streams. To me, just knowing how many bytes were flowing past was not enough. I also wanted to be able to open the bytes in a hex editor (yeah, baby, yeah) to see what bytes were passed around. Please meet, the DebuggingInputStream (lots of applause):

import java.io.*;
import java.net.Socket;

/**
 * This class counts the number of bytes read by it before 
 * passing them on to the next Inputstream in the IO chain.
 * It also dumps the bytes read into a file.
 * Should probably specify a factory for making the file
 * names, however, there is enough stuff to show here without
 * such an extra.
 */
public class DebuggingInputStream extends FilterInputStream {
  // Static data and methods
  private static long totalCount = 0;
  private static long dumpNumber =
    System.currentTimeMillis() / 1000 * 1000;
    
  private synchronized static String makeFileName() {
    return "dump.read." + dumpNumber++ + ".log";
  }
  public synchronized static long getTotalCount() {
    return totalCount;
  }

  // Non-static data and methods
  private final OutputStream copyStream;
  private long count = 0;

  public DebuggingInputStream(Socket socket, InputStream in)
      throws IOException {
    super(in);
    String fileName = makeFileName();
    System.out.println(socket + " -> " + fileName);
    copyStream = new FileOutputStream(fileName);
  }

  public long getCount() {
    return count;
  }

  public int read() throws IOException {
    int result = in.read();
    if (result != -1) {
      synchronized (DebuggingInputStream.class) {
        totalCount++;
      }
      copyStream.write(result);
      count++;
    }
    return result;
  }
  public int read(byte[] b) throws IOException {
    return read(b, 0, b.length);
  }
  public int read(byte[] b, int off, int len)
      throws IOException {
    int length = in.read(b, off, len);
    if (length != -1) {
      synchronized (DebuggingInputStream.class) {
        totalCount += length;
      }
      copyStream.write(b, off, length);
      count += length;
    }
    return length;
  }
  public void close() throws IOException {
    super.close();
    copyStream.close();
  }
}

We have a similar class for the OutputStream. Both these classes contain hardcoded values, like for example the filename generation, the fact that it actually passes the data to a file, etc. Obviously, that is not pretty, and could be refactored.

import java.io.*;
import java.net.Socket;

public class DebuggingOutputStream extends FilterOutputStream {
  // Static data and methods
  private static long totalCount = 0;
  private static long dumpNumber =
    System.currentTimeMillis() / 1000 * 1000;

  private synchronized static String makeFileName() {
    return "dump.written." + dumpNumber++ + ".log";
  }

  public synchronized static long getTotalCount() {
    return totalCount;
  }

  // Non-static data and methods
  private final OutputStream copyStream;
  private long count = 0;

  public DebuggingOutputStream(Socket socket, OutputStream o)
      throws IOException {
    super(o);
    String fileName = makeFileName();
    System.out.println(socket + " -> " + fileName);
    copyStream = new FileOutputStream(fileName);
  }

  public long getCount() {
    return count;
  }

  public void write(int b) throws IOException {
    synchronized (DebuggingOutputStream.class) {
      totalCount++;
    }
    count++;
    out.write(b);
    copyStream.write(b);
  }
  public void write(byte[] b) throws IOException {
    write(b, 0, b.length);
  }
  public void write(byte[] b, int off, int len)
      throws IOException {
    synchronized (DebuggingOutputStream.class) {
      totalCount += len;
    }
    count += len;
    out.write(b, off, len);
    copyStream.write(b, off, len);
  }
  public void close() throws IOException {
    super.close();
    copyStream.close();
  }
  public void flush() throws IOException {
    super.flush();
    copyStream.flush();
  }
}

Next, let us look at our implementation of Socket, called MonitoringSocket. When you look inside java.net.Socket, you can see that all the calls get delegated to a SocketImpl class. The data member inside Socket is called impl and it is package private, meaning that it can be accessed and changed from other classes in the same package. I know what you're thinking - surely that does not happen?! Yes it does - java.net.ServerSocket sometimes sets the impl data member of Socket to null. When we then try and print the socket to the screen in the dump() method, we get a NullPointerException. We therefore have to do some hacking to check whether impl is null and if it is, we skip over it. We still want to keep a handle to that socket, because impl might be set to another value later.

The rest of MonitoringSocket is fairly straight forward. We have a monitoring thread that once every 5 seconds dumps the active sockets. Yes, it is again hard-coded, but this is debugging code, not production code.

We then have a non-static initializer block and two constructors. At compile time, the contents of the non-static initializer blocks are copied into the beginning of the constructors (after the call to super()). We only show the two constructors needed for the socket factories, the no-args constructor and the one taking a hostname as String and the port.

We obviously also override the getInputStream() and getOutputStream() methods to return DebuggingInputStream and DebugggingOutputStream instances respectively.

import java.io.*;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.net.*;
import java.util.*;

public class MonitoringSocket extends Socket {
  // keep a list of active sockets, referenced by SoftReference
  private static final List sockets = new LinkedList();

  private static void dump() {
    System.out.println("Socket dump:");
    System.out.println("------------");
    System.out.println("Total bytes"
        + " read=" + DebuggingInputStream.getTotalCount()
        + ", written=" + DebuggingOutputStream.getTotalCount());
    // print all the sockets, and remove them if the Soft
    // Reference has been set to null.
    synchronized (sockets) {
      Iterator it = sockets.iterator();
      while (it.hasNext()) {
        SoftReference ref = (SoftReference)it.next();
        MonitoringSocket socket = (MonitoringSocket)ref.get();
        if (socket == null)
          it.remove();
        else if (!socket.isImplNull())
          System.out.println(socket);
      }
    }
    System.out.println();
  }

  private static Field socket_impl = null;
  static {
    try {
      socket_impl = Socket.class.getDeclaredField("impl");
    } catch (NoSuchFieldException e) {
      throw new RuntimeException();
    }
    socket_impl.setAccessible(true);
  }
  // Sometimes, the Socket.impl data member gets set to null
  // by the ServerSocket.  Yes, it is ugly, but I did not write
  // the java.net.* package Wink
  private boolean isImplNull() {
    try {
      return null == socket_impl.get(this);
    } catch (Exception ex) {
      return true;
    }
  }

  static {
    new Thread("Socket Monitor") {
      { setDaemon(true); start(); }
      public void run() {
        try {
          while (true) {
            try {
              sleep(5000);
              dump();
            } catch (RuntimeException ex) {
              ex.printStackTrace();
            }
          }
        } catch (InterruptedException e) {} // exit thread
      }
    };
  }

  private DebuggingInputStream din;
  private DebuggingOutputStream dout;

  { // initializer block
    synchronized (sockets) {
      sockets.add(new SoftReference(this));
    }
  }
  public MonitoringSocket() {}
  public MonitoringSocket(String host, int port)
      throws UnknownHostException, IOException {
    super(host, port);
  }

  private long getBytesRead() {
    return din == null ? 0 : din.getCount();
  }

  private long getBytesWritten() {
    return dout == null ? 0 : dout.getCount();
  }

  public synchronized void close() throws IOException {
    synchronized (sockets) {
      Iterator it = sockets.iterator();
      while (it.hasNext()) {
        SoftReference ref = (SoftReference) it.next();
        if (ref.get() == null || ref.get() == this) {
          it.remove();
        }
      }
    }
    super.close();
    if (din != null) { din.close(); din = null; }
    if (dout != null) { dout.close(); dout = null; }
  }
  public InputStream getInputStream() throws IOException {
    if (din != null) return din;
    return din =
      new DebuggingInputStream(this, super.getInputStream());
  }
  public OutputStream getOutputStream() throws IOException {
    if (dout != null) return dout;
    return dout =
      new DebuggingOutputStream(this, super.getOutputStream());
  }
  public String toString() {
      return super.toString()
        + " read=" + getBytesRead()
        + ", written=" + getBytesWritten();
  }
}

The next job is to find all the places in RMI where sockets are created. The most obvious place is in the ServerSocket, so let us change that first:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class MonitoringServerSocket extends ServerSocket {
  public MonitoringServerSocket(int port) throws IOException {
    super(port);
  }
  public Socket accept() throws IOException {
    Socket socket = new MonitoringSocket();
    implAccept(socket);
    return socket;
  }
}

Next, we need to tackle the place where RMI creates sockets. RMI provides the ability to specify your own socket factory inside the java.rmi.server.RMISocketFactory class. The default socket factory provided by Sun is the sun.rmi.transport.proxy.RMIMasterSocketFactory class, and contains logic for reusing sockets. It is quite a sophisticated beast, not something that you want to write an ad-hoc implementation for. We could write our own RMISocketFactory to always create a new socket, but then we are not seeing an accurate reflection of what RMI actually does. I found the best approach (besides simply modifying java.net.Socket) is to extend the default socket factory provided by Sun, but there is a catch: Sun's socket factory delegates the actual creation to another instance of RMISocketFactory, i.e. it is just a Decorator for a plain socket factory. The handle to the decorated object is called initialFactory, so what I did was to make that handle point to an instance of RMISocketFactory that created my MonitoringSocket and MonitoringServerSocket classes. There is another catch that I did not address in my code. Sometimes, when you want to speak RMI from behind a firewall, Sun's socket factory creates a socket that can speak over HTTP or CGI interfaces. I do not cover that case, I only cover normal sockets.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;
import sun.rmi.transport.proxy.RMIMasterSocketFactory;

public class MonitoringMasterSocketFactory
    extends RMIMasterSocketFactory {
public MonitoringMasterSocketFactory() {
    initialFactory = new RMISocketFactory() {
      public Socket createSocket(String host, int port)
          throws IOException {
        return new MonitoringSocket(host, port);
      }
      public ServerSocket createServerSocket(int port)
          throws IOException {
        return new MonitoringServerSocket(port);
      }
    };
  }
}

How do you activate this socket factory? At some point at the start of your program, you have to say:

RMISocketFactory.setSocketFactory(
  new MonitoringMasterSocketFactory());

I'll include some sample code for those who need it:

import java.rmi.*;
import java.util.Map;

public interface RMITestI extends Remote {
  String NAME = "rmitest";
  Map getValues(Map old) throws RemoteException;
}

The implementation of that interface is shown here. It is just a dumb example of sending data backwards and forward, where the size of data being passed grows exponentially:

 
import java.io.IOException;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;

public class RMITest extends UnicastRemoteObject
    implements RMITestI {
  private final Map values = new HashMap();

  public RMITest() throws RemoteException {}

  public Map getValues(Map old) {
    synchronized (values) {
      values.putAll(old);
      return values;
    }
  }

  public static void main(String[] args) throws IOException {
    RMISocketFactory.setSocketFactory(
      new MonitoringMasterSocketFactory());
    System.setSecurityManager(new RMISecurityManager());
    Naming.rebind(RMITestI.NAME, new RMITest());
  }
}

And lastly, some client code that connects to the RMI Server and executes the method a number of times. You can see the data that gets passed backwards and forwards by looking at the dump files.

import java.io.Serializable;
import java.rmi.*;
import java.util.*;

public class RMITestClient {
  public static void main(String args[]) throws Exception {
    System.setSecurityManager(new RMISecurityManager());
    RMITestI test = (RMITestI)Naming.lookup(RMITestI.NAME);
    Map values = new HashMap();
    values.put(new Serializable() {}, "Today");
    for (int i = 0; i < 13; i++) {
      System.out.print('.');
      System.out.flush();
      values.putAll(test.getValues(values));
    }
  }
}

When we run this code, on the server side we can now see the following output:

Socket[addr=cohiba/1.0.0.1,port=1099,localport=2135] read=0, written=0 -> dump.written.1034160774000.log
Socket[addr=cohiba/1.0.0.1,port=1099,localport=2135] read=0, written=7 -> dump.read.1034160775000.log
Socket[addr=cohiba/1.0.0.1,port=2137,localport=2134] read=0, written=0 -> dump.read.1034160775001.log
Socket[addr=cohiba/1.0.0.1,port=2137,localport=2134] read=7, written=0 -> dump.written.1034160774001.log
Socket dump:
------------
Total bytes read=507, written=539
Socket[addr=cohiba/1.0.0.1,port=2137,localport=2134] read=471, written=301
Socket[addr=cohiba/1.0.0.1,port=1099,localport=2135] read=36, written=238

Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=0, written=0 -> dump.read.1034160775002.log
Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=7, written=0 -> dump.written.1034160774002.log
Socket dump:
------------
Total bytes read=460579, written=403442
Socket[addr=cohiba/1.0.0.1,port=2137,localport=2134] read=471, written=301
Socket[addr=cohiba/1.0.0.1,port=1099,localport=2135] read=36, written=238
Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=460072, written=402903

Socket dump:
------------
Total bytes read=652415, written=1052723
Socket[addr=cohiba/1.0.0.1,port=2137,localport=2134] read=471, written=301
Socket[addr=cohiba/1.0.0.1,port=1099,localport=2135] read=36, written=238
Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=651908, written=1052184

Socket dump:
------------
Total bytes read=1702402, written=1091048
Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=1701895, written=1090509

Socket dump:
------------
Total bytes read=1702402, written=2301608
Socket[addr=cohiba/1.0.0.1,port=2140,localport=2134] read=1701895, written=2301069

Socket dump:
------------
Total bytes read=1702402, written=2752353

Socket dump:
------------
Total bytes read=1702402, written=2752353

We can use this MonitoringSocket wherever RMI is used, for example, in EJB servers like JBoss. If the socket factories are too much P.T. for you (P.T. stands for Physical Training, something that computer nerds try to avoid Wink you can go and hack java.net.Socket and add the code from the MonitoringSocket in there.

I hope this newsletter will be as useful to you as it was to me. If you want to know more about these topics, please look at William Grosso's Java RMI.

A special thanks to William Grosso [http://www.wgrosso.com] for all his help in writing custom sockets.

Until the next newsletter ...

Your Java/Design Patterns/Drinking Straw specialist.

Heinz


Copyright 2000-2005 Maximum Solutions, South Africa

Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions [http://www.javaspecialists.co.za] for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

32646 bytes more | comments? | Printer Friendly Page  Send to a Friend | Score: 5
Posted by jalex on Monday, February 20, 2006 (21:00:00) (2637 reads)

Previous 1060 Stories (530 Pages, 2 Per Page) Next

530| 529| 528| 527| 526| 525| 524| 523| 522| 521| 520| 519| 518| 517| 516| 515| 514| 513| 512| 511| 510| 509| 508| 507| 506| 505| 504| 503| 502| 501| 500| 499| 498| 497| 496| 495| 494| 493| 492| 491| 490| 489| 488| 487| 486| 485| 484| 483| 482| 481| 480| 479| 478| 477| 476| 475| 474| 473| 472| 471| 470| 469| 468| 467| 466| 465| 464| 463| 462| 461| 460| 459| 458| 457| 456| 455| 454| 453| 452| 451| 450| 449| 448| 447| 446| 445| 444| 443| 442| 441| 440| 439| 438|
437
| 436| 435| 434| 433| 432| 431| 430| 429| 428| 427| 426| 425| 424| 423| 422| 421| 420| 419| 418| 417| 416| 415| 414| 413| 412| 411| 410| 409| 408| 407| 406| 405| 404| 403| 402| 401| 400| 399| 398| 397| 396| 395| 394| 393| 392| 391| 390| 389| 388| 387| 386| 385| 384| 383| 382| 381| 380| 379| 378| 377| 376| 375| 374| 373| 372| 371| 370| 369| 368| 367| 366| 365| 364| 363| 362| 361| 360| 359| 358| 357| 356| 355| 354| 353| 352| 351| 350| 349| 348| 347| 346| 345| 344| 343| 342| 341| 340| 339| 338| 337| 336| 335| 334| 333| 332| 331| 330| 329| 328| 327| 326| 325| 324| 323| 322| 321| 320| 319| 318| 317| 316| 315| 314| 313| 312| 311| 310| 309| 308| 307| 306| 305| 304| 303| 302| 301| 300| 299| 298| 297| 296| 295| 294| 293| 292| 291| 290| 289| 288| 287| 286| 285| 284| 283| 282| 281| 280| 279| 278| 277| 276| 275| 274| 273| 272| 271| 270| 269| 268| 267| 266| 265| 264| 263| 262| 261| 260| 259| 258| 257| 256| 255| 254| 253| 252| 251| 250| 249| 248| 247| 246| 245| 244| 243| 242| 241| 240| 239| 238| 237| 236| 235| 234| 233| 232| 231| 230| 229| 228| 227| 226| 225| 224| 223| 222| 221| 220| 219| 218| 217| 216| 215| 214| 213| 212| 211| 210| 209| 208| 207| 206| 205| 204| 203| 202| 201| 200| 199| 198| 197| 196| 195| 194| 193| 192| 191| 190| 189| 188| 187| 186| 185| 184| 183| 182| 181| 180| 179| 178| 177| 176| 175| 174| 173| 172| 171| 170| 169| 168| 167| 166| 165| 164| 163| 162| 161| 160| 159| 158| 157| 156| 155| 154| 153| 152| 151| 150| 149| 148| 147| 146| 145| 144| 143| 142| 141| 140| 139| 138| 137| 136| 135| 134| 133| 132| 131| 130| 129| 128| 127| 126| 125| 124| 123| 122| 121| 120| 119| 118| 117| 116| 115| 114| 113| 112| 111| 110| 109| 108| 107| 106| 105| 104| 103| 102| 101| 100| 99| 98| 97| 96| 95| 94| 93| 92| 91| 90| 89| 88| 87| 86| 85| 84| 83| 82| 81| 80| 79| 78| 77| 76| 75| 74| 73| 72| 71| 70| 69| 68| 67| 66| 65| 64| 63| 62| 61| 60| 59| 58| 57| 56| 55| 54| 53| 52| 51| 50| 49| 48| 47| 46| 45| 44| 43| 42| 41| 40| 39| 38| 37| 36| 35| 34| 33| 32| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1|


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy