use of io.apiman.gateway.engine.io.IApimanBuffer in project apiman by apiman.
the class EsCacheStoreComponent method getBinary.
/**
* @see io.apiman.gateway.engine.components.ICacheStoreComponent#getBinary(java.lang.String, java.lang.Class, io.apiman.gateway.engine.async.IAsyncResultHandler)
*/
@Override
public <T> void getBinary(final String cacheKey, final Class<T> type, final IAsyncResultHandler<ISignalReadStream<T>> handler) {
try {
GetResponse response = getClient().get(new GetRequest(getFullIndexName()).id(cacheKey), RequestOptions.DEFAULT);
// Did the GET succeed? If not, return null.
if (!response.isExists()) {
handler.handle(AsyncResultImpl.create((ISignalReadStream<T>) null));
return;
}
// Is the cache entry expired? If so return null.
String sourceAsString = response.getSourceAsString();
CacheEntry cacheEntry = JSON_MAPPER.readValue(sourceAsString, CacheEntry.class);
if (System.currentTimeMillis() > cacheEntry.getExpiresOn()) {
// Cache item has expired. Return null instead of the cached data.
handler.handle(AsyncResultImpl.create((ISignalReadStream<T>) null));
return;
}
try {
final T head = (T) JSON_MAPPER.reader(type).readValue(cacheEntry.getHead());
String b64Data = cacheEntry.getData();
final IApimanBuffer data = bufferFactory.createBuffer(Base64.decodeBase64(b64Data));
ISignalReadStream<T> rval = new ISignalReadStream<T>() {
IAsyncHandler<IApimanBuffer> bodyHandler;
IAsyncHandler<Void> endHandler;
boolean finished = false;
boolean aborted = false;
@Override
public void bodyHandler(IAsyncHandler<IApimanBuffer> bodyHandler) {
this.bodyHandler = bodyHandler;
}
@Override
public void endHandler(IAsyncHandler<Void> endHandler) {
this.endHandler = endHandler;
}
@Override
public T getHead() {
return head;
}
@Override
public boolean isFinished() {
return finished;
}
@Override
public void abort(Throwable t) {
finished = true;
aborted = true;
}
@Override
public void transmit() {
if (!aborted) {
bodyHandler.handle(data);
endHandler.handle(null);
}
finished = true;
}
};
handler.handle(AsyncResultImpl.create(rval));
} catch (Throwable e) {
LOGGER.error(e, "Error attempting to stream cached binary on key {0}", cacheKey);
handler.handle(AsyncResultImpl.create((ISignalReadStream<T>) null));
}
} catch (Throwable e) {
LOGGER.error(e, "Error attempting to GET cached binary on key {0}", cacheKey);
handler.handle(AsyncResultImpl.create((ISignalReadStream<T>) null));
}
}
use of io.apiman.gateway.engine.io.IApimanBuffer in project apiman by apiman.
the class EsCacheStoreComponent method putBinary.
/**
* @see io.apiman.gateway.engine.components.ICacheStoreComponent#putBinary(java.lang.String, java.lang.Object, long)
*/
@Override
public <T> ISignalWriteStream putBinary(final String cacheKey, final T jsonObject, final long timeToLive) throws IOException {
final CacheEntry entry = new CacheEntry();
entry.setExpiresOn(System.currentTimeMillis() + (timeToLive * 1000));
entry.setHead(JSON_MAPPER.writeValueAsString(jsonObject));
final IApimanBuffer data = bufferFactory.createBuffer();
return new ISignalWriteStream() {
boolean finished = false;
boolean aborted = false;
@Override
public void abort(Throwable t) {
finished = true;
aborted = false;
}
@Override
public boolean isFinished() {
return finished;
}
@Override
public void write(IApimanBuffer chunk) {
data.append(chunk);
}
@Override
public void end() {
if (!aborted) {
entry.setData(Base64.encodeBase64String(data.getBytes()));
try {
IndexRequest indexRequest = new IndexRequest(getFullIndexName()).source(JSON_MAPPER.writeValueAsBytes(entry), XContentType.JSON).id(cacheKey);
getClient().index(indexRequest, RequestOptions.DEFAULT);
} catch (Throwable e) {
LOGGER.error(e, "Unable to put binary at {0}. This should be non-fatal.", cacheKey);
}
}
finished = true;
}
};
}
use of io.apiman.gateway.engine.io.IApimanBuffer in project apiman by apiman.
the class URLRewritingStream method processBuffer.
/**
* Scan the buffer for possible URLs. As they are found, extract them from the buffer,
* optionally translate them (only if they match the regular expression), and then
* send along the translated version. If a potential URL match is found but its end
* spans the end of the buffer, just wait for the next chunk of data!
*/
private void processBuffer() {
if (buffer == null || buffer.length() == 0) {
return;
}
position = 0;
int maxPos = buffer.length() - 1;
boolean done = false;
IApimanBuffer originalBuffer = buffer;
int bytesConsumed = 0;
int preUrlFromPos = 0;
int urlsFound = 0;
while (!done) {
if (originalBuffer.get(position) == (byte) 'h' || originalBuffer.get(position) == (byte) 'H') {
if (isURLStart()) {
urlsFound++;
// Write everything up to this point - consider it "consumed"
if (position > 0) {
IApimanBuffer preUrlData = bufferFactory.createBuffer(originalBuffer.getBytes(preUrlFromPos, position));
super.write(preUrlData);
bytesConsumed = position;
}
// Now consume the URL
int originalPos = position;
String url = consumeURL();
// the end of the chunk and need to wait for more data
if (url != null) {
url = rewriteURL(url);
IApimanBuffer urlBuffer;
if (url != null) {
// $NON-NLS-1$
urlBuffer = bufferFactory.createBuffer(url, "UTF-8");
} else {
urlBuffer = bufferFactory.createBuffer(originalBuffer.getBytes(originalPos, position));
}
super.write(urlBuffer);
bytesConsumed = position;
preUrlFromPos = position;
} else {
done = true;
}
} else {
position++;
}
} else {
position++;
}
if (position > maxPos) {
done = true;
}
}
// What do we do with what's left? If there *is* anything left!
if (urlsFound == 0) {
super.write(originalBuffer);
buffer = null;
} else {
buffer = bufferFactory.createBuffer(originalBuffer.getBytes(bytesConsumed, maxPos + 1));
if (atEnd) {
super.write(buffer);
}
}
}
use of io.apiman.gateway.engine.io.IApimanBuffer in project apiman by apiman.
the class InfinispanCacheStoreComponent method putBinary.
/**
* @see io.apiman.gateway.engine.components.ICacheStoreComponent#putBinary(java.lang.String, java.lang.Object, long)
*/
@Override
public <T> ISignalWriteStream putBinary(final String cacheKey, final T jsonObject, final long timeToLive) throws IOException {
final IApimanBuffer dataBuffer = bufferFactory.createBuffer(0);
return new ISignalWriteStream() {
private boolean finished = false;
private boolean aborted = false;
@Override
public void abort(Throwable t) {
aborted = true;
finished = false;
}
@Override
public boolean isFinished() {
return finished;
}
@Override
public void write(IApimanBuffer chunk) {
dataBuffer.append(chunk);
}
@Override
public void end() {
if (!aborted) {
synchronized (mutex) {
InfinispanCacheEntry entry = (InfinispanCacheEntry) getCache().get(cacheKey);
if (entry == null) {
entry = new InfinispanCacheEntry();
}
entry.setHead(jsonObject);
entry.setExpiresOn(System.currentTimeMillis() + (timeToLive * 1000));
entry.setData(dataBuffer.getBytes());
getCache().put(cacheKey, entry);
}
}
}
};
}
use of io.apiman.gateway.engine.io.IApimanBuffer in project apiman by apiman.
the class ApiRequestExecutorImpl method execute.
/**
* @see io.apiman.gateway.engine.IApiRequestExecutor#execute()
*/
@Override
public void execute() {
// load the api data based on request
registry.getApi(request.getApiOrgId(), request.getApiId(), request.getApiVersion(), (IAsyncResult<Api> apiResult) -> {
if (apiResult.isSuccess()) {
api = apiResult.getResult();
} else if (apiResult.isError()) {
resultHandler.handle(AsyncResultImpl.create(apiResult.getError(), IEngineResult.class));
}
});
// check if api disable key are enabled
if (api != null && !api.isKeysStrippingDisabled()) {
// Strip apikey
stripApiKey();
}
// Fill out some of the basic metrics structure.
requestMetric.setRequestStart(new Date());
requestMetric.setUrl(request.getUrl());
requestMetric.setResource(request.getDestination());
requestMetric.setMethod(request.getType());
requestMetric.setApiOrgId(request.getApiOrgId());
requestMetric.setApiId(request.getApiId());
requestMetric.setApiVersion(request.getApiVersion());
// Set request metric
context.setAttribute(PolicyContextKeys.REQUEST_METRIC, requestMetric);
// Set connector config early (allows mutation of certain connector properties)
IConnectorConfig connectorConfig = connectorFactory.createConnectorConfig(request, api);
context.setConnectorConfiguration(connectorConfig);
// Create the handler that will be called once the policies are asynchronously
// loaded (can happen this way due to the plugin framework).
final IAsyncHandler<List<PolicyWithConfiguration>> policiesLoadedHandler = (List<PolicyWithConfiguration> result) -> {
policyImpls = result;
// Set up the policy chain request, call #doApply to execute.
requestChain = createRequestChain((ApiRequest req) -> {
IConnectorInterceptor connectorInterceptor = context.getConnectorInterceptor();
IApiConnector connector;
if (connectorInterceptor == null) {
connector = connectorFactory.createConnector(req, api, RequiredAuthType.parseType(api), hasDataPolicy, connectorConfig);
} else {
connector = connectorInterceptor.createConnector();
}
// TODO check for a null connector
// Open up a connection to the back-end if we're given the OK from the request chain
requestMetric.setApiStart(new Date());
// Attach the response handler here.
apiConnection = connector.connect(req, createApiConnectionResponseHandler());
// Write the body chunks from the *policy request* into the connector request.
requestChain.bodyHandler(buffer -> {
requestMetric.setBytesUploaded(requestMetric.getBytesUploaded() + buffer.length());
apiConnection.write(buffer);
});
// Indicate end from policy chain request to connector request.
requestChain.endHandler(onEnd -> apiConnection.end());
// Once we have returned from connector.request, we know it is safe to start
// writing chunks without buffering. At this point, it is the responsibility
// of the implementation as to how they should cope with the chunks.
handleStream();
});
requestChain.doApply(request);
};
// The handler used when we need to parse the inbound request payload into
// an object and make it available via the policy context.
final IAsyncResultHandler<Object> payloadParserHandler = new IAsyncResultHandler<Object>() {
@Override
public void handle(IAsyncResult<Object> result) {
if (result.isSuccess()) {
final Object payload = result.getResult();
// Store the parsed object in the policy context.
context.setAttribute(PolicyContextKeys.REQUEST_PAYLOAD, payload);
context.setAttribute(PolicyContextKeys.REQUEST_PAYLOAD_IO, payloadIO);
// Now replace the inbound stream handler with one that uses the payload IO
// object to re-marshall the (possibly modified) payload object to bytes
// and sends that (because the *real* inbound stream has already been consumed)
streamHandler(new IAsyncHandler<ISignalWriteStream>() {
@Override
public void handle(ISignalWriteStream connectorStream) {
try {
if (payload == null) {
connectorStream.end();
} else {
payloadIO = context.getAttribute(PolicyContextKeys.REQUEST_PAYLOAD_IO, payloadIO);
byte[] data = payloadIO.marshall(payload);
IApimanBuffer buffer = bufferFactory.createBuffer(data);
connectorStream.write(buffer);
connectorStream.end();
}
} catch (Exception e) {
connectorStream.abort(e);
throw new RuntimeException(e);
}
}
});
// Load and executes the policies
loadPolicies(policiesLoadedHandler);
} else {
resultHandler.handle(AsyncResultImpl.create(result.getError(), IEngineResult.class));
}
}
};
// then we lookup the Contract and use that.
if (request.getApiKey() == null || (api != null && api.isKeysStrippingDisabled())) {
if (api == null) {
// $NON-NLS-1$
ApiNotFoundException error = new ApiNotFoundException(Messages.i18n.format("EngineImpl.ApiNotFound"));
resultHandler.handle(AsyncResultImpl.create(error, IEngineResult.class));
} else if (!api.isPublicAPI()) {
// $NON-NLS-1$
InvalidApiException error = new InvalidApiException(Messages.i18n.format("EngineImpl.ApiNotPublic"));
// Forbidden
error.setStatusCode(403);
resultHandler.handle(AsyncResultImpl.create(error, IEngineResult.class));
} else {
resolvePropertyReplacements(api);
request.setApi(api);
policies = api.getApiPolicies();
policyImpls = new ArrayList<>(policies.size());
// or a JSON document
if (api.isParsePayload()) {
parsePayload(payloadParserHandler);
} else {
loadPolicies(policiesLoadedHandler);
}
}
} else {
String apiOrgId = request.getApiOrgId();
String apiId = request.getApiId();
String apiVersion = request.getApiVersion();
String apiKey = request.getApiKey();
registry.getContract(apiOrgId, apiId, apiVersion, apiKey, (IAsyncResult<ApiContract> contractResult) -> {
if (contractResult.isSuccess()) {
ApiContract apiContract = contractResult.getResult();
resolvePropertyReplacements(apiContract);
requestMetric.setClientOrgId(apiContract.getClient().getOrganizationId());
requestMetric.setClientId(apiContract.getClient().getClientId());
requestMetric.setClientVersion(apiContract.getClient().getVersion());
requestMetric.setPlanId(apiContract.getPlan());
requestMetric.setContractId(request.getApiKey());
api = apiContract.getApi();
request.setContract(apiContract);
request.setApi(api);
policies = apiContract.getPolicies();
policyImpls = new ArrayList<>(policies.size());
if (request.getApiOrgId() != null) {
try {
validateRequest(request);
} catch (InvalidContractException e) {
resultHandler.handle(AsyncResultImpl.create(e, IEngineResult.class));
return;
}
}
// or a JSON document
if (api.isParsePayload()) {
parsePayload(payloadParserHandler);
} else {
// Load and executes the policies
loadPolicies(policiesLoadedHandler);
}
} else {
resultHandler.handle(AsyncResultImpl.create(contractResult.getError(), IEngineResult.class));
}
});
}
}
Aggregations