blob: 348b36894e675c3c3da07ab3b77b067d67e9cf2c [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.camel.component.servicenow;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.util.ObjectHelper;
public abstract class AbstractServiceNowProcessor implements Processor {
protected final ServiceNowEndpoint endpoint;
protected final ServiceNowConfiguration config;
protected final ObjectMapper mapper;
protected final ServiceNowClient client;
// Cache for JavaTypes
private final JavaTypeCache javaTypeCache;
private final List<ServiceNowDispatcher> dispatchers;
protected AbstractServiceNowProcessor(ServiceNowEndpoint endpoint) throws Exception {
this.javaTypeCache = new JavaTypeCache();
this.endpoint = endpoint;
this.config = endpoint.getConfiguration();
this.mapper = config.getOrCreateMapper();
this.client = new ServiceNowClient(endpoint.getCamelContext(), config);
this.dispatchers = new ArrayList<>();
}
protected AbstractServiceNowProcessor setBodyAndHeaders(Message message, Class<?> responseModel, Response response) throws Exception {
if (response != null) {
setHeaders(message, responseModel, response);
setBody(message, responseModel, response);
}
return this;
}
@Override
public void process(Exchange exchange) throws Exception {
final ServiceNowDispatcher dispatcher = findDispatcher(exchange);
if (dispatcher != null) {
dispatcher.process(exchange);
} else {
throw new IllegalArgumentException("Unable to process exchange");
}
}
// *********************************
// Header
// *********************************
protected AbstractServiceNowProcessor setHeaders(Message message, Class<?> responseModel, Response response) throws Exception {
ServiceNowHelper.findOffsets(response, (k, v) -> message.setHeader(k, v));
String attachmentMeta = response.getHeaderString(ServiceNowConstants.ATTACHMENT_META_HEADER);
if (ObjectHelper.isNotEmpty(attachmentMeta)) {
message.setHeader(
ServiceNowConstants.CONTENT_META,
mapper.readValue(attachmentMeta, Map.class)
);
}
copyHeader(response, HttpHeaders.CONTENT_TYPE, message, ServiceNowConstants.CONTENT_TYPE);
copyHeader(response, HttpHeaders.CONTENT_ENCODING, message, ServiceNowConstants.CONTENT_ENCODING);
if (responseModel != null) {
message.getHeaders().putIfAbsent(ServiceNowConstants.MODEL, responseModel.getName());
message.getHeaders().putIfAbsent(ServiceNowConstants.RESPONSE_MODEL, responseModel.getName());
}
return this;
}
// *********************************
// Body
// *********************************
protected AbstractServiceNowProcessor setBody(Message message, Class<?> model, Response response) throws Exception {
if (message != null && response != null) {
if (ObjectHelper.isNotEmpty(response.getHeaderString(HttpHeaders.CONTENT_TYPE))) {
JsonNode root = response.readEntity(JsonNode.class);
Map<String, String> responseAttributes = null;
if (root != null) {
Iterator<Map.Entry<String, JsonNode>> fields = root.fields();
while (fields.hasNext()) {
final Map.Entry<String, JsonNode> entry = fields.next();
final String key = entry.getKey();
final JsonNode node = entry.getValue();
if (ObjectHelper.equal("result", key, true)) {
Object body = unwrap(node, model);
if (body != null) {
message.setHeader(ServiceNowConstants.RESPONSE_TYPE, body.getClass());
message.setBody(body);
}
} else {
if (responseAttributes == null) {
responseAttributes = new HashMap<>();
}
responseAttributes.put(key, node.textValue());
}
}
if (responseAttributes != null) {
message.setHeader(ServiceNowConstants.RESPONSE_META, responseAttributes);
}
}
}
}
return this;
}
protected AbstractServiceNowProcessor validateBody(Message message, Class<?> model) {
return validateBody(message.getBody(), model);
}
protected AbstractServiceNowProcessor validateBody(Object body, Class<?> model) {
ObjectHelper.notNull(body, "body");
if (!body.getClass().isAssignableFrom(model)) {
throw new IllegalArgumentException(
"Body is not compatible with model (body=" + body.getClass() + ", model=" + model);
}
return this;
}
protected Object unwrap(JsonNode node, Class<?> model) throws IOException {
if (model == String.class) {
// If the model is a String, let's just serialize it as
// a json string
return mapper.writeValueAsString(node);
}
final Object result;
if (node.isArray()) {
if (model.isInstance(Map.class)) {
// If the model is a Map, there's no need to use any
// specific JavaType to instruct Jackson about the
// expected element type
result = mapper.treeToValue(node, List.class);
} else {
result = mapper.readValue(node.traverse(), javaTypeCache.get(model));
}
} else {
result = mapper.treeToValue(node, model);
}
return result;
}
// *********************************
// Helpers
// *********************************
protected final void addDispatcher(ServiceNowDispatcher dispatcher) {
this.dispatchers.add(dispatcher);
}
protected final void addDispatcher(String action, Processor processor) {
addDispatcher(ServiceNowDispatcher.on(action, null, processor));
}
protected final void addDispatcher(String action, String subject, Processor processor) {
addDispatcher(ServiceNowDispatcher.on(action, subject, processor));
}
protected final ServiceNowDispatcher findDispatcher(Exchange exchange) {
ServiceNowDispatcher dispatcher = null;
for (int i = 0; i < dispatchers.size(); i++) {
dispatcher = dispatchers.get(i);
if (dispatcher.match(exchange)) {
return dispatcher;
}
}
return null;
}
// *********************************
// Helpers
// *********************************
protected Object getRequestParamFromHeader(ServiceNowParam sysParam, Message message) {
return message.getHeader(
sysParam.getHeader(),
sysParam.getDefaultValue(config),
sysParam.getType()
);
}
protected Object getMandatoryRequestParamFromHeader(ServiceNowParam sysParam, Message message) {
return ObjectHelper.notNull(
getRequestParamFromHeader(sysParam, message),
sysParam.getHeader()
);
}
protected void copyHeader(Response from, String fromId, Message to, String toId) {
Object fromValue = from.getHeaders().getFirst(fromId);
if (ObjectHelper.isNotEmpty(fromValue)) {
to.setHeader(toId, fromValue);
}
}
protected Class<?> getRequestModel(Message message) {
return getRequestModel(message, null);
}
protected Class<?> getRequestModel(Message message, String modelName) {
Class<?> model = null;
if (message != null) {
model = message.getHeader(ServiceNowConstants.REQUEST_MODEL, Class.class);
if (model == null) {
model = message.getHeader(ServiceNowConstants.MODEL, Class.class);
}
}
return model != null
? model
: ObjectHelper.isEmpty(modelName) ? Map.class : config.getRequestModel(modelName, Map.class);
}
protected Class<?> getResponseModel(Message message) {
return getRequestModel(message, null);
}
protected Class<?> getResponseModel(Message message, String modelName) {
Class<?> model = null;
if (message != null) {
model = message.getHeader(ServiceNowConstants.RESPONSE_MODEL, Class.class);
if (model == null) {
model = message.getHeader(ServiceNowConstants.MODEL, Class.class);
}
}
return model != null
? model
: ObjectHelper.isEmpty(modelName) ? Map.class : config.getResponseModel(modelName, Map.class);
}
protected String getApiVersion(Message message) {
return message.getHeader(ServiceNowConstants.API_VERSION, config.getApiVersion(), String.class);
}
protected String getTableName(Message message) {
return message.getHeader(ServiceNowParams.PARAM_TABLE_NAME.getHeader(), config.getTable(), String.class);
}
protected String getSysID(Message message) {
return message.getHeader(ServiceNowParams.PARAM_SYS_ID.getHeader(), String.class);
}
// *************************************************************************
// Use ClassValue to lazy create and cache JavaType
// *************************************************************************
private class JavaTypeCache extends ClassValue<JavaType> {
@Override
protected JavaType computeValue(Class<?> type) {
return mapper.getTypeFactory().constructCollectionType(List.class, type);
}
}
}