Link to home
Start Free TrialLog in
Avatar of crasher88
crasher88

asked on

Post and Get information from IM develop in J2ME to MySQL

I have develop some interface for the midlet in JBuilder MobileEdition. But i don't know how to connect to the database (mysql) to register user, post message and to receive message from the database.

I have read some of the examples in JBuilder and in Sun Blueprint. I just can't understand it.

Thanks alot.


Here's the current codes:

NewUserDisplay.java

package mobilemessenger;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.Displayable;
import javax.microedition.io.*;
import java.io.*;

/**
 * <p>Title: Mobile Messenger</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003/2004</p>
 * <p>Company: </p>
 * @author Patrick Sor Wei Chong
 * @version 1.0
 */
public class NewUserDisplay extends Form implements CommandListener {

  static Displayable instance = null;
  TextField username;
  TextField password;
  TextField email;
  TextField vpassword;
  /** Constructor */
  public NewUserDisplay() {
    super("RegisterNewUser");
    setCommandListener(new CommandListener()  {
      public void commandAction(Command command, Displayable displayable) {
        commandAction(command, displayable);
      }
    });

    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**Component initialization*/
  private void jbInit() throws Exception {
    username = new TextField("", "", 15,TextField.ANY);
    password = new TextField("", "", 15,TextField.ANY);
    email = new TextField("", "", 15,TextField.ANY);
    vpassword = new TextField("", "", 15,TextField.ANY);
    vpassword.setLabel("Verify password");
    vpassword.setConstraints(TextField.ANY | TextField.PASSWORD);
    vpassword.setMaxSize(14);
    vpassword.setPreferredSize(105, 32);
    email.setLabel("Valid email address");
    email.setConstraints(TextField.EMAILADDR);
    email.setMaxSize(29);
    email.setString("");
    email.setPreferredSize(160, 36);
    password.setLabel("Password");
    password.setConstraints(TextField.ANY | TextField.PASSWORD);
    password.setMaxSize(14);
    password.setPreferredSize(105, 32);
    username.setLabel("Username");
    username.setLayout(Item.LAYOUT_DEFAULT);
    username.setMaxSize(14);
    username.setPreferredSize(105, 32);
    this.setTitle("Register");
    // Set up this Displayable to listen to command events
    setCommandListener(this);
    // add command
    addCommand(new Command("Back", Command.BACK, 1));
    addCommand(new Command("OK", Command.OK, 2));
    this.append(username);
    this.append(password);
    this.append(vpassword);
    this.append(email);
  }

  /**Handle command events*/
  public void commandAction(Command command, Displayable displayable) {
    /** @todo Add command handling code */
    if (command.getCommandType() == Command.BACK) {
      MainDisplay main = new MainDisplay();
      Display.getDisplay(mobilemessenger.instance).setCurrent(main);
    }
    else if (command.getCommandType() == Command.OK) {
      password = vpassword;
    }
  }

  public void CreateNewUser (String username, String password, String email){
    HttpConnection conn = null;
    DataInputStream in = null;

    try {
      // Send the account information to the server.
      String message = MessageConstants.CREATE_USER +
          "^" + username + "," + password
          + "," + email;
      conn = open(CreateUser.servlet, message);
      in = conn.openDataInputStream();

    // Save the account to the local store.
            ByteArrayOutputStream bout = new
            ByteArrayOutputStream();
            DataOutputStream out = new
            DataOutputStream(bout);
            out.writeUTF(username);
            out.writeUTF(password);
            out.writeUTF(email);
            byte[] record = bout.toByteArray();
            if (recordStore.getNumRecords() > 0) {
                recordStore.setRecord(1, record, 0,
                    record.length);
            } else {
                recordStore.addRecord(record, 0,
                    record.length);
            }

        } catch (Exception e) {
            smartTicket.stopLoading(e);
        } finally {
            close(conn, in);
        }
  }
}




ChatDisplay.java

package mobilemessenger;

import javax.microedition.lcdui.*;
import javax.microedition.io.*;

/**
 * <p>Title: Mobile Messenger</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003/2004</p>
 * <p>Company: </p>
 * @author Patrick Sor Wei Chong
 * @version 1.0
 */
public class ChatDisplay extends Form implements CommandListener {
  StringItem receivemsg;
  TextField sendmsg;
  private String url = "http://localhost/mobilemessenger";

