Initial implementation of ROP refactoring decoupling Hessian from connectivity 
layer and introducing pluggable serialization and connectivity layers.


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/83185f25
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/83185f25
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/83185f25

Branch: refs/heads/master
Commit: 83185f2558f764cf60b137a2e2eeda47d366a17f
Parents: f72db8b
Author: Dzmitry Kazimirchyk <dkazimirc...@gmail.com>
Authored: Tue Jan 19 01:38:28 2016 +0300
Committer: Dzmitry Kazimirchyk <dkazimirc...@gmail.com>
Committed: Tue Mar 1 12:49:03 2016 +0300

----------------------------------------------------------------------
 .../configuration/rop/client/ClientModule.java  |   9 +-
 .../rop/client/HessianConnectionProvider.java   |  63 -----
 .../apache/cayenne/remote/BaseConnection.java   |  21 --
 .../remote/hessian/ClientSerializerFactory.java |   2 +-
 .../remote/hessian/HessianConnection.java       |   2 +-
 .../cayenne/rop/DefaultClientConnection.java    | 122 ++++++++++
 .../rop/DefaultClientConnectionProvider.java    |  44 ++++
 .../apache/cayenne/rop/ProxyRemoteService.java  |  59 +++++
 .../org/apache/cayenne/rop/ROPConnector.java    |  32 +++
 ...ientHessianSerializationServiceProvider.java |  39 ++++
 .../cayenne/rop/http/HttpROPConnector.java      | 233 +++++++++++++++++++
 .../rop/http/HttpROPConnectorProvider.java      |  58 +++++
 .../rop/client/ClientModuleTest.java            |   4 +-
 .../rop/server/ROPServerModule.java             |   7 +-
 .../service/ServerSerializerFactory.java        |   2 +-
 .../rop/HessianROPSerializationService.java     |  69 ++++++
 .../org/apache/cayenne/rop/ROPConstants.java    |  28 +++
 .../cayenne/rop/ROPSerializationService.java    |  34 +++
 .../java/org/apache/cayenne/rop/ROPServlet.java | 122 ++++++++++
 ...rverHessianSerializationServiceProvider.java |  37 +++
 .../cayenne/rop/ServerHttpRemoteService.java    |  48 ++++
 21 files changed, 943 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/ClientModule.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/ClientModule.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/ClientModule.java
index de64f08..041408a 100644
--- 
a/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/ClientModule.java
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/ClientModule.java
@@ -32,6 +32,10 @@ import org.apache.cayenne.di.Module;
 import org.apache.cayenne.event.DefaultEventManager;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.remote.ClientConnection;
