Syntax Highlighter

Sunday, October 28, 2012

Connecting your Android App to a remote database

       For Android devs to be: in most mobile applications, an external server and database is useful, so I'll show a simple way of connecting an Android app to a backend script written in PHP.

       Well, this can be done using the Apache HttpClient library, which can be found at  http://hc.apache.org/ . Once you add this library to your project's classpath, you'll be able to handle HTTP Requests from Java in a very neat and simple way. Let's use it to write a simple project, in which the user will be able to upload files and perform queries on the server's database.

       In order to make it simple, let's create two basic classes: User and Server, and write them so we can use them later on in the simplest and most intuitive way possible:

           
public class User {
  
    private int id;
 
    private String username;
 
    private String password;
 
    private File image;
 
    private String fileURL;

 public User(String username, String password, File image){
  
    this.username  = username;
    this.password = password;
    this.image = image;
  
 }
 
 
 public String getUserName(){
    return username;
 }
 
 public String getPassword(){
    return password;
 }

 public File getImage() {
    return image;
 }

 public String getFileURL() {
    return fileURL;
 }


 public int getId() {
    return id;
 }

}

public class Server {
 
  private String serverURL;
  private HashMap<ServerScripts,String> serverScripts;
  
  public static enum ServerScripts{
   SQL_QUERY_MAKER, IMAGE_UPLOAD;
  }
  
  public Server(String SUrl){
     setServerURL(SUrl);
     buildScriptReference();
  }
  
  private void buildScriptReference(){
   
   serverScripts = new HashMap<ServerScrpts,String>();
   serverScripts.put(ServerScripts.SQL_QUERY_MAKER,getServerURL() + "/PHP/SQLQueryMakerScript.php");
   serverScripts.put(ServerScripts.IMAGE_UPLOAD, getServerURL() + "/PHP/imageUploadScript.php");
   
  }

  public HashMap<ServerScrpts,String> getServerScripts() {
   return serverScripts;
  }

  public String getServerURL() {
   return serverURL;
  }

  public void setServerURL(String serverURL) {
   this.serverURL = serverURL;
  }
  
  
}
Next we create a class that will be responsible for handling the HTTP Requests so we can add/remove Users to/from the server. So let's focus on the client side, creating a ConnectionHandler class. We'll provide it with a DefaultHttpClient object (so we can use the Apache library), the server with which we wish to communicate and three methods:
  • void uploadFile(File file, String fileId) - Uploads the image to the server, asking it to react to the Request through the script imageUploadScript.php
  • public BufferedInputStream downloadFile(String fileUrl) - Gets an user's image based on the userID given.
  • String performSQLQuery(String sqlCommand) - Queries the server's database, asking it to run the specified SQL query through the script SQLqueryMakerScript.php. The String returned will be JSON encoded, so we can easily manipulate the results.
Now the code:

public class ConnectionHandler {

 private HttpClient httpClient;
 private Server server;
 
 
 public ConnectionHandler(String serverURL){
  
  httpClient = new DefaultHttpClient();
  server = new Server(serverURL);
  
 }
 
 
 public BufferedInputStream downloadFile(String fileUrl) throws IOException{
  

        //since we don't need the server to respond using any
        //particular script, we can use the standard java.net methods
  InputStream is = null;
  URL myFileUrl = null;
  try {
   myFileUrl = new URL(fileUrl);
  } catch (MalformedURLException e1) {
   // TODO Auto-generated catch block
   e1.printStackTrace();
  }
  HttpURLConnection conn;
  conn = (HttpURLConnection) myFileUrl.openConnection();
  conn.setReadTimeout(10000);
  conn.setRequestMethod("POST");
  conn.setDoInput(true); 
  conn.connect();
   
  is = conn.getInputStream();
  BufferedInputStream bis = new BufferedInputStream(is);
   
  return bis;
   
 }
 
 public void uploadFile(File file, String fileId) throws Exception{
  
  HttpPost post = new HttpPost(server.getServerScripts().get(ServerScripts.IMAGE_UPLOAD));

  MultipartEntity  body = new MultipartEntity();
  
  body.addPart("imagem", new FileBody(file));
  body.addPart("fileId", new StringBody(fileId));
  
  post.setEntity(body);
  
  String response = EntityUtils.toString(httpClient.execute(post).getEntity(), "UTF-8");
  System.out.println(response);
 }
 
        

