Revision: 3311
Author: ferguson.sebastian
Date: Thu Feb 18 12:33:51 2010
Log: Threading issue partway fixed. Server now asks a client what revision it is at when it tries to post, and rejects posts that are out of date.
http://code.google.com/p/power-architect/source/detail?r=3311

Modified:
 /trunk/src/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java

=======================================
--- /trunk/src/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java Thu Feb 18 09:29:28 2010 +++ /trunk/src/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java Thu Feb 18 12:33:51 2010
@@ -5,6 +5,7 @@
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.text.DateFormat;
@@ -50,7 +51,6 @@
 import ca.sqlpower.architect.ddl.DDLGenerator;
 import ca.sqlpower.architect.swingui.ArchitectSwingSessionContext;
 import ca.sqlpower.dao.HttpMessageSender;
-import ca.sqlpower.dao.MessageSender;
 import ca.sqlpower.dao.SPPersistenceException;
 import ca.sqlpower.dao.SPPersisterListener;
 import ca.sqlpower.dao.SPSessionPersister;
@@ -115,6 +115,8 @@
         */
        private final SPJSONPersister jsonPersister;
        private final Updater updater;
+       private final Sender sender;
+       private final SPJSONMessageDecoder jsonMessageDecoder;
private final DataSourceCollectionUpdater dataSourceCollectionUpdater = new DataSourceCollectionUpdater();

        private DataSourceCollection <JDBCDataSource> dataSourceCollection;
@@ -151,11 +153,8 @@

                outboundHttpClient = 
createHttpClient(projectLocation.getServiceInfo());

-               getWorkspace().setUUID(projectLocation.getUUID());
-               getWorkspace().setName(projectLocation.getName());
-
- MessageSender <JSONObject> messageSender = new Sender(outboundHttpClient, projectLocation.getServiceInfo(), projectLocation.getUUID());
-               jsonPersister = new SPJSONPersister(messageSender);
+ sender = new Sender(outboundHttpClient, projectLocation.getServiceInfo(), projectLocation.getUUID());
+               jsonPersister = new SPJSONPersister(sender);

                dataSourceCollection = getDataSourceCollection();

@@ -163,7 +162,8 @@
new SessionPersisterSuperConverter(dataSourceCollection, getWorkspace()));
                sessionPersister.setSession(this);

- updater = new Updater(projectLocation.getUUID(), new SPJSONMessageDecoder(sessionPersister));
+               jsonMessageDecoder = new SPJSONMessageDecoder(sessionPersister);
+               updater = new Updater(projectLocation.getUUID(), 
jsonMessageDecoder);
        }

        // -
