Creating a BlackBerry HTTP Connection – Tutorial

Posted October 12th, 2009 by

Introduction

This tutorial will show you the various ways to create an HTTP networking connection from your BlackBerry device to an HTTP server (web service, servlet, etc). The complicated part about doing this on a BlackBerry is deciding which transport you would like to use, and which transport you can use.

The different transports

WiFi – if you use WiFi then you will be able to access all the servers on the WiFi network itself. Also, this will not incur data charges and will work even if your cellular data connection is not available, or radio is turned off. The URL connection string you have to append is as follows: “http://www.testserver.com;interface=wifi

APN/Direct TCP – this will require you to configure the APN settings on your BlackBerry for this to work. “http://www.testserver.com;deviceside=true

BIS-B – this is the most widely available cellular data transport. However, in order to use this, your server has to be whitelisted beforehand by RIM. You have to get the connection string from RIM (I can’t show it to you). Take our Bootcamp training and we will show you how to get going.

BES/MDS – this requires you to have BES server that your BlackBerry is connected to. The URL connection string you have to append is as follows: “http://www.testserver.com;deviceside=false

WAP – this works if you have the WAP service books provisioned to your BlackBerry. The URL connection string you have to append is as follows: “http://www.testserver.com;WAPGatewayIP=?.?.?.?;WAPGatewayAPN=????

The way to select these different transports is pretty simple, and you can see how to do it here. There’s even a debugging toolkit available that will help you test out different connections on your BlackBerry, which can be found here.

Training

To explain all the details and ramifications of using different transports would take a book, not a tutorial. To learn more about the ins and outs of these transports, and how to get access to BIS-B and BIS-Push, you can take our BlackBerry Bootcamp Training courses.

Sample code to connect via WiFi

Here’s more information from RIM on the details of how to connect to various transports, and how to do it. Here’s sample code from the BlackBerry development community forums that will show you how to create connections and read/write from them.

class HttpUtils {
  public static final int CONNECTION_DEFAULT = 0;
  public static final int CONNECTION_BIS = 1;
  public static final int CONNECTION_BES = 2;
  public static final int CONNECTION_TCPIP = 3;
  public static final int CONNECTION_WIFI = 4;

  /**
   * This method opens a HTTP connection to the given url. The method used is
   * GET or POST depending on whether postData is null or not. Only the
   * provided connType is used. For example, if the connType is
   * CONNECTION_BES, the connection is tried using the BES only.
   * The only time provided connection type is not used is when the URL
   * contains ";deviceside=".
   *
   * @param url            The url to connect to.
   * @param requestHeaders The headers in the request. May be null or empty.
   * @param postData       Data to be posted to the server. If null, the GET method used
   *                       for the http connection.
   * @param connType       The type of transport (BES / BIS / WIFI / Default) to be used
   *                       for opening connection.
   *
   * @return Opened HttpConnection object or null if some error occurs.
   */
  public static HttpConnection makeHttpConnection(String url,
                                                  HttpHeaders requestHeaders, byte[] postData, int connType)
  {
    HttpConnection conn = null;
    OutputStream out = null;

    if (StringUtilities.startsWithIgnoreCase(url, "www.")) {
      url = "http://" + url;
    }

    try {
      if (url.indexOf(";deviceside=") == -1) {
        switch (connType) {
          case CONNECTION_BES:
            url = url + ";deviceside=false";
            break;
          case CONNECTION_BIS:
            url = url + ";XXXXXXXXXXXXXXXX";
            break;
          case CONNECTION_TCPIP:
            url = url + ";deviceside=true";
            break;
          case CONNECTION_WIFI:
            url = url + ";interface=wifi";
        }
      }

      conn = (HttpConnection) Connector.open(url);

      if (requestHeaders != null) {
        String referer = requestHeaders.getPropertyValue("referer");

        boolean sendReferrer = true;

        if (referer != null &&

            StringUtilities.startsWithIgnoreCase(referer, "https:") &&

            !StringUtilities.startsWithIgnoreCase(url, "https:"))
        {
          sendReferrer = false;
        }

        int size = requestHeaders.size();
        for (int i = 0; i < size;) {
          String header = requestHeaders.getPropertyKey(i);
// remove header if needed
          if (!sendReferrer && header.equals("referer")) {
            requestHeaders.removeProperty(i);
            --size;
            continue;
          }

          String value = requestHeaders.getPropertyValue(i++);
          if (value != null) {
            conn.setRequestProperty(header, value);
          }
        }
      }

      if (postData == null) {
        conn.setRequestMethod(HttpConnection.GET);
        conn.setRequestProperty("User-Agent",

                                "Profile/MIDP-2.0 Configuration/CLDC-1.0");
      }
      else {
        conn.setRequestMethod(HttpConnection.POST);
        conn.setRequestProperty(

            HttpProtocolConstants.HEADER_CONTENT_LENGTH,

            String.valueOf(postData.length));
        conn.setRequestProperty("Content-Type",

                                "application/x-www-form-urlencoded");
        conn.setRequestProperty("User-Agent",

                                "Profile/MIDP-2.0 Configuration/CLDC-1.0");

        out = conn.openOutputStream();
        out.write(postData);
        out.flush();
      }
    }
    catch (IOException e1) {
      Log.error("UTIL.HTC " + e1);
      close(conn, null); // Close the connection

      conn = null;
    }
    finally {
      close(null, out); // Close the output, but keep connection open
    }

    return conn;
  }