+import org.apache.cayenne.remote.RemoteService;
+import org.apache.cayenne.rop.*;
+import org.apache.cayenne.rop.http.ClientHessianSerializationServiceProvider;
+import org.apache.cayenne.rop.http.HttpROPConnectorProvider;
 
 /**
  * A DI module containing all Cayenne ROP client runtime configurations.
@@ -56,7 +60,10 @@ public class ClientModule implements Module {
         binder.<String> bindMap(Constants.PROPERTIES_MAP).putAll(properties);
 
         
binder.bind(ObjectContextFactory.class).to(CayenneContextFactory.class);
-        
binder.bind(ClientConnection.class).toProvider(HessianConnectionProvider.class);
+        
binder.bind(ROPSerializationService.class).toProvider(ClientHessianSerializationServiceProvider.class);
+        
binder.bind(ROPConnector.class).toProvider(HttpROPConnectorProvider.class);
+        binder.bind(RemoteService.class).to(ProxyRemoteService.class);
+        
binder.bind(ClientConnection.class).toProvider(DefaultClientConnectionProvider.class);
         binder.bind(EventManager.class).to(DefaultEventManager.class);
         
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
         binder.bind(DataChannel.class).toProvider(ClientChannelProvider.class);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/HessianConnectionProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/HessianConnectionProvider.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/HessianConnectionProvider.java
deleted file mode 100644
index 21fda18..0000000
--- 
a/cayenne-client/src/main/java/org/apache/cayenne/configuration/rop/client/HessianConnectionProvider.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.rop.client;
-
-import org.apache.cayenne.ConfigurationException;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.remote.ClientConnection;
-import org.apache.cayenne.remote.hessian.HessianConnection;
-
-public class HessianConnectionProvider implements Provider<ClientConnection> {
-
-    @Inject
-    protected RuntimeProperties runtimeProperties;
-
-    public ClientConnection get() throws ConfigurationException {
-
-        String url = runtimeProperties.get(Constants.ROP_SERVICE_URL_PROPERTY);
-        if (url == null) {
-            throw new ConfigurationException(
-                    "No property defined for '%s', can't initialize 
HessianConnection",
-                    Constants.ROP_SERVICE_URL_PROPERTY);
-        }
-
-        String userName = 
runtimeProperties.get(Constants.ROP_SERVICE_USERNAME_PROPERTY);
-        String password = 
runtimeProperties.get(Constants.ROP_SERVICE_PASSWORD_PROPERTY);
-        String sharedSession = runtimeProperties
-                .get(Constants.ROP_SERVICE_SHARED_SESSION_PROPERTY);
-        long readTimeout = runtimeProperties.getLong(
-                Constants.ROP_SERVICE_TIMEOUT_PROPERTY,
-                -1l);
-
-        HessianConnection result = new HessianConnection(
-                url,
-                userName,
-                password,
-                sharedSession);
-
-        if (readTimeout > 0) {
-            result.setReadTimeout(readTimeout);
-        }
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/remote/BaseConnection.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/remote/BaseConnection.java 
b/cayenne-client/src/main/java/org/apache/cayenne/remote/BaseConnection.java
index 74dd3f4..d02449e 100644
--- a/cayenne-client/src/main/java/org/apache/cayenne/remote/BaseConnection.java
+++ b/cayenne-client/src/main/java/org/apache/cayenne/remote/BaseConnection.java
@@ -33,7 +33,6 @@ public abstract class BaseConnection implements 
ClientConnection {
 
     protected Log logger;
     protected long messageId;
-    protected long readTimeout = 0L;
     
     /**
      * Default constructor that initializes logging and a single threaded 
EventManager.
@@ -111,26 +110,6 @@ public abstract class BaseConnection implements 
ClientConnection {
     public long getProcessedMessagesCount() {
         return messageId + 1;
     }
-
-    /**
-     * The socket timeout on requests in milliseconds. Defaults to infinity.
-     * 
-     * @since 3.1
-     */
-    public long getReadTimeout() {
-        return readTimeout;
-    }
-    
-    /**
-     * Sets the socket timeout.
-     * 
-     * @param readTimeout The socket timeout on requests in milliseconds.
-     * 
-     * @since 3.1
-     */
-    public void setReadTimeout(long readTimeout) {
-        this.readTimeout = readTimeout;
-    }
     
     /**
      * Called before logging the beginning of message processing.

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
index f39d642..ff7aeb3 100644
--- 
a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java
@@ -34,7 +34,7 @@ import com.caucho.hessian.io.Serializer;
  * 
  * @since 1.2
  */