@@ -183,10 +183,8 @@
        }

        try {
-               //TODO: Figure out how to de-register the session &c.
- //HttpUriRequest request = new HttpDelete(getServerURI(projectLocation.getServiceInfo(),
-               //              "session/" + getWorkspace().getUUID()));
-                       //outboundHttpClient.execute(request, new 
BasicResponseHandler());
+           //TODO: Figure out how to de-register the session &c.
+           getContext().getSessions().remove(this);
                } catch (Exception e) {
                        try {
                                logger.error(e);
@@ -316,9 +314,9 @@
        HttpClient httpClient = createHttpClient(serviceInfo);
        try {
HttpUriRequest request = new HttpGet(getServerURI(serviceInfo, "/jcr/projects")); - String responseBody = httpClient.execute(request, new JSONResponseHandler()); + JSONMessage message = httpClient.execute(request, new JSONResponseHandler());
                List<ProjectLocation> workspaces = new 
ArrayList<ProjectLocation>();
-               JSONArray response = new JSONArray(responseBody);
+               JSONArray response = new JSONArray(message.getBody());
                for (int i = 0; i < response.length(); i++) {
                        JSONObject workspace = (JSONObject) response.get(i);
                        workspaces.add(new ProjectLocation(
@@ -349,10 +347,10 @@

         try {

- String responseBody = executeServerRequest(httpClient, projectLocation.getServiceInfo(), + JSONMessage message = executeServerRequest(httpClient, projectLocation.getServiceInfo(), "/project/" + projectLocation.getUUID() + "/revision_list",
                     new JSONResponseHandler());
-            JSONArray jsonArray = new JSONArray(responseBody);
+            JSONArray jsonArray = new JSONArray(message.getBody());

             for (int i = 0; i < jsonArray.length(); i++) {

@@ -378,9 +376,8 @@
        HttpClient httpClient = createHttpClient(serviceInfo);
        try {
HttpUriRequest request = new HttpGet(getServerURI(serviceInfo, "/jcr/projects/new", "name=" + name)); - String responseBody = httpClient.execute(request, new JSONResponseHandler());
-               JSONObject response = new JSONObject(responseBody);
-               logger.debug("New Workspace:" + responseBody);
+ JSONMessage message = httpClient.execute(request, new JSONResponseHandler());
+               JSONObject response = new JSONObject(message.getBody());
                return new ProjectLocation(
                                        response.getString("uuid"),
                                        response.getString("name"),
@@ -428,12 +425,12 @@
         HttpClient httpClient = createHttpClient(serviceInfo);

         try {
- String response = executeServerRequest(httpClient, projectLocation.getServiceInfo(), + JSONMessage response = executeServerRequest(httpClient, projectLocation.getServiceInfo(),
                     "/project/" + projectLocation.getUUID() + "/compare",
                     "versions=" + oldRevisionNo + ":" + newRevisionNo,
                     new JSONResponseHandler());

-            return SimpleDiffChunkJSONConverter.decode(response);
+            return SimpleDiffChunkJSONConverter.decode(response.getBody());

         } finally {
             httpClient.getConnectionManager().shutdown();
@@ -492,7 +489,7 @@

// Contained classes --------------------------------------------------------------------

-        boolean persistingToServer = false;
+       boolean persistingToServer = false;

        /**
         * Sends outgoing JSON
@@ -511,32 +508,48 @@
                }

                public void flush() throws SPPersistenceException {
-                       try {
-                           persistingToServer = true;
-                           logger.debug("starting send ... (v" + currentRevision + 
")");
-
-                               URI serverURI = getServerURI();
-                               HttpPost postRequest = new HttpPost(serverURI);
-                               postRequest.setEntity(new 
StringEntity(message.toString()));
-                               postRequest.setHeader("Content-Type", 
"application/json");
-                               HttpUriRequest request = postRequest;
-
- String response = getHttpClient().execute(request, new JSONResponseHandler()); - currentRevision = (new JSONObject(response)).getInt("currentRevision");
-
-                       } catch (ClientProtocolException e) {
-                               throw new SPPersistenceException(null, e);
-                       } catch (IOException e) {
-                               throw new SPPersistenceException(null, e);
-                       } catch (URISyntaxException e) {
-                               throw new SPPersistenceException(null, e);
-                       } catch (Exception e) {
-                throw new RuntimeException(null, e);
-            } finally {
-                               clear();
-                               persistingToServer = false;
-                               logger.debug("... ending send");
-                       }
+                   try {
+                   logger.debug("Sender: Starting flush ...");
+                persistingToServer = true;
+
+                   URI serverURI = getServerURI();
+                HttpPost postRequest = new HttpPost(serverURI);
+ postRequest.setEntity(new StringEntity(message.toString()));
+                postRequest.setHeader("Content-Type", "application/json");
+                HttpUriRequest request = postRequest;
+
+ final JSONMessage response = getHttpClient().execute(request, new JSONResponseHandler());
+
+                   runInForeground(new Runnable() {
+                       public void run() {
+                           try {
+                               if (response.isSuccessful()) {
+ // Message was sent successfully and accepted by the server. + currentRevision = (new JSONObject(response.getBody())).getInt("currentRevision");
+                               } else {
+ // Message was sent successfully but rejected by the server. We must rollback our
+                                   // changes and update to the head revision.
+
+                                   logger.debug("Response unsuccessful");
+                               }
+                               } catch (JSONException e) {
+                            throw new RuntimeException("");
+                        } finally {
+                                       clear();
+                                       persistingToServer = false;
+                                       logger.debug("... Sender: completing 
flush");
+                               }
+                    }
+                });
+                   } catch (UnsupportedEncodingException e) {
+                       throw new SPPersistenceException(null, e);
+            } catch (URISyntaxException e) {
+                throw new SPPersistenceException(null, e);
+            } catch (ClientProtocolException e) {
+                throw new SPPersistenceException(null, e);
+            } catch (IOException e) {
+                throw new SPPersistenceException(null, e);
+            }
                }

                public void send(JSONObject content) throws 
SPPersistenceException {
@@ -546,7 +559,7 @@
                public URI getServerURI() throws URISyntaxException {
                        String contextPath = getServerInfo().getPath();
return new URI("http", null, getServerInfo().getServerAddress(), getServerInfo().getPort(), - contextPath + "/project/" + getProjectLocation().getUUID(), null, null); + contextPath + "/project/" + getProjectLocation().getUUID(), "currentRevision=" + currentRevision, null);
                }
        }

@@ -599,29 +612,36 @@
                        try {
                                while (!this.isInterrupted() && !cancelled) {
                                        try {
- URI uri = new URI("http", null, projectLocation.getServiceInfo().getServerAddress(), projectLocation.getServiceInfo().getPort(), - projectLocation.getServiceInfo().getPath() + contextRelativePath, "oldRevisionNo=" + currentRevision, null);
+
+ URI uri = getServerURI(projectLocation.getServiceInfo(), contextRelativePath,
+                                                   "oldRevisionNo=" + 
currentRevision);
                                            HttpUriRequest request = new 
HttpGet(uri);

- String message = inboundHttpClient.execute(request, new JSONResponseHandler());
-                        final JSONObject json = new JSONObject(message);
+ JSONMessage message = inboundHttpClient.execute(request, new JSONResponseHandler()); + final JSONObject json = new JSONObject(message.getBody());
                         final String jsonArray = json.getString("data");
-                        currentRevision = json.getInt("currentRevision");
-                        if (!persistingToServer) {
-                               runInForeground(new Runnable() {
-                                   public void run() {
-                                       try {
- logger.debug("Start update ... (v" + json.getInt("currentRevision") + ")");
-                                           jsonDecoder.decode(jsonArray);
-                                           logger.debug("... end update");
-                                       } catch (SPPersistenceException e) {
- logger.error("Update from server failed!", e);
-                                           // TODO discard session and reload
-                                       } catch (JSONException je) {
-                                       }
-                                   }
-                               });
-                                           }
+
+                        runInForeground(new Runnable() {
+                            public void run() {
+                                try {
+                                    if (!persistingToServer) {
+ int newRevision = json.getInt("currentRevision"); + if (currentRevision < newRevision) {
+                                            currentRevision = newRevision;
+ logger.debug("Updater: Starting run ...");
+                                            jsonDecoder.decode(jsonArray);
+ logger.debug("... Updater: completing run");
+                                        }
+                                    }
+                                } catch (SPPersistenceException e) {
+ logger.error("Update from server failed!", e);
+                                    // TODO discard session and reload
+                                } catch (JSONException e) {
+ logger.error("Update from server failed!", e);
+                                }
+                            }
+                        });
+
                                        } catch (Exception ex) {
logger.error("Failed to contact server. Will retry in " + retryDelay + " ms.", ex);
                                                Thread.sleep(retryDelay);
@@ -812,8 +832,27 @@
                     "data-sources/" + type + "/" + ds.getName());
         }
     }
-
- private static class JSONResponseHandler implements ResponseHandler<String> {
+
+       private static class JSONMessage {
+
+           private final String message;
+           private final boolean successful;
+
+           public JSONMessage(String message, boolean successful) {
+               this.message = message;
+               this.successful = successful;
+           }
+
+           public String getBody() {
+               return message;
+           }
+
+           public boolean isSuccessful() {
+               return successful;
+           }
+       }
+
+ private static class JSONResponseHandler implements ResponseHandler<JSONMessage> {

            /*
* Responses from the architect-enterprise resources should always be bundled as
@@ -823,7 +862,7 @@
             * reads, reconstructs, and re-throws an exception from a resource.
             */

- public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + public JSONMessage handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
             try {

                 BufferedReader reader = new BufferedReader(
@@ -840,23 +879,28 @@
// Does the response contain data? If so, return it. Communication
                 // with the resource has been successful.
                 if (message.getString("responseKind").equals("data")) {
-                    return message.getString("data");
+ return new JSONMessage(message.getString("data"), true);
                 } else {
- // Does the response contain an exception? If so, reconstruct, and then - // re-throw it. There has been an exception on the server. - if (message.getString("responseKind").equals("exceptionStackTrace")) {
-
- JSONArray stackTraceStrings = new JSONArray(message.getString("data")); - StringBuffer stackTraceMessage = new StringBuffer(); - for (int i = 0; i < stackTraceStrings.length(); i++) { - stackTraceMessage.append("\n").append(stackTraceStrings.get(i));
-                        }
-
-                        throw new Exception(stackTraceMessage.toString());
-
+                    // Has the request been unsuccessful?
+ if (message.getString("responseKind").equals("unsuccessful")) { + return new JSONMessage(message.getString("data"), false);
                     } else {
- // This exception represents a(n epic) client-server miscommunication
-                        throw new Exception("Unable to parse response");
+ // Does the response contain an exception? If so, reconstruct, and then + // re-throw it. There has been an exception on the server. + if (message.getString("responseKind").equals("exceptionStackTrace")) {
+
+ JSONArray stackTraceStrings = new JSONArray(message.getString("data")); + StringBuffer stackTraceMessage = new StringBuffer(); + for (int i = 0; i < stackTraceStrings.length(); i++) { + stackTraceMessage.append("\n").append(stackTraceStrings.get(i));
+                            }
+
+ throw new Exception(stackTraceMessage.toString());
+
+                        } else {
+ // This exception represents a(n epic) client-server miscommunication + throw new Exception("Unable to parse response");
+                        }
                     }
                 }
             } catch (Exception ex) {

Reply via email to