Monday, December 12, 2005

What is JUG?

Java User Group or JUG, is part of Sun Developer Network (SDN) . It's a community, bulletin board for Java developer to gather and share ideas.

I've just created a local JUG for Malaysian's KL Java group, feel free to join the family!

Friday, November 18, 2005

Encryption Algorithm

Encryption Algorithm in Java

Today, I will be discussing about protecting data by using Java encryption methods. This article also explains different algorithms used for the encryption process.

Most of the web sites today have some sort of a registration module where a user is asked to choose a username/password combination. This data gets stored in the database. You might wonder if the password you provide will be kept well-protected (read encrypted). In case you are the person designing such backend registration component, why not give your users peace of mind by encrypting their passwords?

One-way Hash Encryption
This scenario is a perfect candidate for "one-way hash encryption" also known as a message digest, digital signature, one-way encryption, digital fingerprint, or cryptographic hash. It is referred to as "one-way" because although you can calculate a message digest, given some data, you can't figure out what data produced a given message digest. This is also a collision-free mechanism that guarantees that no two different values will produce the same digest. Another property of this digest is that it is a condensed representation of a message or a data file and as such it has a fixed length.
There are several message-digest algorithms used widely today.


Algorithm

Strength

MD5

128 bit

SHA-1

160 bit


SHA-1 (Secure Hash Algorithm 1) is slower than MD5, but the message digest is larger, which makes it more resistant to brute force attacks. Therefore, it is recommended that Secure Hash Algorithm is preferred to MD5 for all of your digest needs. Note, SHA-1 now has even higher strength brothers, SHA-256, SHA-384, and SHA-512 for 256, 384 and 512-bit digests respectively.

Typical Registration Scenario
Here is a typical flow of how our message digest algorithm can be used to provide one-way password hashing:

1) User registers with some site by submitting the following data:

Username

password

Jsmith

mypass


2) before storing the data, a one-way hash of the password is created: "mypass" is transformed into "5yfRRkrhJDbomacm2lsvEdg4GyY=" .
The data stored in the database ends up looking like this:

username

password

jsmith

5yfRRkrhJDbomacm2lsvEdg4GyY=


3) When jsmith comes back to this site later and decides to login using his credentials (jsmith/mypass), the password hash is created in memory (session) and is compared to the one stored in the database. Both values are equal to "5yfRRkrhJDbomacm2lsvEdg4GyY=" since the same password value "mypass" was used both times when submitting his credentials. Therefore, his login will be successful.

Note, any other plaintext password value will produce a different sequence of characters. Even using a similar password value ("mypast") with only one-letter difference, results in an entirely different hash: "hXdvNSKB5Ifd6fauhUAQZ4jA7o8=" .

plaintext password

encrypted password

mypass

5yfRRkrhJDbomacm2lsvEdg4GyY=

mypast

hXdvNSKB5Ifd6fauhUAQZ4jA7o8=


As mentioned above, given that strong encryption algorithm such as SHA is used, it is impossible to reverse-engineer the encrypted value from "5yfRRkrhJDbomacm2lsvEdg4GyY=" to "mypass". Therefore, even if a malicious hacker gets a hold of your password digest, he/she won't be able determine what your password is.

Java Code that Implements One-way Hash Algorithm

Let's assume that you are writing a web application to be run in a servlet container. Your registration servlet might have the following portion (for clarity, I ommitted input validation steps and assume that a password value was passed in within the password form input field):

[...]
public void doPost(HttpServletRequest request, HttpServletResponse response){
User user = new org.myorg.registration.User(); user.setPassword(org.myorg.services.PasswordService.getInstance().encrypt(request.getParameter("password"));
[...]


Here is the definition of my PasswordService class that does the job of generating a one-way hash value:

package org.myorg.services;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.myorg.SystemUnavailableException;
import sun.misc.BASE64Encoder;
import sun.misc.CharacterEncoder;

public final class PasswordService{
private static PasswordService instance;
private PasswordService() { }
public synchronized String encrypt(String plaintext) throws SystemUnavailableException {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA"); //step 2
}
catch(NoSuchAlgorithmException e) {
throw new SystemUnavailableException(e.getMessage());
}
try {
md.update(plaintext.getBytes("UTF-8")); //step 3
}
catch(UnsupportedEncodingException e) {
throw new SystemUnavailableException(e.getMessage());
}

byte raw[] = md.digest(); //step 4
String hash = (new BASE64Encoder()).encode(raw); //step 5

return hash; //step 6
}

public static synchronized PasswordService getInstance() //step 1 {
if(instance == null) {
return new PasswordService();
}
else {
return instance;
}
}

}


