Android Open Source - Orochi-Framework Request Thread






From Project

Back to project page Orochi-Framework.

License

The source code is released under:

Copyright (c) 2012 Ronald Tsang, ronaldtsang@orochis-den.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Sof...

If you think the Android project Orochi-Framework listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
Copyright (c) 2012 Ronald Tsang, ronaldtsang@orochis-den.com
//  w  ww  .j a v a2 s.  c o  m
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package orochi.nativeadapter;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import orochi.util.FileUtils;
import orochi.util.json.JSONException;
import orochi.util.json.JSONObject;

import android.util.Log;

public class RequestThread extends Thread {
    
  private String requestID;
  private HashMap<String, RequestExecutor> requestExecutors;
    private Socket socket;
    private RequestHandler baseHandler;
    private static int handlerTimeout = 18*1000; //18s
  
  
    public RequestThread(String requestID, HashMap<String, RequestExecutor> requestExecutors, Socket socket, RequestHandler baseHandler) {
      this.requestID = requestID;
      this.requestExecutors = requestExecutors;
        this.socket = socket;
        this.baseHandler = baseHandler;
    }
    
    private static void writeHeader(BufferedOutputStream out, int code, String contentType, String filename, long contentLength, long lastModified) throws IOException {
        out.write(("HTTP/1.0 " + code + " OK\r\n" + 
                   "Date: " + new Date().toString() + "\r\n" +
                   "Server: OrochiNativeEngine/1.0\r\n" +
                   "Content-Type: " + contentType + "\r\n" +
                   (filename!=null?("Content-Disposition: attachment; filename="+filename + "\r\n"):"") +
                   "Expires: Sat, 01 Jan 2000 12:00:00 GMT\r\n" +
                   ((contentLength != -1) ? "Content-Length: " + contentLength + "\r\n" : "") +
                   "Last-modified: " + new Date(lastModified).toString() + "\r\n" +
                   "\r\n").getBytes());
    }
    
    private static void writeError(BufferedOutputStream out, int code, String message) throws IOException {
        message = message + "<hr>";
        out.write(message.getBytes());
        out.flush();
        out.close();
    }
    
    //return a HashMap of the get parameters
    private static HashMap<String,String> hashGetParms(String getParmString){
        StringTokenizer getParmsTokenizer = new StringTokenizer(getParmString, "&");       
        
        Log.d("Orochi", "RequestThead Parmaeters:");
        HashMap<String,String> getParms = new HashMap<String,String>();
        while(getParmsTokenizer.hasMoreTokens()){
          String parmString = getParmsTokenizer.nextToken();
          parmString = URLDecoder.decode(parmString);
          String parmKey = parmString.substring(0, parmString.indexOf("="));
          String parmValue = parmString.substring(parmString.indexOf("=")+1);
          
          getParms.put(parmKey, parmValue);                 
          Log.d("Orochi", "    Key:"+parmKey+"  Value:"+parmValue);
        }
        return getParms;
    }
    