-class ClientSerializerFactory extends AbstractSerializerFactory {
+public class ClientSerializerFactory extends AbstractSerializerFactory {
 
     private Deserializer dataRowDeserializer;
     private Deserializer listDeserializer;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/HessianConnection.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/HessianConnection.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/HessianConnection.java
index d8f6ee2..3bea90d 100644
--- 
a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/HessianConnection.java
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/HessianConnection.java
@@ -226,7 +226,7 @@ public class HessianConnection extends BaseConnection {
         factory.setConnectionFactory(new HessianURLConnectionFactory(this));
         factory.setUser(userName);
         factory.setPassword(password);
-        factory.setReadTimeout(getReadTimeout());
+//        factory.setReadTimeout(getReadTimeout());
 
         this.serializerFactory = factory.getSerializerFactory();
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnection.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnection.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnection.java
new file mode 100644
index 0000000..2004c6e
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnection.java
@@ -0,0 +1,122 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.event.EventBridge;
+import org.apache.cayenne.event.EventBridgeFactory;
+import org.apache.cayenne.remote.BaseConnection;
+import org.apache.cayenne.remote.ClientMessage;
+import org.apache.cayenne.remote.RemoteService;
+import org.apache.cayenne.remote.RemoteSession;
+
+public class DefaultClientConnection extends BaseConnection {
+
+       private RemoteService remoteService;
+       private RemoteSession session;
+
+       private String sharedSessionName;
+    
+    public DefaultClientConnection(RemoteService remoteService, String 
sharedSession) {
+        this.remoteService = remoteService;
+        this.sharedSessionName = sharedSession;
+    }
+
+       @Override
+       protected void beforeSendMessage(ClientMessage message) throws 
CayenneRuntimeException {
+               if (session == null) {
+                       connect();
+               }
+       }
+
+       @Override
+       protected Object doSendMessage(ClientMessage message) throws 
CayenneRuntimeException {
+        try {
+            return remoteService.processMessage(message);
+        }
+        catch (CayenneRuntimeException e) {
+            throw e;
+        }
+        catch (Throwable th) {
+            throw new CayenneRuntimeException(th.getMessage(), th);
+        }
+       }
+
+       @Override
+       public EventBridge getServerEventBridge() throws 
CayenneRuntimeException {
+        if (session == null) {
+            connect();
+        }
+
+        return createServerEventBridge(session);
+       }
+
+       protected synchronized void connect() {
+               if (session != null) {
+                       return;
+               }
+        
+        long t0 = System.currentTimeMillis();
+
+               // create server session...
+               try {
+                       this.session = (sharedSessionName != null) ? 
remoteService
+                                       
.establishSharedSession(sharedSessionName) : remoteService
+                                       .establishSession();
+               }
+               catch (Throwable th) {
+                       logger.info(th.getMessage(), th);
+                       throw new CayenneRuntimeException(th.getMessage(), th);
+               }
+
+        if (logger.isInfoEnabled()) {
+            long time = System.currentTimeMillis() - t0;
+            logger.info("=== Connected, session: "
+                    + session
+                    + " - took "
+                    + time
+                    + " ms.");
+        }
+       }
+
+    /**
+     * Creates an EventBridge that will listen for server events. Returns null 
if server
+     * events support is not configured in the descriptor.
+     *
+     * @throws CayenneRuntimeException if EventBridge startup fails for any 
reason.
+     */
+    protected EventBridge createServerEventBridge(RemoteSession session) 
throws CayenneRuntimeException {
+
+        if (!session.isServerEventsEnabled()) {
+            return null;
+        }
+
+        try {
+            EventBridgeFactory factory = (EventBridgeFactory) 
Class.forName(session.getEventBridgeFactory())
+                    .newInstance();
+
+            // must use "name", not the sessionId as an external subject for 
the
+            // event bridge
+            return factory.createEventBridge(RemoteSession.getSubjects(), 
session.getName(),
+                    session.getEventBridgeParameters());
+        } catch (Exception ex) {
+            throw new CayenneRuntimeException("Error creating EventBridge.", 
ex);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnectionProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnectionProvider.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnectionProvider.java
new file mode 100644
index 0000000..a6dc9e5
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/DefaultClientConnectionProvider.java
@@ -0,0 +1,44 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.remote.ClientConnection;
+import org.apache.cayenne.remote.RemoteService;
+
+public class DefaultClientConnectionProvider implements 
Provider<ClientConnection> {
+
+    @Inject
+    protected RuntimeProperties runtimeProperties;
+    
+    @Inject
+    protected RemoteService remoteService;
+
+    @Override
+    public ClientConnection get() throws DIRuntimeException {
+        String sharedSession = runtimeProperties
+                .get(Constants.ROP_SERVICE_SHARED_SESSION_PROPERTY);
+
+        return new DefaultClientConnection(remoteService, sharedSession);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/ProxyRemoteService.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/ProxyRemoteService.java 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/ProxyRemoteService.java
new file mode 100644
index 0000000..ecfb441
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/ProxyRemoteService.java
@@ -0,0 +1,59 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.remote.ClientMessage;
+import org.apache.cayenne.remote.RemoteService;
+import org.apache.cayenne.remote.RemoteSession;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+
+public class ProxyRemoteService implements RemoteService {
+
+       @Inject
+       protected ROPSerializationService serializationService;
+       
+       @Inject
+       protected ROPConnector ropConnector;
+       
+       @Override
+       public RemoteSession establishSession() throws RemoteException {
+        try {
+            return 
serializationService.deserialize(ropConnector.establishSession(), 
RemoteSession.class);
+        } catch (IOException e) {
+            throw new RemoteException(e.getMessage());
+        }
+       }
+
+       @Override
+       public RemoteSession establishSharedSession(String name) throws 
RemoteException {
+        try {
+            return 
serializationService.deserialize(ropConnector.establishSharedSession(name), 
RemoteSession.class);
+        } catch (IOException e) {
+            throw new RemoteException(e.getMessage());
+        }
+       }
+
+       @Override
+       public Object processMessage(ClientMessage message) throws 
RemoteException, Throwable {
+               return 
serializationService.deserialize(ropConnector.sendMessage(serializationService.serialize(message)),
 Object.class);
+       }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/ROPConnector.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/ROPConnector.java 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/ROPConnector.java
new file mode 100644
index 0000000..4976d80
--- /dev/null
+++ b/cayenne-client/src/main/java/org/apache/cayenne/rop/ROPConnector.java
@@ -0,0 +1,32 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface ROPConnector {
+
+    InputStream establishSession() throws IOException;
+
+    InputStream establishSharedSession(String name) throws IOException;
+
+    InputStream sendMessage(byte[] message) throws IOException;
+    
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/http/ClientHessianSerializationServiceProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/http/ClientHessianSerializationServiceProvider.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/ClientHessianSerializationServiceProvider.java
new file mode 100644
index 0000000..ecf9339
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/ClientHessianSerializationServiceProvider.java
@@ -0,0 +1,39 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop.http;
+
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.remote.hessian.ClientSerializerFactory;
+import org.apache.cayenne.remote.hessian.HessianConfig;
+import org.apache.cayenne.rop.HessianROPSerializationService;
+import org.apache.cayenne.rop.ROPSerializationService;
+
+public class ClientHessianSerializationServiceProvider implements 
Provider<ROPSerializationService> {
+
+    public static final String[] CLIENT_SERIALIZER_FACTORIES = new String[] {
+            ClientSerializerFactory.class.getName()
+    };
+
+    @Override
+    public ROPSerializationService get() throws DIRuntimeException {
+        return new HessianROPSerializationService(
+                HessianConfig.createFactory(CLIENT_SERIALIZER_FACTORIES, 
null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnector.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnector.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnector.java
new file mode 100644
index 0000000..786add2
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnector.java
@@ -0,0 +1,233 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop.http;
+
+import org.apache.cayenne.rop.ROPConnector;
+import org.apache.cayenne.rop.ROPConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpROPConnector implements ROPConnector {
+
+    private static Log logger = LogFactory.getLog(HttpROPConnector.class);
+
+    private String url;
+
+    private String username;
+    private String password;
+
+    private Long readTimeout;
+    
+    public HttpROPConnector(String url, String username, String password) {
+        this.url = url;
+        this.username = username;
+        this.password = password;
+    }
+    
+    public void setReadTimeout(Long readTimeout) {
+        this.readTimeout = readTimeout;
+    }
+
+    @Override
+    public InputStream establishSession() throws IOException {
+        if (logger.isInfoEnabled()) {
+            logConnect(null);
+        }
+               
+               Map<String, String> requestParams = new HashMap<>();
+               requestParams.put(ROPConstants.OPERATION_PARAMETER, 
ROPConstants.ESTABLISH_SESSION_OPERATION);
+               
+        return doRequest(requestParams);
+    }
+
+    @Override
+    public InputStream establishSharedSession(String name) throws IOException {
+        if (logger.isInfoEnabled()) {
+            logConnect(name);
+        }
+
+               Map<String, String> requestParams = new HashMap<>();
+               requestParams.put(ROPConstants.OPERATION_PARAMETER, 
ROPConstants.ESTABLISH_SHARED_SESSION_OPERATION);
+               requestParams.put(ROPConstants.SESSION_NAME_PARAMETER, name);
+
+               return doRequest(requestParams);
+    }
+
+    @Override
+    public InputStream sendMessage(byte[] message) throws IOException {
+        return doRequest(message);
+    }
+       
+       protected InputStream doRequest(Map<String, String> params) throws 
IOException {
+               URLConnection connection = new URL(url).openConnection();
+
+               StringBuilder urlParams = new StringBuilder();
+
+               for (Map.Entry<String, String> entry : params.entrySet()) {
+                       if (urlParams.length() > 0) {
+                               urlParams.append('&');
+                       }
+
+                       urlParams.append(entry.getKey());
+                       urlParams.append('=');
+                       urlParams.append(entry.getValue());
+               }
+
+               if (readTimeout != null) {
+                       connection.setReadTimeout(readTimeout.intValue());
+               }
+
+               addAuthHeader(connection);
+
+               connection.setDoOutput(true);
+               
+               connection.setRequestProperty("Content-Type", 
"application/x-www-form-urlencoded");
+               connection.setRequestProperty("charset", "utf-8");
+
+               try (OutputStream output = connection.getOutputStream()) {
+                       
output.write(urlParams.toString().getBytes(StandardCharsets.UTF_8));
+               }
+
+               return connection.getInputStream();
+       } 
+
+    protected InputStream doRequest(byte[] data) throws IOException {
+        URLConnection connection = new URL(url).openConnection();
+
+        if (readTimeout != null) {
+            connection.setReadTimeout(readTimeout.intValue());
+        }
+
+        addAuthHeader(connection);
+        connection.setDoOutput(true);
+
+        if (data != null) {
+            try (OutputStream output = connection.getOutputStream()) {
+                output.write(data);
+            }
+        }
+
+        return connection.getInputStream();
+    }
+
+    protected void addAuthHeader(URLConnection connection) {
+        String basicAuth = getBasicAuth(username, password);
+
+        if (basicAuth != null) {
+            connection.addRequestProperty("Authorization", basicAuth);
+        }
+    }
+
+    public String getBasicAuth(String user, String password) {
+        if (user != null && password != null) {
+            return "Basic " + base64(user + ":" + password);
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates the Base64 value.
+     */
+    private String base64(String value) {
+        StringBuffer cb = new StringBuffer();
+
+        int i = 0;
+        for (i = 0; i + 2 < value.length(); i += 3) {
+            long chunk = (int) value.charAt(i);
+            chunk = (chunk << 8) + (int) value.charAt(i + 1);
+            chunk = (chunk << 8) + (int) value.charAt(i + 2);
+
+            cb.append(encode(chunk >> 18));
+            cb.append(encode(chunk >> 12));
+            cb.append(encode(chunk >> 6));
+            cb.append(encode(chunk));
+        }
+
+        if (i + 1 < value.length()) {
+            long chunk = (int) value.charAt(i);
+            chunk = (chunk << 8) + (int) value.charAt(i + 1);
+            chunk <<= 8;
+
+            cb.append(encode(chunk >> 18));
+            cb.append(encode(chunk >> 12));
+            cb.append(encode(chunk >> 6));
+            cb.append('=');
+        }
+        else if (i < value.length()) {
+            long chunk = (int) value.charAt(i);
+            chunk <<= 16;
+
+            cb.append(encode(chunk >> 18));
+            cb.append(encode(chunk >> 12));
+            cb.append('=');
+            cb.append('=');
+        }
+
+        return cb.toString();
+    }
+
+    public static char encode(long d) {
+        d &= 0x3f;
+        if (d < 26)
+            return (char) (d + 'A');
+        else if (d < 52)
+            return (char) (d + 'a' - 26);
+        else if (d < 62)
+            return (char) (d + '0' - 52);
+        else if (d == 62)
+            return '+';
+        else
+            return '/';
+    }
+
+    private void logConnect(String sharedSessionName) {
+        StringBuilder log = new StringBuilder("Connecting to [");
+        if (username != null) {
+            log.append(username);
+
+            if (password != null) {
+                log.append(":*******");
+            }
+
+            log.append("@");
+        }
+
+        log.append(url);
+        log.append("]");
+
+        if (sharedSessionName != null) {
+            log.append(" - shared session 
'").append(sharedSessionName).append("'");
+        }
+        else {
+            log.append(" - dedicated session.");
+        }
+
+        logger.info(log.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnectorProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnectorProvider.java
 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnectorProvider.java
new file mode 100644
index 0000000..919a51f
--- /dev/null
+++ 
b/cayenne-client/src/main/java/org/apache/cayenne/rop/http/HttpROPConnectorProvider.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop.http;
+
+import org.apache.cayenne.ConfigurationException;
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.rop.ROPConnector;
+
+public class HttpROPConnectorProvider implements Provider<ROPConnector> {
+
+    @Inject
+    protected RuntimeProperties runtimeProperties;
+
+    @Override
+    public ROPConnector get() throws DIRuntimeException {
+        String url = runtimeProperties.get(Constants.ROP_SERVICE_URL_PROPERTY);
+        if (url == null) {
+            throw new ConfigurationException(
+                    "No property defined for '%s', can't initialize 
HessianConnection",
+                    Constants.ROP_SERVICE_URL_PROPERTY);
+        }
+
+        String userName = 
runtimeProperties.get(Constants.ROP_SERVICE_USERNAME_PROPERTY);
+        String password = 
runtimeProperties.get(Constants.ROP_SERVICE_PASSWORD_PROPERTY);
+
+        long readTimeout = runtimeProperties.getLong(
+                Constants.ROP_SERVICE_TIMEOUT_PROPERTY,
+                -1L);
+
+        HttpROPConnector result = new HttpROPConnector(url, userName, 
password);
+
+        if (readTimeout > 0) {
+            result.setReadTimeout(readTimeout);
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-client/src/test/java/org/apache/cayenne/configuration/rop/client/ClientModuleTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-client/src/test/java/org/apache/cayenne/configuration/rop/client/ClientModuleTest.java
 
b/cayenne-client/src/test/java/org/apache/cayenne/configuration/rop/client/ClientModuleTest.java
index 03d0ad6..836507b 100644
--- 
a/cayenne-client/src/test/java/org/apache/cayenne/configuration/rop/client/ClientModuleTest.java
+++ 
b/cayenne-client/src/test/java/org/apache/cayenne/configuration/rop/client/ClientModuleTest.java
@@ -28,7 +28,7 @@ import org.apache.cayenne.event.DefaultEventManager;
 import org.apache.cayenne.remote.ClientChannel;
 import org.apache.cayenne.remote.ClientConnection;
 import org.apache.cayenne.remote.MockClientConnection;
-import org.apache.cayenne.remote.hessian.HessianConnection;
+import org.apache.cayenne.rop.DefaultClientConnection;
 import org.junit.Test;
 
 import java.util.HashMap;
@@ -52,7 +52,7 @@ public class ClientModuleTest {
 
         ClientConnection connection = 
injector.getInstance(ClientConnection.class);
         assertNotNull(connection);
-        assertTrue(connection instanceof HessianConnection);
+        assertTrue(connection instanceof DefaultClientConnection);
 
         assertSame("Connection must be a singleton", connection, injector
                 .getInstance(ClientConnection.class));

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java
index 6c9a7ea..ceefd62 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java
@@ -25,7 +25,9 @@ import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.MapBuilder;
 import org.apache.cayenne.di.Module;
 import org.apache.cayenne.remote.RemoteService;
-import org.apache.cayenne.remote.hessian.service.HessianService;
+import org.apache.cayenne.rop.ServerHessianSerializationServiceProvider;
+import org.apache.cayenne.rop.ServerHttpRemoteService;
+import org.apache.cayenne.rop.ROPSerializationService;
 
 /**
  * A DI module that defines services for the server-side of an ROP application 
based on
@@ -47,7 +49,8 @@ public class ROPServerModule implements Module {
                 .bindMap(Constants.SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP);
         mapBuilder.putAll(eventBridgeProperties);
 
-        binder.bind(RemoteService.class).to(HessianService.class);
+        binder.bind(RemoteService.class).to(ServerHttpRemoteService.class);
+               
binder.bind(ROPSerializationService.class).toProvider(ServerHessianSerializationServiceProvider.class);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
index 3097e36e..3310cee 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/remote/hessian/service/ServerSerializerFactory.java
@@ -34,7 +34,7 @@ import com.caucho.hessian.io.Serializer;
  * 
  * @since 1.2
  */
-class ServerSerializerFactory extends AbstractSerializerFactory {
+public class ServerSerializerFactory extends AbstractSerializerFactory {
     private ServerPersistentObjectListSerializer 
persistentObjectListSerializer;
     private ServerDataRowSerializer dataRowSerilaizer;
     private Serializer javaSerializer;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/HessianROPSerializationService.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/HessianROPSerializationService.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/HessianROPSerializationService.java
new file mode 100644
index 0000000..5b0c9a0
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/HessianROPSerializationService.java
@@ -0,0 +1,69 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import com.caucho.hessian.io.Hessian2Output;
+import com.caucho.hessian.io.HessianInput;
+import com.caucho.hessian.io.HessianOutput;
+import com.caucho.hessian.io.SerializerFactory;
+import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.remote.hessian.HessianConfig;
+import org.apache.cayenne.remote.hessian.service.HessianService;
+
+import java.io.*;
+
+public class HessianROPSerializationService implements ROPSerializationService 
{
+
+    protected SerializerFactory serializerFactory;
+    
+    public HessianROPSerializationService(SerializerFactory serializerFactory) 
{
+        this.serializerFactory = serializerFactory;
+    }
+    
+    @Override
+    public byte[] serialize(Object object) throws IOException {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        HessianOutput out = new HessianOutput(bytes);
+        out.setSerializerFactory(serializerFactory);
+        out.writeObject(object);
+
+        return bytes.toByteArray();
+    }
+
+       @Override
+       public void serialize(Object object, OutputStream outputStream) throws 
IOException {
+               Hessian2Output out = new Hessian2Output(outputStream);
+               out.setSerializerFactory(serializerFactory);
+               out.writeObject(object);
+       }
+
+       @Override
+       public <T> T deserialize(byte[] serializedObject, Class<T> objectClass) 
{
+               return null;
+       }
+
+       @Override
+    public <T> T deserialize(InputStream input, Class<T> objectClass) throws 
IOException {
+        HessianInput in = new HessianInput(input);
+        in.setSerializerFactory(serializerFactory);
+
+        return objectClass.cast(in.readObject());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java
new file mode 100644
index 0000000..e076eee
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+public class ROPConstants {
+
+    public static final String OPERATION_PARAMETER = "operation";
+    public static final String SESSION_NAME_PARAMETER = "session_name";
+
+    public static final String ESTABLISH_SESSION_OPERATION = 
"establish_session";
+    public static final String ESTABLISH_SHARED_SESSION_OPERATION = 
"establish_shared_session";
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPSerializationService.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPSerializationService.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPSerializationService.java
new file mode 100644
index 0000000..18c8cdb
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPSerializationService.java
@@ -0,0 +1,34 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public interface ROPSerializationService {
+    
+    byte[] serialize(Object object) throws IOException;
+       
+       void serialize(Object object, OutputStream outputStream) throws 
IOException;
+    
+    <T> T deserialize(InputStream inputStream, Class<T> objectClass) throws 
IOException;
+       
+       <T> T deserialize(byte[] serializedObject, Class<T> objectClass) throws 
IOException;
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPServlet.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPServlet.java 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPServlet.java
new file mode 100644
index 0000000..db8d5fb
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/rop/ROPServlet.java
@@ -0,0 +1,122 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import org.apache.cayenne.configuration.CayenneRuntime;
+import org.apache.cayenne.configuration.rop.server.ROPServerModule;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.configuration.web.WebConfiguration;
+import org.apache.cayenne.configuration.web.WebUtil;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.remote.ClientMessage;
+import org.apache.cayenne.remote.RemoteService;
+import org.apache.cayenne.remote.RemoteSession;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+public class ROPServlet extends HttpServlet {
+
+    protected ServletContext servletContext;
+       protected RemoteService remoteService;
+    protected ROPSerializationService serializationService;
+
+    @Override
+    public void init(ServletConfig configuration) throws ServletException {
+
+        checkAlreadyConfigured(configuration.getServletContext());
+
+        this.servletContext = configuration.getServletContext();
+
+        WebConfiguration configAdapter = new WebConfiguration(configuration);
+
+        String configurationLocation = 
configAdapter.getConfigurationLocation();
+        Map<String, String> eventBridgeParameters = 
configAdapter.getOtherParameters();
+
+        Collection<Module> modules = configAdapter.createModules(new 
ROPServerModule(
+                eventBridgeParameters));
+
+        ServerRuntime runtime = new ServerRuntime(configurationLocation, 
modules
+                .toArray(new Module[modules.size()]));
+
+        this.remoteService = 
runtime.getInjector().getInstance(RemoteService.class);
+        this.serializationService = 
runtime.getInjector().getInstance(ROPSerializationService.class);
+
+        WebUtil.setCayenneRuntime(servletContext, runtime);
+        super.init(configuration);
+    }
+
+    protected void checkAlreadyConfigured(ServletContext context) throws 
ServletException {
+        // sanity check
+        if (WebUtil.getCayenneRuntime(context) != null) {
+            throw new ServletException(
+                    "CayenneRuntime is already configured in the servlet 
environment");
+        }
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+
+        CayenneRuntime runtime = WebUtil.getCayenneRuntime(servletContext);
+        if (runtime != null) {
+            runtime.shutdown();
+        }
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
+               try {
+                       String operation = 
req.getParameter(ROPConstants.OPERATION_PARAMETER);
+
+                       if (operation != null) {
+                               switch (operation) {
+                                       case 
ROPConstants.ESTABLISH_SESSION_OPERATION:
+                                               RemoteSession session = 
remoteService.establishSession();
+                                               
serializationService.serialize(session, resp.getOutputStream());
+                                               break;
+                                       case 
ROPConstants.ESTABLISH_SHARED_SESSION_OPERATION:
+                                               String sessionName = 
req.getParameter(ROPConstants.SESSION_NAME_PARAMETER);
+                                               RemoteSession sharedSession = 
remoteService.establishSharedSession(sessionName);
+
+                                               
serializationService.serialize(sharedSession, resp.getOutputStream());
+                                               break;
+                                       default:
+                                               throw new 
ServletException("Unknown operation: " + operation);
+                               }
+                       } else {
+                                       Object response = 
remoteService.processMessage(
+                                                       
serializationService.deserialize(req.getInputStream(), ClientMessage.class));
+
+                                       
serializationService.serialize(response, resp.getOutputStream());
+                       }
+               } catch (RuntimeException | ServletException e) {
+                       throw e;
+               } catch (Throwable e) {
+                       throw new ServletException(e);
+               }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java
new file mode 100644
index 0000000..ec0c21c
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java
@@ -0,0 +1,37 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.remote.hessian.HessianConfig;
+import org.apache.cayenne.remote.hessian.service.ServerSerializerFactory;
+
+public class ServerHessianSerializationServiceProvider implements 
Provider<ROPSerializationService> {
+
+    public static final String[] SERVER_SERIALIZER_FACTORIES = new String[] {
+            ServerSerializerFactory.class.getName()
+    };
+
+    @Override
+    public ROPSerializationService get() throws DIRuntimeException {
+        return new HessianROPSerializationService(
+                HessianConfig.createFactory(SERVER_SERIALIZER_FACTORIES, 
null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/83185f25/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHttpRemoteService.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHttpRemoteService.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHttpRemoteService.java
new file mode 100644
index 0000000..22aba9f
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/rop/ServerHttpRemoteService.java
@@ -0,0 +1,48 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.rop;
+
+import com.caucho.services.server.ServiceContext;
+import org.apache.cayenne.configuration.Constants;
+import org.apache.cayenne.configuration.ObjectContextFactory;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.remote.service.HttpRemoteService;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.util.Map;
+
+public class ServerHttpRemoteService extends HttpRemoteService {
+       
+       public ServerHttpRemoteService(@Inject ObjectContextFactory 
contextFactory,
+                                                                  
@Inject(Constants.SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP) Map<String, String> 
eventBridgeProperties) {
+               super(contextFactory, eventBridgeProperties);
+       }
+
+       @Override
+       protected HttpSession getSession(boolean create) {
+               HttpServletRequest request = (HttpServletRequest) 
ServiceContext.getContextRequest();
+               if (request == null) {
+                       throw new IllegalStateException(
+                                       "Attempt to access HttpSession outside 
the request scope.");
+               }
+
+               return request.getSession(create);
+       }
+}

Reply via email to