The method of interest here is encrypt(). I chose to make this class a singleton in order to ensure that there is only one instance of it at any given time to avoid concurrency issues and conflicts between generated hash values. For an explanation of this design pattern, try a google search for "java singleton pattern".

Let's step through the code above to see what's going on:

Step 1: The registration servlet will interface with our PasswordService class using this static getInstance() method. Whenever it is invoked, a check will be made to see if an instance of this service class already exists. If so, it will be returned back to the caller (registration servlet). Otherwise, a new instance will be created.

Step 2: We are asking Java security API to obtain an instance of a message digest object using the algorithm supplied (in this case, SHA-1 message digest algorithm will be used. Both SHA and SHA-1 refer to the same thing, a revised SHA algorithm). Sun JDK includes JCA (Java Cryptography Architecture) which includes support for SHA algorithm. If your environment does not support SHA, NoSuchAlgorithmException will be thrown.

Step 3: Feed the data:a) convert the plaintext password (eg, "jsmith") into a byte-representation using UTF-8 encoding format.b) apply this array to the message digest object created earlier. This array will be used as a source for the message digest object to operate on.

Step 4: Do the transformation: generate an array of bytes that represent the digested (encrypted) password value.

Step 5: Create a String representation of the byte array representing the digested password value. This is needed to be able to store the password in the database. At this point, the hash value of the plaintext "jsmith" is "5yfRRkrhJDbomacm2lsvEdg4GyY=".

Step 6: Return the String representation of the newly generated hash back to our registration servlet so that it can be stored in the database. The user.getPassword() method now returns "5yfRRkrhJDbomacm2lsvEdg4GyY="

That's all. Your database password data is now encrypted and if an intruder gets a hold of it, he/she won't have much use of it. Note, you have to consider how you will handle "forgot password" functionality in this case as you now cannot simply send a password to the user's email address. (Well, you should not be doing things like that anyway) .

Saturday, October 29, 2005

JSF-Database Demo

JSF-Database Demo

Well it has been a hot topic now people talking about `JavaServer Faces`, and there are a few implementation (RI) of `JSR-000127` (e.g.: MyFaces, JSF).

Ingredients
- JSF(JSR-000127) RI (MyFaces / Tomahawk) 1.1.0
- Server/Servlet Container (Apache Tomcat 5.5)
- Java Developement Kit (JDK 5.0)

Introduction
The reason I picked MyFaces instead of pure JSF is because I'm
using Apache Tomcat as my Servlet Container, but that isn't the main
reason; its because MyFaces had lots more cool UI to pick from than the
official JSF RI (e.g.: Calendar, WSIWYG Editor, Menu, Tree, ...)!

So what is so great about the concept? I will describe it as a
web-based Swing (for those who code in Java desktop b4, you should be
familiar with the swing package)!

JSF is really a technology to separate presentation layer from logic layer, and the content developer need not know programming at all (or at least only know how to use which JavaBean).
Installation
I'm assuming that you are using Windows XP as your developement environment.
- download MyFaces 1.1.0
- download Apache Tomcat 5.5
- go here to download JDK 5.0 (it was JDK 5.0 Update 5 by the time I'm writing this)

When you have all the ingredients ready, install them by following the official guide or my simple steps(windows only):
(1)Installing JDK
- Start installation by excuting the file `jdk-1_5_0_05-windows-i586-p.exe`, choose the path `c:\dev\jdk5` when it ask you `Where to install JDK?`; for the JVM just leave by the default path!
- Second thing to do is to set the environment variable for the JDK:
- right click on `My Computer`->choose `Properties`->click on `Advance` tab->click `Environment Variables` on the lower left->create a new variable name by clicking `New` under section `User variables for xxx`)->put `Variable name` as `JAVA_HOME` put the `Variable value` as `c:\dev\jdk5`->click `Ok` ... `Ok` all the way back
- To make compilation and execution java application easier, create a new entry for Windows to lookup java, edit the `PATH` variable by appending `;c:\dev\jdk5\bin`
- Test the instalation by keying in echo %JAVA_HOME% in command prompt, and you should get this: `c:\dev\jdk5`
- Further test the java command by using java in command prompt, and you should get something like this:

Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_04-b05)
Java HotSpot(TM) Client VM (build 1.5.0_04-b05, mixed mode, sharing)


