Java Notes

no guarantee

Last change May 21, 2005 AD

Index


Notes

Packages

To make your source file to be part of a package, type in the source "package package_name;".

Packages & Directories

         It may be a bit confusing, when you start using packages. Suppose we have directory java/mypackage and our source files, that form the package 'mypackage', are in this directory:
This is our file/directory structure:
java> ls
 mypackage
java> ls mypackage
 MyInterf.java
 MyImpl.java

Compile .java source by javac:
java/mypackage> javac MyInterf.java MyImpl.java

Compile .class source by rmic (assume we want to use RMI) - notice we are in java/ and we don't mention the extension:
java> rmic mypackage.MyImpl

And, finally, let's run it by java (if we indeed use RMI, we have to run rmiregistry first) - notice we are in java/ and we don't mention the extension:
java> java mypackage.MyImpl

Packages revisited

        It can be even more tricky, if you have your code spread over more packages. Assume we have the following directory (and file) structure:
                       home
                           |- worm
                                     |- net
                                     |      |- Network.java
                                     |
                                     |- chat
                                             |- ChatMessage.java
Our main package is "worm" and it contains two sub-packages: "net" and "chat". The directory "worm" is in our home directory.
That's why we have the following:
    In ChatMessage.java there is      : "package worm.chat;"
    In Network.java there is  the line  : "package worm.net;"
Assume also, that the source Network.java uses the class ChatMessage. For that purpose, we add one more line into our source:
    In Network.java there is the line: "import worm.chat.ChatMessage;"
Now, how do we compile it? We go to the home directory, FIRST compile  ChatMessage.java and then Network.java, which depends on ChatMessage.java . See:
Ex (the compiler's output not shown):
home> ls
  worm
home> javac worm/chat/ChatMessage.java
home> javac worm/net/Network.java

Security


- run "policytool" to create/change a policy file (see this article- also about cryptography and security in general, in Java)
- the policy file for your application is in the java.security.policy system property
- if you run a program and set policy to a non-existing file, java won't tell you it can't find the file, so you may believe everything is OK, until something doesn't work because it hasn't the permission it
needs (I guess that if java doesn't find the policy file, it uses the default one)

Granting permission (copied from the article mentioned above):
***
                   When granting permissions, you can base them on who signed the code, where the code came from (the codebase), or grant them to everyone.
                   The java.security.Permission class serves as the base class of all 1.2 permission-related classes. What an actual grant statement
                   looks like in the policy file follows. This would allow write access to the local temporary directory, and all subdirectories recursively, for code
                   signed by JavaJoe and downloaded from http://www.TrustedUserHome.foo. If an asterisks (*) was used instead of a dash (-), the
                   permissions would be for only the specific directory, not its subdirectories, also.

            grant signedBy "JavaJoe", codeBase
                       "http://www.TrustedUserHome.foo" {
                    permission java.io.FilePermission "c:\\temp\-";
                   }
***

For checking the current permissions, you can use AccessController.checkPermission (Permission perm) - if the permission is not granted, it throws the
AccessControlException that is a subclass the SecurityException. "perm" is obtained by a constructor (which takes, e.g., an object and the operation that shall be performed as
parameters). (System does the checking for permissions by itself, except for your own defined perm.).
 


Networking

 

Networking Notes

 

RMI 1 - notes


Note: 'remote object' is also called 'remote service' (for it indeed provides a service to the callers) (and 'service' is wide used, e.g. for rmiregistry)
Terminology:
 

Notes:

 

Registry

Remote Class Loading

See RMIClassLoader.
Used for example if the client is an applet (a browser needs to download the applet and all the other classes)
 
 

Errors (Exceptions):


   1.Connection refused
     a) when running the client:
     java.rmi.ConnectException: Connection refused to host: 130.236.230.140; nested exception is:
      java.net.ConnectException: Connection refused
     This may mean that the server class or rmiregistry is not running (by 'server class' I mean the class which creates&binds the remote interface implementation, in its main() method.
     b) when running the server:
     - the same output as above, only instead of the IP number you will see 'localhost'
     In this case it's likely that rmiregistry is not running.


 

RMI 2 - complete example

(source: Java for Practitioners, John Hunt)

Part 1 - server

To use RMI do:
  1. define a remote interface (which specifies what methods are available remotely)
  2. subclass an appropriate RMI server class ("server" implements the rem.interface)
  3. run the rmic compiler on the server class (=>generates stub and skeleton files)
  4. register the remote object with the RMI registry (contains bindings name-reference)

ad 1) def. rem. interface

  1. def. new interface
  2. make the interface extend the interface java.rmi.Remote
  3. def. any methods which are going to be available remotely (must by public)
  4. each method must declare that it throws the java.rmi.RemoteException

  5. Note: the interface may contain only 'remote' methods.