  /** Constructor */
  public ChatDisplay() {
    super("mobilemessenger");
    setCommandListener(new CommandListener()  {
      public void commandAction(Command command, Displayable displayable) {
        commandAction(command, displayable);
      }
    });

    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**Component initialization*/
  private void jbInit() throws Exception {
    receivemsg = new StringItem("", "");
    sendmsg = new TextField("", "", 15,TextField.ANY);
    sendmsg.setLabel("Message:");
    sendmsg.setConstraints(TextField.ANY);
    sendmsg.setString("");
    sendmsg.setPreferredSize(201, 32);
    receivemsg.setLabel("");
    receivemsg.setLayout(Item.LAYOUT_CENTER);
    receivemsg.setText("");
    receivemsg.setPreferredSize(200, 165);
    receivemsg.setFont(Font.getFont(Font.FONT_STATIC_TEXT));
    this.setTitle("Chat");
    // Set up this Displayable to listen to command events
    setCommandListener(this);
    // add command
    addCommand(new Command("Menu", Command.EXIT, 1));
    addCommand(new Command("Send", Command.OK, 1));

    this.append(receivemsg);
    this.append(sendmsg);
  }

  /**Handle command events*/
  public void commandAction(Command command, Displayable displayable) {
    /** @todo Add command handling code */
  }

}





mobilemessenger.java

package mobilemessenger;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;

/**
 * <p>Title: Mobile Messenger</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003/2004</p>
 * <p>Company: </p>
 * @author Patrick Sor Wei Chong
 * @version 1.0
 */

public class mobilemessenger extends MIDlet {
  static mobilemessenger instance;
  MainDisplay Displayable = new MainDisplay();
  NewUserDisplay newuser = new NewUserDisplay();

  /** Constructor */
  public mobilemessenger() {
    instance = this;
  }

  /** Main method */
  public void startApp() {
    Display.getDisplay(this).setCurrent(Displayable);
  }

  /** Handle pausing the MIDlet */
  public void pauseApp() {
  }

  /** Handle destroying the MIDlet */
  public void destroyApp(boolean unconditional) {
    Displayable = null;
  }

  /** Quit the MIDlet */
  public static void quitApp() {
    instance.destroyApp(true);
    instance.notifyDestroyed();
    instance = null;
  }
}

Avatar of jimmack
jimmack

I'd recommend creating another class that manages the communication with the server.  In that class, you'll need a methods for opening a connection, sending a request, receiving a response and closing the connection.

This should be handled in a separate thread, otherwise your MIDlet may lock up for a considerable amount of time, whilst the handset is waiting for a response from the server.

To send a message to the server (either a registration request of a normal message), you need to append some data to the URL that the server can interpret, eg:

http://localhost/mobilemessenger?action=reg&userID=xxxx&password=yyyy

or

http://localhost/mobilemessenger?action=send&userID=xxxx&msg="Contents of message"

When the connection has been made, you should receive the response from the server.  What I do is to open a DataInputStream and use the readInt(), readUTF() etc. methods to get the results back.

You need to spend some time identifying exactly what data should be passed between the client and server and think about how you can handle problems (what if no connection can be made, what if the connection breaks down during a session, what if the server doesn't receive all the data it expects from the client, what if the client doesn't receive all the data it expects back from the server etc.)

What do you have at the server side?  Is mobilemessenger a servlet or some other CGI handler?

Avatar of crasher88

ASKER

I'm using servlet for the server-side...
OK.  Some more ideas then ;-)

In that case, you can deal with the server side using something like this in the doGet() or doPost() method in the servlet:

        PrintWriter out = new PrintWriter(response.getOutputStream());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        dos = new DataOutputStream(baos);

        // Write data into "dos" here, eg:
        //  dos.writeInt(OK_RESPONSE_CONSTANT);
        //  dos.writeUTF(latestMessageOnServer);
        //  or
        //  dos.writeInt(ERROR_RESPONSE_CONSTANT);
        //  dos.writeUTF("Error ...");

        out.println(new String(baos.toString()));
        out.flush();

At the MIDlet end, you'll need a DataInputStream (eg. "dis") and you can check the response with:

    int responseType = dis.readInt();
    if (responseType == OK_RESPONSE_CONSTANT)
    {
        messageString = dis.readUTF();
    }
    else if (responseType == ERROR_RESPONSE_CONSTANT)
    {
        errorMessage = dis.readUTF();
    }
    else
    {
        errorMessage = "Unknown response type";
    }
jimmack, as in your last reply your coding :
PrintWriter out = new PrintWriter(response.getOutputStream());
My jbuilder have error on it.

So i change to OutputStreamWriter outputwriter = new OutputStreamWriter(response.getOutputStream());
But i still have errors because of my "reponse" doesn't have class on getOutputStream(). Y?

I have import javax.java.io.http.httpresponse in my coding, but i still can't.

So i change the code to :

ByteArrayOutputStream baos = new ByteArrayOutputStream();
          DataOutputStream outputstream = new DataOutputStream(baos);

