Thursday, June 28, 2012

JSR-82 : Java Bluetooth

In the last article we found how to search for other bluetooth devices. Here we look in to how search for a service on a particular bluetooth device.
The following code sample shows you how to use the DiscoveryAgent to search for an OBEX Push bluetooth service. It first searches for all available Bluetooth Devices, and prompts to select a device on which to search the OBEX Push Service.
For this sample to work, you need a JSR-82 Implmentation (Java Bluetooth Stack) like ElectricBlue or aveLink in the class path.


  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.util.Vector;
  5.  
  6. import javax.bluetooth.DeviceClass;
  7. import javax.bluetooth.DiscoveryAgent;
  8. import javax.bluetooth.DiscoveryListener;
  9. import javax.bluetooth.LocalDevice;
  10. import javax.bluetooth.RemoteDevice;
  11. import javax.bluetooth.ServiceRecord;
  12. import javax.bluetooth.UUID;
  13.  
  14. /**
  15. *
  16. * Class that discovers all bluetooth devices in the neighbourhood,
  17. *
  18. * Connects to the chosen device and checks for the presence of OBEX push service in it.
  19. * and displays their name and bluetooth address.
  20. *
  21. *
  22. */
  23. public class BluetoothServiceDiscovery implements DiscoveryListener{
  24.    
  25.     //object used for waiting
  26.     private static Object lock=new Object();
  27.        
  28.     //vector containing the devices discovered
  29.     private static Vector vecDevices=new Vector();
  30.    
  31.     private static String connectionURL=null;
  32.  
  33.    
  34.     /**
  35.      * Entry point.
  36.      */
  37.     public static void main(String[] args) throws IOException {
  38.        
  39.         BluetoothServiceDiscovery bluetoothServiceDiscovery=new BluetoothServiceDiscovery();
  40.        
  41.         //display local device address and name
  42.         LocalDevice localDevice = LocalDevice.getLocalDevice();
  43.         System.out.println("Address: "+localDevice.getBluetoothAddress());
  44.         System.out.println("Name: "+localDevice.getFriendlyName());
  45.        
  46.         //find devices
  47.         DiscoveryAgent agent = localDevice.getDiscoveryAgent();
  48.       
  49.         System.out.println("Starting device inquiry...");
  50.         agent.startInquiry(DiscoveryAgent.GIAC, bluetoothServiceDiscovery);
  51.        
  52.         try {
  53.             synchronized(lock){
  54.                 lock.wait();
  55.             }
  56.         }
  57.         catch (InterruptedException e) {
  58.             e.printStackTrace();
  59.         }
  60.        
  61.        
  62.         System.out.println("Device Inquiry Completed. ");
  63.        
  64.         //print all devices in vecDevices
  65.         int deviceCount=vecDevices.size();
  66.        
  67.         if(deviceCount <= 0){
  68.             System.out.println("No Devices Found .");
  69.         }
  70.         else{
  71.             //print bluetooth device addresses and names in the format [ No. address (name) ]
  72.             System.out.println("Bluetooth Devices: ");
  73.             for (int i = 0; i <deviceCount; i++) {
  74.                 RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(i);
  75.                 System.out.println((i+1)+". "+remoteDevice.getBluetoothAddress()+" ("+remoteDevice.getFriendlyName(true)+")");
  76.             }
  77.         }
  78.        
  79.         System.out.print("Choose the device to search for Obex Push service : ");
  80.         BufferedReader bReader=new BufferedReader(new InputStreamReader(System.in));
  81.        
  82.         String chosenIndex=bReader.readLine();
  83.         int index=Integer.parseInt(chosenIndex.trim());
  84.        
  85.         //check for obex service
  86.         RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(index-1);
  87.         UUID[] uuidSet = new UUID[1];
  88.         uuidSet[0]=new UUID("1105",true);
  89.        
  90.         System.out.println("\nSearching for service...");
  91.         agent.searchServices(null,uuidSet,remoteDevice,bluetoothServiceDiscovery);
  92.        
  93.         try {
  94.             synchronized(lock){
  95.                 lock.wait();
  96.             }
  97.         }
  98.         catch (InterruptedException e) {
  99.             e.printStackTrace();
  100.         }
  101.        
  102.         if(connectionURL==null){
  103.             System.out.println("Device does not support Object Push.");
  104.         }
  105.         else{
  106.             System.out.println("Device supports Object Push.");
  107.         }
  108.     }
  109.    
  110.    
  111.     /**
  112.      * Called when a bluetooth device is discovered.
  113.      * Used for device search.
  114.      */
  115.     public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
  116.         //add the device to the vector
  117.         if(!vecDevices.contains(btDevice)){
  118.             vecDevices.addElement(btDevice);
  119.         }
  120.     }
  121.  
  122.    
  123.     /**
  124.      * Called when a bluetooth service is discovered.
  125.      * Used for service search.
  126.      */
  127.     public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
  128.         if(servRecord!=null && servRecord.length>0){
  129.             connectionURL=servRecord[0].getConnectionURL(0,false);
  130.         }
  131.         synchronized(lock){
  132.             lock.notify();
  133.         }
  134.     }
  135.  
  136.    
  137.     /**
  138.      * Called when the service search is over.
  139.      */
  140.     public void serviceSearchCompleted(int transID, int respCode) {
  141.         synchronized(lock){
  142.             lock.notify();
  143.         }
  144.     }
  145.  
  146.  
  147.     /**
  148.      * Called when the device search is over.
  149.      */
  150.     public void inquiryCompleted(int discType) {
  151.         synchronized(lock){
  152.             lock.notify();
  153.         }
  154.        
  155.     }//end method
  156.    
  157.    
  158. }//end class 
     

