001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2016 ForgeRock AS.
015 */
016
017package org.forgerock.json.resource;
018
019import java.util.Collection;
020
021import org.forgerock.api.models.ApiDescription;
022import org.forgerock.http.ApiProducer;
023import org.forgerock.services.context.Context;
024import org.forgerock.services.descriptor.Describable;
025import org.forgerock.util.promise.Promise;
026
027/**
028 * An abstract base class from which connection wrappers may be easily
029 * implemented. The default implementation of each method is to delegate to the
030 * wrapped connection.
031 *
032 * @param <C>
033 *            The type of wrapped connection.
034 */
035public abstract class AbstractConnectionWrapper<C extends Connection>
036        implements Connection, Describable<ApiDescription, Request> {
037    /**
038     * The wrapped connection.
039     */
040    protected final C connection;
041
042    /**
043     * Creates a new connection wrapper.
044     *
045     * @param connection
046     *            The connection to be wrapped.
047     */
048    protected AbstractConnectionWrapper(final C connection) {
049        this.connection = connection;
050    }
051
052    /**
053     * Optional Context-transformation function if the implementer has
054     * requirements to override the {@link Context} provided in the
055     * {@link Connection}'s method invocations.
056     * <p>
057     * The default implementation is a pass-through no-op.
058     *
059     * @param context
060     *            the request context
061     * @return the transformed context
062     */
063    protected Context transform(Context context) {
064        return context;
065    }
066
067    /**
068     * {@inheritDoc}
069     * <p>
070     * The default implementation is to delegate.
071     */
072    public ActionResponse action(Context context, ActionRequest request) throws ResourceException {
073        return connection.action(transform(context), request);
074    }
075
076    /**
077     * {@inheritDoc}
078     * <p>
079     * The default implementation is to delegate.
080     */
081    public Promise<ActionResponse, ResourceException> actionAsync(Context context, ActionRequest request) {
082        return connection.actionAsync(transform(context), request);
083    }
084
085    /**
086     * {@inheritDoc}
087     * <p>
088     * The default implementation is to delegate.
089     */
090    public void close() {
091        connection.close();
092    }
093
094    /**
095     * {@inheritDoc}
096     * <p>
097     * The default implementation is to delegate.
098     */
099    public ResourceResponse create(Context context, CreateRequest request) throws ResourceException {
100        return connection.create(transform(context), request);
101    }
102
103    /**
104     * {@inheritDoc}
105     * <p>
106     * The default implementation is to delegate.
107     */
108    public Promise<ResourceResponse, ResourceException> createAsync(Context context, CreateRequest request) {
109        return connection.createAsync(transform(context), request);
110    }
111
112    /**
113     * {@inheritDoc}
114     * <p>
115     * The default implementation is to delegate.
116     */
117    public ResourceResponse delete(Context context, DeleteRequest request) throws ResourceException {
118        return connection.delete(transform(context), request);
119    }
120
121    /**
122     * {@inheritDoc}
123     * <p>
124     * The default implementation is to delegate.
125     */
126    public Promise<ResourceResponse, ResourceException> deleteAsync(Context context, DeleteRequest request) {
127        return connection.deleteAsync(transform(context), request);
128    }
129
130    /**
131     * {@inheritDoc}
132     * <p>
133     * The default implementation is to delegate.
134     */
135    public boolean isClosed() {
136        return connection.isClosed();
137    }
138
139    /**
140     * {@inheritDoc}
141     * <p>
142     * The default implementation is to delegate.
143     */
144    public boolean isValid() {
145        return connection.isValid();
146    }
147
148    /**
149     * {@inheritDoc}
150     * <p>
151     * The default implementation is to delegate.
152     */
153    public ResourceResponse patch(Context context, PatchRequest request) throws ResourceException {
154        return connection.patch(transform(context), request);
155    }
156
157    /**
158     * {@inheritDoc}
159     * <p>
160     * The default implementation is to delegate.
161     */
162    public Promise<ResourceResponse, ResourceException> patchAsync(Context context, PatchRequest request) {
163        return connection.patchAsync(transform(context), request);
164    }
165
166    /**
167     * {@inheritDoc}
168     * <p>
169     * The default implementation is to delegate.
170     */
171    public QueryResponse query(Context context, QueryRequest request, QueryResourceHandler handler)
172            throws ResourceException {
173        return connection.query(transform(context), request, handler);
174    }
175
176    /**
177     * {@inheritDoc}
178     * <p>
179     * The default implementation is to delegate.
180     */
181    public QueryResponse query(Context context, QueryRequest request,
182            Collection<? super ResourceResponse> results) throws ResourceException {
183        return connection.query(transform(context), request, results);
184    }
185
186    /**
187     * {@inheritDoc}
188     * <p>
189     * The default implementation is to delegate.
190     */
191    public Promise<QueryResponse, ResourceException> queryAsync(Context context,
192            QueryRequest request, QueryResourceHandler handler) {
193        return connection.queryAsync(transform(context), request, handler);
194    }
195
196    /**
197     * {@inheritDoc}
198     * <p>
199     * The default implementation is to delegate.
200     */
201    public ResourceResponse read(Context context, ReadRequest request) throws ResourceException {
202        return connection.read(transform(context), request);
203    }
204
205    /**
206     * {@inheritDoc}
207     * <p>
208     * The default implementation is to delegate.
209     */
210    public Promise<ResourceResponse, ResourceException> readAsync(Context context, ReadRequest request) {
211        return connection.readAsync(transform(context), request);
212    }
213
214    /**
215     * {@inheritDoc}
216     * <p>
217     * The default implementation is to delegate.
218     */
219    public ResourceResponse update(Context context, UpdateRequest request) throws ResourceException {
220        return connection.update(transform(context), request);
221    }
222
223    /**
224     * {@inheritDoc}
225     * <p>
226     * The default implementation is to delegate.
227     */
228    public Promise<ResourceResponse, ResourceException> updateAsync(Context context, UpdateRequest request) {
229        return connection.updateAsync(transform(context), request);
230    }
231
232    @Override
233    @SuppressWarnings("unchecked")
234    public ApiDescription api(ApiProducer<ApiDescription> producer) {
235        if (connection instanceof Describable) {
236            return ((Describable<ApiDescription, Request>) connection).api(producer);
237        }
238        return null;
239    }
240
241    @Override
242    @SuppressWarnings("unchecked")
243    public ApiDescription handleApiRequest(Context context, Request request) {
244        if (connection instanceof Describable) {
245            return ((Describable<ApiDescription, Request>) connection)
246                    .handleApiRequest(context, request);
247        }
248        throw new UnsupportedOperationException("Connection is not describable");
249    }
250
251    @Override
252    public void addDescriptorListener(Describable.Listener listener) {
253        if (connection instanceof Describable) {
254            ((Describable) connection).addDescriptorListener(listener);
255        }
256    }
257
258    @Override
259    public void removeDescriptorListener(Describable.Listener listener) {
260        if (connection instanceof Describable) {
261            ((Describable) connection).removeDescriptorListener(listener);
262        }
263    }
264}