- Done!
(2)Installing Tomcat
- official guide to install tomcat
- unzip the file `apache-tomcat-5.5.12.zip` to directory `c:\dev\`, and you will get something like `c:\dev\apache-tomcat-5.5.12`. Rename it to `c:\dev\tomcat`.
- Set your environment variables `CATALINA_HOME` and `CATALINA_BASE` to `c:\dev\tomcat`.
- To make server startup/shutdown easier, create a new entry for Windows to lookup tomcat, edit the `PATH` variable by appending `;c:\dev\tomcat\bin`

- To start your server, type `startup.bat` in command prompt, and you should see some message like below and a command prompt will popup:

Using CATALINA_BASE: E:\dev\tomcat
Using CATALINA_HOME: E:\dev\tomcat
Using CATALINA_TMPDIR: E:\dev\tomcat\temp
Using JAVA_HOME: C:\Program Files\Java\jdk1.5.0_04


- Navigate your server by pointing you browser to `http://localhost:8080`
- To shutdown your server, type `shutdown.bat` in command prompt, and you should see same message as well and the popup should be close by itself after a while.
- Done!
(3)Installing MyFaces - A dataTable Example
Extract `myfaces-1.1.0.zip` to any directory
(e.g.:C:\dev\myfaces-1.1.0) for javadoc reference. For real
development, download the example package -
`myfaces-1.1.1RC2-examples.zip` and unzip it to `C:\dev\myfaces-1.1.1RC2-examples`. You will find some examples web applications like `simple.war`,`blank.war`, and so on, extract `blank.war` into `C:\dev\myfaces-1.1.1RC2-examples\blank` using Winrar or similar software. Now copy all the jars files from `C:\dev\myfaces-1.1.1RC2-examples\blank\WEB-INF\lib`
to your web application's library directory(e.g.:
C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\lib)). To follow my tutorial
and avoid confusion, just create a demo web application in tomcat with
the following directory structure:

- C:\dev\tomcat\webapps\myfaces-demo
- C:\dev\tomcat\webapps\myfaces-demo\META-INF
- C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\lib
- C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\classes

Create a `web.xml` file in your `C:\dev\tomcat\webapps\myfaces-demo\WEB-INF` directory, with following content:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>MyFaces Demo</display-name>
<description>a Myfaces demo page</description>
<context-param>
<param-name>javax.faces.application.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml
</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>myfaces_allow_javascript</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>myfaces_pretty_html</param-name>
<param-value>true</param-value>
</context-param>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<resoure-ref>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resoure-ref>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


Now we investigate the line below:

<resoure-ref>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resoure-ref>

Notice that I have registered an resource for the datatbase here
wit h the JNDI=`jdbc/mysql`. Actually we have to create an context of
this before we could use this ... so let's make the configure the
database.

For this example I'm using Mysql as my database, I will not discuss a little on that later when we touched on it.

Now for making a pool of database resources, we have to make a file called `context.xml` in `C:\dev\tomcat\webapps\myfaces-demo\META-INF`
directory. Below is how it should be looking like (Notes: this context
configuration file is for Tomcat 5.0 and above, for others version
please refer to tomcat official site):

<!-- MySQL database context -->
<Context path="/myfaces-demo"
docBase="myfaces-demo"
debug="5"
reloadable="true"
crossContext="true">
<Resource name="jdbc/mysql"
auth="Container"
type="javax.sql.DataSource"
username="root"
password=""
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
maxActive="8"
maxIdle="4"/>
</Context>