Tuesday, June 26, 2012

J2ME and Location-Based Services

Location-based services (LBS) provide users of mobile devices personalized services tailored to their current location. They open a new market for developers, cellular network operators, and service providers to develop and deploy value-added services: advising users of current traffic conditions, supplying routing information, helping them find nearby restaurants, and many more.
This article introduces you to the field of LBS and to the Location API for J2ME (JSR 179), a set of generic APIs that can be used for developing location-based services. In addition, the article offers guidelines for designing location-based services.

What Location-Based Services Do

Location-based services answer three questions: Where am I? What's around me? How do I get there? They determine the location of the user by using one of several technologies for determining position, then use the location and other information to provide personalized applications and services. As an example, consider a wireless 911 emergency service that determines the caller's location automatically. Such a service would be extremely useful, especially to users who are far from home and don't know local landmarks. Traffic advisories, navigation help including maps and directions, and roadside assistance are natural location-based services. Other services can combine present location with information about personal preferences to help users find food, lodging, and entertainment to fit their tastes and pocketbooks.
There are two basic approaches to implementing location-based services:

  1. Process location data in a server and deliver results to the device.
  2. Obtain location data for a device-based application that uses it directly.
This article focuses on device-based location services.

Determining the Device's Location

To discover the location of the device, LBS must use real-time positioning methods. Accuracy depends on the method used.
Locations can be expressed in spatial terms or as text descriptions. A spatial location can be expressed in the widely used latitude-longitude-altitude coordinate system. Latitude is expressed as 0-90 degrees north or south of the equator, and longitude as 0-180 degrees east or west of the prime meridian, which passes through Greenwich, England. Altitude is expressed in meters above sea level. A text description is usually expressed as a street address, including city, postal code, and so on.
Applications can call on any of several types of positioning methods.
  • Using the mobile phone network: The current cell ID can be used to identify the Base Transceiver Station (BTS) that the device is communicating with and the location of that BTS. Clearly, the accuracy of this method depends on the size of the cell, and can be quite inaccurate. A GSM cell may be anywhere from 2 to 20 kilometers in diameter. Other techniques used along with cell ID can achieve accuracy within 150 meters.
  • Using satellites: The Global Positioning System (GPS), controlled by the US Department of Defense, uses a constellation of 24 satellites orbiting the earth. GPS determines the device's position by calculating differences in the times signals from different satellites take to reach the receiver. GPS signals are encoded, so the mobile device must be equipped with a GPS receiver. GPS is potentially the most accurate method (between 4 and 40 meters if the GPS receiver has a clear view of the sky), but it has some drawbacks: The extra hardware can be costly, consumes battery while in use, and requires some warm-up after a cold start to get an initial fix on visible satellites. It also suffers from "canyon effects" in cities, where satellite visibility is intermittent.
  • Using short-range positioning beacons: In relatively small areas, such as a single building, a local area network can provide locations along with other services. For example, appropriately equipped devices can use Bluetooth for short-range positioning.
