Welcome, guest. You are not logged in.
Language / Choose language
 
Username Password  
Today: what do you think of this site?? · More of this
    Search
 

   

:: Java ::.:: Programming ::. - hacking your computer
19.04.2009 14:56 CEST
:: Java ::.:: Programming ::.
Vector (n) does not have n elements
In Java, arrays cannot be resized dynamically. If you want a dynamic data structure with random access, you use a Vector. A vector has a current size and a capacity, the number of elements it can ho1d without having to grow, again.
The constructor Vector (int n) builds a vector with capacity, not with size n, as a C programmer would certainly expect.
 Vector v = new Vector (100);
v.setElementAt(new Double,3.14), 0,); // throws ArrayIndex OutOfBoundsException



If you want a vector with 100 elements, use
 Vector v = new Vector(100);
v.setSize(100);
v.setElementAt(new Double(3.14), 0); // OK



Â
Hassle-free array growth
Suppose you have an array of some type that is full, and you want to grow it.
 Employee[] a = new Employee[100];
// array is full
int newLength = a.length * 11 / 10 + 10;
Employee[] newArray = new Employee[newLength];
System.arraycopy(a, 0, newArray, 0, a.length);
a = newArray;


That gets boring really quickly. Let's try to make it generic.
 static Object[] arrayGrow(Object[] a) // not usefull
{
int newLength = a.length * 11 / 10 + 10;
Object[] newArray = new Object[newLength];
System.arraycopy(a, 0, newArray, 0, a.length);
return newArray;
}
Problem: Return type is Object[], not Employee [] .
a = (Employee[]) arrayGrow(a); // throws ClassCastException.



Use reflection to make a new array of the same type:
 static Object arrayGrow(Object a) // useful
{ Class cl = a.getClass(); if (!cl.isArray()) return null; int length = Array.getLength(a);
int newLength = length * 11 / 10 + 10;
Class componentType = a.getClass().getComponentType();
Object newArray = Array.newlnstance(componentType, newLength);
System.arraycopy(a, 0, newArray, 0, length);
return newArray;
}



Typical usage:
 Employee[] a = new Employee[100]; . . . . .// array is full
a = (Employee[]) arrayGrow(a);



This arrayGrow method can be used to grow arrays of any type, not just arrays of objects.
 int[] ia = ( 1, 2, 3, 4 };
ia = (int[])arrayGrow(a);



Note that the parameter of arrayGrow is declared to be of type object, not an array of objects (Object [] ). The integer array type int [] can be converted to an object, but not to an array of objects!

Anonymous arrays
You can supply initial values to an array as follows:
  int[] primes = { 2, 3, 5, 7, 11, 13 };


If a function requires array parameters, then the traditional solution is to define and initialize an array variable and pass it to the function. For example, the getTables method of the DatabaseMetadata class requires an array of strings "TABLE", "VIEN", "ALIAS", ... to describe which kinds of tables are requested.
 String [] tables = ( "TABLE", "VIEW" );
md.getTables(null, "%", "%", tables);



Rather than introducing a new variable that is only used once, use an anonymous array
 new Type [] ( value1, value2, ... )
In our example,
md.getTables (null, "%", "%", new String[] { "TABLE", "VIEW" ) )
Use ""+x to convert x to a string



The base class Object has a method toString that subclasses redefine to print out a representation of the object. If x is any object, then x.to String()
converts it to a string. If x is a number, then you can't call x. toString (), because numbers aren't objects in Java, and you can't apply methods. Instead, you are supposed to use String.valueOf(x)

Just concatenate with an empty string:
  "" + x



This converts x to a string. If x is a number, then its value is turned into a string. If x is an object, then its toString method is invoked. There is no penalty. The Java compiler is aware of this idiom, and it does not generate code to concatenate an empty string.

The lazy programmer's version of tostring Background
It is boring to write toString for every class. The toString method usually just calls toString for every data field.
 class Employee
{ public String toString()
{ return "Employee{ + "
"name=" + name + "," +
"salary=" + salary + "," +
"hireDay=" + hireDay + "}";
}
private Stzing name;
private double salary;
private Day hireDay;
}


Use the reflection feature to enumerate and print all data fields. Here we take advantage of the fact that a Hash table has a perfectly good toString method. The only drawback is that the fields are printed in random order.
  public String toString()
{ java.util.Hashtable h = new java.util.Hashtable();
Class cls = getClass();
Field[] f = cls.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < f.length; i++)
{ try ( h.put(f[i].getName () , f[i].get (this) ); }
catch (IllegalAccessException e) { }
}
if (cls.getSuperclass () . getSuperclass () ! = null)
h.put("super", super.toString(j);
return cls.getName() + h;
}



Here is a typical printout:
  Employee(hireDay=Day[1996,12,1], salary=35000.0, name=Harry Hacker}