Once we have that, the database should be working well when you
call from the JNDI. Now there is one more ingredient to add in - the `faces-config.xml`. Refer the following code:

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd" >
<faces-config>
<!-- managed beans of the simple hello world app -->
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>com.avatar21.bean.UserBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>


We have to code a little java from this point, create a javabean by the name `UserBean.java`.

-> UserBean.java listing:

package com.avatar21.bean;

import java.util.Map;
import java.util.HashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class UserBean{
private Map users = null;
private String email;
private Logger logger = Logger.getLogger("com.portfolio");

// email
public String getEmail(){
return email;
}
public void setEmail(String email){
this.email = email;
}

public Map getUsers(){
if(users==null){
try{
populateAction();
}
catch(SQLException sqlEx){
logger.log(Level.SEVERE, "loginAction", sqlEx);
}
catch(NamingException nameEx){
logger.log(Level.SEVERE, "loginAction", nameEx);
}
finally{
return users;
}
}
return users;
}

public void emailSelected(ValueChangeEvent e) {
FacesContext context = FacesContext.getCurrentInstance();
setEmail((String) e.getNewValue());

context.renderResponse();
}

public void populateAction() throws SQLException, NamingException{
Context ctx = new InitialContext();
if(ctx==null){
throw new NamingException("No initial context");
}

Context envContext = (Context)ctx.lookup("java:/comp/env");
if(envContext==null){
throw new NamingException("No environment context");
}

DataSource ds = (DataSource)envContext.lookup("jdbc/mysql");
if(ds==null){
throw new NamingException("No data source");
}

Connection conn = ds.getConnection();
if(conn==null){
throw new SQLException("No database connection");
}

try{
PreparedStatement newsQuery = conn.prepareStatement(
"SELECT user_name, user_email FROM test.user ORDER BY user_name");

ResultSet result = newsQuery.executeQuery();

if(!result.next()){
return;
}
else{
channels = new HashMap();

while(result.next()){
users.put(result.getString("user_name"),result.getString("user_email"));
}
}
}
finally{
conn.close();
}
}
}

Compile the class and put the `UserBean.class` in `C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\classes\com.avatar21.bean`

Create a load page: `index.html` in `C:\dev\tomcat\webapps\myfaces-demo`

<html>
<head>
<title>Loading Page</title>
<meta http-equiv="Refresh" content="0; URL=index.faces" />
</head>
<body>
<font color="#ff0000">Application starting ...</font>
</body>
</html>

The JSF test file: `testSelectOneMenu.jsp` in `C:\dev\tomcat\webapps\myfaces-demo`

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
<head>
<title>Test selectOneMenu</title>
</head>
<body>
<f:view>
<h:form>
<h:outputText value="#{user.email}" onchange="submit();" immediate="true" valueChangeListener="#{user.emailSelected}"/>
<f:verbatim><br/></f:verbatim>
<h:selectOneMenu value="#{user.email}">
<f:selectItems value="#{user.users}"/>
</h:selectOneMenu>
<h:commandButton value="#{msgs.sync}" action="#{user.populateAction}"/>
</h:form>
</f:view>
</body>
</html>

Now in order to let the code works, create a table named `user` in `test` database, below is the Mysql scripts for doing this.

USE test;

CREATE TABLE test.user(
user_id INT NOT NULL AUTO_INCREMENT,
user_name VARCHAR(255),
user_email VARCHAR(255),
PRIMARY KEY (user_id)
);

It should be up and running by now when you point your browser to `http://localhost:8080/myfaces-demo`!

I have not run this example on my server, please send me some screenshot if you able to run it, Thanks!


By Avatar

ngavarta@gmail.com

Friday, September 23, 2005

Writing a XMPP chat client in Java (Google Talk)

I think I just start off to the topic, firstly u need a 3rd-party library "smack.jar"+"smackx.jar" which extracted from "smack-2.0.0.zip". Get the file from here !