In addition, location methods can connect to a mobile position center that provides an interface to query for the position of the mobile subscriber. The API to the mobile position center is XML-based. While applications can be fully self-contained on the device, it's clear that a wider array of services is possible when a server-side application is part of the overall service.
Some applications don't need high accuracy, but others will be useless if the location isn't accurate enough. It's okay for the location of a tourist walking around town to be off by 30 meters, but other applications and services may demand higher accuracy.

The Location API for J2ME

The Location API for J2ME specification defines an optional package, javax.microedition.location, that enables developers to write wireless location-based applications and services for resource-limited devices like mobile phones, and can be implemented with any common location method. The compact and generic J2ME location APIs provide mobile applications with information about the device's present physical location and orientation (compass direction), and support the creation and use of databases of known landmarks, stored in the device.
JSR 179 requires the Connected Device Configuration (CDC) or version 1.1 of the Connected Limited Device Configuration (CLDC). CLDC 1.0 isn't adequate because it doesn't support floating-point numbers, which the API uses to represent coordinates and other measurements. The Location API doesn't depend on any particular profile -- it can be used with MIDP or the Personal Profile.
The hardware platform determines which location methods are supported. If it doesn't support at least one location provider, LBS won't be possible. Applications can request providers with particular characteristics, such as a minimum degree of accuracy. Some location methods may be free; others may entail service fees. The application should warn the user before any charges are incurred.
It is up to the application to determine the criteria for selecting the location method. Criteria fields include: accuracy, response time, need for altitude, and speed. Once the application obtains a LocationProvider instance that meets the criteria, it can use that object to obtain the location, in either of two ways:
  • Invoke a method synchronously to get a single location.
  • Register a listener and get periodic updates at application-defined intervals.
The Location class abstracts the location results. Its object contains coordinates, speed if available, textual address if available, and a time stamp that indicates when the location measurements were made.
Coordinates are represented by either of two classes:
  • A Coordinates object represents a point's latitude and longitude in degrees, and altitude in meters.
  • A QualifiedCoordinates object contains latitude, longitude, and altitude, and also an indication of their accuracy, represented as the radius of an area.
The following segment of code demonstrates how to obtain the present location of the device synchronously:
...

// Set criteria for selecting a location provider:
// accurate to 500 meters horizontally
Criteria cr= new Criteria();
cr.setHorizontalAccuracy(500);

// Get an instance of the provider
LocationProvider lp= LocationProvider.getInstance(cr);

// Request the location, setting a one-minute timeout
Location l = lp.getLocation(60);
Coordinates c = l.getQualifiedCoordinates();

if(c != null ) {
  // Use coordinate information
  double lat = c.getLatitude();
  double lon = c.getLongitude();
}
...

Landmarks

A landmark is a location associated with a name and a description. Landmarks can be stored in a device-based database, where they can be shared among all J2ME applications. Landmarks can store frequently used locations: home, office, favorite restaurants, and so on. Each is represented by a Landmark instance, and the database by a LandmarkStore. You can create multiple named LandmarkStores to group locations into categories such as cinemas, museums, or customer sites.
If the device includes a compass, the application may be able to determine not only its location but its orientation, which is useful in navigational applications. The Orientation class represents the device's azimuth as an angle from due north, which the application can easily convert to a compass direction.

Security and Privacy

Many users consider location information to be highly sensitive, and are concerned about a number of privacy issues, including:
  • Target marketing: Mobile users' locations can be used to classify customers for focused marketing efforts.
  • Embarrassment: One customer's knowledge of another's location may lead to embarrassing situations.
  • Harassment: Location information can be used to harass or attack a user.
  • Service denial: A health insurance firm might deny a claim if it learned that a user visited a high-risk area.
  • Legal restrictions: Some countries regulate the use of personal data.