Ex(the package stuff not needed):
package myrmi;
public interface MyInterface extends java.rmi.Remote {
    public String sayHi(String name) throws java.rmi.RemoteException;
}

ad 2) subclass server

- implements the remote interface Ex:
package myrmi;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class RMIServer extends UnicastRemoteObject implements MyInterface{
    public RMIServer() throws RemoteException {
        super();
        try {
                System.setSecurityManager(new RMISecurityManager());
                Naming.rebind("//www.liu.se/~yak/RMIServer",this);/* bind name and reference in registry, so a client can search there for "RMIServer" and obtain a reference to it */
        } catch (Exception e) {
                System.out.println("RMIServer error"+e.getMessage());
                e.printStackTrace();
        }
    }//constructor

/*implementation of the interface method*/
    public String sayHi(String name) throws java.rmi.RemoteException {
    return "Hi "+name;
  }

    public static void main(String args[]){
        try {
            new RMIServer();
        } catch (RemoteException e) {
                System.out.println("RMIServer error"+e.getMessage());
                e.printStackTrace();
        }
    }
}// server class

ad 3) runing the rmic compiler

After the server class is defined and successfully compiled by a normal compiler (javac), rmic applies to a .class file.
Ex: $> rmic myrmi.RMIServer // myrmi is the name of the package into which the file belongs
Produces RMIServer_Skel.class and RMIServer_Stub.class
- used for the communication between the server (Skel file) and a client (Stub file, works as a proxy)

ad 4) starting the registry

The registry service must be started, so clients can use it.
Ex (Windows): C:\> start rmiregistry 1234 // if start isn't available, use javaw; 1234 is port number, by default 1099
Ex (UNIX): $> rmiregistry // I just guess it works in this way ...
Then, when the registry runs (def. on port 1099), you can start the server.
Ex: $> java myrmi.RMIServer  // don't forget RMIServer implements the main() method ...
That's all!

Part 2 - client

Ex:
package myrmi;
import java.rmi.*;

public class RMIClient {
    public RMIClient() {
        try {
            // get reference to remote obj.from the rmiregistry:
            MyInterface remobj = (MyInterface) Naming.lookup("//www.liu.se/~yak/RMIServer");
            // invoke a remote method
            System.out.println( remobj.sayHi("Dick") );
        } catch(Exception e) {
                System.out.println("RMIClient error"+e.getMessage());
                e.printStackTrace();
        }

    }// constructor

    public static void main(String args[]){
        new RMIClient();
    }
} // client class

Sockets

Sockets & ObjectInput/OutputStream



Threads

Note: instead? of threads you can use java.util.Timer or javax.swing.Timer

(source: Java for Practitioners, John Hunt)
- independently running processes
Possible states: runable([R]), sleeping([S]), waiting([W]), interrupted([I])
start()->[R]-sleep()->[S]-time out()->[R]
             [R]-wait()->[W]-notify()->[R]
[?]-interrupt()->[I]
[?]-stop()->dead

Creating a thread

Debugging - it's quite a good idea to use the optional string parameter of the thread constructor, so when you use jdb you'll know what thread is it talking about (name "serverListenThread" is surely better than "Thread-0")

Some methods:

start(), stop(), sleep(long ms)
isAlive()  /*started execution and hasn't been stopped yet*/, isInterrupted()

Synchronization

  1. synchr. methods inside the same class (it means that only 1 of the can run at a time; if another wants to run. must wait till the running one finishes). Use 'synchronized' keyword in the method definition: public synchronized void method(){...} There is one more way (to synchr. only a part of a method)
  2. synchr. 2 threads (thread tTwo waits until tOne finishs): (in the body of tTwo) ... tOne.join() ... code executed after tOne terminates

Thread interaction

- uses wait(), notify() [only the 1st waiting thread unblocked] and notifyAll()
- a "common object" use for the interaction; the methods above must be used in a block synchronized on the common object
Ex (2 threads, one removing things from a queue object, another adding):
// inside the thread that removes:
synchronized (queue) {
    queue.wait(); // wait until something is inserted into the queue
    newData = queue.next();
}
// inside the thread that adds:
synchronized (queue) {
    queue.add(some_object);
    queue.notify(); // unblock the first thread waiting for this queue
}