I'm using "javax.swing" classes to build the UI, below is a brief design layout:
+-----------------------------------------------+
| Login : __________ | <---- login name (e.g.: yourmail.google.com)
| Password: ________ | Login| | <---- password (e.g.: google mail password)
+-----------------------------------------------+
| +------------------------------+ | Send | |
| | | |
| | | |
| +------------------------------+ | quit | |
| _____________________________ V | <--- friend's list
| _______________________________ | <---- chat message here
+-----------------------------------------------+

Now u get what u needed, put the libraries in a the classpath so that your Java compiler can find it.
Here's the code and I'll explains line by line in comments (codes are meant to be small to save up space, simply cut and paste to a textpad for the aid of reading):
____________________________________________________________________________

ChatClient.java
____________________________________________________________________________

package com.avatar.chat;

// import swing classes
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

// import smack classes
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.filter.*;


// packet listener will required you to implement a method
// called
"processPacket(Packet packet)" which lets you
// go lower level to handle the in/out packets better

public class ChatClient extends JFrame implements ActionListener, PacketListener{
private JButton btnLogin, btnSend, btnQuit;
private JTextArea taChatArea;
private JTextField tfChatMessage, tfLoginName;
private JComboBox cbOpponent;
private JPasswordField pfLoginPassword;

// GoogleTalkConnection is one of the class by Smack
private GoogleTalkConnection con = null;

// GroupChat will allowed you to listen to more than 1 opponent
private GroupChat chat = null;
private String login_name = "";
private String login_password = "";
private String opponent = "";
private boolean isLogin = false;

// require class -- PacketFilter and PacketCollector, explain below
private PacketFilter filter = null;
private PacketCollector myCollector = null;

// Message is a class to hold all data which extracted from the packet,
// e.g. sender, receiver, timestamp, message ... etc

private Message msg = null;

public ChatClient(){
super("Chat Client");

setSize(400,300);
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout(0,0));
initComponents();

setVisible(true);
}

public void initComponents(){
btnLogin = new JButton("Login");
btnLogin.addActionListener(this);
btnSend = new JButton("Send");
btnSend.setMnemonic(KeyEvent.VK_ENTER);
btnSend.addActionListener(this);
btnQuit = new JButton("Quit");
btnQuit.addActionListener(this);
taChatArea = new JTextArea(10,40);
taChatArea.setEditable(false);
JScrollPane chatScroller = new JScrollPane(taChatArea);
chatScroller.setPreferredSize(new Dimension(300, 200));
chatScroller.setMinimumSize(new Dimension(300, 200));
chatScroller.setAlignmentX(Component.LEFT_ALIGNMENT);
tfChatMessage = new JTextField(40);
tfLoginName = new JTextField(10);
cbOpponent = new JComboBox();
cbOpponent.setEditable(true);
pfLoginPassword = new JPasswordField(10);

JPanel pnlButton = new JPanel(new GridLayout(2,1,0,0));
JPanel pnlLogin = new JPanel(new GridLayout(3,2,0,0));
JPanel pnlMessage = new JPanel(new GridLayout(2,1,0,0));

pnlLogin.add(new JLabel("User Name:"));
pnlLogin.add(tfLoginName);
pnlLogin.add(new JLabel("Password:"));
pnlLogin.add(pfLoginPassword);
pnlLogin.add(new JLabel("press here to login ->"));
pnlLogin.add(btnLogin);
pnlButton.add(btnSend);
pnlButton.add(btnQuit);
pnlMessage.add(cbOpponent);
pnlMessage.add(tfChatMessage);

setChat(false);

add(pnlLogin, BorderLayout.NORTH);
add(pnlButton, BorderLayout.EAST);
add(chatScroller, BorderLayout.CENTER);
add(pnlMessage, BorderLayout.SOUTH);
}

// disable sending meassage when variable 'mark' is false (offline), and vice-versa
public void setChat(boolean mark){
tfChatMessage.setEnabled(mark);
cbOpponent.setEnabled(mark);
btnSend.setEnabled(mark);
}

// clean up jobs appoint exit
public void logout(){
if(con!=null){
con.close();
}
cbOpponent.removeAllItems();
}