 public String performSQLQuery(String sqlCommand){
 
            
  String result = null;
  InputStream is = null;
  
  try{
   HttpPost httppost = new HttpPost(server.getServerScripts().get(ServerScripts.SQL_QUERY_MAKER));
   
   ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
   
   nameValuePairs.add(new BasicNameValuePair("SQLCommand", sqlCommand));
   
   UrlEncodedFormEntity body = new UrlEncodedFormEntity(nameValuePairs);
   
   httppost.setEntity(body);
   
   HttpResponse response = httpClient.execute(httppost);
   HttpEntity entity = response.getEntity();
   is = entity.getContent();
   
  } catch(Exception e){
    e.printStackTrace();
  }
  try{
   BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
   StringBuilder str = new StringBuilder();
   String line= new String();
   
   while((line = reader.readLine())!=null){
    str.append(line + "\n");
   }
   
   is.close();
   
   result = str.toString();
  }catch(Exception e){
   e.printStackTrace();
  }
  
  return result;
 }
 
 public String getServerUrl(){
  return server.getServerURL();
 }
 
 

 
}

All right, now we're all set. Let's create a user in a local WAMP server, which is an easy to use Apache instance set up to work with PHP and MySQL. It can be downloaded at http://www.wampserver.com/en/ . There are also equivalents for Mac OS X and Linux distros, namely MAMP and LAMP. The OS doesn't really matter, as long as we have an Apache server running PHP and connected to a MySQL db. So let's keep going:
 

public class ConnectionTester{

      public static void main(String[] args){
           File file = new File("filePath");

           ConnectionHandler conn = new ConnectionHandler("http://localhost");
           User user = new User("Eric","abc123", file);

           createNewUser(user.getUserName(), 
                  user.getPassword(), user.getImage(), conn);


      }

      private static void createNewUser(String userName, String password, File image, ConnectionHandler connHandler){
   
   JSONArray jsonArray = null;
   
   int idLastRow=0;
   
   try {
              //this query will just make sure we add the user to the end of
              //the table.
    String jsonResponse= connHandler.performSQLQuery("select * from users order by id desc limit 0,1");
    jsonArray = new JSONArray(jsonResponse);
    idLastRow = jsonArray.getJSONObject(0).getInt("id");
   } catch (JSONException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   int userId = idLastRow + 1;
   
   
   String sqlCommand = "INSERT INTO USERS VALUES (" + userId + ", '" + userName + 
   "', '" + password + "' , '" + "http://localhost/images/" + userId + ".jpg' )";
   
   connHandler.performSQLQuery(sqlCommand);
   
   try {
    connHandler.uploadFile(image, userId + "");
   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
 }



}
Test it and you'll see it adds the file to your server's "imagens" directory and creates a new row on your SQL user's table, as long as you put these PHP scripts on your WAMP's www/PHP folder:

imageUploadScript.php:
<?php 
 $ext = pathinfo($_FILES['imagem']['name'], PATHINFO_EXTENSION);
 $path = $_SERVER['DOCUMENT_ROOT'] . "/images/" . $_POST["fileId"] . "." . $ext;
 if(move_uploaded_file($_FILES["imagem"]['tmp_name'], $path)) {
  echo "The file ".  basename( $_FILES["imagem"]['name']). 
  " has been uploaded";
 } else{
  echo "There was an error uploading the file, please try again!";
 }
?>



SQLqueryMakerScript.php:
<?php
 $con = mysql_connect("localhost","username","password");
 
 if(!$con){
  die('Could not connect: ' . mysql_error());
 }
 
 mysql_select_db("squeak",$con);
 
 
 $result = mysql_query($_POST["SQLCommand"]);
 $output=null;
 
 while($row = mysql_fetch_assoc($result)){
   $output[]=$row;
 }
 
 $jsonresponse = json_encode($output);
 echo $jsonresponse;
 
 mysql_close($con);
?>
Finally, to use this on your Android app, just implement these classes on your project and set the server url to your Apache server, if you allow external TCP connections. This method of sending HTTP requests from Java can be used to connect to any website, you can read more about it at http://hc.apache.org/httpclient-legacy/tutorial.html .  Hopefully this post got you started with mobile client-server applications. Good luck!

Thursday, October 25, 2012

Because sharing is worth it!

       It lives! This blog was created so I had a place to share my findings on computer programming and other stuff. I hope you find my content relevant and I don't bore you to death. So if you're into programming, computer science, web development and technology in general, welcome aboard! Let's get started.