          outputstream.writeUTF(new String(baos.toString()));
          outputstream.flush();
       

Can it be done like this?





I have done the communication handler by opening the connection in "http://localhost/mobilemessenger";

And the login code in communication handler :
public void login(String username, String password)
  {
    try
    {
      connection = openConnection();

      outputstream = openDataOutputStream(connection);
      outputstream.writeUTF(username);
      outputstream.writeUTF(password);
      outputstream.close();

      inputstream = openDataInputStream(connection);

      // Do nothing.
    }
    catch (IOException ex)
    {
      System.out.println("Can't connect");
    }
    finally
    {
      closeConnection(connection, outputstream, inputstream);
    }
  }



So how do i connect it to the mysql server?
Hi crasher,

OK, part 1:

>> I have import javax.java.io.http.httpresponse in my coding

I don't know what this is.  You should be using:

import javax.servlet.http.*;

or

import javax.servlet.http.HttpServletResponse;

and your doGet() or doPost() method should look like this:

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                                                           IOException
    {
        .
        .
        PrintWriter out = new PrintWriter(response.getOutputStream());
        .
        .
    }


Part 2, to connect to the MySQL server, you'll need something along these lines (in your servlet):

        Class.forName("org.gjt.mm.mysql.Driver);

        Connection connection =
                  DriverManager.getConnection(DATABASE_URL,
                                                            DATABASE_USER,
                                                            DATABASE_PASSWORD);

        Statement stmt = conn.createStatement();

        StringBuffer query = new StringBuffer("SELECT * FROM mydatabase");
        ResultSet rs = stmt.executequery(query.toString());

        while (rs.next())
        {
            String username = rs.getString("name");
        }

The parameters you pass to the getConnection() method and the query will obviously be dependent upon your implementation.
Sorry for my typing error,

There is an error about the code:

PrintWriter out = new PrintWriter(response.getOutputStream());

It stated that there is invalid for Printwriter. Do i need to declare PrintWriter somewhere?

Or i need to import first?



And i have :
import javax.servlet.http.HttpServletResponse;

But i have errors in of my "reponse" doesn't have class on getOutputStream().

It have others for eg. goString(), but it doesn't have getOutputStream()


Thanks.
PrintWriter is part of the java.io package.

Try replacing your specific imports with the following:

import javax.servlet.*;
import javax.servlet.http.*;

If it still doesn't build/run, please post the actual errors that you receive.
Here is the error,


"servlet.java": cannot resolve symbol: class PrintWriter in class mobilemessenger.servlet at line 35, column 11

There has no Printwriter but have :
java.io.Writer
java.io.PrintStream



"servlet.java": cannot resolve symbol: method getOutputStream ()in class javax.servlet.http.HttpServletResponse at line 35, column 54
Perhaps this is another import problem.

java.io.PrintWriter has been in the JDK since version 1.1, so you must have it on your system OK.

Try importing java.io.* at the top of the servlet.java file.

Could you post the code for servlet.java?
package mobilemessenger;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.*;

import javax.servlet.http.*;
import javax.servlet.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003/2004</p>
 * <p>Company: </p>
 * @author
 * @version 1.0
 */

public class servlet extends HttpServlet
    {
      public void doGet(HttpServletRequest request, HttpServletResponse response)
      {
        doPost(request, response);
      }

      public void doPost(HttpServletRequest request, HttpServletResponse response)
      {
        try
        {
          PrintWriter out = new PrintWriter(response.getOutputStream());
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          DataOutputStream outputstream = new DataOutputStream(baos);

          out.writeUTF(new String(baos.toString()));
          out.flush();
        }
        catch (IOException ex)
        {
        }
      }
    }
Hi crasher88,

  This looks basically OK to me.

  You can remove all the individual java.io... imports.  Just leave the java.io.*.

  Both the doGet() and doPost() methods should throw IOException and ServletException.

  If you don't mind comments on style, the class name "servlet" should really start with a capital letter, ie. "Servlet".

  I'm not quite sure why the compiler is having a problem with the getOutputStream() method.  When you compile it, are you including servlet.jar on the classpath?  eg. I use (on Linux):

  javac -g -d Target -classpath /var/tomcat4/commons/lib/servlet.jar Source/mypackage/MyServlet.java
I didn't use any compiling in java.

I just rebuild it in jbuilder and it shows me that i have error in it.

I think i have problem too with getOutputStream() because i need to create a new class for :
import javax.servlet.http.HttpServletResponse

Normally import is a build-in in jdk, but now i have to create new class for it.

Is there any problem with my jbuilder? Should i change to SUN ONE?

Thanks for your help.
No, you don't need to change your IDE.  JBuilder should do this OK.

You don't need to create an instance of HttpServletResponse, because the object is passed in as a parameter to the method.

I don't use JBuilder, so I'm not exactly sure how to do this, but you need to include servlet.jar on your classpath.  It's probably an option somewhere under the project (certainly the help should tell you where to put it).

If you're using Tomcat 5, you need servlet-api.jar instead.

I built the code you posted above (having removed the java.io... imports), and I only found one problem.  You need to replace:

   out.writeUTF(...)

with:

   out.println(...)
I have found out that there is no java.io.PrintWriter API in J2ME Wireless Toolkit.
So how to counter it?

For the servlet, i have download the servlet API from SUN.
Are you mixing up the code between the servlet and the MIDlet?

You don't need a PrintWriter in the MIDlet.  In fact, you don't need to worry about any kind of writer in the MIDlet because the writing is taken care of when the connection is opened.

How are you using PrintWriter in the MIDlet at the moment?
Ok, i have solve the problem. And have finish the servlet side. And successfull integrating MySQL and servlet.

But I can't connect the client with the server.

When i execute the client side, i have this message, and it just hang there when trying to connect to servlet side:
Running with storage root DefaultColorPhone
Warning: To avoid potential deadlock, operations that may block, such as
 networking, should be performed in a different thread than the
 commandAction() handler.


In your first post, you advise me to have a seperate thread called CommunicationHandler, But I don't know who to integrates the CommunicationHandler with the MainDisplay (Clientside).
Any ideas?

Thanks...
If you're not too familiar with threads, this might look a bit daunting to start with, but once you've grasped it, you'll see how useful it is ;-)

As an example, I do the following in one of my MIDlets:

1) My CommunicationHandler class contains the code to connect to the server and interpret the results of the response (this class doesn't extend Thread or implement Runnable).
2) I have another class (Monitor) that extends Form and implements Runnable
3) My MIDlet also implements the Runnable interface