In Java 1.1 , you must paste the code into each class - only the class itself can peek inside its private data. In Java 1.2, use Accessible Object. set Accessible and place the code in a convenient base class

Don't catch every exception
Many Java methods throw checked exceptions. You notice them when the compiler complains:
 public void writeStack(DataOutput out)
{ for (int i = 0; i < 100; i++)
{ String s = (String) stk.pop(); // error: throws EmptyStackException
out.writeChars(n); // error: throws IOException
}
}


The first instinct is to surround each line with a try/catch clause.
  public void writeStack(DataOutput out)
{ for (int i = 0; i < 100; i++)
{ String s
try
{ s = (String)s.pop();
}
catch (EmptyStackException ese)
{// stack was empty
}
try
{ out.writeChars(s);
}
catch (IOExcep=ioe ioe)
{ // problem writing file
}
}
}



Whoa! Now the code looks really complicated. Exception handling is supposed to make exceptional situation simpler.

Find the correct place for handling the exception. Perhaps you want to have one try block that contains all commands in the method.
 public void writeStack (DataOutput out)
{ try
{ for (int i = 0; i < 100; i++)
{ String s = (String)s.pop();
out.writeChars (s);
}
}
catch (EmptyStackException ese)
{ // stack was empty
}
catch (IOException ioe)
{ // problem writing file
}
}



Or even better, try to propagate the exception
  public void writeStack(DataOutput out)
throws EmptyStackException, IOException
{ for (int i = 0; i < 100; i++)
{ String s = (String)s.pop();
out.writeChars(s);
}
}



Â

If you don't want to deal with exception handling...
When writing a quick and dirty program, it is a hassle to have to pay attention to all the exceptions that are thrown.
 public void writeStack(DataOutput out)
{ for (int i = 0; i < 100; i-.+)
{ String s = (String) stk.pop(); // compiler complains: EmptyStackE,xception
out.writeChars(n); // compiler complains: IOException
}
}


Add throws Exception after every method, even main!
 public void writeStack(DataOutput out) throws Exception
{ for (int i = 0; i < 100; itt)
{ String s = (String) stk.pop(); // compiler doesn't complain
out.writeChars(n); // compiler doesn't complain
}
}
public static void main () throws Exception
{ . . .
outFile = . . .
writeStack(outFile); // compiler doesn't complain
. . .
}



This is definitely a tactical move for prototyping only. Once you finished your code exploration, you should put the exception handling code at the proper place, and make the exception specifications of all methods precise.

Â

Use printStackTrace when an exception hits
When an exception hits, you want to know the exact circumstances under which it occurred Of course, if you don't catch the exception, the program dies with a stack trace. But if you do catch it, how do you get the stack trace?
You can get a stack trace from any exception object with the printStackTrace method in the Throwable class. The following code catches any exception, prints the exception object and the stack trace, and re throws the exception so it can find its intended handler.
  try

{ . . .
}
catch (Throwable t)
{ t. printStackTrace ();
throw t;
}




Better Buttons
Traditionally, implementing a button is done in two steps:

Add the button to the user interface in the constructor or init method
add(new JButton("Click me"));


Put the button action into the actionPerformed method
if (arg.equals("Click me")) ( /* button action goes here */ )
This separates the button creation from the button action.
Make a base class BetterButton as follows:
 abstract class BetterButton exends JButton implements ActionListener
{ public BetterButton(String label)
{ super(label);
addActionListener(this);
}
abstract void action();
public void actionPerformed(ActionEvent evt) { action(); }
}



