From 71d4454ac1705ad35e63ab2f5127da22b2900eb7 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Tue, 3 Aug 2010 01:18:59 +0000 Subject: Add support for remote procedure calls. --- .../carbonado/capability/RemoteProcedure.java | 232 +++++++++++++++++++++ .../capability/RemoteProcedureCapability.java | 52 +++++ 2 files changed, 284 insertions(+) create mode 100644 src/main/java/com/amazon/carbonado/capability/RemoteProcedure.java create mode 100644 src/main/java/com/amazon/carbonado/capability/RemoteProcedureCapability.java (limited to 'src/main') diff --git a/src/main/java/com/amazon/carbonado/capability/RemoteProcedure.java b/src/main/java/com/amazon/carbonado/capability/RemoteProcedure.java new file mode 100644 index 0000000..fb400db --- /dev/null +++ b/src/main/java/com/amazon/carbonado/capability/RemoteProcedure.java @@ -0,0 +1,232 @@ +/* + * Copyright 2010 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * Licensed 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 com.amazon.carbonado.capability; + +import java.io.Serializable; + +import java.util.Collection; + +import com.amazon.carbonado.Cursor; +import com.amazon.carbonado.Repository; +import com.amazon.carbonado.RepositoryException; + +/** + * Defines a remote procedure which can be executed by {@link + * RemoteProcedureCapability}. Any data within the procedure instance is + * serialized to the remote host, and possibly the class definition + * too. Execution might have security restrictions applied. + * + *

The RemoteProcedure instance is Serializable, and so and serializable + * parameters can be passed with it. Storables and extra data can be sent + * through the {@link Request} object. Any data returned by procedure + * implementation must be sent through the {@link Reply} object. + * + * @param reply object type + * @param request data object type + * @author Brian S O'Neill + */ +public interface RemoteProcedure extends Serializable { + /** + * Request handler for remote procedure implementation. + * + * @param repo repository as seen by host that procedure is running from + * @param request non-null request object + * @return false if request is still active when this method returns; + * request must eventually be explicitly finished + */ + boolean handleRequest(Repository repo, Request request) throws RepositoryException; + + /** + * Client-side call into a remote procedure. To avoid leaking resources, + * the finish method must be invoked or all reply data be fully read. If an + * exception is thrown by a method defined in this interface, resources are + * automatically released. + * + * @param reply object type + * @param request data object type + * @see RemoteProcedureCapability#beginCall + */ + public static interface Call { + /** + * Send data to the remote procedure. + * + * @return this Call instance + * @throws IllegalArgumentException if data is null + * @throws IllegalStateException if a call has been executed + */ + Call send(D data) throws RepositoryException; + + /** + * Send all data from the given iterable to the remote procedure. + * + * @return this Call instance + * @throws IllegalArgumentException if data is null + * @throws IllegalStateException if a call has been executed + */ + Call sendAll(Iterable iterable) throws RepositoryException; + + /** + * Send all data from the given cursor to the remote procedure. + * + * @return this Call instance + * @throws IllegalArgumentException if data is null + * @throws IllegalStateException if a call has been executed + */ + Call sendAll(Cursor cursor) throws RepositoryException; + + /** + * Reset the internal object stream of the call, allowing cached + * objects to get freed. + * + * @return this Call instance + * @throws IllegalStateException if a call has been executed + */ + Call reset() throws RepositoryException; + + /** + * Flushes all the data sent so far. Flush is invoked automatically + * when call is executed. + */ + void flush() throws RepositoryException; + + /** + * Executes the call and receive a reply. Calling this method does not + * block, but methods on the returned Cursor may block waiting for + * data. + * + * @throws IllegalStateException if a call has been executed + */ + Cursor fetchReply() throws RepositoryException; + + /** + * Executes the call without expecting a reply. Method blocks waiting + * for procedure to finish. + * + * @throws IllegalStateException if a call has been executed + */ + void execute() throws RepositoryException; + + /** + * Executes the call without expecting a reply. Method does not block + * waiting for procedure to finish. Asynchronous execution is not + * allowed if the current thread is in a transaction. This is because + * transaction ownership becomes ambiguous. + * + * @throws IllegalStateException if a call has been executed or if + * current thread is in a transaction + */ + void executeAsync() throws RepositoryException; + } + + /** + * Request into a remote procedure, as seen by procedure implementation. To + * avoid leaking resources, the request or reply object must always be + * finished. If an exception is thrown by a method defined in this + * interface, resources are automatically released. + * + * @param reply object type + * @param request data object type + */ + public static interface Request { + /** + * Receive data from caller. + * + * @return null if no more data + */ + D receive() throws RepositoryException; + + /** + * Receive all remaining data from caller. + * + * @param c collection to receive data + * @return amount received + */ + int receiveInto(Collection c) throws RepositoryException; + + /** + * Begin a reply after receiving all data. If no data is expected, + * reply can be made without calling receive. + * + * @throws IllegalStateException if reply was already begun, or if + * request is finished, or if more data must be received + */ + Reply beginReply() throws RepositoryException; + + /** + * Reply and immediately finish, without sending any data to caller. + * + * @throws IllegalStateException if a reply was already begun or if + * more data must be received + */ + void finish() throws RepositoryException; + } + + /** + * Reply from remote procedure implementation. To avoid leaking resources, + * the finish method must always be invoked. If an exception is thrown by a + * method defined in this interface, resources are automatically released. + * + * @param reply object type + */ + public static interface Reply { + /** + * Send reply data to the caller. + * + * @return this Reply instance + * @throws IllegalStateException if reply is finished + */ + Reply send(R data) throws RepositoryException; + + /** + * Reply with all data from the given iterable to the caller. + * + * @return this Reply instance + * @throws IllegalStateException if reply is finished + */ + Reply sendAll(Iterable iterable) throws RepositoryException; + + /** + * Reply with all data from the given cursor to the caller. + * + * @return this Reply instance + * @throws IllegalStateException if reply is finished + */ + Reply sendAll(Cursor cursor) throws RepositoryException; + + /** + * Reset the internal object stream of the reply, allowing cached + * objects to get freed. + * + * @return this Reply instance + * @throws IllegalStateException if reply is finished + */ + Reply reset() throws RepositoryException; + + /** + * Flushes all the data sent so far. Flush is invoked automatically + * when reply is finished. + */ + void flush() throws RepositoryException; + + /** + * Finish the reply. + */ + void finish() throws RepositoryException; + } +} diff --git a/src/main/java/com/amazon/carbonado/capability/RemoteProcedureCapability.java b/src/main/java/com/amazon/carbonado/capability/RemoteProcedureCapability.java new file mode 100644 index 0000000..92e0712 --- /dev/null +++ b/src/main/java/com/amazon/carbonado/capability/RemoteProcedureCapability.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * Licensed 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 com.amazon.carbonado.capability; + +import com.amazon.carbonado.RepositoryException; + +/** + * Capability which allows arbitrary code to run on a remote host and access + * its repository. The remote procedure might have security restrictions + * applied to it. + * + *

Examples:

+ * RemoteProcedureCapability cap = ...
+ * Cursor<MyRecord> c1 = cap.beginCall(new CustomQuery<MyRecord>(params)).fetchReply();
+ * ...
+ *
+ * Cursor<InputRecord> c2 = ...
+ * cap.beginCall(new Importer<InputRecord>()).sendAll(c2).finish();
+ * 
+ * + * @author Brian S O'Neill + * @see RemoteProcedure + */ +public interface RemoteProcedureCapability extends Capability { + /** + * Begins a call to execute the given procedure on a remote host. + * Execution commences when the Call object is instructed to do so. + * + * @param reply object type + * @param request data object type + * @param proc procedure to execute + * @return object for defining the call and receiving a reply + */ + RemoteProcedure.Call beginCall(RemoteProcedure proc) + throws RepositoryException; +} -- cgit v1.2.3