Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.linkedin.restli.client.ScatterGatherBuilder Maven / Gradle / Ivy
/*
Copyright (c) 2012 LinkedIn Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* $Id: $
*/
package com.linkedin.restli.client;
import com.linkedin.common.callback.Callback;
import com.linkedin.d2.balancer.KeyMapper;
import com.linkedin.d2.balancer.ServiceUnavailableException;
import com.linkedin.d2.balancer.util.MapKeyResult;
import com.linkedin.data.schema.PathSpec;
import com.linkedin.data.template.RecordTemplate;
import com.linkedin.r2.message.RequestContext;
import com.linkedin.restli.client.response.BatchKVResponse;
import com.linkedin.restli.common.BatchResponse;
import com.linkedin.restli.common.TypeSpec;
import com.linkedin.restli.common.UpdateStatus;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author Josh Walker
* @version $Revision: $
*/
public class ScatterGatherBuilder
{
private final KeyMapper _mapper;
private final String D2_URI_PREFIX = "d2://";
public ScatterGatherBuilder(KeyMapper mapper)
{
_mapper = mapper;
}
// for those who do not care about trouble keys.
@Deprecated
public Collection> buildRequests(BatchGetRequest request, RequestContext requestContext) throws
ServiceUnavailableException
{
return buildRequestsV2(request, requestContext).getRequestInfo();
}
// return value contains the request info and the unmapped keys (also the cause)
// V2 is here to differentiate it from the older API
public ScatterGatherResult buildRequestsV2(BatchGetRequest request, RequestContext requestContext) throws
ServiceUnavailableException
{
Set idObjects = request.getObjectIds();
MapKeyResult mapKeyResult = mapKeys(request, idObjects);
Map> batches = mapKeyResult.getMapResult();
Collection> scatterGatherRequests = new ArrayList>(batches.size());
for (Map.Entry> batch : batches.entrySet())
{
BatchGetRequestBuilder builder = new BatchGetRequestBuilder(request.getBaseUriTemplate(),
request.getResponseDecoder(),
request.getResourceSpec(),
request.getRequestOptions());
builder.ids(batch.getValue());
builder.fields(request.getFields().toArray(new PathSpec[0]));
for (Map.Entry header : request.getHeaders().entrySet())
{
builder.setHeader(header.getKey(), header.getValue());
}
RequestContext context = requestContext.clone();
KeyMapper.TargetHostHints.setRequestContextTargetHost(context, batch.getKey());
scatterGatherRequests.add(new RequestInfo(builder.build(), context));
}
return new ScatterGatherResult(scatterGatherRequests, mapKeyResult.getUnmappedKeys());
}
public KVScatterGatherResult buildRequests(BatchUpdateRequest request, RequestContext requestContext) throws
ServiceUnavailableException
{
Set idObjects = request.getObjectIds();
Collection ids = new HashSet(idObjects.size());
for (Object o : idObjects)
{
@SuppressWarnings("unchecked")
K k = (K) o;
ids.add(k);
}
MapKeyResult mapKeyResult = mapKeys(request, ids);
@SuppressWarnings("unchecked")
TypeSpec valueType = (TypeSpec) request.getResourceSpec().getValueType();
Map> batches = keyMapToInput(mapKeyResult, request);
Collection> scatterGatherRequests = new ArrayList>(batches.size());
for (Map.Entry> batch : batches.entrySet())
{
BatchUpdateRequestBuilder builder =
new BatchUpdateRequestBuilder(request.getBaseUriTemplate(),
valueType.getType(),
request.getResourceSpec(),
request.getRequestOptions());
builder.inputs(batch.getValue());
for (Map.Entry header : request.getHeaders().entrySet())
{
builder.setHeader(header.getKey(), header.getValue());
}
RequestContext context = requestContext.clone();
KeyMapper.TargetHostHints.setRequestContextTargetHost(context, batch.getKey());
scatterGatherRequests.add(new KVRequestInfo(builder.build(), context));
}
return new KVScatterGatherResult(scatterGatherRequests, mapKeyResult.getUnmappedKeys());
}
@SuppressWarnings("deprecation")
private MapKeyResult mapKeys(BatchRequest> request, Collection ids)
throws ServiceUnavailableException
{
URI serviceUri;
try
{
if (request.hasUri())
{
// legacy constructor used to construct the request
serviceUri = new URI(D2_URI_PREFIX + request.getUri().toString());
}
else
{
serviceUri = new URI(D2_URI_PREFIX + request.getServiceName());
}
}
catch (URISyntaxException e)
{
throw new IllegalArgumentException(e);
}
return _mapper.mapKeysV2(serviceUri, ids);
}
/**
* Helper function to map services to inputs, rather than services to ids.
* Each input is represented by a Map from keys to {@link RecordTemplate}s.
*
* Essentially, instead of calling {@link com.linkedin.d2.balancer.util.MapKeyResult#getMapResult()}
* to get a map from services to keys, you would instead call this to get a map from services to inputs.
* You can then use this input to create a new BatchRequest by calling
* {@link BatchUpdateRequestBuilder#inputs(java.util.Map)} or similar function.
*
* @param mapKeyResult {@link MapKeyResult} of mapping U to keys.
* @param batchRequest the {@link BatchRequest}.
* @param the service that will handle each set of inputs; Generally {@link URI}, for a host that will handle the request.
* @param the key type.
* @return a map from U to request input, where request input is a map from keys to {@link RecordTemplate}s.
*/
private Map> keyMapToInput(MapKeyResult mapKeyResult, BatchUpdateRequest batchRequest)
{
Map updateInput = batchRequest.getUpdateInputMap();
if (updateInput == null)
{
throw new IllegalArgumentException("given BatchRequest must have input data");
}
Map> map = mapKeyResult.getMapResult();
Map> result = new HashMap>(map.size());
for(Map.Entry> entry : map.entrySet())
{
Collection keyList = entry.getValue();
Map keyRecordMap = new HashMap(keyList.size());
for(K key : keyList)
{
T record = updateInput.get(key);
if (record == null)
{
throw new IllegalArgumentException("given BatchRequest input must have all keys present in mapKeyResult");
}
keyRecordMap.put(key, record);
}
result.put(entry.getKey(), keyRecordMap);
}
return result;
}
public KVScatterGatherResult buildRequests(BatchDeleteRequest request, RequestContext requestContext) throws
ServiceUnavailableException
{
Set idObjects = request.getObjectIds();
Collection ids = new HashSet(idObjects.size());
for (Object o : idObjects)
{
@SuppressWarnings("unchecked")
K k = (K) o;
ids.add(k);
}
MapKeyResult mapKeyResult = mapKeys(request, ids);
Map> batches = mapKeyResult.getMapResult();
Collection> scatterGatherRequests = new ArrayList>(batches.size());
for (Map.Entry> batch : batches.entrySet())
{
TypeSpec extends RecordTemplate> value = request.getResourceSpec().getValueType();
@SuppressWarnings("unchecked")
Class valueClass = (Class) ((value == null) ? null : value.getType());
BatchDeleteRequestBuilder builder =
new BatchDeleteRequestBuilder(request.getBaseUriTemplate(),
valueClass,
request.getResourceSpec(),
request.getRequestOptions());
builder.ids(batch.getValue());
for (Map.Entry header : request.getHeaders().entrySet())
{
builder.setHeader(header.getKey(), header.getValue());
}
RequestContext context = requestContext.clone();
KeyMapper.TargetHostHints.setRequestContextTargetHost(context, batch.getKey());
BatchRequest> build = builder.build();
scatterGatherRequests.add(new KVRequestInfo(build, context));
}
return new KVScatterGatherResult(scatterGatherRequests, mapKeyResult.getUnmappedKeys());
}
/**
* A convenience function for caller to issue batch request with one call.
* If finer-grain control is required, users should call buildRequests instead and send requests by themselves
*
* @param client - the RestClient to use
* @param request - the batch get request
* @param requestContext - the original request context
* @param callback - callback to be used for each request
* @throws ServiceUnavailableException
*/
public void sendRequests(RestClient client, BatchGetRequest request, RequestContext requestContext, Callback>> callback)
throws ServiceUnavailableException
{
ScatterGatherResult scatterGatherResult = buildRequestsV2(request, requestContext);
for (RequestInfo requestInfo : scatterGatherResult.getRequestInfo())
{
client.sendRequest(requestInfo.getRequest(), requestInfo.getRequestContext(), callback);
}
}
public void sendRequests(RestClient client,
BatchUpdateRequest request,
RequestContext requestContext,
Callback>> callback)
throws ServiceUnavailableException
{
KVScatterGatherResult scatterGatherResult = buildRequests(request, requestContext);
for(KVRequestInfo requestInfo : scatterGatherResult.getRequestInfo())
{
client.sendRequest(requestInfo.getRequest(), requestInfo.getRequestContext(), callback);
}
}
public void sendRequests(RestClient client,
BatchDeleteRequest request,
RequestContext requestContext,
Callback>> callback)
throws ServiceUnavailableException
{
KVScatterGatherResult scatterGatherResult = buildRequests(request, requestContext);
for(KVRequestInfo requestInfo : scatterGatherResult.getRequestInfo())
{
client.sendRequest(requestInfo.getRequest(), requestInfo.getRequestContext(), callback);
}
}
public static class RequestInfo
{
private final BatchRequest> _request;
private final RequestContext _requestContext;
public RequestInfo(BatchRequest> request, RequestContext requestContext)
{
_request = request;
_requestContext = requestContext;
}
public Request> getRequest()
{
return _request;
}
public BatchRequest> getBatchRequest()
{
return _request;
}
public RequestContext getRequestContext()
{
return _requestContext;
}
}
public static class ScatterGatherResult
{
private final Collection> _requestInfos;
private final Collection> _unmappedKeys;
public ScatterGatherResult(Collection> requestInfos, Collection> unmappedKeys)
{
_requestInfos = Collections.unmodifiableCollection(requestInfos);
_unmappedKeys = Collections.unmodifiableCollection(unmappedKeys);
}
Collection> getRequestInfo()
{
return _requestInfos;
}
Collection> getUnmappedKeys()
{
return _unmappedKeys;
}
}
public static class KVRequestInfo
{
private final BatchRequest> _request;
private final RequestContext _requestContext;
public KVRequestInfo(BatchRequest> request, RequestContext requestContext)
{
_request = request;
_requestContext = requestContext;
}
public BatchRequest> getRequest()
{
return _request;
}
public RequestContext getRequestContext()
{
return _requestContext;
}
}
public static class KVScatterGatherResult
{
private final Collection> _requestInfos;
private final Collection> _unmappedKeys;
public KVScatterGatherResult(Collection> requestInfos, Collection> unmappedKeys)
{
_requestInfos = Collections.unmodifiableCollection(requestInfos);
_unmappedKeys = Collections.unmodifiableCollection(unmappedKeys);
}
Collection> getRequestInfo()
{
return _requestInfos;
}
Collection> getUnmappedKeys()
{
return _unmappedKeys;
}
}
}