001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/ds/resource/legal-notices/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/ds/resource/legal-notices/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Copyright 2013-2016 UnboundID Corp.
026 */
027package com.unboundid.directory.sdk.broker.api;
028
029import com.unboundid.directory.sdk.broker.config.StoreAdapterConfig;
030import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
031import com.unboundid.directory.sdk.broker.types.BrokerContext;
032import com.unboundid.directory.sdk.broker.types.StoreAttributeDefinition;
033import com.unboundid.directory.sdk.broker.types.StoreCreateRequest;
034import com.unboundid.directory.sdk.broker.types.StoreDeleteRequest;
035import com.unboundid.directory.sdk.broker.types.StoreSearchRequest;
036import com.unboundid.directory.sdk.broker.types.StoreRetrieveRequest;
037import com.unboundid.directory.sdk.broker.types.StoreUpdateRequest;
038import com.unboundid.directory.sdk.common.internal.Configurable;
039import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
040import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
041import com.unboundid.scim2.common.exceptions.ScimException;
042import com.unboundid.util.Extensible;
043import com.unboundid.util.ThreadSafety;
044import com.unboundid.util.ThreadSafetyLevel;
045import com.unboundid.util.args.ArgumentException;
046import com.unboundid.util.args.ArgumentParser;
047
048import java.util.Collection;
049import java.util.Collections;
050import java.util.List;
051import java.util.Map;
052
053
054/**
055 * This class defines an API that must be implemented by extensions that need
056 * to store user data in some non-LDAP data store. This adapter API is generic
057 * and can support a wide range of repositories. When using multiple
058 * Data Broker instances in a deployment, the data store should be accessible
059 * from all instances.
060 * <p>
061 * After the Store Adapter is initialized (via the initializeStoreAdapter()
062 * method), all methods will be guarded by a call to {@link #isAvailable()} to
063 * make sure that the adapter is currently connected and ready to service
064 * requests. If this returns {@code false}, the SCIMResourceType will return an
065 * appropriate 503 response code to clients until the adapter becomes available
066 * again.
067 * <H2>Configuring Store Adapters</H2>
068 * In order to configure a store adapter created using this API, use
069 * a command like:
070 * <PRE>
071 *      dsconfig create-store-adapter \
072 *           ---adapter-name "<I>{name}</I>" \
073 *           --type third-party \
074 *           --set "extension-class:<I>{class-name}</I>" \
075 *           --set "extension-argument:<I>{name=value}</I>"
076 * </PRE>
077 * where "<I>{name}</I>" is the name to use for the token store
078 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
079 * that extends
080 * {@code com.unboundid.directory.sdk.broker.api.StoreAdapter},
081 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
082 * provide to the store adapter. If multiple arguments should be
083 * provided to the extension, then the
084 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
085 * provided multiple times.
086 */
087@Extensible()
088@BrokerExtension
089@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
090public abstract class StoreAdapter implements UnboundIDExtension,
091        Configurable, ExampleUsageProvider
092{
093  /**
094   * Creates a new instance of this store adapter.  All
095   * implementations must include a default constructor, but any
096   * initialization should generally be done in the
097   * {@link #initializeStoreAdapter} method.
098   */
099  public StoreAdapter()
100  {
101    // No implementation is required.
102  }
103
104  /**
105   * {@inheritDoc}
106   */
107  @Override
108  public abstract String getExtensionName();
109
110  /**
111   * {@inheritDoc}
112   */
113  @Override
114  public abstract String[] getExtensionDescription();
115
116  /**
117   * {@inheritDoc}
118   */
119  @Override
120  public Map<List<String>,String> getExamplesArgumentSets()
121  {
122    return Collections.emptyMap();
123  }
124
125  /**
126   * {@inheritDoc}
127   */
128  @Override
129  public void defineConfigArguments(final ArgumentParser parser)
130         throws ArgumentException
131  {
132    // No arguments will be allowed by default.
133  }
134
135  /**
136   * Initializes this store adapter. Any initialization should be performed
137   * here. This method should generally store the {@link BrokerContext} in
138   * a class member so that it can be used elsewhere in the implementation.
139   * <p>
140   * The default implementation is empty.
141   *
142   * @param  serverContext  A handle to the server context for the server in
143   *                        which this extension is running. Extensions should
144   *                        typically store this in a class member.
145   * @param  config         The general configuration for this object.
146   * @param  parser         The argument parser which has been initialized from
147   *                        the configuration for this store adapter.
148   * @throws Exception      If a problem occurs while initializing this store
149   *                        adapter.
150   */
151  public void initializeStoreAdapter(final BrokerContext serverContext,
152                                     final StoreAdapterConfig config,
153                                     final ArgumentParser parser)
154      throws Exception
155  {
156    // No initialization will be performed by default.
157  }
158
159  /**
160   * This hook is called when the SCIMResourceType is disabled or the Broker
161   * shuts down. Any clean-up of this store adapter should be performed here.
162   * <p>
163   * The default implementation is empty.
164   */
165  public void finalizeStoreAdapter()
166  {
167    // No implementation is performed by default.
168  }
169
170  /**
171   * Retrieves a collection of attribute definitions describing the schema
172   * for objects supported by this Store Adapter. The default implementation
173   * returns an empty collection indicating that the schema is not defined.
174   * Use StoreAttributeDefinition.Builder to create instances of
175   * StoreAttributeDefinition.
176   *
177   * @return  The attribute definitions describing the schema, or an empty
178   *          collection if the schema is not defined.
179   */
180  public Collection<StoreAttributeDefinition> getNativeSchema()
181  {
182    return Collections.emptyList();
183  }
184
185  /**
186   * Determines whether this Store Adapter is currently available and
187   * in-service. This may return {@code false} in the case that all
188   * backend servers are down, for example; during this time the
189   * SCIMResourceType will return an appropriate 503 response code to clients.
190   *
191   * @return {@code true} if the Store Adapter initialized and connected;
192   *         {@code false} otherwise.
193   */
194  public abstract boolean isAvailable();
195
196  /**
197   * Fetches the specified entry.
198   *
199   * @param request  The retrieve request.
200   * @return  The retrieved entry as a JSON object. This string can be created
201   *          by any JSON library. For example, the Jackson library's
202   *          ObjectNode.toString() or the UnboundID LDAP SDK's
203   *          JSONObject.toString().
204   * @throws ScimException  If there is a problem fulfilling the request.
205   */
206  public abstract String retrieve(
207          final StoreRetrieveRequest request) throws ScimException;
208
209  /**
210   * Search for entries in the native store which could match the
211   * specified criteria. The contract is for the store adapter to return a
212   * superset of matching entries, i.e. The store adapter must return all
213   * entries which match the specified filter but may also return entries
214   * which do not match. The results from the store adapter are subsequently
215   * filtered by the broker.
216   *
217   * @param request  The search request.
218   * @throws ScimException  If there is a problem fulfilling the search request.
219   */
220  public abstract void search(
221          final StoreSearchRequest request) throws ScimException;
222
223  /**
224   * Create the specified entry in the native data store.
225   *
226   * @param request  The create request.
227   * @return The entry that was just created as a JSON object. This string can
228   *         be created by any JSON library. For example, the Jackson library's
229   *         ObjectNode.toString() or the UnboundID LDAP SDK's
230   *         JSONObject.toString().
231   * @throws ScimException  If there is a problem creating the entry.
232   */
233  public abstract String create(final StoreCreateRequest request)
234          throws ScimException;
235
236  /**
237   * Update the specified entry in the native data store.
238   *
239   * @param request  The update request.
240   * @return  The updated resource as a JSON object. This string can be created
241   *          by any JSON library. For example, the Jackson library's
242   *          ObjectNode.toString() or the UnboundID LDAP SDK's
243   *          JSONObject.toString().
244   * @throws ScimException  If there is a problem modifying the entry.
245   */
246  public abstract String update(final StoreUpdateRequest request)
247          throws ScimException;
248
249  /**
250   * Delete the specified entry from the native data store.
251   *
252   * @param request  The delete request.
253   * @throws ScimException  If there is a problem deleting the entry.
254   */
255  public abstract void delete(final StoreDeleteRequest request)
256          throws ScimException;
257}