.. _sharding_dev: ******** Sharding ******** For a general feature overview please see the :ref:`Backend Sharding ` chapter. Following the key components are explained, that are needed to find a shard for a request or to extract a shard from the given request information. .. _shard_detector_dev: Shard detector ============== The ``ShardDetector`` interface is the key component and needs to be implemented to introduce a new shard detector. There is only one method that contains all the logic to extract the shard information from a request, ``detectShard``. The inner ``ShardDetectionContext`` class contains the request. .. code-block:: java public interface ShardDetector { String DEFAULT_SHARD = "default"; String NOT_FOUND = null; /** * Detects the shard for a given HTTP request. * * @param context Shard detection context * @return A valid shard identifier or ShardDetector.NOT_FOUND if a shard could not be determined * @throws Exception */ String detectShard(ShardDetectionContext context) throws Exception; class ShardDetectionContext { private final HttpRequestMessage request; public ShardDetectionContext(HttpRequestMessage request) { this.request = request; } public HttpRequestMessage getRequest() { return request; } } } The following example shows how the ``CookieShardDetector`` works. All needed logic is executed in the ``detectShard`` method. The request is obtained from the ``ShardDetectionContext`` and the cookies are parsed. If a cookie with the name ``open-xchange-shard`` is present, its value is returned, ``null`` otherwise. **Example:** .. code-block:: java public class CookieShardDetector implements ShardDetector { @Override public String detectShard(ShardDetectionContext context) throws Exception { HttpRequestMessage request = context.getRequest(); Cookies cookies = request.parseCookies(); String shard = cookies.getFirstValue("open-xchange-shard"); if (shard == null) { return NOT_FOUND; } return shard; } } .. _shard_bootstrap_handler_dev: Shard bootstrap handler ======================= The shard bootstrap handler comes into play, if the shard detector is unable to find any kind of shard information in the processed request. A new bootstrap handler can be simply registered via configuration, like in the example found in the :ref:`operators guide `. The registered shard bootstrap handlers endpoint needs to be an endpoint filter. This filters purpose is to initiate the process that associates a user with a shard. In the example the ``InitOidcSso`` Endpoint is shown. This endpoint creates a login request whose destination is the OpenID server that is configured in the bootstrap handlers parameter section. **Example:** .. code-block:: java public class InitOidcSso extends HttpSyncEndpoint { private static final Logger logger = LoggerFactory.getLogger(InitOidcSso.class); @Override public HttpResponseMessage apply(HttpRequestMessage input) { SessionContext context = input.getContext(); try { HttpResponseMessage resp = new HttpResponseMessageImpl(context, input, HttpStatus.SC_MOVED_PERMANENTLY); resp.getHeaders().set(HttpHeaders.LOCATION, buildLoginRequest( (Map) context.get(ContextKeys.ShardBootstrapParameters))); // need to set this manually since we are not going through the ProxyEndpoint StatusCategoryUtils.setStatusCategory(context, ZuulStatusCategory.SUCCESS); resp.getHeaders().set("Content-Length", "0"); return resp; } catch (URISyntaxException e) { logger.error("Failed to build URI to IDP login location", e); HttpResponseMessage resp = new HttpResponseMessageImpl(context, input, HttpStatus.SC_INTERNAL_SERVER_ERROR); resp.getHeaders().set(HttpHeaders.CONTENT_LENGTH, "0"); StatusCategoryUtils.setStatusCategory(context, ZuulStatusCategory.FAILURE_LOCAL); return resp; } } private String buildLoginRequest(Map parameters) throws URISyntaxException { return new URIBuilder(parameters.get("endpoint")) .setParameter("response_type", parameters.get("responseType")) .setParameter("scope", parameters.get("scope")) .setParameter("client_id", parameters.get("clientId")) .setParameter("redirect_uri", parameters.get("redirectUri")) .build().toString(); } }