The Monitor class displays "Connecting..." and from within the run() method, it updates this string to display 1, 2 or 3 dots to indicate activity.  This is done within the run() method.  The run() method uses a "while (running)" loop, where "running" is a boolean attribute in the class.

In the run() method of the MIDlet, I set the display to the Monitor object and start it's thread.  Following this, I perform the communication with the server by calling the appropriate method(s) in the CommunicationHandler to open the connection, retrieve the results and process the data.

When the CommunicationHandler is finished I call a stop() method in the Monitor which sets the "running" variable to false.  This should allow the Monitor thread to complete.

There are 3 threads involved in this.

Thread 1) is the main MIDlet execution thread.
Thread 2) is the Monitor thread that is updating the "Please wait..." message every second or so
Thread 3) is the communication thread (in this case, it's run() method is defined inside the MIDlet)

Some skeleton example code might help:

Monitor
------------

public class Monitor extends Form implements Runnable
{
    private boolean running;

    public Monitor()
    {
        // create the form and contents
    }

    public void run()
    {
        running = true;
        while (running)
        {
            // update the display every second
        }
    }

    public void stop()
    {
        running = false;
    }
}


CommunicationHandler
------------------------------------
.
.
    public String communicateWithServlet()
    {
        String result = "Failed to connect";
        // try to connect and set the "result" value accordingly
        return (result);
    }
.
.


MIDlet
----------
public class MyMidlet extends MIDlet implements Runnable
.
.
    public void run()
    {
        Thread monThread = new Thread(myMonitor);
        monThread.start();
        myResult = commHandler.communicateWithServlet();
        monThread.stop();
        // Put results on another Form (eg. resultForm)
        display.setCurrent(resultForm);
    }
.
.
    public void actionPerformed(...)
    {
        if (command == connectCommand)
        {
            Thread runIt = new Thread(this);
            runIt.start();
        }
    }
.
.

If I've missed something, or not explained something clearly enough, let men know ;-)
Ok, Lets say i need to intergrate both threads, how do i do it?
Do i need to import the threads?

I'm not quite sure what you mean with the last two questions ;-)

Maybe if I justify the reasons for the above threads it may help.

When a connection is made to the server, the thread making the connection "blocks" until a response is received.  If this is being done from the main MIDlet thread, then screen updates cannot take place and the handset will appear to have frozen.  If problems occur with the connection or a large amount of data is being successfully downloaded, but the connection is intermittent, then this locking could potentially last for several minutes.  This is why a separate thread should be used for the connection (and explains why the toolkit compains about it).

The Monitor thread could potentially be merged with the main MIDlet thread (so that only the communication thread is running separately), but the reason I created another thread for this (in my example) was because I have a "cancel" command on the Monitor form.  Because the Monitor thread is continuously updating the screen (pausing for 1 second using Thread.sleep()), again this is effectively a "blocking" thread.  If this was done in the MIDlet thread, the cancel command would not be recognised until the operation was complete.
Ok, my application is running well.

What is the purpose of declaring:

private static final int ID_LOGIN = 1;
private static final int ID_SEND_MESSAGE = 2;
private static final int ID_GET_MESSAGE = 3;
private static final int ID_VERIFY_RECIPIENT = 4;
private static final int ID_LOGOUT = 5;
private static final int OK_RESPONSE_CONSTANT = 6;
private static final int ERROR_RESPONSE_CONSTANT = 7;


As I see in your previous answer, you also stated using this code:

//
At the MIDlet end, you'll need a DataInputStream (eg. "dis") and you can check the response with:

    int responseType = dis.readInt();
    if (responseType == OK_RESPONSE_CONSTANT)
    {
        messageString = dis.readUTF();
    }
    else if (responseType == ERROR_RESPONSE_CONSTANT)
    {
        errorMessage = dis.readUTF();
    }
    else
    {
        errorMessage = "Unknown response type";
    }
//

Thanks...
There are two main reasons for using constant (static final) values:

1) They provide meaningful names to otherwise obscure values, eg. it's easier to understand:

    if (responseType == ERROR_RESPONSE_CONSTANT)