  private static void close(HttpConnection con, OutputStream out) {
    if (out != null) {
      try {
        out.close();
      }
      catch (IOException e2) {
      }
    }
    if (con != null) {
      try {
        con.close();
      }
      catch (IOException e) {
      }
    }
  }
}

Source code example

Here is an BlackBerry client app (NetworkDemo) that connects to a servlet (DataPingServlet) using HTTP and transfers byte[] from client –> servlet –> client. The client app checks for network coverage first, before trying to connect over cellular (not wifi).

Here is the code for the client app.

public class NetworkDemo extends UiApplication {
// main method
public static void main(String[] args) {

  NetworkDemo theApp = new NetworkDemo();
  UiApplication.getUiApplication().pushScreen(new MyScreen());
  theApp.enterEventDispatcher();

}

}

// HFM
class MyScreen extends MainScreen {

public MyScreen() {

  VerticalFieldManager vfm = new VerticalFieldManager();

  final TextField ttfUri = new TextField("URL:",
                                         "http://nazmul-thinkpad:9090/DataPingServlet/ping" +
                                         CellularConnectionDirectives);
  ButtonField btn = new ButtonField("POST");
  final TextField ttfData = new TextField("Data:", "Hello!");

  btn.setChangeListener(new FieldChangeListener() {
    public void fieldChanged(Field field, int i) {
      // actually perform POST operation
      final String uri = ttfUri.getText();
      final byte[] data = ttfData.getText().getBytes();

      Runnable runnable = new Runnable() {
        public void run() {
          checkEDT();
          checkCoverage();
          try {
            actuallyConnect(uri, data);
          }
          catch (final Exception e) {
            System.out.println(e.toString());
            showToast("Exception: " + e.toString());
          }
        }
      };

      Dialog.inform("About to start http connection...");

      try {
        new Thread(runnable).start();
      }
      catch (Exception e) {
        System.out.println(e.toString());
        showToast("Exception: " + e.toString());
      }

    }
  });

  vfm.add(ttfUri);
  vfm.add(ttfData);
  vfm.add(btn);

  add(vfm);

}

private void actuallyConnect(String uri, byte[] data) throws Exception {
  // create the connection...
  HttpConnection _connection = (HttpConnection) Connector.open(uri, Connector.READ_WRITE, true);

  // Set the request method and headers
  {
    _connection.setRequestMethod(HttpConnection.POST);
    _connection.setRequestProperty("If-Modified-Since",
                                   "29 Oct 1999 19:43:31 GMT");
    _connection.setRequestProperty("User-Agent",
                                   "Profile/MIDP-2.0 Configuration/CLDC-1.0");
    _connection.setRequestProperty("Content-Language", "en-US");
  }

  OutputStream _outputStream = _connection.openOutputStream();

  _outputStream.write(data);
  _outputStream.flush(); // Optional, getResponseCode will flush

  // Getting the response code will open the connection, send the request, and read the HTTP response headers.
  // The headers are stored until requested.
  {
    int rc = _connection.getResponseCode();
    if (rc != HttpConnection.HTTP_OK) {
      throw new IOException("HTTP response code: " + rc);
    }
  }

  // Getting the response code will open the connection, send the request, and read the HTTP response headers.
  // The headers are stored until requested.
  {
    int rc = _connection.getResponseCode();
    if (rc != HttpConnection.HTTP_OK) {
      throw new IOException("HTTP response code: " + rc);
    }
  }

  // get the data from the service
  {
    InputStream _inputStream = _connection.openInputStream();
    final ByteBuffer bb = new ByteBuffer(_inputStream);

    // run this in EDT... not BGT!
    showToast("Got reply from servlet: " + bb.getString());

    // close everything out
    {
      if (_inputStream != null) try {_inputStream.close();}catch (Exception e) {}
      if (_outputStream != null) try {_outputStream.close();}catch (Exception e) {}
      if (_connection != null) try {_connection.close();}catch (Exception e) {}

    }

  }

}

private void checkCoverage() {
  // attach listener...
//  CoverageInfo.addListener(Application.getApplication(), new CoverageStatusListener() {
//    /**
//     * Indicates that the coverage status has changed.
//     * Note that a CoverageInfo.COVERAGE_* flag being set in newCoverage is not a guarantee that a
//     *  connection of that type will succeed. For example, it is possible for the device to lose coverage
//     * between the time this notification was fired and a subsequent connection is attempted, or for
//     * a destination server to be unresponsive.
//     *
//     * @param newCoverage - The new coverage status, consisting of a bitwise OR of one or more CoverageInfo.COVERAGE_* flags.
//     */
//    public void coverageStatusChanged(int newCoverage) {
//    }
//  });

  boolean _outOfCoverage = false;

  if (!CoverageInfo.isOutOfCoverage()) {

    // check to see if the available coverage is of sufficient strength
    _outOfCoverage = !(
        CoverageInfo.isCoverageSufficient(RadioInfo.WAF_WLAN) ||
        CoverageInfo.isCoverageSufficient(RadioInfo.WAF_3GPP) ||
        CoverageInfo.isCoverageSufficient(RadioInfo.WAF_CDMA) ||
        CoverageInfo.isCoverageSufficient(RadioInfo.WAF_IDEN)
    );

    if (_outOfCoverage) {
      showToast("In network coverage, but insufficient strength");
    }
    else {
      showToast("In network coverage");
    }

  }
  else {
    // definitely out of network coverage
    _outOfCoverage = true;
    showToast("Out of network coverage");

  }

  if (_outOfCoverage) throw new IllegalArgumentException("Out of network coverage");

}

private void checkEDT() {

  if (Application.isEventDispatchThread())
    throw new IllegalStateException("Can't call this method in the EDT.");

}

public static void showToast(final String msg) {
  UiApplication.getApplication().invokeLater(new Runnable() {
    public void run() {
      Status.show(msg);
    }
  });
}

/** this gets appended to the URI before a 3g connection is made */
public static final String CellularConnectionDirectives =
    DeviceInfo.isSimulator() ? "" : ";deviceside=false;ConnectionType=mds-public";

/** this gets appended to the URI before a WiFi connection is made */
public static final String WiFiConnectionDirectives =
    DeviceInfo.isSimulator() ? ";interface=wifi" : ";deviceside=true;interface=wifi";

}