    private static void handleFileRequest(BufferedOutputStream out, String filePath){
      InputStream reader = null;
      
      try {
        File file = new File(filePath);
          
          if (file.isDirectory() || !file.exists()) {
              // The file was not found.
              writeError(out, 404, "File Not Found.");
          }
          else {
            reader = new BufferedInputStream(new FileInputStream(file));
          
              String contentType = (String)NativeEngine.MIME_TYPES.get(FileUtils.getExtension(file));
              String encodeFilename = null;
              if (contentType == null) { //if unknown file type
                  contentType = "application/octet-stream";
                  encodeFilename=URLEncoder.encode(file.getName());
              }
              
              writeHeader(out, 200, contentType, encodeFilename, file.length(), file.lastModified());
              
              byte[] buffer = new byte[4096];
              int bytesRead;
              while ((bytesRead = reader.read(buffer)) != -1) {
                  out.write(buffer, 0, bytesRead);
              }
              reader.close();
          }
          out.flush();
          out.close();      
      }
        catch (IOException e) {
            if (reader != null) {
                try {
                    reader.close();
                }
                catch (Exception anye) {
                    // Do nothing.
                }
            }
        }        
    }
    
    
    public void run() {
        try {                     
            socket.setSoTimeout(30000);
            BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream()); 
            
            //reject invalid ip
            if ( !NativeService.isValidIP(socket.getInetAddress().toString()) ){
              writeHeader(out, 200, "text/html", null, -1, System.currentTimeMillis());
                writeError(out, 500, "Access Denied.");
              return;
            }
            
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            
            String request = in.readLine();
            
            if (request == null || !request.startsWith("GET /?") || !(request.endsWith(" HTTP/1.0") || request.endsWith("HTTP/1.1"))) {
                // Invalid request type (no "GET")
              writeHeader(out, 200, "text/html", null, -1, System.currentTimeMillis());
                writeError(out, 500, "Invalid Method.");
                return;
            }             
            
            Log.d("Orochi", "RequestThead: ["+(new Date().toString())+"]Receive Request from: "+socket.getInetAddress().toString());
            final HashMap<String,String> getParms = hashGetParms(request.substring(6, request.lastIndexOf(" HTTP/1.")));
            
            if(getParms.containsKey("fileRequestHandler")){
              //file request, instead of native request
              handleFileRequest(out, getParms.get("fileRequestHandler"));
              return;
            }
            
            //send html header
            writeHeader(out, 200, "text/html", null, -1, System.currentTimeMillis());
            
            //send jsonp header if it is jsonp request
            boolean isJsonpRequest = getParms.containsKey("callback");
            if(isJsonpRequest)
              out.write((getParms.get("callback")+"(").getBytes());
            
            if (baseHandler != null) {
              RequestExecutor requestExecutor;
              if(getParms.containsKey("requestID")){ //handle back request
                requestExecutor = requestExecutors.get(getParms.get("requestID"));
                if(requestExecutor==null){
                        writeError(out, 500, "Invalid Method.");
                        return;
                }                  
              }
              else //handle new request
                requestExecutor = new RequestExecutor(getParms);
              
              //send request result
        out.write((requestExecutor.getResult().toString()).getBytes()); 
            }
            
            //send jsonp footer if it is jsonp request
            if(isJsonpRequest)
              out.write((");").getBytes());            
                     
            out.flush();
            out.close();            
        }
        catch (IOException e) {
            Log.e("Orochi", "RequestThead: "+e.toString());
        }
    }
    
    protected class RequestExecutor {

    private FutureTask<JSONObject> futureTask;
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    
      public RequestExecutor(final HashMap<String,String> getParms){
        futureTask = new FutureTask<JSONObject>(
            new Callable<JSONObject>(){
              public JSONObject call() {
                    JSONObject respJsonObj = new JSONObject();
                    try {
                  baseHandler.handle(getParms, respJsonObj);
                } catch (JSONException e) {
                  Log.e("Orochi", "RequestThead: "+e.toString());
                }
                    return respJsonObj;
              }
            }
        );
        executor.execute(futureTask);
      }
      
      public JSONObject getResult(){
        JSONObject respJsonObj = new JSONObject();
      try {
        respJsonObj = futureTask.get(handlerTimeout, TimeUnit.MILLISECONDS);
        
        //if request done within the handlerTimeout (default 18s)
        executor.shutdown();
        //remove this object from the executing request pool
        requestExecutors.remove(requestID);
        try {
          respJsonObj.put("requestDone", true);
          respJsonObj.put("serviceName", NativeService.serviceName);
          respJsonObj.put("requestID", requestID);
        } catch (JSONException e) {
          Log.e("Orochi", "RequestThead: "+e.toString());
        }
        
      } catch (InterruptedException e) {
        Log.e("Orochi", "RequestThead: "+e.toString());
      } catch (ExecutionException e) {
        Log.e("Orochi", "RequestThead: "+e.toString());
      } catch (TimeoutException e) {
        //request is not done within the handlerTimeout (default 18s)
        //change to long request        
        Log.d("Orochi", "RequestThead: handler timeout, change to long request.");
        if(!requestExecutors.containsKey(requestID)){
          //put this object into the executing request pool
          requestExecutors.put(requestID, this);
        }
        try {
          //return the requestID to the client side for back request
          respJsonObj.put("requestDone", false);
          respJsonObj.put("serviceName", NativeService.serviceName);
          respJsonObj.put("requestID", requestID);
        } catch (JSONException e1) {
          Log.e("Orochi", "RequestThead: "+e1.toString());
        }          
      }
      return respJsonObj;
      }

  }
    
}




Java Source Code List

orochi.example.MainActivity.java
orochi.nativeadapter.NativeEngine.java
orochi.nativeadapter.NativeService.java
orochi.nativeadapter.OrochiActivity.java
orochi.nativeadapter.RequestHandler.java
orochi.nativeadapter.RequestThread.java
orochi.nativeadapter.requesthandler.AccelerometerHandler.java
orochi.nativeadapter.requesthandler.BasicHandler.java
orochi.nativeadapter.requesthandler.CompassHandler.java
orochi.nativeadapter.requesthandler.FlashlightHandler.java
orochi.nativeadapter.requesthandler.MediaHandler.java
orochi.nativeadapter.requesthandler.NetworkHandler.java
orochi.nativeadapter.requesthandler.NotificationHandler.java
orochi.testing.MainActivity.java
orochi.util.AccelerationListener.java
orochi.util.ActivityForResultObject.java
orochi.util.CompassListener.java
orochi.util.FileUtils.java
orochi.util.NetworkUtils.java
orochi.util.OrochiSensorEventListener.java
orochi.util.json.JSONArray.java
orochi.util.json.JSONException.java
orochi.util.json.JSONObject.java
orochi.util.json.JSONString.java
orochi.util.json.JSONStringer.java
orochi.util.json.JSONTokener.java
orochi.util.json.JSONWriter.java