JavaBeans

(source: Java for Practitioners, John Hunt)
See http://java.sun.com/beans/ for documentation. Also Java in Nutshell, O'Reilly. Sun's tutorials.
A class is a bean if either it follows the bean naming convention or it defines the BeanInfo object.
If a bean has a visual appearance, it must subclass the AWT Component (or some of its subclasses). (True at least when using BeanBox for the development)
Used together with "bean aware" development tool (very limited demo is the BeanBox available for free from SUN)

JavaBean is distinguished from a normal class by:

Properties:

- property itself: private <property type> <prop. name>;
- setter: public void set<Prop. name>(<property type> parameter)
- getter: public <prop. type> get<Prop. name>()
- if the property is boolean, we use in addition: public boolean is<prop. name>()
Ex: private int max; public void setMax(int par){max=par}; public int getMax(){return max;}

Events:

Naming conventions for adding/removing listeners:
- add: public void add<listener type> (<listener type> listener)
- remove: public void remove<listener type> (<listener type> listener)

Bean Notes

- normal methods must not match the conventions mentioned above
- beans communicate  via events and (public) methods

BeanInfo

If you use BeanInfo object, it's name must be of form <BeanName>BeanInfo
Actually, BeanInfo is an interface. The JavaBean API includes some implementations (e.g. SimpleBeanInfo)

BeanBox tool

- simple tool for developing beans.
Requires the bean files to be placed in a .jar file and either located in jars directory or loaded from another dir. using BeanBox file menu command "load jar". The .jar file must contain a manifest file, which contains lines similar to the following (tells what files are beans):
Ex (manifest.tmp file):
...
Name: package_name/file_name.class
Java-Bean: False
...

JAR archives

Sun: jar - the basics
        Jar archive is a single archive containing [compressed] files (not only .java) and so called manifest file, that describes the content of the jar archive. A very simple manifest file is created by default. To be able to use the advanced features of jar archives, you must edit it. (see sun's intro). For example, if the jar archive is your packed application and you want it to be runnable, you must add a line similar to the following one into the manifest file: Main-Class: classname, where classname is the name of the class containing the main() method.

Creating jar file:

C:\> jar myfile.jar manifest.tmp *.class
- put all .class files in the current directory and the manifest.tmp as the manifest file into a jar archive called myfile.jar
$> jar cvf jar-file *.java
- puts all .java files (in the current dir.) into jar-file (c-create, v-verbose, f-output file [must be the last])

Extracting jar file:

$> jar xf jar-file [archived-file(s)]
- archived-file(s) are the files to be extracted; if omitted, all will be extracted
$> jar tf jar-file
- lists the content of jar-file

Creating and executing executable jar file:

Old way (java 1.1):
Suppose you have a package called worm that contains the main class Worm.java (respectively Worm.class)
$> ls
worm/
$> find worm/ -name '*.class' | xargs jar cf worm.jar
- create a jar archive.
The first part("find ... xargs") finds all the .class files in worm/ and supplies them as the input parameter for jar.
$> java -cp worm.jar worm.Worm
- run the jar, look for the main method in worm.Worm

New way (java >= 1.2)
Though I have java 2SDK, version > 1.3, I haven't managed to used the new way (though I followed the instruction). It should work as follows:
$> find worm/ -name '*.class' | xargs jar cmf main.txt worm.jar
- create jar archive, merge the manifest with the specified file; in this case, main.txt contains a single line: "Main-Class: worm.Worm"
$> java -jar worm.jar
-run the package. For me it always throws "Failed to load Main-Class manifest attribute from worm.jar". I wonder why.


GUI and Graphics in Java

- AWT, Swing, Java2D .

AWT

Notes: Basic classes: Frame(window frame), Component(=widget; displayed in a frame), Container (subclass of component, contains other components; e.g. Panel subclass)
jawa.awt package:
Component (abstract)
 |
 |-- Canvas
 |-- Container (abstract)
        |
        |-- Window (windows with no borders/menus)
        |        |
        |        |-- Frame (has borders, title, frame buttons: close, min.,max.)
        |        |-- Dialog
        |                |
        |                |-- FileDialog
        |
        |-- Panel
                |
                |-- Applet (java.applet package)

Enable closing your window (probably a subclass of Frame):

  1. let your window implement the WindowListener
  2. in its constructor, call addWindowListener(this)
  3. define the listener's methods (must be public) - leave them empty (methodName(..){}) , except:

  4. public void windowClosing(WindowEvent we){ System.exit(0); }
    OR
To react to an event: 1) implement ActionListener and 2) define public void actionPerformed(ActionEvent ae)