// when user logged in, set the flag to true (online)
public boolean login(String login_name,String login_password){

// get textfield's username
this.login_name = login_name;

// get passwordfield's password
this.login_password = login_password;
boolean flag = false;

try{
con = new GoogleTalkConnection();
con.login(login_name, login_password);

// filter the XML packet into a PacketCollector (much like a queue),
// so that you can get them back later

filter = new AndFilter(
new PacketTypeFilter(Message.class),
new FromContainsFilter(opponent));
myCollector = con.createPacketCollector(filter);

// initialise your chatgroup
chat = con.createGroupChat(login_name+"'s Chat");

// initialise your message
msg = new Message();

// get all user from your friends list
Roster roster = con.getRoster();
for (Iterator i=roster.getEntries(); i.hasNext(); ) {
RosterEntry re = (RosterEntry)i.next();
cbOpponent.addItem(re.getUser());

// Register the listener.
}

con.addPacketListener(this, filter);

setChat(true);
flag = true;
}catch(Exception ex){
ex.printStackTrace();

// any thing during login, disable user to send message
setChat(false);
flag = false;
}finally{
return flag;
}
}

public void windowClosing(WindowEvent we){
logout();
}


// implementing processPacket for PacketListener interface
public void processPacket(Packet packet) {
// Put the incoming message on the chat history or chat board.
Message msg = (Message)packet;
taChatArea.append(msg.getFrom()+
": "+msg.getBody()+"\n");
}

public void actionPerformed(ActionEvent e){
if(e.getSource()==btnLogin){
String test = btnLogin.getLabel();
if(test.equals("Login")){
isLogin = login(tfLoginName.getText().toString().trim(),
pfLoginPassword.getText().toString().trim());
btnLogin.setLabel("Logout");
}else if(test.equals("Logout")){
logout();
setChat(false);
isLogin = false;
btnLogin.setLabel("Login");
}
}else if(e.getSource()==btnSend){
opponent = cbOpponent.getSelectedItem().toString();
String content = tfChatMessage.getText().toString();
if(isLogin){
try{
msg.setTo(opponent);
msg.setBody(content);
chat.sendMessage(msg);

// append your sent message to chat board
taChatArea.append(login_name+": "+tfChatMessage.getText()+"\n");
}catch(Exception ex){
ex.printStackTrace();
}
}
}
else if(e.getSource()==btnQuit){
logout();
System.exit(0);
}
}

public static void main(String[] args){
ChatClient c = new ChatClient();
}
}

___________________________________________________________
End of
"ChatClient.java"
___________________________________________________________
Thanks to Smack by JiveSoftware, online messager never got easier to write!

The final output should looks like this, still depends on platform and versioning of JDK.

Other resoures:

[NOTE: Smack is a trademark of Jive Software, Google Talk is a trademark of Google.]

Thursday, September 08, 2005

WSDL Sample

Before porting the web service module into a J2EE application, firstly lets look at how I get a stock quote in a normal Java concole.

As I will continue on application of WSDL on my next post ... .

Below is the full generic code to demostrate on calling a WSDL:

//
// XMethods sample client for the Stock Quote service
//

import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.soap.util.xml.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;

public class StockQuoteClient{

public static float getQuote (URL url, String symbol) throws Exception {

Call call = new Call ();

// Service uses standard SOAP encoding
String encodingStyleURI = Constants.NS_URI_SOAP_ENC;
call.setEncodingStyleURI(encodingStyleURI);

// Set service locator parameters
call.setTargetObjectURI ("urn:xmethods-delayed-quotes");
call.setMethodName ("getQuote");

// Create input parameter vector
Vector params = new Vector ();
params.addElement (new Parameter("symbol", String.class, symbol, null));
call.setParams (params);

// Invoke the service ....
Response resp = call.invoke (url,"");

// ... and evaluate the response
if (resp.generatedFault ()) {
throw new Exception();
} else {
// Call was successful. Extract response parameter and return result
Parameter result = resp.getReturnValue ();
Float rate=(Float) result.getValue();
return rate.floatValue();
}
}

// Driver to illustrate service invocation
public static void main(String[] args) {
try {
URL url=new URL("http://services.xmethods.net:80/soap");
String symbol= args[0];
float quote = getQuote(url,symbol);
System.out.println(quote);
}
catch (Exception e) {e.printStackTrace();}
}
}