// ************************************************************************ // Microsoft Script Library // Visual InterDev 6.0 Remote Scripting proxy // Copyright 1998 Microsoft Corporation. All Rights Reserved. // ************************************************************************ import java.applet.*; import java.awt.*; import java.net.URL; import java.io.InputStream; import java.io.IOException; //============================================================================== // Main Class for applet RSProxy // //============================================================================== public class RSProxy extends Applet implements Runnable { // APPLET INFO SUPPORT: // The getAppletInfo() method returns a string describing the applet's // author, copyright date, or miscellaneous information. //-------------------------------------------------------------------------- public String getAppletInfo() { return "Name: RSProxy\r\n" + "Author: Microsoft\r\n" + "Copyright (c) 1998 Microsoft Corp."; } public void init() { resize(0,0); } public void destroy() {} public void paint(Graphics g) {} public void start() {} public void stop() {} // Event Status Codes //-------------------------------------------------------------------------- static final int E_FAIL = -1; static final int S_COMPLETED = 0; static final int S_PENDING = 1; static final int S_PARTIAL = 2; // Request Object Definition //-------------------------------------------------------------------------- static final int REQUEST_NEXT = 0; static final int REQUEST_PREV = 1; static final int REQUEST_ID = 2; static final int REQUEST_URL = 3; static final int REQUEST_URLCONTEXT = 4; static final int REQUEST_MODE = 5; static final int REQUEST_THREAD = 6; static final int C_REQUEST = 7; // Request Object Modes //-------------------------------------------------------------------------- static final int REQUEST_MODE_COMPLETE = 0; static final int REQUEST_MODE_PARTIAL = 1; // Response Object Definition //-------------------------------------------------------------------------- static final int RESPONSE_NEXT = 0; static final int RESPONSE_REQUESTID = 1; static final int RESPONSE_STATUS = 2; static final int RESPONSE_MESSAGE = 3; static final int RESPONSE_DATA = 4; static final int C_RESPONSE = 5; // Other Constants //-------------------------------------------------------------------------- static final int BUFFER_SIZE = 512; static final int EXPECTED_MAX_CONCURRENT_CALLS = 5; // Private Members //-------------------------------------------------------------------------- // Request list. Requests are inserted at head and removed when completed. private Object m_requestLock; private Object[] m_requestHead; // Response queue. private Object m_responseLock; private Object[] m_responseHead; private Object[] m_responseTail; // Public Methods //-------------------------------------------------------------------------- // RSProxy class constructor public RSProxy() { m_requestLock = new Object(); m_responseLock = new Object(); } // initiates a request given an id and url public void startRequest(String requestID,String url_context,String url,int mode) { Object[] request = newRequest(requestID,url_context,url,mode); insertRequest(request); Thread thread = new Thread(this,requestID); request[REQUEST_THREAD] = thread; thread.start(); } // used to poll applet for response public synchronized boolean waitForResponse() { // a response is already queued up if (null != m_responseHead) return true; // a response cannot be generated without a request if (null == m_requestHead) return false; try { // try waiting for a response while (null == m_responseHead) wait(); return true; } catch (InterruptedException ie) { return false; } } public synchronized void cancelRequest(String requestId) { Object [] request = findRequest(requestId); if (request == null) return; if (request[REQUEST_THREAD] != null) ((Thread)request[REQUEST_THREAD]).stop(); } // The following methods get the response information // Only the UI thread should call these methods. public boolean hasResponse() { return null != m_responseHead; } public void endResponse() { removeResponse(); } public String getRequestID() { if (null == m_responseHead) return ""; return (String)m_responseHead[RESPONSE_REQUESTID]; } public int getStatus() { if (null == m_responseHead) return 0; return getInteger(m_responseHead[RESPONSE_STATUS]); } public String getMessage() { if (null == m_responseHead) return ""; return (String)m_responseHead[RESPONSE_MESSAGE]; } public String getData() { if (null == m_responseHead) return ""; return (String)m_responseHead[RESPONSE_DATA]; } // Runnable Protocol //-------------------------------------------------------------------------- public void run() { String requestID = Thread.currentThread().getName(); runUrlDownloadThread(requestID); } // Protected Methods //-------------------------------------------------------------------------- // spawns worker thread to asynchronously retrieve data for given request protected void runUrlDownloadThread(String requestID) { Object[] request = findRequest(requestID); Object[] response; if (null == request) response = newErrorResponse(requestID,"Unknown request id."); else { try { int bytesRead; byte[] buffer = new byte[BUFFER_SIZE]; URL contextURL = new URL((String)request[REQUEST_URLCONTEXT]); InputStream stream = new URL(contextURL,(String)request[REQUEST_URL]).openStream(); StringBuffer responseBuffer = new StringBuffer(); while (-1 != (bytesRead = stream.read(buffer))) { if (request[REQUEST_MODE] == getObject(REQUEST_MODE_PARTIAL)) { // generate response as partial data buffers are received response = newDataResponse(requestID,new String(buffer,0,0,bytesRead),false); handleResponse(request,response); } else //if (request[REQUEST_MODE] == getObject(REQUEST_MODE_COMPLETE)) { // generate a single response when request is complete responseBuffer.append(new String(buffer,0,0,bytesRead)); } } stream.close(); if (request[REQUEST_MODE] == getObject(REQUEST_MODE_PARTIAL)) response = newDataResponse(requestID, "", true); else //if (request[REQUEST_MODE] == getObject(REQUEST_MODE_COMPLETE)) response = newDataResponse(requestID,responseBuffer.toString(),true); } catch (Exception e) { response = newErrorResponse(requestID,e.getMessage()); } } handleResponse(request,response); } // handle response, inserts response into queue, removes request when complete protected synchronized void handleResponse(Object[] request,Object[] response) { insertResponse(response); int status = getInteger(response[RESPONSE_STATUS]); if (S_COMPLETED == status || E_FAIL == status) removeRequest(request); notifyAll(); } // Object constructors //-------------------------------------------------------------------------- // constructor for new Request object protected Object[] newRequest(String requestID,String url_context,String url,int mode) { Object[] request = new Object[C_REQUEST]; request[REQUEST_ID] = requestID; request[REQUEST_URL] = url; request[REQUEST_URLCONTEXT] = url_context; request[REQUEST_MODE] = getObject(mode); return request; } // constructor for new Response object protected Object[] newDataResponse(String requestID,String data,boolean finished) { Object[] response = new Object[C_RESPONSE]; response[RESPONSE_REQUESTID] = requestID; response[RESPONSE_STATUS] = new Integer(finished ? S_COMPLETED : S_PARTIAL); response[RESPONSE_MESSAGE] = "Completed"; response[RESPONSE_DATA] = data; return response; } // constructor for new ErrorResponse object protected Object[] newErrorResponse(String requestID,String message) { Object[] response = new Object[C_RESPONSE]; response[RESPONSE_REQUESTID] = requestID; response[RESPONSE_STATUS] = new Integer(E_FAIL); response[RESPONSE_MESSAGE] = message; response[RESPONSE_DATA] = ""; return response; } // list management routines //-------------------------------------------------------------------------- // find a given request object in the request list protected Object[] findRequest(String requestID) { synchronized (m_requestLock) { Object[] i; for (i = m_requestHead; null != i; i = (Object[])i[REQUEST_NEXT]) { if (0 == requestID.compareTo((String)i[REQUEST_ID])) return i; } } return null; } // insert a request object at the head of the request list protected void insertRequest(Object[] request) { synchronized (m_requestLock) { request[REQUEST_PREV] = null; request[REQUEST_NEXT] = m_requestHead; if (null != m_requestHead) m_requestHead[REQUEST_PREV] = request; m_requestHead = request; } } // remove a request object from the request list protected void removeRequest(Object[] request) { synchronized (m_requestLock) { if (null == request[REQUEST_PREV]) m_requestHead = (Object[])request[REQUEST_NEXT]; else ((Object[])request[REQUEST_PREV])[REQUEST_NEXT] = request[REQUEST_NEXT]; if (null != request[REQUEST_NEXT]) ((Object[])request[REQUEST_NEXT])[REQUEST_PREV] = request[REQUEST_PREV]; } } // insert a response object onto the tail of the queue protected void insertResponse(Object[] response) { synchronized (m_responseLock) { if (null == m_responseHead) { m_responseHead = response; m_responseTail = response; } else { m_responseTail[RESPONSE_NEXT] = response; m_responseTail = response; } } } // remove response at the head of the queue protected void removeResponse() { synchronized (m_responseLock) { if (null != m_responseHead) { m_responseHead = (Object[])m_responseHead[RESPONSE_NEXT]; if (null == m_responseHead) m_responseTail = null; } } } // private helper functions //-------------------------------------------------------------------------- // casts int as Object private Object getObject(int integer) { return new Integer(integer); } // casts Object as int private int getInteger(Object obj) { if (null == obj) return 0; return ((Integer)obj).intValue(); } }