public class ByteBuffer {

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// constants
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public static final int BUFFER_SIZE = 512;
//
// jvm constants for string encoding
//
public static final String ASCII = "US-ASCII";
public static final String UTF8 = "UTF-8";
public static final String DEFAULT_CHAR_ENCODING = UTF8;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// data
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

protected byte[] byteRay = null;
protected String enc = DEFAULT_CHAR_ENCODING;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// constructors
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public ByteBuffer() {
}

public ByteBuffer(byte[] srcBuf) {
  append(srcBuf);
}

public ByteBuffer(ByteBuffer bb) {
  append(bb);
}

/**
 * this method does not close the InputStream. Simply reads all data on the stream into a byte
 * buffer.
 */
public ByteBuffer(InputStream is) throws IOException {
  byte[] readBuf = new byte[BUFFER_SIZE];
  while (true) {
    int read = is.read(readBuf);
    if (read == -1) break;
    append(readBuf, 0, read);
  }
}
public ByteBuffer(String s) throws IllegalArgumentException {
  append(s.getBytes());
}

//
// pure functionality of the class
//
public ByteBuffer append(
    byte[] srcBuf, int srcStartIndex, int srcLength)
{
  if (byteRay == null) {
    //create a new array
    byteRay = new byte[srcLength];
    //copy the src array to the new one
    /*
    System.out.println(
      "byteRay.length="+byteRay.length +
      ",srcBuf.length="+srcBuf.length +
      ",srcStartIndex="+srcStartIndex +
      ",srcLength="+srcLength );
    */
    arrayCopy(
        srcBuf, srcStartIndex, byteRay, 0, srcLength);
  }
  else {
    int currentSize = byteRay.length;
    //create a new array (which is bigger than existing one)
    byte[] newByteRay = new byte[currentSize + srcLength];
    //copy the old (internal) array into the new one
    arrayCopy(byteRay, 0, newByteRay, 0, currentSize);
    //copy the src array into the new one
    int newByteRayStartIndex = currentSize;
    arrayCopy(
        srcBuf, srcStartIndex,
        newByteRay, newByteRayStartIndex,
        srcLength);
    //now blow away the old internal byte array with the bigger one
    byteRay = newByteRay;
  }

  return this;
}

public byte[] toByteArray() {
  return getBytes();
}

/**
 * This method simply returns the size of this object in KB.
 * This is <b>not</b> the same as {@link #getString()}, which should be used if you're trying to encode the bytes to
 * string form.
 */
public String toString() {
  if ((byteRay != null) && (byteRay.length > 0)) {
    float sizeInKB = byteRay.length / 1024f;
    return sizeInKB + " KB";
  }
  else {
    return "0 KB";
  }
}

/*
public String toString() {
  if (byteRay == null) {
    return null;
  }

  try {
    return new String(byteRay, enc);
  }
  catch (UnsupportedEncodingException e) {
    //this will never happen, unless the DEFAULT_CHAR_ENCODING
    //is invalid
    return "support.ConstantsIF.DEFAULT_CHAR_ENCODING=" +
           DEFAULT_CHAR_ENCODING + " is invalid!";
  }
}
*/

public void setEncoding(String enc) {
  if (enc == null) {
    return;
  }
  else {
    //test this encoding string to be valid
    try {
      byte[] bytes = {(byte) '0', (byte) '1'};
      new String(bytes, enc);
      this.enc = enc;
    }
    catch (UnsupportedEncodingException e) {
      //don't override the default encoding
      System.out.println("unsupported encoding");
    }
  }
}

/** might return null if encoding fails; unlike {@link #getString()} this does not use system default encoding */
public String getEncodedString() {
  try {
    return new String(byteRay, enc);
  }
  catch (Exception e) {
    return null;
  }
}

/** returns a string representation of the byte[] using system default encoding */
public String getString() {
  if (byteRay != null) return new String(byteRay);
  else return "";
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// internal impl methods
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

protected final void arrayCopy(byte[] srcBuf, int srcStartIndex,
                               byte[] destBuf, int destStartIndex,
                               int numberOfBytesToCopy)
{
  System.arraycopy(srcBuf, srcStartIndex,
                   destBuf, destStartIndex,
                   numberOfBytesToCopy);
  /*
  System.out.println( "arrayCopy start" );
  for( int i=0; i<numberOfBytesToCopy; i++) {
    destBuf[ destStartIndex + i ] = srcBuf[ srcStartIndex + i ];
    System.out.println( "\tindex="+i );
  }
  System.out.println( "arrayCopy end" );
  */
}

//
// accessors for internal state
//
public byte[] getBytes() {
  if (byteRay == null) {
    return new byte[0];
  }
  return byteRay;
}

public ByteArrayInputStream getInputStream() {
  return new ByteArrayInputStream(getBytes());
}

public int getSize() {
  if (byteRay != null) {
    return byteRay.length;
  }
  else {
    return 0;
  }
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// convenience methods
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public void append(byte[] srcBuf) {
  append(srcBuf, 0, srcBuf.length);
}

public void append(ByteBuffer buf) {
  append(buf.getBytes(), 0, buf.getSize());
}

public void clear() {
  if (byteRay != null) {
    byteRay = null;
  }
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// self test method
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public static void selftest() {
  byte[] br1 = {(byte) '0', (byte) '1'};
  byte[] br2 = {(byte) '<', (byte) 'T', (byte) '>'};

  System.out.println("::bb1.append( br1 )");
  ByteBuffer bb1 = new ByteBuffer().append(br1, 0, 2);
  bb1.setEncoding(UTF8);
  System.out.println();

  System.out.println("::bb1.toString():" + bb1.toString());
  System.out.println();

  System.out.println("::bb1.append( br2 )");
  bb1.append(br2, 0, 3);
  System.out.println();

  System.out.println("::bb1.toString():" + bb1.toString());
  System.out.println();
}

}//end of ByteBuffer

Here is the code for the servlet.

public class DataPingServlet extends HttpServlet {

protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
{
  System.out.println(":: " + getClass().getSimpleName() + " GET request... ::");

  StringBuilder sb = new StringBuilder();
  sb.append("<html><body>");
  sb.append(getClass().getSimpleName()).append("...");
  sb.append("</body></html>");

  response.getOutputStream().write(sb.toString().getBytes());
  response.flushBuffer();

}

protected void doPost(HttpServletRequest request, HttpServletResponse res)
    throws ServletException, IOException
{
  System.out.println(":: " + getClass().getSimpleName() + " POST request... ::");

  ByteBuffer inputBB = new ByteBuffer(request.getInputStream());
  ByteBuffer outputBB = null;

  try {

    // get input
    System.out.println("-> got data from client:" + inputBB);
    if (inputBB.getSize() < 1024) System.out.println(":: request data payload:\n" + inputBB.getString());

    outputBB = _getResponse(inputBB);

    System.out.println("<- send data to client:" + outputBB);
    if (outputBB.getSize() < 1024) System.out.println(":: response data payload:\n" + outputBB.getString());

  }
  catch (Exception e) {
    System.out.println(e);
    e.printStackTrace();
  }

  ServletOutputStream sos = res.getOutputStream();

  if (outputBB != null) {
    res.setContentType("application/octet-stream");
    res.setContentLength(outputBB.getSize());
    sos.write(outputBB.getBytes());
  }
  else {
    res.setContentType("application/octet-stream");
    res.setContentLength(inputBB.getSize());
    sos.write(inputBB.getBytes());
  }

  sos.flush();
  sos.close();

}

private ByteBuffer _getResponse(ByteBuffer bb) {

  ByteBuffer resp = new ByteBuffer();

  resp.append(bb);
//  resp.append(("\n:: sent by the " + getClass().getSimpleName() + " class ::").getBytes());

  return resp;
}

}//end class DataPingServlet

public class ByteBuffer {

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// constants
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public static final int BUFFER_SIZE = 512;
//
// jvm constants for string encoding
//
public static final String ASCII = "US-ASCII";
public static final String UTF8 = "UTF-8";
public static final String DEFAULT_CHAR_ENCODING = UTF8;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// data
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

protected byte[] byteRay = null;
protected String enc = DEFAULT_CHAR_ENCODING;

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// constructors
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public ByteBuffer() {
}

public ByteBuffer(byte[] srcBuf) {
  append(srcBuf);
}

public ByteBuffer(ByteBuffer bb) {
  append(bb);
}

/**
 * this method does not close the InputStream. Simply reads all data on the stream into a byte
 * buffer.
 */
public ByteBuffer(InputStream is) throws IOException {
  byte[] readBuf = new byte[BUFFER_SIZE];
  while (true) {
    int read = is.read(readBuf);
    if (read == -1) break;
    append(readBuf, 0, read);
  }
}
public ByteBuffer(String s) throws IllegalArgumentException {
  append(s.getBytes());
}

//
// pure functionality of the class
//
public ByteBuffer append(
    byte[] srcBuf, int srcStartIndex, int srcLength)
{
  if (byteRay == null) {
    //create a new array
    byteRay = new byte[srcLength];
    //copy the src array to the new one
    /*
    System.out.println(
      "byteRay.length="+byteRay.length +
      ",srcBuf.length="+srcBuf.length +
      ",srcStartIndex="+srcStartIndex +
      ",srcLength="+srcLength );
    */
    arrayCopy(
        srcBuf, srcStartIndex, byteRay, 0, srcLength);
  }
  else {
    int currentSize = byteRay.length;
    //create a new array (which is bigger than existing one)
    byte[] newByteRay = new byte[currentSize + srcLength];
    //copy the old (internal) array into the new one
    arrayCopy(byteRay, 0, newByteRay, 0, currentSize);
    //copy the src array into the new one
    int newByteRayStartIndex = currentSize;
    arrayCopy(
        srcBuf, srcStartIndex,
        newByteRay, newByteRayStartIndex,
        srcLength);
    //now blow away the old internal byte array with the bigger one
    byteRay = newByteRay;
  }

  return this;
}

public byte[] toByteArray() {
  return getBytes();
}

/**
 * This method simply returns the size of this object in KB.
 * This is <b>not</b> the same as {@link #getString()}, which should be used if you're trying to encode the bytes to
 * string form.
 */
public String toString() {
  if ((byteRay != null) && (byteRay.length > 0)) {
    float sizeInKB = byteRay.length / 1024f;
    return sizeInKB + " KB";
  }
  else {
    return "0 KB";
  }
}

/*
public String toString() {
  if (byteRay == null) {
    return null;
  }

  try {
    return new String(byteRay, enc);
  }
  catch (UnsupportedEncodingException e) {
    //this will never happen, unless the DEFAULT_CHAR_ENCODING
    //is invalid
    return "support.ConstantsIF.DEFAULT_CHAR_ENCODING=" +
           DEFAULT_CHAR_ENCODING + " is invalid!";
  }
}
*/

public void setEncoding(String enc) {
  if (enc == null) {
    return;
  }
  else {
    //test this encoding string to be valid
    try {
      byte[] bytes = {(byte) '0', (byte) '1'};
      new String(bytes, enc);
      this.enc = enc;
    }
    catch (UnsupportedEncodingException e) {
      //don't override the default encoding
      System.out.println("unsupported encoding");
    }
  }
}

/** might return null if encoding fails; unlike {@link #getString()} this does not use system default encoding */
public String getEncodedString() {
  try {
    return new String(byteRay, enc);
  }
  catch (Exception e) {
    return null;
  }
}

/** returns a string representation of the byte[] using system default encoding */
public String getString() {
  if (byteRay != null) return new String(byteRay);
  else return "";
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// internal impl methods
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

protected final void arrayCopy(byte[] srcBuf, int srcStartIndex,
                               byte[] destBuf, int destStartIndex,
                               int numberOfBytesToCopy)
{
  System.arraycopy(srcBuf, srcStartIndex,
                   destBuf, destStartIndex,
                   numberOfBytesToCopy);
  /*
  System.out.println( "arrayCopy start" );
  for( int i=0; i<numberOfBytesToCopy; i++) {
    destBuf[ destStartIndex + i ] = srcBuf[ srcStartIndex + i ];
    System.out.println( "\tindex="+i );
  }
  System.out.println( "arrayCopy end" );
  */
}

//
// accessors for internal state
//
public byte[] getBytes() {
  if (byteRay == null) {
    return new byte[0];
  }
  return byteRay;
}

public ByteArrayInputStream getInputStream() {
  return new ByteArrayInputStream(getBytes());
}

public int getSize() {
  if (byteRay != null) {
    return byteRay.length;
  }
  else {
    return 0;
  }
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// convenience methods
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public void append(byte[] srcBuf) {
  append(srcBuf, 0, srcBuf.length);
}

public void append(ByteBuffer buf) {
  append(buf.getBytes(), 0, buf.getSize());
}

public void clear() {
  if (byteRay != null) {
    byteRay = null;
  }
}

//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// self test method
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

public static void selftest() {
  byte[] br1 = {(byte) '0', (byte) '1'};
  byte[] br2 = {(byte) '<', (byte) 'T', (byte) '>'};

  System.out.println("::bb1.append( br1 )");
  ByteBuffer bb1 = new ByteBuffer().append(br1, 0, 2);
  bb1.setEncoding(UTF8);
  System.out.println();

  System.out.println("::bb1.toString():" + bb1.toString());
  System.out.println();

  System.out.println("::bb1.append( br2 )");
  bb1.append(br2, 0, 3);
  System.out.println();

  System.out.println("::bb1.toString():" + bb1.toString());
  System.out.println();
}

}//end of ByteBuffer

Sending key/value pairs to forms

Instead of using an RPC approach as I have shown above, you might just want to pass some key/value pairs to a form that is hosted in a .php script or Java servlet. In this case, the client code is not much different, but the data that is sent to the server is. Here is some code that shows you how to convert key/value pairs in a Hashtable to a form that can be sent to a web form.

/** converts a given hashtable object to post key/val pair params */
public static byte[] convertToUrlencoded(Hashtable data) {

  URLEncodedPostData keyvalpairs = new URLEncodedPostData(URLEncodedPostData.DEFAULT_CHARSET, false);
  Enumeration enumeration = data.keys();
  while (enumeration.hasMoreElements()) {
    String key = (String) enumeration.nextElement();
    keyvalpairs.append(key, (String) data.get(key));
  }

  return keyvalpairs.getBytes();

}

Here is what is happening in the code:

  1. The Hashtable contains the key/value pairs to transmit to the web form. This is just like an HTML form would post params to that same web form. You can use this Firefox plugin (UrlParams) to test this out before hand.
  2. The table then gets converted toa  URLEncodedPostData object, which is then turned into a byte array.

Need more help? developerlife.com offers training courses to empower you, and consulting services to enable you.

Uploading files to forms

If you want to send file attachments to web forms, this is doable as well. Please sign up for our training programs to learn how to effectively use networking techniques for your apps and services.

Here is the code to create parameters that you can include a file in, to upload a form:

public class HttpMultipartRequest {

static final String BOUNDARY = "----------ZGV2bGlmZXJvY2tz";

byte[] postBytes = null;

public HttpMultipartRequest(Hashtable params,
                            String fileField,
                            String fileName,
                            String fileType,
                            byte[] fileBytes) throws IOException
{

  String boundary = getBoundaryString();

  String boundaryMessage = getBoundaryMessage(boundary, params, fileField, fileName, fileType);

  String endBoundary = "\r\n--" + boundary + "--\r\n";

  ByteArrayOutputStream bos = new ByteArrayOutputStream();

  bos.write(boundaryMessage.getBytes());

  bos.write(fileBytes);

  bos.write(endBoundary.getBytes());

  this.postBytes = bos.toByteArray();

  bos.close();
}

public byte[] getBytes() {

  return postBytes;

}

String getBoundaryString() {
  return BOUNDARY;
}

String getBoundaryMessage(String boundary, Hashtable params, String fileField, String fileName, String fileType) {
  StringBuffer res = new StringBuffer("--").append(boundary).append("\r\n");

  Enumeration keys = params.keys();

  while (keys.hasMoreElements()) {
    String key = (String) keys.nextElement();
    String value = (String) params.get(key);

    res.append("Content-Disposition: form-data; name=\"").append(key).append("\"\r\n")
        .append("\r\n").append(value).append("\r\n")
        .append("--").append(boundary).append("\r\n");
  }
  res.append("Content-Disposition: form-data; name=\"")
      .append(fileField)
      .append("\"; filename=\"")
      .append(fileName)
      .append("\"\r\n")
      .append("Content-Type: ")
      .append(fileType)
      .append("\r\n\r\n");

  return res.toString();
}

}

Important thing to note

Whether you are using form encoding or multipart form upload, you must set a header to let the server know of your intentions. If you skip this step, then most servers will return an error. Here is the code to set the headers:

if (data instanceof Hashtable)
  conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
else {
  HttpMultipartRequest mr = (HttpMultipartRequest) data;
  conn.setRequestProperty(
     "Content-Type", "multipart/form-data; boundary=" + mr.getBoundaryString());
}

Comments are closed.