For these and other reasons, users must know when their location is given to an application.

Guidelines

Keep the following guidelines in mind when designing location-based services:
  • Handle unavailability of services gracefully. The user's location may not always be available, for any of several reasons.
    • The device is cut off from any of the location methods it supports, in a tunnel or on an airplane for example.
    • The user withholds permission to release the information.
    • No location provider that the device supports is available.
  • Depending on the method used, determining the location may take a long time. The delay may be so long that the end result isn't useful in, for example, a navigation application. Keep the user informed.
  • Location service fees, typical of network-assisted location methods, can add up quickly, so don't overuse fee-based services.
  • Be sensitive to privacy concerns.
    • Tell customers about the information being collected on them and how it will be used.
    • Offer customers the choice of what location information to disclose, and when appropriate an option not to participate.
    • Allow customers to review their permission profiles so that they know what they are permitting.
    • Protect location information so that it cannot be accessed by unauthorized persons.
You should also take full advantage of the MIDP 2.0 security framework, which restricts the application's access to location data to cases in which the user explicitly confirms permission.

Summary

Through the Location API for J2ME, you can use information about the user's position to build new kinds of applications and services for mobile devices such as cell phones and PDAs, and to enhance existing services. JSR 179 specifies a generic API for obtaining locations, and thus makes porting LBS applications to a wide range of devices much easier. The critical issue that LBS developers must address is the privacy of the customer. To ensure privacy, follow sound programming guidelines and use the security framework in MIDP 2.0.

For More Information

 Link: http://www.oracle.com/technetwork/systems/location-156846.html

Wednesday, June 20, 2012

Sun Mobile Device Technology - Introduction to Mobility Java Technology

To develop applications using wireless Java technology, you'll need to assimilate information from several fields. You'll need to understand something about wireless communications technology, the business of wireless communications, and a lot about the Java platform. Where should you begin? This page contains a high-level overview of wireless Java technology and many links to detailed information about specific subjects.

Overview of Wireless Communications

Wireless communications is a huge field, encompassing everything from radio and television broadcasting through pagers, mobile phones, and satellite communications. The field of mobile phones is expanding very fast at the same time that standards and protocols are being adopted, used, updated, and sometimes discarded. The other rapidly expanding part of the wireless world is that of wireless local area networks (LANs). Driven by widespread acceptance of the IEEE 802.11 standard, wireless local networking for computers and other devices is spreading rapidly.

Although wireless may seem like a special case, it is actually more intuitive and more natural than wired networking. Some day soon the need to plug a laptop into a network physically will seem quaint and antiquated. The notion that you could walk into a room with your cell phone and have it unable to interact with other devices in the room will seem unbelievably primitive. The future will reveal that wired networks are the special case.

Conceptually, wireless communications can be split into two types, local and wide area. A local device is similar to a key fob with a button that unlocks a car, a 900 MHz cordless phone, a radio control toy, or a Bluetooth network. All of these devices operate over short distances, typically just a few meters.

Wide area wireless devices operate effectively over a much greater area. A pager or mobile phone is a good example; you can talk on your mobile phone to any other phone on the planet. These devices' greater range relies on a trick, however: a more elaborate land-based network. A mobile phone doesn't have that much more radio power than a radio control toy. What it does have is a network of carefully placed radio antennas (cell towers); the phone can continue to operate as long as it is within range of at least one tower. The mobile phone device receives service from a wireless carrier, a company that operates the land-based network.
While a number of industry consortia and standard bodies, such as the International Telecommunication Union, are trying to define or foster the development of standards for the wireless world, today's wireless world is still fragmented and complex. If you buy a mobile phone in the U.S. today, it might run on Motorola's iDEN network or Sprint's PCS network. Take it overseas to Europe and you'll be out of luck--your phone will not work with Europe's GSM network, nor will it work with the PDC network or any of the other mobile networks that live in Japan.