than

    if (responseType == 7)

2) If a value needs to be changed, then you only need to change it in one place, rather than hunting for all the places it might occur in the code.

jim,

I am able to retrieve user message from the database. But i'm only successful retrieve the first data in the table.

How would I retrive the next data from the table? Is there a SQL command to select the next data?

Thanks...
If you're retrieving the data into a ResultSet, then you should be using:

ResultSet rs = stmt.executeQuery(...

while (rs.next())
{

}

When you first receive a ResultSet, the "cursor" (current record) is *before* the first row.  The rs.next() moves the cursor to the next row and returns a boolean to indicate whether it has found one or not.  Using a while loop will let you deal with each row that has been returned.

If you're only getting 1 row back, then that's more to do with your query than the processing of the result.
Here are my code. But resultset don't seems to move to the next row. What's wrong with it?


Statement statement = connection.createStatement();
      String SQLstr = "Select sender, message, messagetime FROM message WHERE sender = '" +
          sender + "'";
      ResultSet resultset = statement.executeQuery(SQLstr);

      while (resultset.next()) {
        StringBuffer content = new StringBuffer();
        content.append(resultset.getString(3));
        content.append('\n');
        content.append('\n');
        content.append("Sender: ");
        content.append(resultset.getString(1));
        content.append('\n');
        content.append('\n');
        content.append("Content: ");
        content.append(resultset.getString(2));
        request.setAttribute("content", content.toString());
        reply = "/ReceiveMessage.jsp";


      }
You are re-setting the "content" attribute of the request for each row.  I'm not 100% sure how you intend this to work, but I would think it should be more like:

Statement statement = connection.createStatement();
String SQLstr = "Select sender, message, messagetime FROM message WHERE sender = '" +
          sender + "'";
ResultSet resultset = statement.executeQuery(SQLstr);

StringBuffer content = new StringBuffer();
while (resultset.next()) {
    content.append(resultset.getString(3));
    content.append('\n');
    content.append('\n');
    content.append("Sender: ");
    content.append(resultset.getString(1));
    content.append('\n');
    content.append('\n');
    content.append("Content: ");
    content.append(resultset.getString(2));
}
request.setAttribute("content", content.toString());
reply = "/ReceiveMessage.jsp";
Yes, the result I have try it with the 'If' and 'While' statement together and it receive the similar resut as yours.

But thats not what I intend to have. I intend my Next button to be able to retrieve the next message that means the next row of data. But in a different screen. Is about the same as retrieving SMS messages. How do I do that?
ASKER CERTIFIED SOLUTION
Avatar of jimmack
jimmack

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok, I have a problem. I finish doing choice 1. But lets say I have messageid 1, 2, and 3.
Messageid 2 has been deleted. And I'm viewing messageid 1 now. But after press next, messageid 1; increments 1. And it look for messageid 2 but there isn't because it's been deleted. So it shows no messages in database.

My question, how to jump from messageid 1 to messageid 3 without poping out "no messages in database"?

p/s In servlet i'm using sessionid to determine messageid.

Thanks...

jimmack? There?