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}