Overview of the Java Platform
The Java Platform comprises three elements:
  1. The Java programming language is syntactically similar to C++ but differs fundamentally. While C++ uses unsafe pointers and programmers are responsible for allocating and freeing memory, the Java programming language uses type safe object references, and unused memory is reclaimed automatically. Furthermore, the Java programming language eschews multiple inheritance (a likely source of confusion and ambiguity in C++) in favor of a cleaner construct, interfaces.
  2. A virtual machine forms the foundation of the Java platform. This architecture offers several attractive features: The virtual machine can be implemented to run a top a variety of operating systems and hardware, with binary-compatible Java applications operating consistently across many implementations. In addition, the virtual machine provides tight control of executed binaries, enabling safe execution of untrusted code.
  3. Finally, an extensive set of standard application programming interfaces(APIs) rounds out the Java platform. These support almost everything you might want your applications to do, from user interface through cryptography, from CORBA connectivity through internationalization.
Taken together, the Java language, Java virtual machine1, and Java APIs compose the Java platform. Moreover, the Java platform is designed to encompass a wide range of computer hardware, everything from smart cards through enterprise servers. Therefore, the Java platform comes in three flavors:
  • Java Platform, Standard Edition (Java SE) is designed for desktop computers. Most often it runs on top of OS X, Linux, Solaris, or Microsoft Windows.
  • Java Platform, Enterprise Edition (Java EE) is a comprehensive platform for multiuser,enterprise-wide applications. It is based on Java SE and adds APIs for server-side computing.
  • Java Platform, Micro Edition (Java ME) is a set of technologies and specifications developed for small devices like pagers, mobile phones, and set-top boxes. Java ME uses subsets of Java SE components, such as smaller virtual machines and leaner APIs.
  • The New to Java Programming Center offers an excellent entry point into the Java platform, understanding it, getting it installed on your computer, and starting to program.

The Java Community Process (JCP)

Specifications for Java SE, Java EE, and Java ME are developed under the aegis of the Java Community Process (JCP). A specification begins life as a Java Specification Request (JSR). An expert group consisting of representatives from interested companies is formed to create the specification. The JSR then passes through various stages in the JCP before it is finished. Every JSR is assigned a number. Java ME specifications are commonly referred to by their JSR number.

Overview of Java ME

Unlike Java SE, Java ME is not a piece of software, nor is it a single specification. This difference can be confusing, even for developers who are already familiar with Java SE. Instead, Java ME is a platform, a collection of technologies and specifications that are designed for different parts of the small device market. Because Java ME spans such a variety of devices, it wouldn't make sense to try to create a one-size-fits-all solution.

Java ME, therefore, is divided into configurations, profiles,and optional packages. Configurations are specifications that detail a virtual machine and a base set of APIs that can be used with a certain class of device. A configuration, for example, might be designed for devices that have less than 512 KB of memory and an intermittent network connection. The virtual machine is either a full Java Virtual Machine (as described in the specification) or some subset of the full JVM1. The set of APIs is customarily a subset of the Java SE APIs.

A profile builds on a configuration but adds more specific APIs to make a complete environment for building applications. While a configuration describes a JVM1 and a basic set of APIs, it does not by itself specify enough detail to enable you to build complete applications. Profiles usually include APIs for application life cycle, user interface, and persistent storage.

An optional package provides functionality that may not be associated with a specific configuration or profile. One example of an optional package is the Bluetooth API (JSR 82), which provides a standardized API for using Bluetooth networking. This optional package could be implemented alongside virtually any combination of configurations and profiles.

 Link: http://www.oracle.com/technetwork/systems/getstart-155582.html

Sunday, June 17, 2012

HTTP POST from a J2ME midlet

Although there are several examples and tutorials about how to connect to an HTTP server from a J2ME Midlet, I found that they all seem to concentrate a lot on the details of a GET and the POST is always assumed as an "exercise to the reader."

Now, although it is indeed rather straightforward to work out how to send POST requests to a server, I found (the hard way) that there are certain "minor details" that are best not forgotten.

I have thus decided to post here a brief example of how to send a request to a server, using a form-encoded body, so that either a JSP or a servlet can retriever the parameters, but one can benefit from the many advantages of POSTing, as oppposed to GETting.

The source code follows, I believe it is reasonably self-explanatory and comments should guide even the most novice reader through, but please do let me know if you feel that this is still too cryptic:



private void OpenConnection(String server) 
throws java.io.IOException {
// TODO: the actual "resource" part of the URL (/test in this case)
// should be either passed as a parameter or obtained at application
// level (maybe even set up at runtime).
// To test this code, I have written the simple Servlet below, however
// this would also work with a JSP page that echoes back the contents
// in text/plain format for the midlet to display.
//
  String url = "http://"+server+"/test"; 
  byte[] data = null;
  InputStream istrm = null;

  HttpConnection http = (HttpConnection)Connector.open(url);
  http.setRequestMethod(HttpConnection.POST);

  // This allows a JSP page to process the parameters correctly
  // This format (or content type) is the same as when forms are
  // submitted from a web page.
  http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

  // You may want to indicate to the server side (eg servlet) that 
  // this request is coming from a specific application.  This would
  // allow generation of appropriate format for the content.
  http.setRequestProperty("User-Agent", "HttpMidlet/0.2");

  // You can send any custom property as part of the HTTP header
  // This would matter for the "infrastructure" code, as opposed
  // to "body parameters" that would matter to the application
  // (eg, user=marco)
  http.setRequestProperty("Custom-Property", 
      "MyCustomProperty/1.0; AnotherProperty/debug_0.1");

  // You MUST create the body of the post BEFORE actually opening
  // the stream, otherwise you won't be able to set the length of
  // the request (see next step).
  // In this example, I am sending coordinates to a mapping server
  String msg = "x="+location.getX()+"&y="+location.getY();

  // THIS is important! without it a JSP won't process the POST data
  // it would also appear that CASE MATTERS (using "Content-Length" -note 
  // the capital 'L'- caused my servlet to return -1 from the 
  //    HttpServletRequest.getContentLenght() method
  http.setRequestProperty("Content-length", ""+msg.getBytes().length);

  // After this point, any call to http.setRequestProperty() will
  // cause an IOException
  OutputStream out = http.openOutputStream();
  out.write(msg.getBytes());
  out.flush();

  if (http.getResponseCode() == HttpConnection.HTTP_OK) {
    int len = (int)http.getLength();
    istrm = http.openInputStream();
    if (istrm == null) {
      log("Cannot open stream - aborting");
      throw new IOException("Cannot open HTTP InputStream, aborting");
    }
    if (len != -1) {
      data = new byte[len];
      int bytesRead = istrm.read(data);
      addProgressMsg("Read "+bytesRead+" bytes");
    } else {
    ByteArrayOutputStream bo = new ByteArrayOutputStream();
      int ch;
      int count = 0;

      // This is obviously not particularly efficient
      // You may want to use a byte[] buffer to read bytes in chunks
      while ((ch = istrm.read()) != -1) {
        bo.write(ch);
        count++;
      }
      data = bo.toByteArray();
      bo.close();
      addProgressMsg("Read "+count+" bytes");
    }
    response = new String(data);
    addProgressMsg("finished");
  } else {
    log("Response: "+http.getResponseCode()+", "+http.getResponseMessage());
    response = null;
    addProgressMsg("failed: "+http.getResponseMessage());
  }
  // This is critical, unless you close the HTTP connection, the application
  // will either be consuming needlessly resources or, even worse, sending
  // 'keep-alive' data, causing your user to foot unwanted bills!
  http.close();
}


To test this code, all that is required is a simple Serlvet that runs, for example, in an Apache Tomcat JSP container:
public class ConnectivityDiag extends HttpServlet {

  private static final String REVISION = "0.0.04";
  private static Logger log;

  public ConnectivityDiag() {
    if (log == null) {
      log = Logger.getLogger(getClass().getName());
      BasicConfigurator.configure();
    }
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    doProcessRequest(req, res);
  } 
 
public void doPost(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    doProcessRequest(req, res);
  }

