001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.store.crypto.keymanager.messagebroker;
019    
020    import java.util.concurrent.TimeoutException;
021    
022    import org.cumulus4j.keymanager.back.shared.ErrorResponse;
023    import org.cumulus4j.keymanager.back.shared.GetKeyRequest;
024    import org.cumulus4j.keymanager.back.shared.GetKeyResponse;
025    import org.cumulus4j.keymanager.back.shared.Message;
026    import org.cumulus4j.keymanager.back.shared.NullResponse;
027    import org.cumulus4j.keymanager.back.shared.Request;
028    import org.cumulus4j.keymanager.back.shared.Response;
029    import org.cumulus4j.store.crypto.CryptoSession;
030    import org.cumulus4j.store.crypto.keymanager.rest.ErrorResponseException;
031    
032    /**
033     * <p>
034     * Broker transmitting {@link Message messages} between application-server and key-manager.
035     * </p>
036     * <p>
037     * As documented in <a target="_blank" href="http://cumulus4j.org/1.0.0/documentation/deployment-scenarios.html">Deployment scenarios</a>,
038     * TCP connections are always established from the key-manager (i.e. client or key-server) to the application server.
039     * Since this means that the key-exchange-request-response-cycle works opposite the HTTP-request-response-cycle,
040     * we need this <code>MessageBroker</code>.
041     * </p>
042     * <p>
043     * Within every JVM, there is one single {@link MessageBrokerRegistry#getActiveMessageBroker() active MessageBroker}.
044     * This instance must make sure that messages can be exchanged from every cluster-node to every key-manager; i.e. if
045     * the key-manager connects to a different cluster-node than the primary connection (established by the application logic),
046     * the {@link Request}s must be proxied over the right cluster-node to the key-manager. The {@link Response} must
047     * of course be routed appropriately back to the correct cluster-node:
048     * </p>
049     * <p>
050     * <img src="http://cumulus4j.org/1.0.0/images/deployment-scenario/deployment-scenario-without-keyserver-with-cluster.png" />
051     * </p>
052     * <p>
053     * <b>Important:</b> You should not directly implement this interface but instead subclass {@link AbstractMessageBroker}!
054     * </p>
055     *
056     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
057     */
058    public interface MessageBroker
059    {
060            /**
061             * <p>
062             * System property to control the timeout (in milliseconds) for the {@link #query(Class, Request)} method.
063             * </p>
064             * <p>
065             * The <code>query(...)</code> method will throw a {@link TimeoutException}, if no {@link Response}
066             * to a given {@link Request} arrived within this timeout.
067             * </p>
068             * <p>
069             * If the system property is not present or not a valid number, it is up to the <code>MessageBroker</code>
070             * implementation, what default value should be used. See {@link AbstractMessageBroker#getQueryTimeout()}
071             * for the default implemented there.
072             * </p>
073             */
074            static final String SYSTEM_PROPERTY_QUERY_TIMEOUT = "cumulus4j.MessageBroker.queryTimeout";
075    
076            /**
077             * <p>
078             * System property to control the timeout (in milliseconds) for the {@link #pollRequest(String)} method.
079             * </p>
080             * <p>
081             * The <code>pollRequest(...)</code> method returns <code>null</code>, if no {@link Request} popped up
082             * in the to-do-queue within the timeout.
083             * </p>
084             * <p>
085             * If the system property is not present or not a valid number, it is up to the <code>MessageBroker</code>
086             * implementation, what default value should be used. See {@link AbstractMessageBroker#getPollRequestTimeout()}
087             * for the default implemented there.
088             * </p>
089             */
090            static final String SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT = "cumulus4j.MessageBroker.pollRequestTimeout";
091    
092    //      ActiveKeyManagerChannelRegistration registerActiveKeyManagerChannel(String cryptoSessionIDPrefix, String internalKeyManagerChannelURL);
093    //
094    //      void unregisterActiveKeyManagerChannel(ActiveKeyManagerChannelRegistration registration);
095    
096            /**
097             * <p>
098             * Send <code>request</code> to the key-manager (embedded in client or separate in key-server) and return its response.
099             * </p>
100             * <p>
101             * This method is used for example by a {@link CryptoSession} to request keys via a {@link GetKeyRequest}. As soon as
102             * this method entered with the <code>request</code>, it is expected that the {@link #pollRequest(String)} returns
103             * this <code>request</code> to the appropriate key-manager. The <code>query(...)</code> method blocks then until
104             * the key-manager handled the <code>request</code> and sent a {@link GetKeyResponse} back. As soon as the <code>response</code>
105             * was {@link #pushResponse(Response) pushed} into the <code>MessageBroker</code>, <code>query(...)</code> should return it.
106             * </p>
107             * <p>
108             * If the expected {@link Response} does not arrive within the query-timeout (configurable via
109             * system property {@value #SYSTEM_PROPERTY_QUERY_TIMEOUT}), this method should throw
110             * a {@link TimeoutException}.
111             * </p>
112             *
113             * @param responseClass the type of the expected response; can be null, if you expect to receive null (i.e. you pass a "void" request).
114             * @param request the request to be sent to the key-manager.
115             * @return the response from the key-manager. Will be <code>null</code>, if the key-manager replied with a {@link NullResponse}.
116             * @throws TimeoutException if the request was not replied within the {@link #SYSTEM_PROPERTY_QUERY_TIMEOUT query-timeout}.
117             * @throws ErrorResponseException if the key-manager (either running embedded on the remote client or
118             * in a separate key-server) sent an {@link ErrorResponse}.
119             */
120            <R extends Response> R query(Class<R> responseClass, Request request)
121            throws TimeoutException, ErrorResponseException;
122    
123            /**
124             * <p>
125             * Poll the next {@link Request} that is waiting to be processed.
126             * </p>
127             * <p>
128             * This method is - indirectly via a REST web-service - called by the key-manager periodically
129             * in order to receive requests. If there is a request waiting, this method should immediately
130             * return it. If there is no request in the queue, this method should wait for an incoming
131             * request for a short time. If there is still no request available after a short blocking time,
132             * this method should return <code>null</code> (before the remote client would timeout).
133             * </p>
134             * <p>
135             * Usually, blocking about 1 minute is recommended in most situations. However, when
136             * using certain runtimes, it must be much shorter  (e.g. the Google App Engine allows
137             * requests not to take longer than 30 sec, thus 20 sec are an appropriate time to stay safe).
138             * </p>
139             * <p>
140             * Additionally, since the remote key-manager must wait at maximum this time, its HTTP-client's
141             * timeout must be longer than this timeout.
142             * </p>
143             * <p>
144             * It should be possible to configure this timeout via the system property
145             * {@value #SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT}. Implementors should use
146             * {@link #getPollRequestTimeout()} for this purpose.
147             * </p>
148             * @param cryptoSessionIDPrefix usually, every key-manager uses the same prefix for
149             * all crypto-sessions. Thus, this prefix is used to efficiently route requests to
150             * the right key-manager.
151             * @return the next request waiting for processing and fitting to the given <code>cryptoSessionIDPrefix</code>
152             * or <code>null</code>, if no such request pops up in the to-do-queue within the timeout.
153             */
154            Request pollRequest(String cryptoSessionIDPrefix);
155    
156            /**
157             * <p>
158             * Push a {@link Response} in order to reply a previous request.
159             * </p>
160             * <p>
161             * This method is - indirectly via a REST web-service - called by the key-manager after
162             * it successfully handled a {@link Request}.
163             * </p>
164             * @param response the response answering a previous {@link Request} enqueued by {@link #query(Class, Request)}.
165             */
166            void pushResponse(Response response);
167    
168            /**
169             * <p>
170             * Get the {@link MessageBroker#pollRequest(String) pollRequest(....)} timeout in milliseconds.
171             * </p>
172             * <p>
173             * This method takes the system property {@link MessageBroker#SYSTEM_PROPERTY_POLL_REQUEST_TIMEOUT} into account.
174             * If the system property is not present or not a valid number, the default value 60000 (1 minute) is returned.
175             * </p>
176             * <p>
177             * Usually, a value of about 1 minute is recommended in most situations. However, when
178             * using certain runtimes, it must be much shorter  (e.g. the Google App Engine allows
179             * requests not to take longer than 30 sec, thus 20 sec are an appropriate time to stay safe).
180             * </p>
181             * <p>
182             * Additionally, since the remote key-manager must wait at maximum this time, its HTTP-client's
183             * timeout must be longer than this timeout.
184             * </p>
185             *
186             * @return the {@link MessageBroker#pollRequest(String) pollRequest(....)} timeout in milliseconds.
187             */
188            long getPollRequestTimeout();
189    
190            /**
191             * <p>
192             * Get the {@link MessageBroker#query(Class, Request) query} timeout in milliseconds.
193             * </p>
194             * <p>
195             * This method takes the system property {@link MessageBroker#SYSTEM_PROPERTY_QUERY_TIMEOUT} into account.
196             * If the system property is not present or not a valid number, the default value 300000 (5 minutes) is returned.
197             * </p>
198             *
199             * @return the {@link MessageBroker#query(Class, Request) query} timeout in milliseconds.
200             */
201            long getQueryTimeout();
202    }