blob: 4e5668fb8d0a03c29e244bc61cdd21e4ddc5333c [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.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import javax.net.ssl.SSLContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.apache.camel.CamelContext;
import org.apache.camel.Message;
import org.apache.camel.component.servicenow.annotations.ServiceNowSysParm;
import org.apache.camel.component.servicenow.auth.AuthenticationRequestFilter;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.jsse.SSLContextParameters;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.ProxyAuthorizationPolicy;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ServiceNowClient {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceNowClient.class);
private final CamelContext camelContext;
private final ServiceNowConfiguration configuration;
private final WebClient client;
public ServiceNowClient(CamelContext camelContext, ServiceNowConfiguration configuration) {
this.camelContext = camelContext;
this.configuration = configuration;
this.client = WebClient.create(
configuration.getApiUrl(),
Arrays.asList(
new AuthenticationRequestFilter(configuration),
new JacksonJsonProvider(configuration.getOrCreateMapper())
),
true
);
configureRequestContext(camelContext, configuration, client);
configureTls(camelContext, configuration, client);
configureHttpClientPolicy(camelContext, configuration, client);
configureProxyAuthorizationPolicy(camelContext, configuration, client);
}
public ServiceNowClient types(MediaType type) {
return types(type, type);
}
public ServiceNowClient types(MediaType accept, MediaType type) {
client.accept(accept);
client.type(type);
return this;
}
public ServiceNowClient path(Object path) {
if (ObjectHelper.isNotEmpty(path)) {
client.path(path);
}
return this;
}
public ServiceNowClient type(MediaType ct) {
client.type(ct);
return this;
}
public ServiceNowClient type(String type) {
client.type(type);
return this;
}
public ServiceNowClient accept(MediaType... types) {
client.accept(types);
return this;
}
public ServiceNowClient accept(String... types) {
client.accept(types);
return this;
}
public ServiceNowClient query(String name, Object... values) {
client.query(name, values);
return this;
}
public ServiceNowClient queryF(String name, String format, Object... values) {
client.query(name, String.format(format, values));
return this;
}
public ServiceNowClient query(ServiceNowParam param, Message message) {
Object value = param.getHeaderValue(message, configuration);
if (value != null) {
client.query(param.getId(), value);
}
return this;
}
public ServiceNowClient query(Class<?> model) {
if (model != null) {
String name;
String value;
for (ServiceNowSysParm parm : model.getAnnotationsByType(ServiceNowSysParm.class)) {
name = parm.name();
value = parm.value();
// SysParms defined on model have precedence and replace query param
// with same name set via Message headers.
if (ObjectHelper.isNotEmpty(name) && ObjectHelper.isNotEmpty(value)) {
LOGGER.debug("Replace query param {} with value {}", name, value);
client.replaceQueryParam(name, value);
}
}
}
return this;
}
public Response invoke(String httpMethod) throws Exception {
return invoke(client, httpMethod, null);
}
public Response invoke(String httpMethod, Object body) throws Exception {
return invoke(client, httpMethod, body);
}
public <T> T trasform(String httpMethod, Function<Response, T> function) throws Exception {
return function.apply(invoke(client, httpMethod, null));
}
public <T> T trasform(String httpMethod, Object body, Function<Response, T> function) throws Exception {
return function.apply(invoke(client, httpMethod, body));
}
public ServiceNowClient reset() {
client.back(true);
client.reset();
client.resetQuery();
return this;
}
// *******************************
// Helpers
// *******************************
private Response invoke(WebClient client, String httpMethod, Object body) throws Exception {
Response response = client.invoke(httpMethod, body);
int code = response.getStatus();
// Only ServiceNow known error status codes are mapped
// See http://wiki.servicenow.com/index.php?title=REST_API#REST_Response_HTTP_Status_Codes
switch(code) {
case 200:
case 201:
case 204:
// Success
break;
case 400:
case 401:
case 403:
case 404:
case 405:
case 406:
case 415:
ServiceNowExceptionModel model = response.readEntity(ServiceNowExceptionModel.class);
throw new ServiceNowException(
code,
model.getStatus(),
model.getError().get("message"),
model.getError().get("detail")
);
default:
throw new ServiceNowException(
code,
response.readEntity(Map.class)
);
}
return response;
}
private static void configureRequestContext(
CamelContext context, ServiceNowConfiguration configuration, WebClient client) {
WebClient.getConfig(client)
.getRequestContext()
.put("org.apache.cxf.http.header.split", true);
}
private static void configureTls(
CamelContext camelContext, ServiceNowConfiguration configuration, WebClient client) {
SSLContextParameters sslContextParams = configuration.getSslContextParameters();
if (sslContextParams != null) {
HTTPConduit conduit = WebClient.getConfig(client).getHttpConduit();
TLSClientParameters tlsClientParams = conduit.getTlsClientParameters();
if (tlsClientParams == null) {
tlsClientParams = new TLSClientParameters();
}
try {
SSLContext sslContext = sslContextParams.createSSLContext(camelContext);
tlsClientParams.setSSLSocketFactory(sslContext.getSocketFactory());
conduit.setTlsClientParameters(tlsClientParams);
} catch (IOException | GeneralSecurityException e) {
throw ObjectHelper.wrapRuntimeCamelException(e);
}
}
}
private static void configureHttpClientPolicy(
CamelContext context, ServiceNowConfiguration configuration, WebClient client) {
HTTPClientPolicy httpPolicy = configuration.getHttpClientPolicy();
if (httpPolicy == null) {
String host = configuration.getProxyHost();
Integer port = configuration.getProxyPort();
if (host != null && port != null) {
httpPolicy = new HTTPClientPolicy();
httpPolicy.setProxyServer(host);
httpPolicy.setProxyServerPort(port);
}
}
if (httpPolicy != null) {
WebClient.getConfig(client).getHttpConduit().setClient(httpPolicy);
}
}
private static void configureProxyAuthorizationPolicy(
CamelContext context, ServiceNowConfiguration configuration, WebClient client) {
ProxyAuthorizationPolicy proxyPolicy = configuration.getProxyAuthorizationPolicy();
if (proxyPolicy == null) {
String username = configuration.getProxyUserName();
String password = configuration.getProxyPassword();
if (username != null && password != null) {
proxyPolicy = new ProxyAuthorizationPolicy();
proxyPolicy.setAuthorizationType("Basic");
proxyPolicy.setUserName(username);
proxyPolicy.setPassword(password);
}
}
if (proxyPolicy != null) {
WebClient.getConfig(client).getHttpConduit().setProxyAuthorization(proxyPolicy);
}
}
}