Now you can define the label and the button action at the same time:
 add(new BetterButton("Click me") {void action(){ /* button action goes here +/ }});



Note that the action. procedure was not defined as public. That saves typing when it is redefined in the anonymous subclass. But it only works if BetterButton is in the same package as the class that creates the buttons.

Easier menus
Adding menu items and listeners by hand is incredibly tedious. Here is some code to build up a typical menu.
 JMenu m = new JMenu ("Edit");
JMenuItem mi = new JMenuItem("Undo");
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Redo");
mi.addActionListener(this);
m.add(mi);
m.addSeparator();
mi = new JMenuItem("Cut");
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Copy");
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Paste");
mi.addActionListener(this);
m.add (mi );
menuBar. add (m);


Use a procedure makeMenu to take the drudgery out of making menus. This procedure takes three parameters. The first parameter is either a string or a menu. If it is a string, makeMenu makes a menu with that title. The second parameter is an array of items, each of which is a string, a menu item or null. The makeMenu procedure makes a menu item out of each string and a separator out of each null, then adds all items and separators to the menu. The third parameter is the listener for the menu items. (We assume that all menu items have the same listener.) Here is the call to makeMenu that is equivalent to the preceding menu construction code.
 mbar.add( makeMenu( "Edit",
new Object[]
{ "Undo",
"Redo",
null,
"Cut",
"Copy",
"Paste",
}, this));



Here's the source code for the makeMenu procedure, which can easily be added to any program that requires a sophisticated menuing system.
 private static JMenu makeMenu(Object parent, Object[] items, Object target)
{ JMenu m = null;
if (parent instanceof JMenu)
m = (JMenu)parent;
else if (parent instanceof String)
m = new JMenu((String)parent);
else
return null;
for (int i = 0; i < items.length; i++)
{ if (items[i] instanceof String)
{ JMenuItem mi = new JMenuItem((String)items[i]);
if (target instanceof ActionListener)
mi.addActionListener((ActionListener)target);
m.add(mi);
}
else if (items [i] instanceof JMenuZtem)
{ JMenultem mi = (JMenuItem)items[i];
if(target instanceof ActionListener)
mi.addActionListener((ActionListener)target);
m.add(mi);
}
else if (items[i] == null)
m.addSeparator();
}
return m;
}



In Windows programs, menus are generally defined in an external resource file and tied to the application with resource identifiers. It is possible to build menus programmatically, but it is not commonly done. In Java, there are no external UI resources and menus must be built programmatically.

Â

Enumeration values in a List field
Suppose you want the user to choose a color from one of the predefined Java colors,
 Color.red
Color.yellow


The traditional solution is tedious:

Add strings to a list field


When a string was selected, use an if/else/else branch to convert it to the enum Value.
if (selection.equals("red")) color = Color.red;
else if (selection.equals("yellow")) color = Color.yellow;
else . . .


Feel bad for not having set up a hash table instead.
The problem is that color. red is the name of a constant, whereas "red" is a string object.
Use reflection to convert the strings!
Sample usage:
 new EnumList(Color.class, new String[] {"red", "yellow", . . .})
The code:
class EnumList extends JList
{ public EnumList(Class cl, String[] labels)
{for (int i = 0; i < Labels.length; i++)
{ String label = labels[i];
int value = 0;
try
{ java.lang.reflect.Field f = cl.getField(label);
value = f.getInt(cl);
}
catch(Exception e)
{ Label = "(" + label + ")";
}
table.put (label, new Integer (value i ));
}
setListData(labels);
setSelectedIndex(0);
}
public int getValue()
{ return ((Integer)table.get(getSelectedValue())).intValue();
}
private Hashtable table = new Hashtable();
}



The drawback of this trick is that it does not work for internationalization. The enumerated constants are usually in English, but your users may want to see them in the local language, i.e. ot
gelb

Don't use = to compare strings

In Java, strings are immutable. That means, you can't change a value of a string like you can in C
 string greeting = "Hello"; // C++
greeting[4] = '!'; // can't do this in Java



Of course, in Java you can replace the string to which a string variable refers.
 String greeting = "He llo"; // Java
greeting = greeting.substr(0, 4) +



The string "Hello" is unchanged, but greeting now refers to a different string.
That means, strings act just like numbers.
 int x = 5;
x++; // 5 is unchanged, but x is now 6



Strings have the look and feel of numbers in every way but one. You cannot use == to compare them.
 if {cmd == "Help!")... // no!



This code tests whether cmd and "Help! " are the identical object, not whether they have the same
contents. You must use equals.
 if (cmd.equals ("Help! ") )... // OK



It is unfortunate that the == code compiles. This is one of the few instances in Java where nonsense code
compiles without a warning. (Of course, in C++, there are lots of traps where nonsense code compiles.)

Don't return references to mutable objects
Especially for simple classes, it is common to supply accessory functions for all data fields.
 class Employee
{ public Employee(String n, double s, Day
{ name = n;
salary = s;
hireDay = d"'
}
public String getName()
{ return name;
}
public double getSalary()
{ return salary;
}
public Day getDay() // WRONG!
{ return hireDay;
}
private String name;
private double salary;
private Day hireDay;
}


Never return a reference to a mutable object. Consider the following.
 Employee harry = new Employee("Harry Hacker", 35000, new Day(1996, 10, 1,l));
Day d = harry.getDay();
d.setYear(1997); // oops--now changed Harry's hire day
Remedy: Return a clone of the field:
public Day getDay() // OK
{ return hireDay.clone ();
}



Â

EZClone with serialization
Cloning in Java is tedious to implement. You need to
have the class implement cloneable


implement the clone method
public void clone
{ try
{ X ret = super.clone();
// now clone all object data fields and" copy all number Data fields
ret.objdata1 = objdata1.clone
ret.numdata1 = numdata1;
return ret;
} catch(CloneNotSupportedException)
{ return null;
}
}


Use serialization for cloning. As long as all data fields are serializable. the entire cloning process can be automated.
 class EZClone implements Cloneable, Serializable
{ public Object clone()
try
{ ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeQbject(this);
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = in.readObject();
in.close();
return ret;
} catch(Exception e)
{ return null;
}
}
class X extends EZClone
{ // no clone necessary
}

Â

A debug window for applets
When you debug an applet inside a browser (especially Internet Explorer), you can't always issue print statements - they don't show up, or they are only logged to a file.
Display the debug printout in a separate window. Here is the code for the window class.
 import java.awt.*;
import java.awt.event.";
import javax.swing.
class DebugWin extends JFrame
{ public void print(Object ob)
output.append("\n" + ob);
public DebugWin()
{
setTitle("DebugWin");
output.setEditable(false);
output.setText("[DebugWin]");
getContentPane().add(new JScrollPane(output), "Center");
setSize(300, 200);
setLocation(200, 200);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ setVisible(false); }
} );
show();
}
private JTextArea output = new JTextArea ();
}



Here is how you use it.
 class MyFrame extends JFrame implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
dw.print("Event = " + evt);
}
private DebugWin dw = new DebugWin();
}



Â

Use main for unit tests in every class
Of course, you start a Java program by loading a class and invoking the main procedure. If another class has a main procedure, it is ignored (unless you explicitly call it).
Add a main procedure to every class so that you can run a simple unit test:
 class MyClass
{ // methods
// fields
public static void main(String[] args) // for testing only
{
MyClass myObject = new MyClass();
System.out.println(myObject.myMethod());
}
}



Class Objects

Objects of type Class are useful to analyze the capabilities of classes, and to generate new objects. In Java 1,0, you could use the forName method to generate an object of a particular class:
 Class cl = Class.forName("java.lang.Double");



In Java 1.1, you can simply add .class to the name of any type to get the representative class.
 Class cll = Double.class; // it works for classes
Class c12 = double.class; // it works for numeric types
Class c13 = double[].class; // it works for arrays
Class c14 = Cloneable.class; // it works for interfaces
Sample code:
Number n = numberFormat.parse ();
if (n.getClass( ) == Double.class ) . . .



The Class class should have been called Type since it can represent non-classes as well (i.e. numbers and interfaces). Note that arrays are classes in Java.

Class names of arrays

Class objects are useful for programs that inquire dynamically about the capabilities of classes. The construct Type. class returns an object of type class, as does the static forName method. The getName method returns the name of the class.

These methods are inconsistently implemented for basic types and arrays. Consider the following:
 Class cll = Double.class;
Class c12 = double.class;
Class c13 = double[].class;
Class c14 = Double[].class;
System.out.println(cll.getName()); // prints java.lang.Double
System.out.println(c12.getName()); // prints double
System.out.println(c13.getName()); // prints [D (!)
System.out.println(c14.getName()); // prints[Ljava.lang.Double;
cll = Class.forName("java.lang.Double"); // ok
c12 = Class.forName("double"); // throws exception
c13 = Class.forName("double[]"); // throws exception
c13 = Class.forName("[D"); // ok



Â

Method pointers
One of the less safe features of C is function pointers - it is usually not possible to write generic and typesafe code with function pointers. (In C++, templates can be used to for typesafe generic code.) For example, consider qsort in the standard C library, or a callback in Windows or X Windows. These callbacks use unchecked void* parameters. For that reason, Java did not have function pointers. But they Of course, normally you would use a dynamically bound method with a known name and signature, and then use inheritance to call different functions with similar properties, But sometimes, that is too constraining.
Consider this example - we want to print tables of mathematical functions.
 { double dx = (to - from) / 20;
for (double x = from; x <= to; x += dx)
{
double y = f(x); // wrong syntax
Format.print(System.out, "%12.4f |", x);
Fozmat.print(System.out, "%12.4f\n", y);
}
static void printTable(double from, double to, Method f)
}
printTable(0, 10, Math.sin); // wrong syntax



In principle, this is now possible in Java, but the syntax is more complex. Here is how you can get a method pointer:
 printTable(0, 10, java.lang.Math.class.getMethod("sqrt", new Class[] { double.class }));



And here is how you make the call:
 static void printTable(double from, double to, Method f)
{ . . .
// compute y = f (x);
Object [] args = ( new Double (x) );
Double d = (Double) f. invoke (null, args);
double y = d.doubleValue ();
}



However, keep in mind that invoking a method is very slow. Only use this as a last resort, if there is no better design involving an inter face and a dynamically bound method.

Â

Using Passwords to protect your Midlets
The simplest way for a MIDlet to safeguard sensitive information, is to prompt the user for a password. You can program this into the MIDlet so that the MIDlet does this when it starts or the first time it accesses sensitive data. You can also have the MIDlet ask the user to confirm certain sensitive operations by reentering the password.
Prompting the user for a password is easily done using either the TextBox or the TextField class, both part of the javax.microedition.lcdui package. The TextBox class displays a top-level window consisting of a title, an optional label, and a text entry field. No other user interface components can be added to a TextBox. So for more flexibility, you can use a TextField component. A TextField is a text entry field that can be placed on a Form, that is, a top-level window that can display multiple user interface components. Both components have an identical interface, so what's being discussed here applies to either component.

Here's the code for a simple password prompter using the TextBox class:
 // Defines a class that prompts the user
// for a numeric password.
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class PasswordPrompter
extends TextBox
implements CommandListener {
private Display display;
private Displayable next;
private int pin;
// Constructor with a default title
public PasswordPrompter( int pin,
int maxchars,
Display display,
Displayable next ){
this( defaultTitle, pin, maxchars,
display, next );
}
// Constructor with a specific title
public PasswordPrompter( String title,
int pin,
int maxchars,
Display display,
Displayable next ){
super( title, "", maxchars,
TextField.NUMERIC | TextField.PASSWORD );
addCommand( okCommand );
setCommandListener( this );
this.display = display;
this.next = next;
this.pin = pin;
display.setCurrent( this );
}
// Responds to the one-and-only command event
// by checking the entered password against
// the pin. If it's OK, the user is "forwarded"
// to the next displayable, otherwise an alert
// is displayed.
public void commandAction( Command c,
Displayable d ){
String pinStr = getString();
try {
if( Integer.parseInt( pinStr ) == pin ){
display.setCurrent( next );
return;
}
}
catch( NumberFormatException e ){
}
Alert alert = new Alert( "Error!",
"Invalid password",
null,
AlertType.ERROR );
setString( "" );
display.setCurrent( alert, this );
}
private static final Command okCommand =
new Command( "OK", Command.OK, 1 );
private static final String defaultTitle =
"Enter Password";
}



To invoke the prompter, just create an instance of the PasswordPrompter class, passing it the password to check against (as an integer), the maximum number of characters to allow for the password, the Display instance for the MIDlet, and the screen to display if the correct password is entered. Here is a simple MIDlet that demonstrates the use of the prompter:
 // A MIDlet that demonstrates the use of the
// password prompter.
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class PasswordTester extends MIDlet
implements CommandListener {
private Display display;
private Command exitCommand
= new Command( "Exit ", Command.EXIT, 1 );
public PasswordTester(){
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
protected void pauseApp(){
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){ // first time called...
initMIDlet();
}
}
private void initMIDlet(){
display = Display.getDisplay( this );
// First time through, ask for the password.
new PasswordPrompter( 1234, 4, display,
new TrivialForm() );
}
public void exitMIDlet(){
notifyDestroyed();
}
public void commandAction(
Command c, Displayable d ){
exitMIDlet();
}
// A trivial UI screen
class TrivialForm extends Form {
TrivialForm(){
super( "MainApp" );
addCommand( exitCommand );
setCommandListener( PasswordTester.this );
}
}
}



In the example above, the password is hard coded to be "1234." Of course, you wouldn't do this in a real application. What you would do is get the password either from a record store maintained by the application or else from an application property. An application property is a value stored in either the MIDlet suite manifest or the suite's application descriptor. To retrieve an application property just call the MIDlet's getAppProperty method. For example:
 MIDlet midlet = ....;
int password;
try {
String p = midlet.getAppProperty( "Password" );
password = Integer.parseInt( p );
}
catch( NumberFormatException e ){
}



Using an application property allows you to customize a MIDlet suite for a particular customer. For example, as part of a servlet-controlled download process, the customer could be asked to enter an email address. The process could then generate a random password and a custom version of the MIDlet suite, and send the password to the customer by email. The customer would have to enter the password to activate the application, once it's on the device.

A word of caution in all of this: no security measure is foolproof, and password protection might not be enough security to protect every application. Data stored in the application manifest or descriptor is easily read by anyone with access to those files. Even data stored in a record store isn't secure. On a Palm device, for example, it's trivial for an experienced developer to examine the native Palm database that underlies a record store. If data is truly important, then it should be stored in an encrypted format.

Optimizing J2ME Application Size
If there's anything that differentiates J2ME applications from their J2SE(tm) counterparts, it's the limited environment in which they run. The primary limitation in many J2ME systems is the amount of memory available to store and run applications. Many current MIDP devices, for example, limit application sizes to 50K or less -- a far cry from the multi-megabyte applications possible in server-based J2SE environments. It's very easy to run up against these limits.
 import javax.microedition.lcdui.*;
public class BeforeSizeOptimization extends
BasicMIDlet {
public static final Command exitCommand =
new Command( "Exit",
Command.EXIT, 1 );
public BeforeSizeOptimization(){
}
protected void initMIDlet(){
getDisplay().setCurrent( new MainForm() );
}
public class MainForm extends Form {
public MainForm(){
super( "MainForm" );
addCommand( exitCommand );
append( textf );
setCommandListener( new CommandListener(){
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
}
}
}
);
setItemStateListener(
new ItemStateListener() {
public void itemStateChanged(
Item item ){
if( item == textf ){
AlertType.INFO.playSound(
getDisplay() );
}
}
}
);
}
private TextField textf =
new TextField( "Type anything", null,
20, 0 );
}
}


Although a MIDlet serves as the example, the techniques described here apply to size optimization for any J2ME profile.

Note that the MIDlet class shown above depends on the following convenience class:
 package com.j2medeveloper.techtips;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public abstract class BasicMIDlet extends MIDlet {
private Display display;
public BasicMIDlet(){
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
public void exitMIDlet(){
notifyDestroyed();
}
public Display getDisplay(){ return display; }
protected abstract void initMIDlet();
protected void pauseApp(){
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
display = Display.getDisplay( this );
initMIDlet();
}
}
}



When packaged using the J2ME Wireless Toolkit, the sample MIDlet is just over 4K bytes in size.

The first step in reducing size is to remove unnecessary classes by pruning the application's functionality. Are all the features of your application really necessary? Can your users get by without all the "bells and whistles?" Build the most minimal version of the application. Notice that the sample MIDlet is pretty minimal already.

The second step is to look closely at any inner classes defined by the application, particularly anonymous classes. Remember that each class file has a certain amount of overhead associated with it. Even the most trivial class has overhead:
 public class foo {
// nothing here
}



Compile this class and you get a class file that is almost 200 bytes in size. A common use for an anonymous class, for example, is to implement an event listener. The sample MIDlet defines two listeners this way. An easy optimization to make, then, is to make the main MIDlet class (which is not an optional or unnecessary class) implement the CommandListener and ItemStateListener interfaces, and move the listener code there. Remember that multiple objects can use the same listeners. Use the arguments passed to the commandAction and itemStateChanged methods to distinguish between them if necessary.

Inner classes also bloat code other ways, because the compiler must generate special variables and methods to allow an inner class to access its enclosing class' private information. Read the original inner class specification at

Click Here for more details.

T he third step is to maximize your use of pre-installed classes. For example, in CLDC-based profiles don't build your own set of collection classes. Use the built-in Hashtable and Vector classes and work around their limitations. The same goes for form creation in MIDP applications. The sample MIDlet defines a Form subclass to create its main form, but it could just as easily create it directly:
 mainForm = new Form( "MainForm" );
mainForm.addCommand( okCommand );
mainForm.setCommandListener( listener );



There's no right or wrong answer, it's simply something to consider.

The fourth step is to collapse your application's inheritance hierarchies. You might have factored common code into one or more abstract classes, a recommended technique for object-oriented design that promotes code reuse between applications. It might contradict what you've learned, but it might make more sense to simplify the inheritance hierarchy. This is especially true if your abstract class -- which might be from another project -- is
only sub classed once. The sample MIDlet extends the BasicMIDlet class, for example, but the two are easily combined into a single class.

The fifth step is to shorten the names of your packages, classes, methods and data members. This might seem silly, but a class file holds a lot of symbolic information. Shorten the names of things and you'll reduce the size of the class file. The savings won't be dramatic, but they can add up when spread over several classes. Package names are particularly ripe for shortening. Because MIDP applications are completely self-contained, you can avoid package names completely -- there is no chance of conflict with other classes on the device. The sample MIDlet could be moved out of the com.j2medeveloper.techtips package.

Note that name shortening is not normally something you want to do by hand. Instead, use a tool called an "obfuscator" to do it for you. An obfuscator's primary purpose is to "hide" the code for an application by making it nearly unreadable when decompiled. A side effect of this process is to shrink the size of the application. That's because the hiding is done primarily by renaming methods and data members. There is an open source
obfuscator called RetroGuard that is available for free from http://www.retrologic.com, and there are a number of commercial packages also available. (When obfuscating code for CLDC-based profiles, remember to do the obfuscation before the preverification step, otherwise the obfuscation will invalidate the preverification data stored in the class file.)

Finally, look closely at array initialization. (The sample MIDlet doesn't do any array initialization, but this is an important step for applications that do array initialization.) When compiled, an array initialization statement such as this:
 int arr[] = { 0, 1, 2, 3 };



actually produces code that behaves more like this:
 arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;



To see this, use the javap tool that ships with the Java 2 SDK to disassemble the byte code to a class (use the -c option). You might be unpleasantly surprised at what you see, especially if what you expected was a straight binary copy of constant data. Two alternative approaches are to (1) encode the data into a string and decode it into an array at runtime, or (2) store the data as a binary file packaged with the application and make it
accessible at runtime using the class loader's getResourceAsStream method.

These are just guidelines, and not every step mentioned here makes sense for every J2ME application. However, most of them do apply to the sample MIDlet. The optimized version of the MIDlet looks like this:
 import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class ASO extends MIDlet
implements CommandListener,
ItemStateListener {
private Display
private Form mainForm;
private TextField mainFormTF =
new TextField( "Type anything", null,
20, 0 );
public static final Command exitCommand =
new Command( "Exit",
Command.EXIT, 1 );
public ASO(){
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
}
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
public void exitMIDlet(){
notifyDestroyed();
}
public Display getDisplay(){ return display; }
protected void initMIDlet(){
mainForm = new Form( "MainForm" );
mainForm.addCommand( exitCommand );
mainForm.setCommandListener( this );
mainForm.setItemStateListener( this );
mainForm.append( mainFormTF );
getDisplay().setCurrent( mainForm );
}
public void itemStateChanged( Item item ){
if( item == mainFormTF ){
AlertType.INFO.playSound( getDisplay() );
}
}
protected void pauseApp(){
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
display = Display.getDisplay( this );
initMIDlet();
}



Â

Enable copy and paste functionality between Swing's JTables and Excel
This Java Tip will help you understand the system clipboard and enable your JTable to interact and interoperate with Excel. As you'll see, adding this valuable functionality can be accomplished by adding just one extra line of code to your existing applications.
All you need to do to achieve this goal is copy the file ExcelAdapter.java represented here, compile it, and make sure your applications can find the ExcelAdapter.class file; once you've done that, your JTable is ready to talk with Excel! We'll show you how, with this single line of code, to enable copy (control-C) and paste (control-V) to and from Excel. A sample application using the ExcelAdapter is also provided.

Here is the adapter code, called ExcelAdapter.java, that actually accomplishes this task:
 import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.datatransfer.*;
import java.util.*;
/**
* ExcelAdapter enables Copy-Paste Clipboard functionality on JTables.
* The clipboard data format used by the adapter is compatible with
* the clipboard format used by Excel. This provides for clipboard
* interoperability between enabled JTables and Excel.
*/
public class ExcelAdapter implements ActionListener
{
private String rowstring,value;
private Clipboard system;
private StringSelection stsel;
private JTable jTable1 ;
/**
* The Excel Adapter is constructed with a
* JTable on which it enables Copy-Paste and acts
* as a Clipboard listener.
*/
public ExcelAdapter(JTable myJTable)
{
jTable1 = myJTable;
KeyStroke copy = KeyStroke.getKeyStroke(KeyEvent.VK_C,ActionEvent.CTRL_MASK,false);
// Identifying the copy KeyStroke user can modify this
// to copy on some other Key combination.
KeyStroke paste = KeyStroke.getKeyStroke(KeyEvent.VK_V,ActionEvent.CTRL_MASK,false);
// Identifying the Paste KeyStroke user can modify this
//to copy on some other Key combination.
jTable1.registerKeyboardAction(this,"Copy",copy,JComponent.WHEN_FOCUSED);
jTable1.registerKeyboardAction(this,"Paste",paste,JComponentWHEN_FOCUSED);
system = Toolkit.getDefaultToolkit().getSystemClipboard();
}
/**
* Public Accessor methods for the Table on which this adapter acts.
*/
public JTable getJTable() {return jTable1;}
public void setJTable(JTable jTable1) {this.jTable1=jTable1;}
/**
* This method is activated on the Keystrokes we are listening to
* in this implementation. Here it listens for Copy and Paste ActionCommands.
* Selections comprising non-adjacent cells result in invalid selection and
* then copy action cannot be performed.
* Paste is done by aligning the upper left corner of the selection with the
* 1st element in the current selection of the JTable.
*/
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().compareTo("Copy")==0)
{
StringBuffer sbf=new StringBuffer();
// Check to ensure we have selected only a contiguous block of
// cells
int numcols=jTable1.getSelectedColumnCount();
int numrows=jTable1.getSelectedRowCount();
int[] rowsselected=jTable1.getSelectedRows();
int[] colsselected=jTable1.getSelectedColumns();
if (!((numrows-1==rowsselected[rowsselected.length-1]-rowsselected[0] &&
numrows==rowsselected.length) &&
(numcols-1==colsselected[colsselected.length-1]-colsselected[0] &&
numcols==colsselected.length)))
{
JOptionPane.showMessageDialog(null, "Invalid Copy Selection",
"Invalid Copy Selection",
JOptionPane.ERROR_MESSAGE);
return;
}
for (int i=0;i{
for (int j=0;j{
sbf.append(jTable1.getValueAt(rowsselected[i],colsselected[j]));
if (j}
sbf.append("\n");
}
stsel = new StringSelection(sbf.toString());
system = Toolkit.getDefaultToolkit().getSystemClipboard();
system.setContents(stsel,stsel);
}
if (e.getActionCommand().compareTo("Paste")==0)
{
System.out.println("Trying to Paste");
int startRow=(jTable1.getSelectedRows())[0];
int startCol=(jTable1.getSelectedColumns())[0];
try
{
String trstring= (String)(system.getContents(this).getTransferData(DataFlavor.stringFlavor));
System.out.println("String is:"+trstring);
StringTokenizer st1=new StringTokenizer(trstring,"\n");
for(int i=0;st1.hasMoreTokens();i++)
{
rowstring=st1.nextToken();
StringTokenizer st2=new StringTokenizer(rowstring,"\t");
for(int j=0;st2.hasMoreTokens();j++)
{
value=(String)st2.nextToken();
if (startRow+i< jTable1.getRowCount() &&
startCol+j< jTable1.getColumnCount())
jTable1.setValueAt(value,startRow+i,startCol+j);
System.out.println("Putting "+ value+"at
row="+startRow+i+"column="+startCol+j);
}
}
}
catch(Exception ex){ex.printStackTrace();}
}
Locate runtime code with getStackTrace()



Â

Utilize the EjbProxy
This tip introduces you to the EjbProxy utility class. It instantiates and invokes a remote EJB without coupling your code directly to a specific implementation of that particular EJB.
You must follow four basic steps to invoke an EJB:

Create a JNDI initial context
Look up the EJB name in the context
Get the home object
Create the EJB object's instance via the home object's create() method
The implementation for Steps 1 through 3 is trivial:
 InitialContext ctx = new InitialContext (prop);
Object home = ctx.lookup(beanName);
EJBHome obHome =(EJBHome) PortableRemoteObject.narrow (home, EJBHome.class);



As you can see, you can obtain the EJB home object without knowing the specific implementation of that particular EJB, except the JNDI name lookup string.

Step 4 is not so straightforward. When you try to create the EJB object using the home object, you can't invoke the create() method from the home object, since the EJBHome interface doesn't define the create() method. Only the actual EJB implementations define and implement this method.
As one possible solution, you could define an interface that extends EJBHome and declares the create() method. Then you could simply cast the home object to this interface and call the create() method. However, this approach has one drawback: it requires all EJBs to implement this particular interface. You'd want to invoke the create() method of an arbitrary home interface.

A better solution would use Java's Reflection API capabilities. (You can refer to Resources for detailed information on the Reflection API.) By using reflection, you can load the specified class using Class.forName, and then call getDeclaredMethod() to retrieve the method the class declares. Once you obtain the Method object, you can execute the method with Method.invoke.

The following code uses reflection to create the EJB object's instance from its home object:
 Method m = obHome.getClass().getDeclaredMethod("create", new Class[0]);
Object objRemote = m.invoke (obHome, new Object[0]);
Object obj = PortableRemoteObject.narrow(objRemote, theClass);



That is, this code segment gets the class from the home object, and then calls getDeclaredMethod() with the create() method's name in order to retrieve creates Method object. It also uses the invoke() method to execute the create() method, which returns the EJB object's instance.

The EjbProxy class

The EjbProxy class, found in the source code's EjbProxy.java, manages these nasty details for you.

Using EjbProxy is fairly simple. First, you construct an EjbProxy object -- you may pass the parameters, such as the initial context factory and the provider URL for creating the initial context. Then you call the getObj() method with the EJB's JNDI lookup name to get the EJB's instance. Note that if you use the reference name when invoking another EJB from an EJB, you may need to add a lookup environment string to the lookup name, such as java.comp/env/.

Sample code shows you how to use the EjbProxy class to instantiate and invoke an EJB. For testing purposes, I also implemented an EJB called EjbProxyExample, which has one public method:

public String hello (String name) throws RemoteException;

This method simply accepts a name string and returns a string that makes up "Hello," and the name string. The JNDI name for the EJB proxy example is com.javaworldtip.ejbproxyexample.EjbProxyExample. Suppose you use WebLogic to build and deploy this sample EJB on the local machine with port 7001; to instantiate EjbProxyExample, the client code might be:
 EjbProxy myproxy = new EjbProxy ("weblogic.jndi.WLInitialContextFactory",
"t3://localhost:7001");
EjbProxyExample obj = (EjbProxyExample)myproxy.getObj
("com.javaworldtip.ejbproxyexample.EjbProxyExample");
//now get "Hello, World!" string and show it
String strHello = obj.hello("World");
System.out.println (strHello);



If you invoke this EJB from another EJB located inside the same server, then the code looks like:
 EjbProxy myproxy = new EbjProxy ();
EjbProxyExample obj = (EjbProxyExample)myproxy.getObj
("com.javaworldtip.ejbproxyexample.EjbProxyExample ");
If you've already specified the EjbProxyExample in the ejb- ref section of your caller EJB with reference name "EjbProxyExample", then you can directly use the reference name in the getObj() method:
EjbProxyExample obj =
(EjbProxyExample) myproxy.getObj ("java:comp/env/EjbProxyExmaple");



How it works?

You can use the extended constructor or the setContextProperties() method to set up any context property that EJBProxy must use:
 public void setContextProperties (String initContextFactory,
String providerUrl,
String user,
String password)
{
_pr




   
 Top


Advertise on our site! Click here

 powered by Peperoni.de Users online right now: 16643   Help/FAQ   Terms   Imprint