LayoutManager
GridBagLayout (gbl) is one of the most advanced; requires a GridBagConstraints (gbc) object to be used
1. set constraints (gdc.weightx=?,.weighty,.fill,.gridx[column],.gridwidth[how many columns occupies] etc.)
2. apply the constraints(before adding a component): gbl.setConstraints(Component toBeAdded, gbc)
3.add component to the container (add(toBeAdded);)

Swing

javax.swing package (for JDK 1.2; for 1.1 it's com.sun.java.swing)

Layouts etc.

BorderLayout
Guarantees to its components their preferred sizes. When it grows, the change is distributed as follows:
GridBagLayout
More about layouts -see links.

Java2D

Animation

I assume that the animation is done in the paintComponent(Graphics g) method (it's for Swing what paint() is for AWT), which is called from time to time (probably by a thread, using the repaint() method). I use rotation and movement (translation) of the coordinate system to make the effect of an object moving in various directions. That's easy. The problem is to remember the current position & orientation between calls of the paintComponent(), so that in the next call we continue where we stopped in the last one.
  1. in the first call initialize a non-local variable of the type AffineTransform , called e.g. aAT, to contain the identity transform (aAT = new AffineTransform; does it). Use this way, not aGraphics2D.getTransform()!
  2. all the transforms (rotations, translations) you want to apply to your object, apply to aAT (e.g. aAT.translate(30,0) or aAT.rotate(Math.PI, rotationCentre.x, rotationCentre.y) )
  3. before you draw the object, apply the transformation done so far to the graphics object, via its .transform(...) method. Don't use setTransform(...)! The trouble with .getTransform() and .setTransform(...) is that they sometimes give strange results, especially if you use them to get, remeber and restore a transform between calls. They should be used only inside one call, to get and reset the unchanged transform (e.g. at the very beginning you use getTransform, then you apply a transform for one of your objects via .transform(...), then you reset the initial transform via setTransform and apply a transform - via .transform(...) - for another object).

  4. Ex: aGraphics2D.transform(aAT);

Note: if you apply a new transform (e.g. .rotate(Math.PI)) to the aAT, it's concatenated on the 'top' of the previous ones. You can think about it as if the aAT first performed all the old transforms and then, in the end, the last one you have added. The order here is important. It's different if you first translate and then rotate or if you first rotate and then translate.

Backwards mapping

If you have an AffineTransform object, aAT and you know a point in a coordinate system with respect to aAT (i.e. the point in the coordinate system created by applying aAT) and you want to know what are the point's coordinates in the space not transformed by aAT (i.e. in the original space), you can use aAT.transform(Point2D pointInaAT, Point2D pointInOriginalCoordinates);
Example:
AffineTransform aAT = new AffineTransform();
aAT.translate(50, 80); // move to the coordinates [50,80] in the original-static- space
Point2D pointInaAT = new Point2D.Double(0,0); // origin of the coordinates transformed by aAT
Point2D pointInOriginalCoordinates;
aAT.trasnform(pointInaAT, pointInOriginalCoordinates)
System.out.println("Position of pointInaAT in the static coord. system is: "+ pointInOriginalCoordinates); // prints out values [50, 80]
.
 

Strings

RegExps: Pattern & Matcher

String text = "11 22    3.33 a string to be matched"
// 1. Create a pattern
// Here: something line " int int float any_text...". \\s = whitespace, \\d = decimal.
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\s*\\d+){2}(\\s*\\d+\\.\\d+).*");
// 2. Get a matcher for it
java.util.regex.Matcher matcher = pattern.matcher( text );
// 3. Find a match. The matcher remebers its position (last match) in the string.
// Find the next match and print it. group can only be called after a successful find.
if( matcher.find() ){ System.out.println( matcher.group() ); }
// 4. Reset the matcher to start searching the string from the beginning.
matcher.reset()     // Reset its inernal state => find() would find the first match

File I/O

Write/read a string into/from a file:

import java.io.*;

PrintWriter writer;
File file = new File("myfilename");
try { file.createNewFile(); } catch (IOException e) {/*do something*/}
try { writer = new PrintWriter( (new FileOutputStream(file)), true);/*autoflush on*/ } catch (FileNotFoundException e) {/*do something*/}
writer.print("something"); /*or println */
/* ... */ writer.close();

---
try { 
    BufferedReader reader = new BufferedReader ( new FileReader("myfilename") );
    String s = reader.readline();
} catch (IOException e) {/*do something*/}
reader.close();

JavaDoc Comments

- see Sun guide to javadoc comments and javadoc reference.(short overview of what is discussed in the guide).

- run javadoc (include a list of all packages adn subpackages in the project):
$> javadoc -d mydir/ -private -windowtitle 'WormDoc' worm worm.bug worm.net worm.chat

- used when generating HTML documentation via javadoc
- of the form /** comment */
- keywords: @author, @version,, @see (what shall the reader read else, form package.Class#method(type,...)),
        (function:) @param(required, form @param name type description), @return(required unless void or constructor), @exception

- HTML tags may be embedded
- break each line that has over 80 characters

- javadoc omitts some tags by default (author, version). May be changed by options when running the javadoc( e.g.- author, -version)
- use -d flag to specify the destination folder: $> javadoc -d mydirectory/HTML MyClass.java

Style etc.
- the first sentence (closed be period followed by space/tab/line break) shall be on overview of the class/method
- use <code></code> tag for keywords, package names etc.
 

Ex:
/**
  *  This counts the number of drivers killed per month.
  *
  *  @author Jakub Holy
  *  @see CountAccidents
  *  @param highway_part part of the highway we are interested in
  *  @exception TooManyDeadException rised when the number of dead exceeds MAX_DEAD
  */
...

jdb debugger

Since I'm used to gcc, I think that jdb is a bit crappy, but sometimes you have no other choice than to use it.

Other

synchronized key word

Used to synchronize threads on an object (so that only one thread can access the object at time, the others have to wait).
Use:
  1. synchronized method method() of an object obj: if a thread calls obj.method(), the other threads who call obj.method() (on the same object) have to wait until its call returns. (Note: also static methods may be synchronized)
  2. synchronized block of statements has the form: synchronized(object){ statements }. Only one thread may be executing the block (the statements) for the object at time.

Makefile for Java

You can use the make utility for java as well as for c or c++. See an example makefile (tested both with make and gmake) or a more advanced example2.

GCJ - GNU Java Compiler

My version of gcj: cygwin gcj 3.2; Today: June 1 2003

Limitations of GCJ
Notes

Compile (Java to native code):

1> gcj -c mypackage/MyJavaProg.java
2> gcj --main=mypackage.MyJavaProg -o myprog.exe mypackage/MyJavaProg.o

Or both in one step:
> gcj --main=mypackage.MyJavaProg -o myprog.exe mypackage/MyJavaProg.java

- Flags: '-c' = compile to object (.o), '-o name' =  give name to the output, --main tells gcj name of the class that contain the main() method that shall be run
- Other flags for the 1st line: '-C' = compile to .class, '-ggdb' create debug info. for gdb, -On where n=nothing or 0..3; perform optimization of the given level, 0 implies no optimization.
- It seems to be better to compile like this, not .java->.class->.exe (less troubles).

If you compile with cygwin gcj 3.2 it prints pretty often a warning like this: "/cygdrive/c/TEMP/cczKbTsy.s:93: Warning: .stabs: description field 'a0006' too big, try a different debug format". It's a bug in the compiler itself which prevents it from creating debug info thus making it produce useless information about exceptions. GCJ produces by default some debugging info in the stabs format (hence '.stabs'). It's highly recommended to use another - not buggy - debug format (-gdwarf-1, -gvms, -gxcoff etc.).

Debug with GDB

You must set GDB to ignore the signals used by Java garbage collector:

(gdb) handle SIGPWR nostop noprint
(gdb) handle SIGXCPU nostop noprint

GCJ Links

Compiling Java with GCJ, Debugging Java with GDB


NetBeans Integrated Development Environment

version 4.0

Compile with "-deprecation": Tools->Options->Building->Ant Settings, click to the right of "Properties" (...), type on a new line "javac.deprecation=on".

Create a new GUI JavaBean that can be added to the Palette: see NetBeans: the Definitive Guide. It refers to an older version but still it's usable.

version 3.5.1

Create new project using CVS (a versioning system)

Out of NetBeans:

  1. Create a directory (you want to hold the project in)
  2. Add it to a CVS repository (how to); don't forget to check it out and work with that version (to ensure that Cvs subdirectory is there).

Inside NetBeans:

  1. Create a new project (Project->Project Manager, click "New")
  2. Mount your directory as a CVS repository (File->Mount Filesystem, select Version Control->CVS; enter required info [connection method is perhaps "Local"])

Links

SUN:

Others: