//Example with XML, SSL, Basic Auth
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.client.WebTarget;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import com.mycompany.exception.MyException;
/**
* Purpose of this class is to use jersey/jaxb related connection to an external API via REST WS.
*/
public class RestClient {
private static final Logger LOG = LogManager.getLogger(RestClient.class);
private int connectTimeout = 30000;
private int readTimeout = 30000;
private String uri;
protected WebTarget service;
protected MyConfiguration config; private Client client;
public void initialize() throws MyException {
if (uri == null || uri.trim().isEmpty()) {
uri = "https://myapi";
}
if (!(uri != null && !uri.trim().isEmpty())) {
throw new MyException("[x] uri wrong: " + uri);
}
ClientBuilder builder = ClientBuilder.newBuilder();
String proxy = "172.00.00.00:1234";
if (proxy != null) {
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ClientProperties.PROXY_URI, proxy);
builder = builder.withConfig(clientConfig);
}
builder = builder.sslContext(initializeHttpClientWithKeyStoreAndCert());
client = builder.build();
client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout);
client.property(ClientProperties.READ_TIMEOUT, readTimeout);
client.register((ClientResponseFilter) (requestContext, responseContext) -> responseContext.getHeaders()
.putSingle("Content-Type", "application/xml"));
client.register(new EntityLoggingFilter());
service = client.target(uri);
LOG.debug("RestClient initialized.");
}
private TrustManager[] getTrustManager() throws Exception {
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("com/mycompany/my_keystore.jks")) {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(inputStream, "somepassword".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
}
}
private SSLContext initializeHttpClientWithKeyStoreAndCert() throws MyException {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
try {
sslContext.init(null, getTrustManager(), null);
} catch (Exception e) {
throw new MyException("[x] Failed to create SSL Context. ", e);
}
return sslContext;
} catch (NoSuchAlgorithmException e) {
LOG.error(e);
throw new MyException(e.getClass().getSimpleName() + " while Creating HttpClient: " + e.getMessage(), e);
}
}
}
============== POST a request POJO =====================
public MyResponsePOJO postRequest(MyRequestPojo myrequestPojo) {
// credentials shown for teaching purpose. Usually they are stored in a properties file or config.
String basicAuthUser = "someUser";
String basicAuthPass = "somePassword";
String base64Creds = Base64.getEncoder()
.encodeToString((basicAuthUser + ":" + basicAuthPass).getBytes("UTF-8"));
Response response = service.path("mypath").request().accept("application/xml")
.header("Content-type", "application/xml")
.header("Authorization", "Basic " + base64Creds).post(Entity.xml(myRequestPojo));
return response.readEntity(MyResponsePOJO.class);
}
============== LOG response and request bodies in XML or JSON with the RequestResponseLoggingFilter =======
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.logging.Logger;
import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
/**
* @author tim
*
* Purpose is to log request and response payload as XML.
*/
@Provider@Priority(Integer.MIN_VALUE)
public class RequestResponseLoggingFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor {
private static final Logger LOG = Logger.getLogger(RequestResponseLoggingFilter.class.getName());
private final int maximumSizeForEntity = 1024 * 8;
private class StreamLogger extends FilterOutputStream {
private final StringBuilder builder = new StringBuilder();
private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
StreamLogger(OutputStream outputStream) {
super(outputStream);
}
public StringBuilder writeEntity(Charset charset) {
final byte[] pojo = byteArrayOutputStream.toByteArray();
builder.append(new String(pojo, 0, pojo.length, charset));
if (pojo.length > maximumSizeForEntity) {
builder.append("...more...");
}
builder.append('\n');
return builder;
}
@Override
public void write(final int i) throws IOException {
if (byteArrayOutputStream.size() <= maximumSizeForEntity) {
byteArrayOutputStream.write(i);
}
out.write(i);
}
}
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (requestContext.hasEntity()) {
final OutputStream stream = new StreamLogger(requestContext.getEntityStream());
requestContext.setEntityStream(stream);
requestContext.setProperty("EntityLoggingFilter.entityStream", stream);
} else {
// nop
}
}
@Override
public void filter(ClientRequestContext requestCtx, ClientResponseContext responseCtx) throws IOException {
final StringBuilder stringBuilder = new StringBuilder();
if (responseCtx.hasEntity()) {
responseCtx.setEntityStream(logIncoming(stringBuilder, responseCtx.getEntityStream(), StandardCharsets.UTF_8));
LOG.info(stringBuilder.toString());
}
}
@Override
public void aroundWriteTo(WriterInterceptorContext ctx) throws IOException, WebApplicationException {
final StreamLogger stream = (StreamLogger) ctx.getProperty("EntityLoggingFilter.entityStream");
ctx.proceed();
if (stream != null) {
LOG.info(stream.writeEntity(StandardCharsets.UTF_8).toString());
} else {
// nop
}
}
private InputStream logIncoming(final StringBuilder b, InputStream stream, final Charset charset) throws IOException {
if (!stream.markSupported()) {
stream = new BufferedInputStream(stream);
}
stream.mark(maximumSizeForEntity + 1);
final byte[] pojo = new byte[maximumSizeForEntity + 1];
final int entitySize = stream.read(pojo);
b.append(new String(pojo, 0, Math.min(entitySize, maximumSizeForEntity), charset));
if (entitySize > maximumSizeForEntity) {
b.append("...more...");
} else {
// nop
}
b.append('\n');
stream.reset();
return stream;
}
}
================ DEPENDENCIES ================================
org="org.apache.logging.log4j" name="log4j" version = 2.5
org="org.glassfish.jersey" name="jersey" version =2.25.1
org="org.eclipse.persistence" name="eclipse-persistence" version = 2.6.0
<!-- required for Eclipse moxy, jaxb alternative) -->
org="javax.validation" name="validation-api" version = 1.1.0.Final
Dienstag, 15. Mai 2018
Freitag, 4. Mai 2018
Java UNIT Test Exception Handling with @Rule
A nice way to get rid of manual Exception handling in JUnit Tests is this:
@Rule
public ExpectedException thrownException = ExpectedException.none();
@Test
public void testSomething() {
// given
thrownException.expect(MyExpectedException.class);
thrownException.expectMessage("my expected msg");
thrownException.reportMissingExceptionWithMessage("my custom msg");
/* possibly doing setup of mocks which throw the Exception... */
// when / then
testee.doSomething(); // throws the Exception...
}
@Rule
public ExpectedException thrownException = ExpectedException.none();
@Test
public void testSomething() {
// given
thrownException.expect(MyExpectedException.class);
thrownException.expectMessage("my expected msg");
thrownException.reportMissingExceptionWithMessage("my custom msg");
/* possibly doing setup of mocks which throw the Exception... */
// when / then
testee.doSomething(); // throws the Exception...
}
Donnerstag, 3. Mai 2018
Java Logging Log4j vs. SLF4J
Very good article which I recently found:
https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/
https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/https://blog.frankel.ch/thoughts-on-java-logging-and-slf4j/
Java Optional Example
Some people say that Optionals should only be used for API designs.
I think there is more to it and we can modernize our code. See this Nullpointer Exception. In this example we get rid of this:
//myList = null;
myList.add(myParam);
In favor of that:
Optional.ofNullable(myParam).ifPresent(myList::add);
//.of(myParam) would have thrown a Nullpointer if not present...
And for Exceptions, we get rid of this:
if (token == null) {
throw new MyException("message");
}
In favor of that:
Optional.ofNullable(token).orElseThrow(() -> new MyException("message"));
I think there is more to it and we can modernize our code. See this Nullpointer Exception. In this example we get rid of this:
//myList = null;
myList.add(myParam);
In favor of that:
Optional.ofNullable(myParam).ifPresent(myList::add);
//.of(myParam) would have thrown a Nullpointer if not present...
And for Exceptions, we get rid of this:
if (token == null) {
throw new MyException("message");
}
In favor of that:
Optional.ofNullable(token).orElseThrow(() -> new MyException("message"));
Abonnieren
Posts (Atom)
NEW BLOG! http://cleancode.consulting/
Dear Reader, This Blog is closed and remains as an archive. Please find our new Blog at http://cleancode.consulting/
-
Resolve a Merge Conflict in GIT with IntelliJ Let us assume you are using Bitbucket or a similar tool to administrate and host your GI...
-
Just create a package-info.java file for your package in which you have your POJO: @javax.xml.bind.annotation.XmlSchema(namespace = ...