  public void doProcessRequest(HttpServletRequest req, HttpServletResponse res) {
    BufferedReader reader = null;
    Writer writer = null;

    try {
      // Note this call seems to be case-sensitive
      // if the midlet does not set exactly "Content-length"
      // as the property, -1 will be returned
      int len = req.getContentLength();
      String contentType = req.getContentType();
      log.debug("Len: " + len);
      log.debug("Type: "+contentType);

      int bytesRead = 0;
      String remoteHost = req.getRemoteHost();
      String userAgent = req.getHeader("user-agent");
      log.info("Accessed at " + (new Date()) + " from " + remoteHost
          + ", using " + userAgent);

      // This simply echoes the parameters back to the client.
      // A JSP would use these in a  tag
      // and the ${param} macro.
      ArrayList strings = new ArrayList();
      Enumeration e = req.getParameterNames();
      while (e.hasMoreElements()) {
        String param = (String)e.nextElement();
        String value = (String)req.getParameter(param);
        strings.add(param+" = "+value);
      }
      res.setContentType("text/plain");

      // This is a custom property, that the remote client 
      // could query
      res.setHeader("Sent-at", new Date().toString());

      writer = res.getWriter();
      writer.write("Diagnostic servlet - Rev. "+REVISION);
      writer.write("\nBytes received: " + len);
      writer.write("\nFrom: " + remoteHost);
      writer.write("\nUsing: " + userAgent);
      writer.write("\n=== Parameters ===\n");
      for(String s:strings) {
        writer.write(s);
        writer.write('\n');
      }
      writer.write("=== Parameters end here ===\n");
      writer.flush();

    } catch (IOException e) {
      log.error(e.getMessage());
    } finally {
      try {
        if (reader != null)
          reader.close();
        if (writer != null)
          writer.close();
      } catch (IOException ex) {
        log.error(ex.getMessage());
      }
    }
  }
}
 
 
Link: http://codetrips.blogspot.com/2007/04/http-post-from-j2me-midlet.html 

Thursday, June 14, 2012

HTTP Post multipart file upload in Java ME

Here is a J2ME class to handle file uploads via HTTP POST Multipart Requests.

Source Code: HttpMultipartRequest class

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
 
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
 
public class HttpMultipartRequest
{
	static final String BOUNDARY = "----------V2ymHFg03ehbqgZCaKO6jy";
 
	byte[] postBytes = null;
	String url = null;
 
	public HttpMultipartRequest(String url, Hashtable params, String fileField, String fileName, String fileType, byte[] fileBytes) throws Exception
	{
		this.url = url;
 
		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();
	}
 
	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();
	}
 
	public byte[] send() throws Exception
	{
		HttpConnection hc = null;
 
		InputStream is = null;
 
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
		byte[] res = null;
 
		try
		{
			hc = (HttpConnection) Connector.open(url);
 
			hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + getBoundaryString());
 
			hc.setRequestMethod(HttpConnection.POST);
 
			OutputStream dout = hc.openOutputStream();
 
			dout.write(postBytes);
 
			dout.close();
 
			int ch;
 
			is = hc.openInputStream();
 
			while ((ch = is.read()) != -1)
			{
				bos.write(ch);
			}
			res = bos.toByteArray();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				if(bos != null)
					bos.close();
 
				if(is != null)
					is.close();
 
				if(hc != null)
					hc.close();
			}
			catch(Exception e2)
			{
				e2.printStackTrace();
			}
		}
		return res;
	}
}

Sample usage

Here's a code snippet to upload a file via HttpMultipartRequest class:
byte[] fileBytes = getFileBytes(); //retrieve file bytes with your own code
 
Hashtable params = new Hashtable();
params.put("custom_param", "param_value");
params.put("custom_param2", "param_value2");
 
HttpMultipartRequest req = new HttpMultipartRequest(
	"http://www.server.com/uploadScript.php",
	params,
	"upload_field", "original_filename.png", "image/png", fileBytes
);
 
byte[] response = req.send();

Sample server code (PHP)

This is a sample PHP script that handles the upload. It doesn't actually save the uploaded file, but only displays some infos about the upload size and parameters.
<?php
 
$filesize = filesize($_FILES['upload_field']['tmp_name']);
 
echo "The uploaded file size is " . $filesize . " bytes\n";
 
foreach($_POST as $key => $value)
{
	echo "Parameter name: " . $key . ", value: " . $value . "\n";
}
 
?>
 
 
 
Link: http://www.developer.nokia.com/Community/Wiki/HTTP_Post_multipart_file_upload_in_Java_ME