private static ObjectMapper objectMapper(InvocationContext ctx) { Optional<ObjectMapper> omo = ctx.getRuntimeContext().getAttribute(OM_KEY, ObjectMapper.class); if (!omo.isPresent()) { ObjectMapper om = new ObjectMapper(); ctx.getRuntimeContext().setAttribute(OM_KEY, om); return om; } else { return omo.get(); } }
@Override public void setResponseHeader(String key, String value, String... vs) { if (Headers.canonicalKey(key).equals(OutputEvent.CONTENT_TYPE_HEADER)) { invocationContext.setResponseContentType(value); invocationContext.setResponseHeader("Fn-Http-H-" + key, value); } else { invocationContext.setResponseHeader("Fn-Http-H-" + key, value, vs); } }
@Override public void addResponseHeader(String key, String value) { invocationContext.addResponseHeader("Fn-Http-H-" + key, value); }
@Override public synchronized Flow currentFlow() { if (runtime == null) { String functionId = ctx.getRuntimeContext().getFunctionID(); CompleterClientFactory factory = getOrCreateCompleterClientFactory(completerBaseUrl); final FlowId flowId = factory.getCompleterClient().createFlow(functionId); runtime = new RemoteFlow(flowId); InvocationListener flowInvocationListener = new InvocationListener() { @Override public void onSuccess() { factory.getCompleterClient().commit(flowId); } public void onFailure() { factory.getCompleterClient().commit(flowId); } }; ctx.addListener(flowInvocationListener); } return runtime; } };
/** * Sets the response content type, this will override the default content type of the output * * @param contentType a mime type for the response */ default void setResponseContentType(String contentType) { this.setResponseHeader(OutputEvent.CONTENT_TYPE_HEADER, contentType); }
public FunctionHTTPGatewayContext(InvocationContext invocationContext) { this.invocationContext = Objects.requireNonNull(invocationContext, "invocationContext"); Map<String, List<String>> myHeaders = new HashMap<>(); String requestUri = ""; String method = ""; for (Map.Entry<String, List<String>> e : invocationContext.getRequestHeaders().asMap().entrySet()) { String key = e.getKey(); if (key.startsWith("Fn-Http-H-")) { String httpKey = key.substring("Fn-Http-H-".length()); if (httpKey.length() > 0) { myHeaders.put(httpKey, e.getValue()); } } if (key.equals("Fn-Http-Request-Url")) { requestUri = e.getValue().get(0); } if (key.equals("Fn-Http-Method")) { method = e.getValue().get(0); } } this.queryParameters = QueryParametersParser.getParams(requestUri); this.requestUrl = requestUri; this.method = method; this.httpRequestHeaders = Headers.emptyHeaders().setHeaders(myHeaders); }
@Override public void setStatusCode(int code) { if (code < 100 || code >= 600) { throw new IllegalArgumentException("Invalid HTTP status code: " + code); } invocationContext.setResponseHeader("Fn-Http-Status", "" + code); } }
private Object coerceParameter(InvocationContext ctx, MethodWrapper targetMethod, int param, InputEvent evt) { RuntimeContext runtimeContext = ctx.getRuntimeContext(); return runtimeContext.getInputCoercions(targetMethod, param) .stream() .map((c) -> c.tryCoerceParam(ctx, param, evt, targetMethod)) .filter(Optional::isPresent) .map(Optional::get) .findFirst() .orElseThrow(() -> new FunctionInputHandlingException("No type coercion for argument " + param + " of " + targetMethod + " of found")); }
private Object coerceParameter(InvocationContext ctx, MethodWrapper targetMethod, int param, InputEvent evt) { RuntimeContext runtimeContext = ctx.getRuntimeContext(); return runtimeContext.getInputCoercions(targetMethod, param) .stream() .map((c) -> c.tryCoerceParam(ctx, param, evt, targetMethod)) .filter(Optional::isPresent) .map(Optional::get) .findFirst() .orElseThrow(() -> new FunctionInputHandlingException("No type coercion for argument " + param + " of " + targetMethod + " of found")); }
@Override public Optional<Object> tryCoerceParam(InvocationContext currentContext, int arg, InputEvent input, MethodWrapper method) { Class<?> paramClass = method.getParamType(arg).getParameterClass(); if (paramClass.equals(RuntimeContext.class)) { return Optional.of(currentContext.getRuntimeContext()); } else if (paramClass.equals(InvocationContext.class)) { return Optional.of(currentContext); } else if (paramClass.equals(HTTPGatewayContext.class)) { return Optional.of(new FunctionHTTPGatewayContext(currentContext)); } else { return Optional.empty(); } } }
private Optional<OutputEvent> coerceReturnValue(InvocationContext ctx, MethodWrapper method, Object rawResult) { try { return Optional.of((ctx.getRuntimeContext()).getOutputCoercions(method.getTargetMethod()) .stream() .map((c) -> c.wrapFunctionResult(ctx, method, rawResult)) .filter(Optional::isPresent) .map(Optional::get) .findFirst() .orElseThrow(() -> new FunctionOutputHandlingException("No coercion found for return type"))); } catch (RuntimeException e) { throw new FunctionOutputHandlingException("An exception was thrown during Output Coercion: " + e.getMessage(), e); } }
protected Optional<OutputEvent> coerceReturnValue(InvocationContext ctx, MethodWrapper method, Object rawResult) { try { return Optional.of(ctx.getRuntimeContext().getOutputCoercions(method.getTargetMethod()) .stream() .map((c) -> c.wrapFunctionResult(ctx, method, rawResult)) .filter(Optional::isPresent) .map(Optional::get) .findFirst() .orElseThrow(() -> new FunctionOutputHandlingException("No coercion found for return type"))); } catch (RuntimeException e) { throw new FunctionOutputHandlingException("An exception was thrown during Output Coercion: " + e.getMessage(), e); } }
/** * Invoke the function wrapped by this loader * * @param evt The function event * @return the function response * @throws InternalFunctionInvocationException if the invocation fails */ @Override public Optional<OutputEvent> tryInvoke(InvocationContext ctx, InputEvent evt) throws InternalFunctionInvocationException { FunctionRuntimeContext runtimeContext = (FunctionRuntimeContext) ctx.getRuntimeContext(); MethodWrapper method = runtimeContext.getMethodWrapper(); Object[] userFunctionParams = coerceParameters(ctx, method, evt); Object rawResult; try { rawResult = method.getTargetMethod().invoke(ctx.getRuntimeContext().getInvokeInstance().orElse(null), userFunctionParams); } catch (IllegalAccessException | InvocationTargetException e) { throw new InternalFunctionInvocationException(e.getCause().getMessage(), e.getCause()); } return coerceReturnValue(ctx, method, rawResult); }
Optional<String> graphIdOption = evt.getHeaders().get(FLOW_ID_HEADER); final String completerBaseUrl = ctx.getRuntimeContext().getConfigurationByKey(COMPLETER_BASE_URL).orElse(DEFAULT_COMPLETER_BASE_URL);