Quantcast
Channel: Baeldung
Viewing all 4752 articles
Browse latest View live

Using InfluxDB with Java

$
0
0

1. Overview

InfluxDB is a high-performance store for time-series data. It supports insertion and real-time querying of data via a SQL-like query language.

In this introductory article, we’ll demonstrate how to connect to an InfluxDb server, create a database, write time-series information, and then query the database.

2. Setup

To connect to the database, we’ll need to add an entry to our pom.xml file:

<dependency>
    <groupId>org.influxdb</groupId>
    <artifactId>influxdb-java</artifactId>
    <version>2.8</version>
</dependency>

The latest version of this dependency can be found on Maven Central.

We’ll also need an InfluxDB instance. Instructions for downloading and installing a database can be found on the InfluxData website.

3. Connecting to a Server

3.1. Creating a Connection

Creating a database connection requires passing a URL String and user credentials to a connection factory:

InfluxDB influxDB = InfluxDBFactory.connect(databaseURL, userName, password);

3.2. Verifying the Connection

Communications with the database are performed over a RESTful API, so they aren’t persistent.

The API offers a dedicated “ping” service to confirm that the connection is functional. If the connection is good, the response contains a database version. If not, it contains “unknown”.

So after creating a connection, we can verify it by doing:

Pong response = this.influxDB.ping();
if (response.getVersion().equalsIgnoreCase("unknown")) {
    log.error("Error pinging server.");
    return;
} 

3.3. Creating a Database

Creating an InfluxDB database is similar to creating a database on most platforms. But we need to create at least one retention policy before using it.

A retention policy tells the database how long a piece of data should be stored. Time series, such as CPU or memory statistics, tend to accumulate in large datasets.

A typical strategy for controlling the size of time series databases is downsampling. “Raw” data is stored at a high rate, summarized, and then removed after a short time.

Retention policies simplify this by associating a piece of data with an expiration time. InfluxData has an in-depth explanation on their site.

After creating the database, we’ll add a single policy named defaultPolicy. It will simply retain data for 30 days:

influxDB.createDatabase("baeldung");
influxDB.createRetentionPolicy(
  "defaultPolicy", "baeldung", "30d", 1, true);

To create a retention policy, we’ll need a name, the database, an interval, a replication factor (which should be 1 for a single-instance database), and a boolean indicating it’s a default policy.

3.4. Setting a Logging Level

Internally, InfluxDB API uses Retrofit and exposes an interface to Retrofit’s logging facility, via a logging interceptor.

So, we can set the logging level using:

influxDB.setLogLevel(InfluxDB.LogLevel.BASIC);

And now we can see messages when we open a connection and ping it:

Dec 20, 2017 5:38:10 PM okhttp3.internal.platform.Platform log
INFO: --> GET http://127.0.0.1:8086/ping

The available levels are BASIC, FULL, HEADERS, and NONE. 

4. Adding and Retrieving Data

4.1. Points

So now we’re ready to start inserting and retrieving data.

The basic unit of information in InfluxDB is a Point, which is essentially a timestamp and a key-value map.

Let’s have a look at a point holding memory utilization data:

Point point = Point.measurement("memory")
  .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
  .addField("name", "server1")
  .addField("free", 4743656L)
  .addField("used", 1015096L)
  .addField("buffer", 1010467L)
  .build();

We’ve created an entry that contains three Longs as memory statistics, a hostname, and a timestamp.

Let’s see how to add this to the database.

4.2. Writing Batches

Time series data tends to consist of many small points, and writing those records one at a time would be very inefficient. The preferred method is to collect records into batches.

The InfluxDB API provides a BatchPoint object:

BatchPoints batchPoints = BatchPoints
  .database(dbName)
  .retentionPolicy("defaultPolicy")
  .build();

Point point1 = Point.measurement("memory")
  .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
  .addField("name", "server1") 
  .addField("free", 4743656L)
  .addField("used", 1015096L) 
  .addField("buffer", 1010467L)
  .build();

Point point2 = Point.measurement("memory")
  .time(System.currentTimeMillis() - 100, TimeUnit.MILLISECONDS)
  .addField("name", "server1")
  .addField("free", 4743696L)
  .addField("used", 1016096L)
  .addField("buffer", 1008467L)
  .build();

batchPoints.point(point1);
batchPoints.point(point2);
influxDB.write(batchPoints);

We create a BatchPoint and then add Points to it. We set the timestamp for our second entry to 100 milliseconds in the past since the timestamps are a primary index. If we send two points with the same timestamp, only one will be kept.

Note that we must associate BatchPoints with a database and a retention policy.

4.3. Writing One at a Time

Batching may be impractical for some use-cases.

Let’s enable batch mode with a single call to an InfluxDB connection:

influxDB.enableBatch(100, 200, TimeUnit.MILLISECONDS);

We enabled batching of 100 for insertion into the server or sending what it has every 200 milliseconds.

With batch mode enabled, we can still write one at a time. However, some additional setup is required:

influxDB.setRetentionPolicy("defaultPolicy");
influxDB.setDatabase(dbName);

Moreover, now we can write individuals points, and they are being collected in batches by a background thread:

influxDB.write(point);

Before we enqueue individual points, we need to set a database (similar to the use command in SQL) and set a default retention policy. Therefore, if we wish to take advantage of downsampling with multiple retention policies, creating batches is the way to go.

Batch mode utilizes a separate thread pool. So it’s a good idea to disable it when it’s no longer needed:

influxDB.disableBatch();

Closing the connection will also shut down the thread pool:

influxDB.close();

4.4. Mapping Query Results

Queries return a QueryResult, which we can map to POJOs.

Before we look at the query syntax, let’s create a class to hold our memory statistics:

@Measurement(name = "memory")
public class MemoryPoint {

    @Column(name = "time")
    private Instant time;

    @Column(name = "name")
    private String name;

    @Column(name = "free")
    private Long free;

    @Column(name = "used")
    private Long used;

    @Column(name = "buffer")
    private Long buffer;
}

The class is annotated with @Measurement(name = “memory”), corresponding to the Point.measurement(“memory”) we used to create our Points.

For each field in our QueryResult, we add the @Column(name = “XXX”) annotation with the name of the corresponding field.

QueryResults are mapped to POJOs with an InfluxDBResultMapper.

4.5. Querying InfluxDB

So let’s use our POJO with the points we added to the database in our two-point batch:

QueryResult queryResult = connection
  .performQuery("Select * from memory", "baeldung");

InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
List<MemoryPoint> memoryPointList = resultMapper
  .toPOJO(queryResult, MemoryPoint.class);

assertEquals(2, memoryPointList.size());
assertTrue(4743696L == memoryPointList.get(0).getFree());

The query illustrates how our measurement named memory is stored as a table of Points that we can select from.

InfluxDBResultMapper accepts a reference to MemoryPoint.class with the QueryResult and returns a list of points.

After we map the results, we verify that we received two by checking the length of the List we received from the query. Then we look at the first entry in the list and see the free memory size of the second point we inserted. The default ordering of query results from InfluxDB is ascending by timestamp.

Let’s change that:

queryResult = connection.performQuery(
  "Select * from memory order by time desc", "baeldung");
memoryPointList = resultMapper
  .toPOJO(queryResult, MemoryPoint.class);

assertEquals(2, memoryPointList.size());
assertTrue(4743656L == memoryPointList.get(0).getFree());

Adding order by time desc reverses the order of our results.

InfluxDB queries look very similar to SQL. There is an extensive reference guide on their site.

5. Conclusion

We’ve connected to an InfluxDB server, created a database with a retention policy, and then inserted and retrieved data from the server.

The full source code of the examples is over on GitHub.


Introduction to Future in Vavr

$
0
0

1. Introduction

Core Java provides a basic API for asynchronous computations – Future. CompletableFuture is one of its newest implementations.

Vavr provides its new functional alternative to the Future API. In this article, we’ll discuss the new API and show how to make use of some of its new features.

More articles on Vavr can be found here.

2. Maven Dependency

The Future API is included in the Vavr Maven dependency.

So, let’s add it to our pom.xml:

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.9.2</version>
</dependency>

We can find the latest version of the dependency on Maven Central.

3. Vavr’s Future

The Future can be in one of two states:

  • Pending – the computation is ongoing
  • Completed – the computation finished successfully with a result, failed with an exception or was canceled

The main advantage over the core Java Future is that we can easily register callbacks and compose operations in a non-blocking way.

4. Basic Future Operations

4.1. Starting Asynchronous Computations

Now, let’s see how we can start asynchronous computations using Vavr:

String initialValue = "Welcome to ";
Future<String> resultFuture = Future.of(() -> someComputation());

4.2. Retrieving Values from a Future

We can extract values from a Future by simply calling one of the get() or getOrElse() methods:

String result = resultFuture.getOrElse("Failed to get underlying value.");

The difference between get() and getOrElse() is that get() is the simplest solution, while getOrElse() enables us to return a value of any type in case we weren’t able to retrieve the value inside the Future.

It’s recommended to use getOrElse() so we can handle any errors that occur while trying to retrieve the value from a Future. For the sake of simplicity, we’ll just use get() in the next few examples.

Note that the get() method blocks the current thread if it’s necessary to wait for the result.

A different approach is to call the nonblocking getValue() method, which returns an Option<Try<T>> which will be empty as long as computation is pending.

We can then extract the computation result which is inside the Try object:

Option<Try<String>> futureOption = resultFuture.getValue();
Try<String> futureTry = futureOption.get();
String result = futureTry.get();

Sometimes we need to check if the Future contains a value before retrieving values from it.

We can simply do that by using:

resultFuture.isEmpty();

It’s important to note that the method isEmpty() is blocking – it will block the thread until its operation is finished.

4.3. Changing the Default ExecutorService

Futures use an ExecutorService to run their computations asynchronously. The default ExecutorService is Executors.newCachedThreadPool().

We can use another ExecutorService by passing an implementation of our choice:

@Test
public void whenChangeExecutorService_thenCorrect() {
    String result = Future.of(newSingleThreadExecutor(), () -> HELLO)
      .getOrElse(error);
    
    assertThat(result)
      .isEqualTo(HELLO);
}

5. Performing Actions Upon Completion

The API provides the onSuccess() method which performs an action as soon as the Future completes successfully.

Similarly, the method onFailure() is executed upon the failure of the Future.

Let’s see a quick example:

Future<String> resultFuture = Future.of(() -> appendData(initialValue))
  .onSuccess(v -> System.out.println("Successfully Completed - Result: " + v))
  .onFailure(v -> System.out.println("Failed - Result: " + v));

The method onComplete() accepts an action to be run as soon as the Future has completed its execution, whether or not the Future was successful. The method andThen() is similar to onComplete() – it just guarantees the callbacks are executed in a specific order:

Future<String> resultFuture = Future.of(() -> appendData(initialValue))
  .andThen(finalResult -> System.out.println("Completed - 1: " + finalResult))
  .andThen(finalResult -> System.out.println("Completed - 2: " + finalResult));

6. Useful Operations on Futures

6.1. Blocking the Current Thread

The method await() has two cases:

  • if the Future is pending, it blocks the current thread until the Future has completed
  • if the Future is completed, it finishes immediately

Using this method is straightforward:

resultFuture.await();

6.2. Canceling a Computation

We can always cancel the computation:

resultFuture.cancel();

6.3. Retrieving the Underlying ExecutorService

To obtain the ExecutorService that is used by a Future, we can simply call executorService():

resultFuture.executorService();

6.4. Obtaining a Throwable from a Failed Future

We can do that using the getCause() method which returns the Throwable wrapped in an io.vavr.control.Option object.

We can later extract the Throwable from the Option object:

@Test
public void whenDivideByZero_thenGetThrowable2() {
    Future<Integer> resultFuture = Future.of(() -> 10 / 0)
      .await();
    
    assertThat(resultFuture.getCause().get().getMessage())
      .isEqualTo("/ by zero");
}

Additionally, we can convert our instance to a Future holding a Throwable instance using the failed() method:

@Test
public void whenDivideByZero_thenGetThrowable1() {
    Future<Integer> resultFuture = Future.of(() -> 10 / 0);
    
    assertThatThrownBy(resultFuture::get)
      .isInstanceOf(ArithmeticException.class);
}

6.5. isCompleted(), isSuccess(), and isFailure()

These methods are pretty much self-explanatory. They check if a Future completed, whether it completed successfully or with a failure. All of them return boolean values, of course.

We’re going to use these methods with the previous example:

@Test
public void whenDivideByZero_thenCorrect() {
    Future<Integer> resultFuture = Future.of(() -> 10 / 0)
      .await();
    
    assertThat(resultFuture.isCompleted()).isTrue();
    assertThat(resultFuture.isSuccess()).isFalse();
    assertThat(resultFuture.isFailure()).isTrue();
}

6.6. Applying Computations on Top of a Future

The map() method allows us to apply a computation on top of a pending Future:

@Test
public void whenCallMap_thenCorrect() {
    Future<String> futureResult = Future.of(() -> "from Baeldung")
      .map(a -> "Hello " + a)
      .await();
    
    assertThat(futureResult.get())
      .isEqualTo("Hello from Baeldung");
}

If we pass a function that returns a Future to the map() method, we can end up with a nested Future structure. To avoid this, we can leverage the flatMap() method:

@Test
public void whenCallFlatMap_thenCorrect() {
    Future<Object> futureMap = Future.of(() -> 1)
      .flatMap((i) -> Future.of(() -> "Hello: " + i));
         
    assertThat(futureMap.get()).isEqualTo("Hello: 1");
}

6.7. Transforming Futures

The method transformValue() can be used to apply a computation on top of a Future and change the value inside it to another value of the same type or a different type:

@Test
public void whenTransform_thenCorrect() {
    Future<Object> future = Future.of(() -> 5)
      .transformValue(result -> Try.of(() -> HELLO + result.get()));
                
    assertThat(future.get()).isEqualTo(HELLO + 5);
}

6.8. Zipping Futures

The API provides the zip() method which zips Futures together into tuples – a tuple is a collection of several elements that may or may not be related to each other. They can also be of different types. Let’s see a quick example:

@Test
public void whenCallZip_thenCorrect() {
    Future<String> f1 = Future.of(() -> "hello1");
    Future<String> f2 = Future.of(() -> "hello2");
    
    assertThat(f1.zip(f2).get())
      .isEqualTo(Tuple.of("hello1", "hello2"));
}

The point to note here is that the resulting Future will be pending as long as at least one of the base Futures is still pending.

6.9. Conversion between Futures and CompletableFutures

The API supports integration with java.util.CompletableFuture. So, we can easily convert a Future to a CompletableFuture if we want to perform operations that only the core Java API supports.

Let’s see how we can do that:

@Test
public void whenConvertToCompletableFuture_thenCorrect()
  throws Exception {
 
    CompletableFuture<String> convertedFuture = Future.of(() -> HELLO)
      .toCompletableFuture();
    
    assertThat(convertedFuture.get())
      .isEqualTo(HELLO);
}

We can also convert a CompletableFuture to a Future using the fromCompletableFuture() method.

6.10. Exception Handling

Upon the failure of a Future, we can handle the error in a few ways.

For example, we can make use of the method recover() to return another result, such as an error message:

@Test
public void whenFutureFails_thenGetErrorMessage() {
    Future<String> future = Future.of(() -> "Hello".substring(-1))
      .recover(x -> "fallback value");
    
    assertThat(future.get())
      .isEqualTo("fallback value");
}

Or, we can return the result of another Future computation using recoverWith():

@Test
public void whenFutureFails_thenGetAnotherFuture() {
    Future<String> future = Future.of(() -> "Hello".substring(-1))
      .recoverWith(x -> Future.of(() -> "fallback value"));
    
    assertThat(future.get())
      .isEqualTo("fallback value");
}

The method fallbackTo() is another way to handle errors. It’s called on a Future and accepts another Future as a parameter.

If the first Future is successful, then it returns its result. Otherwise, if the second Future is successful, then it returns its result. If both Futures fail, then the failed() method returns a Future of a Throwable, which holds the error of the first Future:

@Test
public void whenBothFuturesFail_thenGetErrorMessage() {
    Future<String> f1 = Future.of(() -> "Hello".substring(-1));
    Future<String> f2 = Future.of(() -> "Hello".substring(-2));
    
    Future<String> errorMessageFuture = f1.fallbackTo(f2);
    Future<Throwable> errorMessage = errorMessageFuture.failed();
    
    assertThat(
      errorMessage.get().getMessage())
      .isEqualTo("String index out of range: -1");
}

7. Conclusion

In this article, we’ve seen what a Future is and learned some of its important concepts. We’ve also walked through some of the features of the API using a few practical examples.

The full version of the code is available over on GitHub.

A Guide to Iterator in Java

$
0
0

1. Introduction

An Iterator is one of many ways we can traverse a collection, and as every option, it has its pros and cons.

It was first introduced in Java 1.2 as a replacement of Enumerations and:

In this tutorial, we’re going to review the simple Iterator interface to learn how we can use its different methods.

We’ll also check the more robust ListIterator extension which adds some interesting functionality.

2. The Iterator Interface

To start, we need to obtain an Iterator from a Collection; this is done by calling the iterator() method.

For simplicity, we’ll obtain Iterator instance from a list:

List<String> items = ...
Iterator<String> iter = items.iterator();

The Iterator interface has three core methods:

2.1. hasNext()

The hasNext() method can be used for checking if there’s at least one element left to iterate over.

It’s designed to be used as a condition in while loops:

while (iter.hasNext()) {
    // ...
}

2.2. next()

The next() method can be used for stepping over the next element and obtaining it:

String next = iter.next();

It’s good practice to use hasNext() before attempting to call next().

Iterators for Collections don’t guarantee iteration in any particular order unless particular implementation provides it.

2.3. remove()

Finally, if we want to remove the current element from the collection, we can use the remove:

iter.remove();

This is a safe way to remove elements while iterating over a collection without a risk of a ConcurrentModificationException.

2.4. Full Example

Now we can combine them all and have a look at how we use the three methods together for collection filtering:

while (iter.hasNext()) {
    String next = iter.next();
    System.out.println(next);
 
    if( "TWO".equals(next)) {
        iter.remove();				
    }
}

This is how we commonly use an Iterator, we check ahead of time if there is another element, we retrieve it and then we perform some action on it.

2.5. Lambda Expressions

As we saw in the previous examples, it’s very verbose to use an Iterator when we just want to go over all the elements and do something with them.

Since Java 8, we have the forEachRemaining method that allows the use of lambdas to processing remaining elements:

iter.forEachRemaining(System.out::println);

3. The ListIterator Interface

ListIterator is an extension that adds new functionality for iterating over lists:

ListIterator<String> listIterator = items.listIterator(items.size());

Notice how we can provide a starting position which in this case is the end of the List.

3.1. hasPrevious() and previous()

ListIterator can be used for backward traversal so it provides equivalents of hasNext() and next():

while(listIterator.hasPrevious()) {
    String previous = listIterator.previous();
}

3.2. nextIndex() and previousIndex()

Additionally, we can traverse over indices and not actual elements:

String nextWithIndex = items.get(listIterator.nextIndex());
String previousWithIndex = items.get(listIterator.previousIndex());

This could prove very useful in case we need to know the indexes of the objects we’re currently modifying, or if we want to keep a record of removed elements.

3.3. add()

The add method, which, as the name suggests, allows us to add an element before the item that would be returned by next() and after the one returned by previous():

listIterator.add("FOUR");

3.4. set()

The last method worth mentioning is set(), which lets us replace the element that was returned in the call to next() or previous():

String next = listIterator.next();
if( "ONE".equals(next)) {
    listIterator.set("SWAPPED");
}

It’s important to note that this can only be executed if no prior calls to add() or remove() were made.

3.5. Full Example

We can now combine them all to make a complete example:

ListIterator<String> listIterator = items.listIterator();
while(listIterator.hasNext()) {
    String nextWithIndex = items.get(listIterator.nextIndex());		
    String next = listIterator.next();
    if("REPLACE ME".equals(next)) {
        listIterator.set("REPLACED");
    }
}
listIterator.add("NEW");
while(listIterator.hasPrevious()) {
    String previousWithIndex
     = items.get(listIterator.previousIndex());
    String previous = listIterator.previous();
    System.out.println(previous);
}

In this example, we start by getting the ListIterator from the List, then we can obtain the next element either by index –which doesn’t increase the iterator’s internal current element – or by calling next.

Then we can replace a specific item with set and insert a new one with add.

After reaching the end of the iteration, we can go backward to modify additional elements or simply print them from bottom to top.

4. Conclusion

The Iterator interface allows us to modify a collection while traversing it, which is more difficult with a simple for/while statement. This, in turn, gives us a good pattern we can use in many methods that only requires collections processing while maintaining good cohesion and low coupling.

Finally, as always the full source code is available over at GitHub.

Phantom References in Java

$
0
0

1. Overview

In this article, we’ll have a look at the concept of a Phantom Reference – in the Java language.

2. Phantom References

Phantom references have two major differences from soft and weak references.

We can’t get a referent of a phantom reference. The referent is never accessible directly through the API and this is why we need a reference queue to work with this type of references.

The Garbage Collector adds a phantom reference to a reference queue after the finalize method of its referent is executed. It implies that the instance is still in the memory.

3. Use Cases

There’re two common use-cases they are used for.

The first technique is to determine when an object was removed from the memory which helps to schedule memory-sensitive tasks. For example, we can wait for a large object to be removed before loading another one.

The second practice is to avoid using the finalize method and improve the finalization process.

3.1. Example

Now, let’s implement the second use case to practically figure out how this kind of references works.

First off, we need a subclass of the PhantomReference class to define a method for clearing resources:

public class LargeObjectFinalizer extends PhantomReference<Object> {

    public LargeObjectFinalizer(
      Object referent, ReferenceQueue<? super Object> q) {
        super(referent, q);
    }

    public void finalizeResources() {
        // free resources
        System.out.println("clearing ...");
    }
}

Now we’re going to write an enhanced fine-grained finalization:

ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
List<LargeObjectFinalizer> references = new ArrayList<>();
List<Object> largeObjects = new ArrayList<>();

for (int i = 0; i < 10; ++i) {
    Object largeObject = new Object();
    largeObjects.add(largeObject);
    references.add(new LargeObjectFinalizer(largeObject, referenceQueue));
}

largeObjects = null;
System.gc();

Reference<?> referenceFromQueue;
for (PhantomReference<Object> reference : references) {
    System.out.println(reference.isEnqueued());
}

while ((referenceFromQueue = referenceQueue.poll()) != null) {
    ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
    referenceFromQueue.clear();
}

First, we’re initializing all necessary objects: referenceQueue – to keep track of enqueued references, references – to perform cleaning work afterward, largeObjects – to imitate a large data structure.

Next, we’re creating these objects using the Object and LargeObjectFinalizer classes.

Before we call the Garbage Collector, we manually free up a large piece of data by dereferencing the largeObjects list. Note that we used a shortcut for the Runtime.getRuntime().gc() statement to invoke the Garbage Collector.

It’s important to know that System.gc() isn’t triggering garbage collection immediately – it’s simply a hint for JVM to trigger the process.

The for loop demonstrates how to make sure that all references are enqueued – it will print out true for each reference.

Finally, we used a while loop to poll out the enqueued references and do cleaning work for each of them.

4. Conclusion

In this quick tutorial, we introduced Java’s phantom references.

We learned what these are and how they can be useful in some simple and to-the-point examples.

Weak References in Java

$
0
0

1. Overview

In this article, we’ll have a look at the concept of a weak reference – in the Java language.

We’re going to explain what these are, what they’re used for and how to work with them properly.

2. Weak References

A weakly referenced object is cleared by the Garbage Collector when it’s weakly reachable.

Weak reachability means that an object has neither strong nor soft references pointing to it. The object can be reached only by traversing a weak reference.

First off, the Garbage Collector clears a weak reference, so the referent is no longer accessible. Then the reference is placed in a reference queue (if any associated exists) where we can obtain it from.

At the same time, formerly weakly-reachable objects are going to be finalized.

3. Use Cases

As stated by Java documentation, weak references are most often used to implement canonicalizing mappings. A mapping is called canonicalized if it holds only one instance of a particular value. Rather than creating a new object, it looks up the existing one in the mapping and uses it.

Of course, the most known use of these references is the WeakHashMap class. It’s the implementation of the Map interface where every key is stored as a weak reference to the given key. When the Garbage Collector removes a key, the entity associated with this key is deleted as well.

For more information, check out our guide to WeakHashMap.

Another area where they can be used is the Lapsed Listener problem.

A publisher (or a subject) holds strong references to all subscribers (or listeners) to notify them about events that happened. The problem arises when a listener can’t successfully unsubscribe from a publisher.

Therefore, a listener can’t be garbage collected since a strong reference to it’s still available to a publisher. Consequently, memory leaks may happen.

The solution to the problem can be a subject holding a weak reference to an observer allowing the former to be garbage collected without the need to be unsubscribed (note that this isn’t a complete solution, and it introduces some other issues which aren’t covered here).

4. Working with Weak References

Weak references are represented by the java.lang.ref.WeakReference class. We can initialize it by passing a referent as a parameter. Optionally, we can provide a java.lang.ref.ReferenceQueue:

Object referent = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();

WeakReference weakReference1 = new WeakReference<>(referent);
WeakReference weakReference2 = new WeakReference<>(referent, referenceQueue);

The referent of a reference can be fetched by the get method, and removed manually using the clear method:

Object referent2 = weakReference1.get();
weakReference1.clear();

The pattern for safe working with this kind of references is the same as with soft references:

Object referent3 = weakReference2.get();
if (referent3 != null) {
    // GC hasn't removed the instance yet
} else {
    // GC has cleared the instance
}

5. Conclusion

In this quick tutorial, we had a look at the low-level concept of a weak reference in Java – and focused on the most common scenarios to use these.

Introduction to Java Primitives

$
0
0

1. Overview

The Java Programming Language features eight primitive data types.

In this article, we’ll recall what primitives are and go over them.

2. Primitive Data Types

The eight primitives defined in Java are int, byte, short, long, float, double, boolean, and char – those aren’t considered objects and represent raw values.

They’re stored directly on the stack (check out this article for more information about memory management in Java).

Let’s take a look at storage size, default values, and examples of how to use each type.

Let’s start with a quick reference:

Type Size (bits) Minimum Maximum Example
byte 8 -27 27– 1 byte b = 100;
short 16 -215 215– 1 short s = 30_000;
int 32 -231 231– 1 int i = 100_000_000;
long 64 -263 263– 1 long l = 100_000_000_000_000;
float 32 -2-149 (2-2-23)·2127 float f = 1.456f;
double 64 -2-1074 (2-2-52)·21023 double f = 1.456789012345678;
char 16 0 216– 1 char c = ‘c’;
boolean 1 boolean b = true;

2.1. int

The first primitive data type we’re going to cover is int. Also known as an integer, int type holds a wide range of non-fractional number values.

Specifically, Java stores it using 32 bits of memory. In other words, it can represent values from -2,147,483,648 (-231) to 2,147,483,647 (231-1).

In Java 8, it’s possible to store an unsigned integer value up to 4,294,967,295 (232-1) by using new special helper functions.

We can simply declare an int simply:

int x = 424_242;

int y;

The default value of an int declared without an assignment is 0.

If the variable is defined in a method, we must assign a value before we can use it.

We can perform all standard arithmetic operations on ints. Just be aware that decimal values will be chopped off when performing these on integers.

2.2. byte

byte is a primitive data type similar to int, except it only takes up 8 bits of memory. Thus, why we call it a byte. Because the memory size being so small, byte can only hold the values from -128 (-27) to 127 (27 – 1).

We can create byte:

byte b = 100;

byte empty;

The default value of byte is also 0.

2.3. short

The next stop on our list of primitive data types in Java is short.

If we want to save memory and byte is too small, we can use the type halfway between the two: short.

At 16 bits of memory, it’s half the size of int and twice the size of byte. Its range of possible values is -32,768(-215) to 32,767(215 – 1).

short is declared like this:

short s = 202_020;

short s;

Also similar to the other types, the default value is 0. We can use all standard arithmetic on it as well.

2.4. long

Our last primitive data type related to integers is long.

long is the big brother of int. It’s stored in 64 bits of memory so it can hold a significantly larger set of possible values.

The possible values of a long are between -9,223,372,036,854,775,808 (-263) to 9,223,372,036,854,775,807 (263 – 1).

We can simply declare one:

long l = 1_234_567_890;

long l;

As with other integer types, the default is also 0. We can use all arithmetic on long that works on int.

2.5. float

We represent basic fractional numbers in Java using the float type. This is a single-precision decimal number. Which means if we get past six decimal points, this number becomes less precise and more of an estimate.

In most cases, we don’t care about the precision loss. But, if our calculation requires absolute precision (i.e., financial operations, landing on the moon, etc.) we need to use specific types designed for this work. For more information, check out the Java class Big Decimal.

This type is stored in 32 bits of memory just like int. However, because of the floating decimal point its range is much different. It can represent both positive and negative numbers. The smallest decimal is 1.40239846 x 10-45, and the largest value is 3.40282347 x 1038.

We declare floats the same as any other type:

float f = 3.145f;

float f;

And the default value is 0.0 instead of 0. Also, notice we add the f designation to the end of the literal number to define a float. Otherwise, Java will throw an error because the default type of a decimal value is double.

We can also perform all standard arithmetic operations on floats. However, it’s important to note that we perform floating point arithmetic very differently than integer arithmetic.

2.6. double

Next, we look at double – its name comes from the fact that it’s a double-precision decimal number.

It’s stored in 64 bits of memory. Which means it represents a much larger range of possible numbers than float.

Although, it does suffer from the same precision limitation as float does. The range is 4.9406564584124654 x 10-324 to 1.7976931348623157 x 10308. That range can also be positive or negative.

Declaring double is the same as other numeric types:

double d = 3.13457599923384753929348D;

double d;

The default value is also 0.0 as it is with float. Similar to float, we attach the letter D to designate the literal as a double.

2.7. boolean

The simplest primitive data type is boolean. It can contain only two values: true or false. It stores its value in a single bit.

However, for convenience, Java pads the value and stores it in a single byte.

Declare boolean like this:

boolean b = true;

boolean b;

Declaring it without a value defaults to false. boolean is the cornerstone of controlling our programs flow. We can use boolean operators on them (i.e., and, or, etc.).

2.8. char

The final primitive data type to look at is char.

Also called a character, char is a 16-bit integer representing a Unicode-encoded character. Its range is from 0 to 65,535. Which in Unicode represents ‘\u0000’ to ‘\uffff’.

For a list of all possible Unicode values check out sites like Unicode Table.

Let’s now declare a char:

char c = 'a';

char c = 65;

char c;

When defining our variables, we can use any character literal, and they will get automatically transformed into their Unicode encoding for us. A characters default value is ‘/u0000’.

2.9. Overflow

The primitive data types have size limits. But what happens if we try to store a value that’s larger than the maximum value?

We run into a situation called overflow.

When an integer overflows, it rolls over to the minimum value and begins counting up from there.

Floating point number overflow by returning Infinity. When they underflow, they return 0.0.

Here’s an example:

int i = Integer.MAX_VALUE;
int j = i + 1;
// j will roll over to -2_147_483_648

double d = Double.MAX_VALUE;
double o = d + 1;
// o will be Infinity

Underflow is the same issue except if we store a value smaller than the minimum value.

2.10. Autoboxing

Each primitive data type also has a full Java class implementation that can wrap it. For instance, the Integer class can wrap an int. There is sometimes a need to convert from the primitive type to its object wrapper (e.g., using them with generics).

Luckily, Java can perform this conversion for us automatically. We call this process Autoboxing. Here is an example:

Character c = 'c';

Integer i = 1;

3. Conclusion

In this tutorial, we’ve covered the eight primitive data types supported in Java.

These are the building blocks used by most, of not all Java programs out there – so it’s well worth understanding how they work.

Java Weekly, Issue 211

$
0
0

Let’s jump right in …

1. Spring and Java

>> Spring, Reactor and ElasticSearch: from callbacks to reactive streams [nurkiewicz.com]

Even if some tools don’t provide out-of-the-box support for reactive APIs, we can quickly construct these ourselves.

>> JPA Criteria API Bulk Update and Delete [vladmihalcea.com]

CriteriaUpdate and CriteriaDelete made it into the JPA specification starting with 2.1.

At this point, they’re not very well known or acknowledged; this article shows how useful they are and how to use them.

>> How to Choose the Most Efficient Data Type for To-Many Associations – Bag vs. List vs. Set [thoughts-on-java.org]

The title says it all – getting efficiency out of Hibernate is never a bad thing 🙂

>> Java Reflection, but much faster [optaplanner.org]

There are much faster alternatives to plain-old Java Reflection.

>> Facebook Open-Sources RacerD – Java Race Condition Detector [infoq.com]

An interesting tool from Facebook – for detecting race conditions in multithreaded Java code.

Also worth reading:

Webinars and presentations:

Time to upgrade:

2. Technical and Musings

>> A Career Guide for the Recovering Software Generalist [daedtech.com]

You can’t excel at everything (even if you do, no one will believe you), so it’s better to start specializing at some point 🙂

>> JMeter VS Gatling Tool [octoperf.com]

A comprehensive comparison of the two very popular performance testing tools.

Also worth reading:

4. Comics

And my favorite Dilberts of the week:

>> Coworkers Who Are Special [dilbert.com]

>> Boss Hits Jackpot [dilbert.com]

>> Boss Counts Cards [dilbert.com]

5. Pick of the Week

>> The presence prison [m.signalvnoise.com]

Spring Cloud AWS – S3

$
0
0

In this quick article, we’re going to explore the AWS support provided in the Spring Cloud platform – focusing on S3.

1. Simple S3 Download

Let’s start by easily accessing files stored on S3:

@Autowired
ResourceLoader resourceLoader;

public void downloadS3Object(String s3Url) throws IOException {
    Resource resource = resourceLoader.getResource(s3Url);
    File downloadedS3Object = new File(resource.getFilename());
 
    try (InputStream inputStream = resource.getInputStream()) {
        Files.copy(inputStream, downloadedS3Object.toPath(), 
          StandardCopyOption.REPLACE_EXISTING);
    }
}

2. Simple S3 Upload

We can also upload files:

public void uploadFileToS3(File file, String s3Url) throws IOException {
    WritableResource resource = (WritableResource) resourceLoader
      .getResource(s3Url);
 
    try (OutputStream outputStream = resource.getOutputStream()) {
        Files.copy(file.toPath(), outputStream);
    }
}

3. S3 URL Structure

The s3Url is represented using the format:

s3://<bucket>/<object>

For example, if a file bar.zip is in the folder foo on a my-s3-bucket bucket, then the URL will be:

s3://my-s3-bucket/foo/bar.zip

And, we can also download multiple objects at once using ResourcePatternResolver and the Ant-style pattern matching:

@Autowired
ResourcePatternResolver resourcePatternResolver;

public void downloadMultipleS3Objects(String s3Url) throws IOException {
    Resource[] allFileMatchingPatten = this.resourcePatternResolver
      .getResources(s3Url);
        // ...
    }
}

URLs can contain wildcards instead of exact names.

For example the s3://my-s3-bucket/**/a*.txt URL will recursively look for all text files whose name starts with ‘a‘ in any folder of the my-s3-bucket.

Note that the beans ResourceLoader and ResourcePatternResolver are created at application startup using Spring Boot’s auto-configuration feature.

4. Conclusion

And we’re done – this is a quick and to-the-point introduction to accessing S3 with Spring Cloud AWS.

In the next article of the series, we’ll explore the EC2 support of the framework.


Spring Cloud AWS – EC2

$
0
0

In the previous article, we’re focusing on S3; now we’ll focus on the Elastic Compute Cloud – commonly known as EC2.

1. EC2 Metadata Access

The AWS EC2MetadataUtils class provides static methods to access instance metadata like AMI Id and instance type. With Spring Cloud AWS we can inject this metadata directly using the @Value annotation.

This can be enabled by adding the @EnableContextInstanceData annotation over any of the configuration classes:

@Configuration
@EnableContextInstanceData
public class EC2EnableMetadata {
    //
}

In a Spring Boot environment, instance metadata is enabled by default which means this configuration is not required.

Then, we can inject the values:

@Value("${ami-id}")
private String amiId;

@Value("${hostname}")
private String hostname;

@Value("${instance-type}")
private String instanceType;

@Value("${services/domain}")
private String serviceDomain;

1.1. Custom Tags

Additionally, Spring also supports injection of user-defined tags. We can enable this by defining an attribute user-tags-map in context-instance-data using the following XML configuration:

<beans...>
    <aws-context:context-instance-data user-tags-map="instanceData"/>
</beans>

Now, let’s inject the user-defined tags with the help of Spring expression syntax:

@Value("#{instanceData.myTagKey}")
private String myTagValue;

2. EC2 Client

Furthermore, if there are user tags configured for the instance, Spring will create an AmazonEC2 client which we can inject into our code using @Autowired:

@Autowired
private AmazonEC2 amazonEc2;

Please note that these features work only if the app is running on an EC2 instance.

3. Conclusion

This was a quick and to-the-point introduction to accessing EC2d data with Spring Cloud AWS.

In the next article of the series, we’ll explore the RDS support.

Spring Cloud AWS – RDS

$
0
0

In the previous article, we were focusing on EC2; now, let’s move on to the Relational Database Service.

1. RDS Support

1.1. Simple Configuration

Spring Cloud AWS can automatically create a DataSource just by specifying the RDS database identifier and the master password. The username, JDBC driver, and the complete URL are all resolved by Spring.

If an AWS account has an RDS instance with DB instance identifier as spring-cloud-test-db having master password se3retpass, then all that’s required to create a DataSource is the following two lines in application.properties:

cloud.aws.rds.spring-cloud-test-db
cloud.aws.rds.spring-cloud-test-db.password=se3retpass

Three other properties can be added if you wish to use values other than the RDS default:

cloud.aws.rds.spring-cloud-test-db.username=testuser
cloud.aws.rds.spring-cloud-test-db.readReplicaSupport=true
cloud.aws.rds.spring-cloud-test-db.databaseName=test

1.2. Custom Datasource

In an application without Spring Boot or in cases where custom configurations are required, we can also create the DataSource using the Java-based configuration:

@Configuration
@EnableRdsInstance(
  dbInstanceIdentifier = "spring-cloud-test-db", 
  password = "se3retpass")
public class SpringRDSSupport {

    @Bean
    public RdsInstanceConfigurer instanceConfigurer() {
        return () -> {
            TomcatJdbcDataSourceFactory dataSourceFactory
             = new TomcatJdbcDataSourceFactory();
            dataSourceFactory.setInitialSize(10);
            dataSourceFactory.setValidationQuery("SELECT 1");
            return dataSourceFactory;
        };
    }
}

Also, note that we need to add the correct JDBC driver dependency.

2. Conclusion

In this article, we had a look at various ways of accessing AWS RDS service; in the next and final article of the series, we’ll have a look at AWS Messaging support.

Spring Cloud AWS – Messaging Support

$
0
0

In the final article, we move on to AWS Messaging Support.

1. AWS Messaging Support

1.1. SQS (Simple Queue Service)

We can send messages to an SQS queue using the QueueMessagingTemplate.

To create this bean, we can use an AmazonSQSAsync client which is available by default in the application context when using Spring Boot starters:

@Bean
public QueueMessagingTemplate queueMessagingTemplate(
  AmazonSQSAsync amazonSQSAsync) {
    return new QueueMessagingTemplate(amazonSQSAsync);
}

Then, we can send the messages using the convertAndSend() method:

@Autowired
QueueMessagingTemplate messagingTemplate;
 
public void send(String topicName, Object message) {
    messagingTemplate.convertAndSend(topicName, message);
}

Since Amazon SQS only accepts String payloads, Java objects are automatically serialized to JSON.

We can also configure listeners using @SqsListener:

@SqsListener("spring-cloud-test-queue")
public void receiveMessage(String message, 
  @Header("SenderId") String senderId) {
    // ...
}

This method will receive messages from spring-cloud-test-queue and then process them. We can also retrieve message headers using the @Header annotation on method parameters.

If the first parameter is a custom Java object instead of String, Spring will convert the message to that type using JSON conversion.

1.2. SNS (Simple Notification Service)

Similar to SQS, we can use NotificationMessagingTemplate to publish messages to a topic.

To create it, we need an AmazonSNS client:

@Bean
public NotificationMessagingTemplate notificationMessagingTemplate(
  AmazonSNS amazonSNS) {
    return new NotificationMessagingTemplate(amazonSNS);
}

Then, we can send notifications to the topic:

@Autowired
NotificationMessagingTemplate messagingTemplate;

public void send(String Object message, String subject) {
    messagingTemplate
      .sendNotification("spring-cloud-test-topic", message, subject);
}

Out of the multiple SNS endpoints supported by AWS – SQS, HTTP(S), email and SMS, the project only supports HTTP(S).

We can configure the endpoints in an MVC controller:

@Controller
@RequestMapping("/topic-subscriber")
public class SNSEndpointController {

    @NotificationSubscriptionMapping
    public void confirmUnsubscribeMessage(
      NotificationStatus notificationStatus) {
        notificationStatus.confirmSubscription();
    }
 
    @NotificationMessageMapping
    public void receiveNotification(@NotificationMessage String message, 
      @NotificationSubject String subject) {
        // handle message
    }

    @NotificationUnsubscribeConfirmationMapping
    public void confirmSubscriptionMessage(
      NotificationStatus notificationStatus) {
        notificationStatus.confirmSubscription();
    }
}

We need to add the topic name to the @RequestMapping annotation on the controller level. This controller enables an HTTP(s) endpoint – /topic-subscriber which be used by an SNS topic to create a subscription.

For example, we can subscribe to a topic by calling the URL:

https://host:port/topic-subscriber/

The header in the request determines which of the three methods is invoked.

The method with @NotificationSubscriptionMapping annotation is invoked when the header [x-amz-sns-message-type=SubscriptionConfirmation] is present and confirms a new subscription to a topic.

Once subscribed, the topic will send notifications to the endpoint with the header [x-amz-sns-message-type=Notification]. This will invoke the method annotated with @NotificationMessageMapping.

Finally, when the endpoint unsubscribes from the topic, a confirmation request is received with the header [x-amz-sns-message-type=UnsubscribeConfirmation].

This calls the method annotated with @NotificationUnsubscribeConfirmationMapping which confirms unsubscribe action.

Please note that the value in @RequestMapping has nothing to do with the topic name to which it’s subscribed.

2. Conclusion

In this final article, we explored Spring Cloud’s support for AWS Messaging – which concludes this quick series about Spring Cloud and AWS.

A Quick Guide to Maven Wrapper

$
0
0

1. Overview

The Maven Wrapper is an excellent choice for projects that need a specific version of Maven (or for users that don’t want to install Maven at all). Instead of installing many versions of it in the operating system, we can just use the project-specific wrapper script.

In this quick article, we’ll show how to set up a Maven Wrapper for an existing Maven project.

2. Setting Up the Maven Wrapper

There’re two ways to configure it in a project, where the simplest one is to use an appropriate plugin to automate it or by applying the manual installation.

2.1. Plugin

Let’s use this Maven Wrapper plugin to make auto installation in a simple Spring Boot project.

First, we need to go in the main folder of the project and run this command:

mvn -N io.takari:maven:wrapper

We can also specify the version of Maven:

mvn -N io.takari:maven:wrapper -Dmaven=3.5.2

The option -N means –non-recursive so that the wrapper will only be applied to the main project of the current directory, not in any submodules.

After executing the goal, we’ll have more files and directories in the project:

  • mvnw: it’s an executable Unix shell script used in place of a fully installed Maven
  • mvnw.cmd: it’s the Batch version of the above script
  • mvn: the hidden folder that holds the Maven Wrapper Java library and its properties file

2.2. Manual

With a manual approach, we can copy files and folders seen above from another project to the main folder of the current project.

Afterwards, we need to specify the version of Maven to use in the wrapper properties file located in .mvn/wrapper/maven-wrapper.properties file.

For instance, our properties file has the following line:

distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip

Consequently, the version 3.5.2 will be downloaded and used.

3. Use Cases

The wrapper should work with different operating systems such as:

  • Linux
  • OSX
  • Windows
  • Solaris

After that, we can run our goals like this for the Unix system:

./mvnw clean install

And the following command for Batch:

./mvnw.cmd clean install

If we don’t have the specified Maven in the wrapper properties, it’ll be downloaded and installed in the folder $USER_HOME/.m2/wrapper/dists of the system. 

Let’s run our Spring-Boot project:

./mvnw spring-boot:run

The output is the same as for a fully installed Maven:

Note: we use the executable mvnw in place of mvn, which stands now as the Maven command line program.

4. Conclusion

In this tutorial, we’ve seen how to set up and use Maven Wrapper in a Maven project.

As always, the source code for this article can be found over on GitHub.

Spring Security 5 – OAuth2 Login

$
0
0

1. Overview

Spring Security 5 introduces a new OAuth2LoginConfigurer class that we can use for configuring an external authorization server.

In this article, we’ll explore some of the various configuration options available for the oauth2Login() element.

2. Maven Dependencies

In addition to the standard Spring and Spring Security dependencies, we’ll also need to add the spring-security-oauth2-client and spring-security-oauth2-jose dependencies:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

In our example, dependencies are managed by the Spring Boot starter parent, version 2.0.0.M7, which corresponds to version 5.0.0.RELEASE of the Spring Security artifacts.

For now, since we’re using a milestone version of Spring Boot, we’ll also need to add the repository:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

3. Clients Setup

In a Spring Boot project, all we need to do is add a few standard properties for each client we want to configure.

Let’s set up our project for login with clients registered with Google and Facebook as authentication providers.

3.1. Obtaining Client Credentials

To obtain client credentials for Google OAuth2 authentication, head on over to the Google API Console – section “Credentials”.

Here we’ll create credentials of type “OAuth2 Client ID” for our web application. This results in Google setting up a client id and secret for us.

We also have to configure an authorized redirect URI in the Google Console, which is the path that users will be redirected to after they successfully login with Google.

By default, Spring Boot configures this redirect URI as /login/oauth2/client/{clientId}. Therefore, for Google we’ll add the URI:

http://localhost:8081/login/oauth2/client/google

To obtain the client credentials for authentication with Facebook, we need to register an application on the Facebook for Developers website and set up the corresponding URI as a “Valid OAuth redirect URI”:

http://localhost:8081/login/oauth2/client/facebook

3.3. Security Configuration

Next, we need to add client credentials in the application.properties file. The Spring Security properties are prefixed with “spring.security.oauth2.client.registration” followed by the client name, then the name of the client property:

spring.security.oauth2.client.registration.google.client-id=<your client id>
spring.security.oauth2.client.registration.google.client-secret=<your client secret>

spring.security.oauth2.client.registration.facebook.client-id=<your client id> 
spring.security.oauth2.client.registration.facebook.client-secret=<your client secret>

Adding these properties for at least one client will enable the Oauth2ClientAutoConfiguration class which sets up all the necessary beans.

The automatic web security configuration is equivalent to defining a simple oauth2Login() element:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
         .anyRequest().authenticated()
         .and()
         .oauth2Login();
    }
}

Here, we can see the oauth2Login() element is used in a similar manner to already known httpBasic() and formLogin() elements.

Now, when we try to access a protected URL, the application will display an auto-generated login page with two clients:

3.4. Other Clients

Note that in addition to Google and Facebook, the Spring Security project also contains default configurations for GitHub and Okta. These default configurations provide all the necessary information for authentication, which is what allows us to only enter the client credentials.

If we want to use a different authentication provider not configured in Spring Security, we’ll need to define the full configuration, with information such as authorization URI and token URI. Here‘s a look at the default configurations in Spring Security to have an idea of the properties needed.

4. Setup in a Non-Boot Project

4.1. Creating a ClientRegistrationRepository Bean

If we’re not working with a Spring Boot application, we’ll need to define a ClientRegistrationRepository bean that contains an internal representation of the client information owned by the authorization server:

@Configuration
@EnableWebSecurity
@PropertySource("classpath:application.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private static List<String> clients = Arrays.asList("google", "facebook");

    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        List<ClientRegistration> registrations = clients.stream()
          .map(c -> getRegistration(c))
          .filter(registration -> registration != null)
          .collect(Collectors.toList());
        
        return new InMemoryClientRegistrationRepository(registrations);
    }
}

Here we’re creating an InMemoryClientRegistrationRepository with a list of ClientRegistration objects.

4.2. Building ClientRegistration Objects

Let’s see the getRegistration() method that builds these objects:

private static String CLIENT_PROPERTY_KEY 
  = "spring.security.oauth2.client.registration.";

@Autowired
private Environment env;

private ClientRegistration getRegistration(String client) {
    String clientId = env.getProperty(
      CLIENT_PROPERTY_KEY + client + ".client-id");

    if (clientId == null) {
        return null;
    }

    String clientSecret = env.getProperty(
      CLIENT_PROPERTY_KEY + client + ".client-secret");
 
    if (client.equals("google")) {
        return CommonOAuth2Provider.GOOGLE.getBuilder(client)
          .clientId(clientId).clientSecret(clientSecret).build();
    }
    if (client.equals("facebook")) {
        return CommonOAuth2Provider.FACEBOOK.getBuilder(client)
          .clientId(clientId).clientSecret(clientSecret).build();
    }
    return null;
}

Here, we’re reading the client credentials from a similar application.properties file, then using the CommonOauth2Provider enum already defined in Spring Security for the rest of the client properties for Google and Facebook clients.

Each ClientRegistration instance corresponds to a client.

4.3. Registering the ClientRegistrationRepository

Finally, we have to create an OAuth2AuthorizedClientService bean based on the ClientRegistrationRepository bean and register both with the oauth2Login() element:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated()
      .and()
      .oauth2Login()
      .clientRegistrationRepository(clientRegistrationRepository())
      .authorizedClientService(authorizedClientService());
}

@Bean
public OAuth2AuthorizedClientService authorizedClientService() {
 
    return new InMemoryOAuth2AuthorizedClientService(
      clientRegistrationRepository());
}

As evidenced here, we can use the clientRegistrationRepository() method of oauth2Login() to register a custom registration repository.

We’ll also have to define a custom login page, as it won’t be automatically generated anymore. We’ll see more information on this in the next section.

Let’s continue with further customization of our login process.

5. Customizing oauth2Login()

There are several elements that the OAuth 2 process uses and that we can customize using oauth2Login() methods.

Note that all these elements have default configurations in Spring Boot and explicit configuration isn’t required.

Let’s see how we can customize these in our configuration.

5.1. Custom Login Page

Even though Spring Boot generates a default login page for us, we’ll usually want to define our own customized page.

Let’s start with configuring a new login URL for the oauth2Login() element by using the loginPage() method:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .antMatchers("/oauth_login")
      .permitAll()
      .anyRequest()
      .authenticated()
      .and()
      .oauth2Login()
      .loginPage("/oauth_login");
}

Here, we’ve set up our login URL to be /oauth_login.

Next, let’s define a LoginController with a method that maps to this URL:

@Controller
public class LoginController {

    private static String authorizationRequestBaseUri
      = "oauth2/authorization";
    Map<String, String> oauth2AuthenticationUrls
      = new HashMap<>();

    @Autowired
    private ClientRegistrationRepository clientRegistrationRepository;

    @GetMapping("/oauth_login")
    public String getLoginPage(Model model) {
        // ...

        return "oauth_login";
    }
}

This method has to send a map of the clients available and their authorization endpoints to the view, which we’ll obtain from the ClientRegistrationRepository bean:

public String getLoginPage(Model model) {
    Iterable<ClientRegistration> clientRegistrations = null;
    ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository)
      .as(Iterable.class);
    if (type != ResolvableType.NONE && 
      ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
        clientRegistrations = (Iterable<ClientRegistration>) clientRegistrationRepository;
    }

    clientRegistrations.forEach(registration -> 
      oauth2AuthenticationUrls.put(registration.getClientName(), 
      authorizationRequestBaseUri + "/" + registration.getRegistrationId()));
    model.addAttribute("urls", oauth2AuthenticationUrls);

    return "oauth_login";
}

Finally, we need to define our oauth_login.html page:

<h3>Login with:</h3>
<p th:each="url : ${urls}">
    <a th:text="${url.key}" th:href="${url.value}">Client</a>
</p>

This is a simple HTML page which displays links to authenticate with each client.

After adding some styling to it, we can have a much nicer looking login page:

5.2. Custom Authentication Success and Failure Behavior

We can control the post-authentication behavior by using different methods:

  • defaultSuccessUrl() and failureUrl() – to redirect the user to a given URL
  • successHandler() and failureHandler() – to execute custom logic following the authentication process

Let’s see how we can set custom URL’s to redirect the user to:

.oauth2Login()
  .defaultSuccessUrl("/loginSuccess")
  .failureUrl("/loginFailure");

If the user visited a secured page before authenticating, they will be redirected to that page after logging in; otherwise, they will be redirected to /loginSuccess.

If we want the user to always be sent to the /loginSuccess URL regardless if they were on a secured page before or not, we can use the method defaultSuccessUrl(“/loginSuccess”, true).

To use a custom handler, we would have to create a class that implements the AuthenticationSuccessHandler or AuthenticationFailureHandler interfaces, override the inherited methods, then set the beans using the successHandler() and failureHandler() methods.

5.3. Custom Authorization Endpoint

The authorization endpoint is the endpoint that Spring Security uses to trigger an authorization request to the external server.

First, let’s set new properties for the authorization endpoint:

.oauth2Login() 
  .authorizationEndpoint()
  .baseUri("/oauth2/authorize-client")
  .authorizationRequestRepository(authorizationRequestRepository());

Here, we’ve modified the baseUri to /oauth2/authorize-client instead of the default /oauth2/authorization. We’re also explicitly setting an authorizationRequestRepository() bean that we have to define:

@Bean
public AuthorizationRequestRepository<OAuth2AuthorizationRequest> 
  authorizationRequestRepository() {
 
    return new HttpSessionOAuth2AuthorizationRequestRepository();
}

In our example, we’ve used the Spring-provided implementation for our bean, but we could also provide a custom one.

5.4. Custom Token Endpoint

The token endpoint processes access tokens.

Let’s explicitly configure the tokenEndpoint() with the default response client implementation:

.oauth2Login()
  .tokenEndpoint()
  .accessTokenResponseClient(accessTokenResponseClient());

And here’s the response client bean:

@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> 
  accessTokenResponseClient() {
 
    return new NimbusAuthorizationCodeTokenResponseClient();
}

This configuration is the same as the default one and is using the Spring implementation which is based on exchanging an authorization code with the provider.

Of course, we could also substitute a custom response client.

5.5. Custom Redirection Endpoint

This is the endpoint to redirect to after authentication with the external provider.

Let’s see how we can change the baseUri for the redirection endpoint:

.oauth2Login()
  .redirectionEndpoint()
  .baseUri("/oauth2/redirect")

The default URI is login/oauth2/client.

Note that if we change it, we also have to update the redirectUriTemplate property of each ClientRegistration and add the new URI as an authorized redirect URI for each client.

5.6. Custom User Information Endpoint

The user info endpoint is the location we can leverage to obtain user information.

We can customize this endpoint using the userInfoEndpoint() method. For this, we can use methods such as userService() and customUserType() to modify the way user information is retrieved.

6. Accessing User Information

A common task we may want to achieve is finding information about the logged-in user. For this, we can make a request to the user information endpoint.

First, we’ll have to get the client corresponding to the current user token:

@Autowired
private OAuth2AuthorizedClientService authorizedClientService;

@GetMapping("/loginSuccess")
public String getLoginInfo(Model model, OAuth2AuthenticationToken authentication) {
    OAuth2AuthorizedClient client = authorizedClientService
      .loadAuthorizedClient(
        authentication.getAuthorizedClientRegistrationId(), 
          authentication.getName());
    //...
    return "loginSuccess";
}

Next, we’ll send a request to the client’s user info endpoint and retrieve the userAttributes Map:

String userInfoEndpointUri = client.getClientRegistration()
  .getProviderDetails().getUserInfoEndpoint().getUri();

if (!StringUtils.isEmpty(userInfoEndpointUri)) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + client.getAccessToken()
      .getTokenValue());
    HttpEntity entity = new HttpEntity("", headers);
    ResponseEntity <map>response = restTemplate
      .exchange(userInfoEndpointUri, HttpMethod.GET, entity, Map.class);
    Map userAttributes = response.getBody();
    model.addAttribute("name", userAttributes.get("name"));
}

By adding the name property as a Model attribute, we can display it in the loginSuccess view as a welcome message to the user:

Besides the name, the userAttributes Map also contains properties such as email, family_name, picture, locale.

7. Conclusion

In this article, we’ve seen how we can use the oauth2Login() element in Spring Security to authenticate with different providers such as Google and Facebook. We’ve also gone through some common scenarios of customizing this process.

The full source code of the examples can be found over on GitHub.

Integration Guide for Spring and EJB

$
0
0

1. Overview

In this article, we’ll show how to integrate Spring and remote Enterprise Java Beans (EJB).

To do this, we’ll create some EJBs and the necessary remote interfaces, and then we’ll run them inside a JEE container. After that, we’ll start our Spring application and, using the remote interfaces, instantiate our beans so that they can execute remote calls.

If there is any doubt about what EJBs are or how they work, we already published an introductory article on the topic here.

2. EJB Setup

We’ll need to create our remote interfaces and our EJB implementations. To make them usable, we’ll also need a container to hold and manage beans.

2.1. EJB Remote Interfaces

Let’s start by defining two very simple beans — one stateless and one stateful.

We’ll begin with their interfaces:

@Remote
public interface HelloStatefulWorld {
    int howManyTimes();
    String getHelloWorld();
}

@Remote
public interface HelloStatelessWorld {
    String getHelloWorld();
}

2.2. EJB Implementation

Now, let’s implement our remote EJB interfaces:

@Stateful(name = "HelloStatefulWorld")
public class HelloStatefulWorldBean implements HelloStatefulWorld {

    private int howManyTimes = 0;

    public int howManyTimes() {
        return howManyTimes;
    }

    public String getHelloWorld() {
        howManyTimes++;
        return "Hello Stateful World";
    }
}

@Stateless(name = "HelloStatelessWorld")
public class HelloStatelessWorldBean implements HelloStatelessWorld {

    public String getHelloWorld() {
        return "Hello Stateless World!";
    }
}

If stateful and stateless beans sound unfamiliar, this intro article may come in handy.

2.3. EJB Container

We can run our code in any JEE container, but for practicality purposes, we’ll use Wildfly and the cargo Maven plugin to do the heavy lifting for us:

<plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.6.1</version>
    <configuration>
        <container>
            <containerId>wildfly10x</containerId>
            <zipUrlInstaller>
                <url>
                  http://download.jboss.org/wildfly/10.1.0.Final/wildfly-10.1.0.Final.zip
                </url>
            </zipUrlInstaller>
        </container>
        <configuration>
            <properties>
                <cargo.hostname>127.0.0.1</cargo.hostname>
                <cargo.jboss.configuration>standalone-full</cargo.jboss.configuration>
                <cargo.jboss.management-http.port>9990</cargo.jboss.management-http.port>
                <cargo.servlet.users>testUser:admin1234!</cargo.servlet.users>
            </properties>
        </configuration>
    </configuration>
</plugin>

2.4. Running the EJBs

With these configured, we can run the container directly from the Maven command line:

mvn clean package cargo:run -Pwildfly-standalone

We now have a working instance of Wildfly hosting our beans. We can confirm this by the log lines:

java:global/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld
java:app/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld
java:module/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld
java:jboss/exported/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld
java:global/ejb-remote-for-spring/HelloStatefulWorld
java:app/ejb-remote-for-spring/HelloStatefulWorld
java:module/HelloStatefulWorld

java:global/ejb-remote-for-spring/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld
java:app/ejb-remote-for-spring/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld
java:module/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld
java:jboss/exported/ejb-remote-for-spring/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld
java:global/ejb-remote-for-spring/HelloStatelessWorld
java:app/ejb-remote-for-spring/HelloStatelessWorld
java:module/HelloStatelessWorld

3. Spring Setup

Now that we have our JEE container up and running, and our EJBs deployed, we can start our Spring application. We’ll use spring-boot-web to make it easier to test manually, but it isn’t mandatory for the remote call.

3.1. Maven Dependencies

To be able to connect to the remote EJBs, we’ll need the Wildfly EJB Client library and our remote interface:

<dependency>
    <groupId>org.wildfly</groupId>
    <artifactId>wildfly-ejb-client-bom</artifactId>
    <version>10.1.0.Final</version>
    <type>pom</type>
</dependency>
<dependency>
    <groupId>com.baeldung.spring.ejb</groupId>
    <artifactId>ejb-remote-for-spring</artifactId>
    <version>1.0.1</version>
    <type>ejb</type>
</dependency>

The last version of wildfly-ejb-client-bom can be found here.

3.2. Naming Strategy Context

With these dependencies in the classpath, we can instantiate a javax.naming.Context to do the lookup of our remote beans. We’ll create this as a Spring Bean so that we can autowire it when we need it:

@Bean   
public Context context() throws NamingException {
    Properties jndiProps = new Properties();
    jndiProps.put("java.naming.factory.initial", 
      "org.jboss.naming.remote.client.InitialContextFactory");
    jndiProps.put("jboss.naming.client.ejb.context", true);
    jndiProps.put("java.naming.provider.url", 
      "http-remoting://localhost:8080");
    return new InitialContext(jndiProps);
}

The properties are necessary to inform both the remote URL and the naming strategy context.

3.3. JNDI Pattern

Before we can wire our remote beans inside the Spring container, we’ll need to know how to reach them. For this, we’ll use their JNDI bindings. Let’s see the standard pattern for these bindings:

${appName}/${moduleName}/${distinctName}/${beanName}!${viewClassName}

Keep in mind that, since we deployed a simple jar instead of an ear and didn’t explicitly set up a name, we don’t have an appName and a distinctName. There are more details at our EJB Intro article in case something seems odd.

We’ll use this pattern to bind our remote beans to our Spring ones.

3.4. Building our Spring Beans

To reach our EJBs, we’ll use the aforementioned JNDI. Remember log lines that we used to check if our enterprise beans were deployed?

We’ll see that information in use now:

@Bean
public HelloStatelessWorld helloStatelessWorld(Context context) 
  throws NamingException {
 
    return (HelloStatelessWorld) 
      context.lookup(this.getFullName(HelloStatelessWorld.class));
}
@Bean
public HelloStatefulWorld helloStatefulWorld(Context context) 
  throws NamingException {
 
    return (HelloStatefulWorld) 
      context.lookup(this.getFullName(HelloStatefulWorld.class));
}
private String getFullName(Class classType) {
    String moduleName = "ejb-remote-for-spring/";
    String beanName = classType.getSimpleName();
    String viewClassName = classType.getName();
    return moduleName + beanName + "!" + viewClassName;
}

We need to be very careful about the correct full JNDI binding, or the context won’t be able to reach the remote EJB and create the necessary underlying infrastructure.

Keep in mind that the method lookup from Context will throw a NamingException in case it doesn’t find the bean you are requiring.

4. Integration

With everything in place, we can inject our beans in a controller, so we can test if the wiring is right:

@RestController
public class HomeEndpoint {
 
    // ...
 
    @GetMapping("/stateless")
    public String getStateless() {
        return helloStatelessWorld.getHelloWorld();
    }
    
    @GetMapping("/stateful")
    public String getStateful() {
        return helloStatefulWorld.getHelloWorld()
          + " called " + helloStatefulWorld.howManyTimes() + " times";
    }
}

Let’s start our Spring server and check some logs. We’ll see the following line, indicating that everything is OK:

EJBCLIENT000013: Successful version handshake completed

Now, let’s test our stateless bean. We can try some curl commands to verify that they’re operating as expected:

curl http://localhost:8081/stateless
Hello Stateless World!

And let’s check our stateful one:

curl http://localhost:8081/stateful
Hello Stateful World called 1 times

curl http://localhost:8081/stateful
Hello Stateful World called 2 times

5. Conclusion

In this article, we learned how to integrate Spring to EJB and make remote calls to the JEE container. We created two remote EJB interfaces, and we were able to call those using Spring Beans in a transparent way.

Even though Spring is widely adopted, EJBs are still popular in enterprise environments, and in this quick example, we’ve shown that it’s possible to make use of both the distributed gains of JavaEE and the ease of use of Spring applications.

As always, the code can be found over on GitHub.

Try-with-resources in Kotlin

$
0
0

1. Introduction

Managed languages, such as those targeting the JVM, automatically handle the most common resource: memory.

However, we need to deal with all kinds of resources, not just memory: files, network connections, streams, windows, etc. And, just like memory, those need to be released when no longer needed.

In this article, we’re going to look at how resources can be managed automatically in Kotlin and how it differs from Java’s try-with-resources construct.

If you want to skip the theory, jump straight to the example.

2. Automatic Resource Management

We can distinguish three different phases when working with resources in Java (pseudocode):

resource = acquireResource()
try {
    useResource(resource)
} finally {
    releaseResource(resource)
}

If the language or library is responsible for releasing the resource (the finally part), then we call it Automatic Resource Management. Such feature relieves us from having to remember to free a resource.

Also, since resource management is usually tied to a block scope, if we deal with more than one resource at the same time, they will be always released in the correct order.

In Java, objects that hold a resource and are eligible for automatic resource management implement a specific interface: Closeable for I/O related resources and AutoCloseable.

Also, Java 7 retrofitted the pre-existing Closeable interface to extend AutoCloseable.

Therefore, Kotlin has the same concept of resource holders: that is, objects implementing either Closeable or AutoCloseable.

3. The use Function in Kotlin

To automatically manage resources, some languages have a dedicated construct: Java 7 introduced try-with-resources, for example, while C# has the using keyword.

Sometimes, they offer us a pattern, like RAII in C++. In some other cases, they give us a library method.

Kotlin falls into the latter category.

By design, it doesn’t have a language construct akin to try-with-resources in Java.

Instead, we can find an extension method called use in its standard library.

We’ll look at it in detail later. For now, we just need to know that every resource holder object has the use method that we can invoke.

3.1. How to Use It

A simple example:

val writer = FileWriter("test.txt")
writer.use {
    writer.write("something")
}

We can invoke the use function on any object which implements AutoCloseable or Closeable, just as with try-with-resources in Java.

The method takes a lambda expression, executes it and disposes of the resource of (by calling close() on it) whenever execution leaves the block, either normally or with an exception.

So, in this case, after use, the writer is no longer usable, because Kotlin has automatically closed it.

3.2. A Shorter Form

In the example above, for clarity, we used a variable called writer, thus creating a closure.

However, use accepts a lambda expression with a single parameter – the object holding the resource:

FileWriter("test.txt")
  .use { w -> w.write("something") }

Inside the block, we can also use the implicit variable it:

FileWriter("test.txt")
  .use { it.write("something") }

So, as we can see, we don’t have to give the object an explicit name. However, it is usually a good idea to be clear rather than writing overly concise code.

3.3. The Definition of use()

Let’s look at the definition of use function in Kotlin, as found in its standard library:

public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R

We can see, in the <T : Closeable?, R> part, that use is defined as an extension function on Java’s Closeable interface.

More about extension methods can be found in our introductory article.

Of course, the use function is documented as part of Kotlin’s standard library.

3.4. Closeable vs AutoCloseable

If we pay closer attention to the example from the previous section, we can see that the use function signature is defined only on the Closeable interface. This is because Kotlin’s standard library targets Java 6.

In Java versions before 7, AutoCloseable didn’t exist and, of course, Closeable didn’t extend it.

In practice, classes that implement AutoCloseable but not Closeable are rare. Still, we may encounter one of them.

In that case, we only have to add a dependency on Kotlin’s extensions for Java 7, 8 or whatever version we’re targeting:

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib-jre8</artifactId>
    <version>1.2.10</version>
</dependency>

The latest version of the dependency can be found on Maven Central.

That gives us another use extension function defined on the AutoCloseable interface:

public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R

4. Conclusion

In this tutorial, we’ve seen how a simple extension function in Kotlin’s standard library is all that we need to manage all kinds of resources known to the JVM automatically.

The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.


Writing a Jenkins Plugin

$
0
0

1. Overview

Jenkins is an open-source Continuous Integration server, which enables to create a custom plugin creation for particular task/environment.

In this article, we’ll go through the whole process of creating an extension which adds statistics to the build output, namely, number of classes and lines of code.

2. Setup

The first thing to do is to set up the project. Luckily, Jenkins provides convenient Maven archetypes for that.

Just run the command below from a shell:

mvn archetype:generate -Dfilter=io.jenkins.archetypes:plugin

We’ll get the following output:

[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart
  (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of
  a Jenkins plugin with a POM and an empty source tree.)
2: remote -> io.jenkins.archetypes:global-configuration-plugin
  (Skeleton of a Jenkins plugin with a POM and an example piece
  of global configuration.)
3: remote -> io.jenkins.archetypes:hello-world-plugin
  (Skeleton of a Jenkins plugin with a POM and an example build step.)

Now, choose the first option and define group/artifact/package in the interactive mode. After that, it’s necessary to make refinements to the pom.xml – as it contains entries such as <name>TODO Plugin</name>.

3. Jenkins Plugin Design

3.1. Extension Points

Jenkins provides a number of extension points. These are interfaces or abstract classes which define contracts for particular use-cases and allow other plugins to implement them.

For example, every build consists of a number of steps, e.g. “Checkout from VCS”, “Compile”, “Test”, “Assemble”, etc. Jenkins defines hudson.tasks.BuildStep extension point, so we can implement it to provide a custom step which can be configured.

Another example is hudson.tasks.BuildWrapper – this allows us to define pre/post actions.

We also have a non-core Email Extension plugin that defines the hudson.plugins.emailext.plugins.RecipientProvider extension point, which allows providing email recipients. An example implementation is available in here: hudson.plugins.emailext.plugins.recipients.UpstreamComitterRecipientProvider.

Note: there is a legacy approach where plugin class needs to extend hudson.Plugin. However, it’s now recommended to use extension points instead.

3.2. Plugin Initialization

It’s necessary to tell Jenkins about our extension and how it should be instantiated.

First, we define a static inner class within the plugin and mark it using the hudson.Extension annotation:

class MyPlugin extends BuildWrapper {
    @Extension
    public static class DescriptorImpl 
      extends BuildWrapperDescriptor {

        @Override
        public boolean isApplicable(AbstractProject<?, ?> item) {
            return true;
        }

        @Override
        public String getDisplayName() {
            return "name to show in UI";
        }
    }
}

Secondly, we need to define a constructor to be used for plugin’s object instantiation and mark it by the org.kohsuke.stapler.DataBoundConstructor annotation.

It’s possible to use parameters for it. They’re shown in UI and are automatically delivered by Jenkins.

E.g. consider the Maven plugin:

@DataBoundConstructor
public Maven(
  String targets,
  String name,
  String pom,
  String properties,
  String jvmOptions,
  boolean usePrivateRepository,
  SettingsProvider settings,
  GlobalSettingsProvider globalSettings,
  boolean injectBuildVariables) { ... }

It’s mapped to the following UI:

It’s also possible to use org.kohsuke.stapler.DataBoundSetter annotation with setters.

4. Plugin Implementation

We intend to collect basic project stats during a build, so, hudson.tasks.BuildWrapper is the right way to go here.

Let’s implement it:

class ProjectStatsBuildWrapper extends BuildWrapper {

    @DataBoundConstructor
    public ProjectStatsBuildWrapper() {}

    @Override
    public Environment setUp(
      AbstractBuild build,
      Launcher launcher,
      BuildListener listener) {}

    @Extension
    public static class DescriptorImpl extends BuildWrapperDescriptor {

        @Override
        public boolean isApplicable(AbstractProject<?, ?> item) {
            return true;
        }

        @Nonnull
        @Override
        public String getDisplayName() {
            return "Construct project stats during build";
        }

    }
}

Ok, now we need to implement the actual functionality.

Let’s define a domain class for the project stats:

class ProjectStats {

    private int classesNumber;
    private int linesNumber;

    // standard constructors/getters
}

And write the code which builds the data:

private ProjectStats buildStats(FilePath root)
  throws IOException, InterruptedException {
 
    int classesNumber = 0;
    int linesNumber = 0;
    Stack<FilePath> toProcess = new Stack<>();
    toProcess.push(root);
    while (!toProcess.isEmpty()) {
        FilePath path = toProcess.pop();
        if (path.isDirectory()) {
            toProcess.addAll(path.list());
        } else if (path.getName().endsWith(".java")) {
            classesNumber++;
            linesNumber += countLines(path);
        }
    }
    return new ProjectStats(classesNumber, linesNumber);
}

Finally, we need to show the stats to end-users. Let’s create an HTML template for that:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>$PROJECT_NAME$</title>
</head>
<body>
Project $PROJECT_NAME$:
<table border="1">
    <tr>
        <th>Classes number</th>
        <th>Lines number</th>
    </tr>
    <tr>
        <td>$CLASSES_NUMBER$</td>
        <td>$LINES_NUMBER$</td>
    </tr>
</table>
</body>
</html>

And populate it during the build:

public class ProjectStatsBuildWrapper extends BuildWrapper {
    @Override
    public Environment setUp(
      AbstractBuild build,
      Launcher launcher,
      BuildListener listener) {
        return new Environment() {
 
            @Override
            public boolean tearDown(
              AbstractBuild build, BuildListener listener)
              throws IOException, InterruptedException {
 
                ProjectStats stats = buildStats(build.getWorkspace());
                String report = generateReport(
                  build.getProject().getDisplayName(),
                  stats);
                File artifactsDir = build.getArtifactsDir();
                String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH;
                File reportFile = new File("path");
                // write report's text to the report's file
            }
        };
    }
}

5. Usage

It’s time to combine everything we’ve created so far – and see it in action.

It’s assumed that Jenkins is up and running in the local environment. Please refer to the installation details otherwise.

5.1. Add the Plugin to Jenkins

Now, let’s build our plugin:

mvn install

This will create a *.hpi file in the target directory. We need to copy it to the Jenkins plugins directory (~/.jenkins/plugin by default):

cp ./target/jenkins-hello-world.hpi ~/.jenkins/plugins/

Finally, let’s restart the server and ensure that the plugin is applied:

  1. Open CI dashboard at http://localhost:8080
  2. Navigate to Manage Jenkins | Manage Plugins | Installed
  3. Find our plugin

5.2. Configure Jenkins Job

Let’s create a new job for an open-source Apache commons-lang project and configure the path to its Git repo there:

We also need to enable our plugin for that:

5.3. Check the Results

We’re all set now, let’s check how it works.

We can build the project and navigate to the results. We can see that a stats.html file is available here:

Let’s open it:

That’s what we expected – a single class which has three lines of code.

6. Conclusion

In this tutorial, we created a Jenkins plugin from scratch and ensured that it works.

Naturally, we didn’t cover all aspects of the CI extensions development, we just provided a basic overview, design ideas and an initial setup.

And, as always, the source code can be found over on GitHub.

Java Weekly, Issue 212

$
0
0

Here we go…

1. Spring and Java

>> Creating a Kotlin DSL for validation [blog.sourced-bvba.be]

DSLs can be powerful in Kotlin – especially when they leverage reified generics.

>> Spring, Reactor and ElasticSearch: bechmarking with fake test data [nurkiewicz.com]

>> Monitoring and measuring reactive application with Dropwizard Metrics [nurkiewicz.com]

A couple of interesting examples of monitoring a reactive application using Dropwizard.

>> Building richer hypermedia with Spring HATEOAS [spring.io]

Affordance is another interesting concept that allows squeezing more from Hypermedia by including domain-specific metadata in responses generated by a REST API.

>> No JCP for Java EE [infoq.com]

Looks like Java EE will not utilize the standard Java Community Process.

>> Java EE vs Spring Testing [antoniogoncalves.org]

Integration tests are important in a managed environment; even when they’re slightly more difficult to maintain, they should be as easy to write as possible. That’s not always the case in Java EE where integration tests can sometimes be difficult to set up and quite heavy.

>> Sneak peek at Reactor-Core 3.2 with Milestone 1 [spring.io]

Looks like Reactor-Core 3.2 will finally feature a handy way of defining exception fallbacks.

>> Spring Boot metrics monitoring using Prometheus & Grafana [aboullaite.me]

A minimalistic example of monitoring a Spring Boot application using Prometheus and Grafana. Good stuff.

Also worth reading:

Webinars and presentations:

Time to upgrade:

2. Technical and Musings

>> The Death of Microservice Madness in 2018 [dwmkerr.com]

Microservices aren’t always the optimal way to go – it’s good that the awareness of that simple fact increases.

>> Unit tests vs integration tests, why the opposition? [blog.frankel.ch]

Unit tests and integration tests complement each other – no need to pick exclusively here.

Also worth reading:

3. Comics

And my favorite Dilberts of the week:

>> Success Diminishes Other Guy [dilbert.com]

>> Offensive Tweet From Long Ago [dilbert.com]

>> Boss Gets A Troll [dilbert.com]

4. Pick of the Week

>> Let them paste passwords [www.ncsc.gov.uk]

Introduction to Spring Method Security

$
0
0

1. Introduction

Simply put, Spring Security supports authorization semantics at the method level.

Typically, we could secure our service layer by, for example, restricting which roles are able to execute a particular method – and test it using dedicated method-level security test support.

In this article, we’re going to review the use of some security annotations first. Then, we’ll focus on testing our method security with different strategies.

2. Enabling Method Security

First of all, to use Spring Method Security, we need to add the spring-security-config dependency:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>

We can find its latest version on Maven Central.

If we want to use Spring Boot, we can use the spring-boot-starter-security dependency which includes spring-security-config:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Again, the latest version can be found on Maven Central.

Next, we need to enable global Method Security:

@Configuration
@EnableGlobalMethodSecurity(
  prePostEnabled = true, 
  securedEnabled = true, 
  jsr250Enabled = true)
public class MethodSecurityConfig 
  extends GlobalMethodSecurityConfiguration {
}
  • The prePostEnabled property enables Spring Security pre/post annotations
  • The securedEnabled property determines if the @Secured annotation should be enabled
  • The jsr250Enabled property allows us to use the @RoleAllowed annotation

We’ll explore more about these annotations in the next section.

3. Applying Method Security

3.1. Using @Secured Annotation

The @Secured annotation is used to specify a list of roles on a method. Hence, a user only can access that method if she has at least one of the specified roles.

Let’s define a getUsername method:

@Secured("ROLE_VIEWER")
public String getUsername() {
    SecurityContext securityContext = SecurityContextHolder.getContext();
    return securityContext.getAuthentication().getName();
}

Here, the @Secured(“ROLE_VIEWER”) annotation defines that only users who have the role ROLE_VIEWER are able to execute the getUsername method.

Besides, we can define a list of roles in a @Secured annotation:

@Secured({ "ROLE_VIEWER", "ROLE_EDITOR" })
public boolean isValidUsername(String username) {
    return userRoleRepository.isValidUsername(username);
}

In this case, the configuration states that if a user has either ROLE_VIEWER or ROLE_EDITOR, that user can invoke the isValidUsername method.

The @Secured annotation doesn’t support Spring Expression Language (SpEL).

3.2. Using @RoleAllowed Annotation

The @RoleAllowed annotation is the JSR-250’s equivalent annotation of the @Secured annotation.  

Basically, we can use the @RoleAllowed annotation in a similar way as @Secured. Thus, we could re-define getUsername and isValidUsername methods:

@RolesAllowed("ROLE_VIEWER")
public String getUsername2() {
    //...
}
    
@RolesAllowed({ "ROLE_VIEWER", "ROLE_EDITOR" })
public boolean isValidUsername2(String username) {
    //...
}

Similarly, only the user who has role ROLE_VIEWER can execute getUsername2.

Again, a user is able to invoke isValidUsername2 only if she has at least one of ROLE_VIEWER or ROLER_EDITOR roles.

3.3. Using @PreAuthorize and @PostAuthorize Annotations

Both @PreAuthorize and @PostAuthorize annotations provide expression-based access control. Hence, predicates can be written using SpEL (Spring Expression Language).

The @PreAuthorize annotation checks the given expression before entering the method, whereas, the @PostAuthorize annotation verifies it after the execution of the method and could alter the result.

Now, let’s declare a getUsernameInUpperCase method as below:

@PreAuthorize("hasRole('ROLE_VIEWER')")
public String getUsernameInUpperCase() {
    return getUsername().toUpperCase();
}

The @PreAuthorize(“hasRole(‘ROLE_VIEWER’)”) has the same meaning as @Secured(“ROLE_VIEWER”) which we used in the previous section. Feel free to discover more security expressions details in previous articles.

Consequently, the annotation @Secured({“ROLE_VIEWER”,”ROLE_EDITOR”}) can be replaced with @PreAuthorize(“hasRole(‘ROLE_VIEWER’) or hasRole(‘ROLE_EDITOR’)”):

@PreAuthorize("hasRole('ROLE_VIEWER') or hasRole('ROLE_EDITOR')")
public boolean isValidUsername3(String username) {
    //...
}

Moreover, we can actually use the method argument as part of the expression:

@PreAuthorize("#username == authentication.principal.username")
public String getMyRoles(String username) {
    //...
}

Here, a user can invoke the getMyRoles method only if the value of the argument username is the same as current principal’s username.

It’s worth to note that @PreAuthorize expressions can be replaced by @PostAuthorize ones.

Let’s rewrite getMyRoles:

@PostAuthorize("#username == authentication.principal.username")
public String getMyRoles2(String username) {
    //...
}

In the previous example, however, the authorization would get delayed after the execution of the target method.

Additionally, the @PostAuthorize annotation provides the ability to access the method result:

@PostAuthorize
  ("returnObject.username == authentication.principal.nickName")
public CustomUser loadUserDetail(String username) {
    return userRoleRepository.loadUserByUserName(username);
}

In this example, the loadUserDetail method would only execute successfully if the username of the returned CustomUser is equal to the current authentication principal’s nickname.

In this section, we mostly use simple Spring expressions. For more complex scenarios, we could create custom security expressions.

3.4. Using @PreFilter and @PostFilter Annotations

Spring Security provides the @PreFilter annotation to filter a collection argument before executing the method:

@PreFilter("filterObject != authentication.principal.username")
public String joinUsernames(List<String> usernames) {
    return usernames.stream().collect(Collectors.joining(";"));
}

In this example, we’re joining all usernames except for the one who is authenticated.

Here, our expression uses the name filterObject to represent the current object in the collection.

However, if the method has more than one argument which is a collection type, we need to use the filterTarget property to specify which argument we want to filter:

@PreFilter
  (value = "filterObject != authentication.principal.username",
  filterTarget = "usernames")
public String joinUsernamesAndRoles(
  List<String> usernames, List<String> roles) {
 
    return usernames.stream().collect(Collectors.joining(";")) 
      + ":" + roles.stream().collect(Collectors.joining(";"));
}

Additionally, we can also filter the returned collection of a method by using @PostFilter annotation:

@PostFilter("filterObject != authentication.principal.username")
public List<String> getAllUsernamesExceptCurrent() {
    return userRoleRepository.getAllUsernames();
}

In this case, the name filterObject refers to the current object in the returned collection.

With that configuration, Spring Security will iterate through the returned list and remove any value which matches with the principal’s username.

More detail of @PreFilter and @PostFilter can be found in the Spring Security – @PreFilter and @PostFilter article.

3.5. Method Security Meta-Annotation

We typically find ourselves in a situation where we protect different methods using the same security configuration.

In this case, we can define a security meta-annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasRole('VIEWER')")
public @interface IsViewer {
}

Next, we can directly use the @IsViewer annotation to secure our method:

@IsViewer
public String getUsername4() {
    //...
}

Security meta-annotations are a great idea because they add more semantics and decouple our business logic from the security framework.

3.6. Security Annotation at the Class Level

If we find ourselves using the same security annotation for every method within one class, we can consider putting that annotation at class level:

@Service
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class SystemService {

    public String getSystemYear(){
        //...
    }
 
    public String getSystemDate(){
        //...
    }
}

In above example, the security rule hasRole(‘ROLE_ADMIN’) will be applied to both getSystemYear and getSystemDate methods.

3.7. Multiple Security Annotations on a Method

We can also use multiple security annotations on one method:

@PreAuthorize("#username == authentication.principal.username")
@PostAuthorize("returnObject.username == authentication.principal.nickName")
public CustomUser securedLoadUserDetail(String username) {
    return userRoleRepository.loadUserByUserName(username);
}

Hence, Spring will verify authorization both before and after the execution of the securedLoadUserDetail method.

4. Important Considerations

There are two points we’d like to remind regarding method security:

  • By default, Spring AOP proxying is used to apply method security – if a secured method A is called by another method within the same class, security in A is ignored altogether. This means method A will execute without any security checking. The same applies to private methods
  • Spring SecurityContext is thread-bound – by default, the security context isn’t propagated to child-threads. For more information, we can refer to Spring Security Context Propagation article

5. Testing Method Security

5.1. Configuration

To test Spring Security with JUnit, we need the spring-security-test dependency:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
</dependency>

We don’t need to specify the dependency version because we’re using the Spring Boot plugin. Latest versions of this dependency can be found on Maven Central.

Next, let’s configure a simple Spring Integration test by specifying the runner and the ApplicationContext configuration:

@RunWith(SpringRunner.class)
@ContextConfiguration
public class TestMethodSecurity {
    // ...
}

5.2. Testing Username and Roles 

Now that our configuration is ready, let’s try to test our getUsername method which is secured by the annotation @Secured(“ROLE_VIEWER”):

@Secured("ROLE_VIEWER")
public String getUsername() {
    SecurityContext securityContext = SecurityContextHolder.getContext();
    return securityContext.getAuthentication().getName();
}

Since we use the @Secured annotation here, it requires a user to be authenticated to invoke the method. Otherwise, we’ll get an AuthenticationCredentialsNotFoundException.

Hence, we need to provide a user to test our secured method. To achieve this, we decorate the test method with @WithMockUser and provide a user and roles:

@Test
@WithMockUser(username = "john", roles = { "VIEWER" })
public void givenRoleViewer_whenCallGetUsername_thenReturnUsername() {
    String userName = userRoleService.getUsername();
    
    assertEquals("john", userName);
}

We’ve provided an authenticated user whose username is john and whose role is ROLE_VIEWER. If we don’t specify the username or role, the default username is user and default role is ROLE_USER.

Note that it isn’t necessary to add the ROLE_ prefix here, Spring Security will add that prefix automatically.

If we don’t want to have that prefix, we can consider using authority instead of role. 

For example, let’s declare a getUsernameInLowerCase method:

@PreAuthorize("hasAuthority('SYS_ADMIN')")
public String getUsernameLC(){
    return getUsername().toLowerCase();
}

We could test that using authorities:

@Test
@WithMockUser(username = "JOHN", authorities = { "SYS_ADMIN" })
public void givenAuthoritySysAdmin_whenCallGetUsernameLC_thenReturnUsername() {
    String username = userRoleService.getUsernameInLowerCase();

    assertEquals("john", username);
}

Conveniently, if we want to use the same user for many test cases, we can declare the @WithMockUser annotation at test class:

@RunWith(SpringRunner.class)
@ContextConfiguration
@WithMockUser(username = "john", roles = { "VIEWER" })
public class TestWithMockUserAtClassLevel {
    //...
}

If we wanted to run our test as an anonymous user, we could use the @WithAnonymousUser annotation:

@Test(expected = AccessDeniedException.class)
@WithAnonymousUser
public void givenAnomynousUser_whenCallGetUsername_thenAccessDenied() {
    userRoleService.getUsername();
}

In the example above, we expect an AccessDeniedException because the anonymous user isn’t granted the role ROLE_VIEWER or the authority SYS_ADMIN.

5.3. Testing with a Custom UserDetailsService

For most applications, it’s common to use a custom class as authentication principal. In this case, the custom class needs to implement the org.springframework.security.core.userdetails.UserDetails interface.

In this article, we declare a CustomUser class which extends the existing implementation of UserDetails, which is org.springframework.security.core.userdetails.User:

public class CustomUser extends User {
    private String nickName;
    // getter and setter
}

Let’s take back the example with the @PostAuthorize annotation in section 3:

@PostAuthorize("returnObject.username == authentication.principal.nickName")
public CustomUser loadUserDetail(String username) {
    return userRoleRepository.loadUserByUserName(username);
}

In this case, the method would only execute successfully if the username of the returned CustomUser is equal to the current authentication principal’s nickname.

If we wanted to test that method, we could provide an implementation of UserDetailsService which could load our CustomUser based on the username:

@Test
@WithUserDetails(
  value = "john", 
  userDetailsServiceBeanName = "userDetailService")
public void whenJohn_callLoadUserDetail_thenOK() {
 
    CustomUser user = userService.loadUserDetail("jane");

    assertEquals("jane", user.getNickName());
}

Here, the @WithUserDetails annotation states that we’ll use a UserDetailsService to initialize our authenticated user. The service is referred by the userDetailsServiceBeanName propertyThis UserDetailsService might be a real implementation or a fake for testing purposes.

Additionally, the service will use the value of the property value as the username to load UserDetails.

Conveniently, we can also decorate with a @WithUserDetails annotation at the class level, similarly to what we did with the @WithMockUser annotation.

5.4. Testing with Meta Annotations

We often find ourselves reusing the same user/roles over and over again in various tests.

For these situations, it’s convenient to create a meta-annotation.

Taking back the previous example @WithMockUser(username=”john”, roles={“VIEWER”}), we can declare a meta-annotation as:

@Retention(RetentionPolicy.RUNTIME)
@WithMockUser(value = "john", roles = "VIEWER")
public @interface WithMockJohnViewer { }

Then we can simply use @WithMockJohnViewer in our test:

@Test
@WithMockJohnViewer
public void givenMockedJohnViewer_whenCallGetUsername_thenReturnUsername() {
    String userName = userRoleService.getUsername();

    assertEquals("john", userName);
}

Likewise, we can use meta-annotations to create domain-specific users using @WithUserDetails.

6. Conclusion

In this tutorial, we’ve explored various options for using Method Security in Spring Security.

We also have gone through a few techniques to easily test method security and learned how to reuse mocked users in different tests.

All examples of this tutorial can be found over on Github.

A Guide to JavaLite – Building a RESTful CRUD application

$
0
0

1. Introduction

JavaLite is a collection of frameworks for simplifying common tasks that every developer has to deal with when building applications.

In this tutorial, we’re going to take a look at JavaLite features focused on building a simple API.

2. Setup

Throughout this tutorial, we’ll create a simple RESTful CRUD application. In order to do that, we’ll use ActiveWeb and ActiveJDBC – two of the frameworks that JavaLite integrates with.

So, let’s get started and add the first dependency that we need:

<dependency>
    <groupId>org.javalite</groupId>
    <artifactId>activeweb</artifactId>
    <version>1.15</version>
</dependency>

ActiveWeb artifact includes ActiveJDBC, so there’s no need to add it separately. Please note that the latest activeweb version can be found in Maven Central.

The second dependency we need is a database connector. For this example, we’re going to use MySQL so we need to add:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>

Again, latest mysql-connector-java dependency can be found over on Maven Central.

The last dependency that we have to add is something specific to JavaLite:

<plugin>
    <groupId>org.javalite</groupId>
    <artifactId>activejdbc-instrumentation</artifactId>
    <version>1.4.13</version>
    <executions>
        <execution>
            <phase>process-classes</phase>
            <goals>
                <goal>instrument</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The latest activejdbc-instrumentation plugin can also be found in Maven Central.

Having all this in place and before starting with entities, tables, and mappings, we’ll make sure that one of the supported databases is up and running. As we said before, we’ll use MySQL.

Now we’re ready to start with object-relational mapping.

3. Object-Relational Mapping

3.1. Mapping and Instrumentation

Let’s get started by creating a Product class that will be our main entity:

public class Product {}

And, let’s also create the corresponding table for it:

CREATE TABLE PRODUCTS (
    id int(11) DEFAULT NULL auto_increment PRIMARY KEY,
    name VARCHAR(128)
);

Finally, we can modify our Product class to do the mapping:

public class Product extends Model {}

We only need to extend org.javalite.activejdbc.Model class. ActiveJDBC infers DB schema parameters from the database. Thanks to this capability, there’s no need to add getters and setters or any annotation.

Furthermore, ActiveJDBC automatically recognizes that Product class needs to be mapped to PRODUCTS table. It makes use of English inflections to convert singular form of a model to a plural form of a table. And yes, it works with exceptions as well.

There’s one final thing that we will need to make our mapping work: instrumentation. Instrumentation is an extra step required by ActiveJDBC that will allow us to play with our Product class as if it had getters, setters, and DAO-like methods.

After running instrumentation, we’ll be able to do things like:

Product p = new Product();
p.set("name","Bread");
p.saveIt();

or:

List<Product> products = Product.findAll();

This is where activejdbc-instrumentation plugin comes in. As we already have the dependency in our pom, we should see classes being instrumented during build:

...
[INFO] --- activejdbc-instrumentation:1.4.11:instrument (default) @ javalite ---
**************************** START INSTRUMENTATION ****************************
Directory: ...\tutorials\java-lite\target\classes
Instrumented class: .../tutorials/java-lite/target/classes/app/models/Product.class
**************************** END INSTRUMENTATION ****************************
...

Next, we’ll create a simple test to make sure this is working.

3.2. Testing

Finally, to test our mapping, we’ll follow three simple steps: open a connection to the database, save a new product and retrieve it:

@Test
public void givenSavedProduct_WhenFindFirst_ThenSavedProductIsReturned() {
    
    Base.open(
      "com.mysql.jdbc.Driver",
      "jdbc:mysql://localhost/dbname",
      "user",
      "password");

    Product toSaveProduct = new Product();
    toSaveProduct.set("name", "Bread");
    toSaveProduct.saveIt();

    Product savedProduct = Product.findFirst("name = ?", "Bread");

    assertEquals(
      toSaveProduct.get("name"), 
      savedProduct.get("name"));
}

Note that all this (and more) is possible by only having an empty model and instrumentation.

4. Controllers

Now that our mapping is ready, we can start thinking about our application and its CRUD methods.

For that, we’re going to make use of controllers which process HTTP requests.

Let’s create our ProductsController:

@RESTful
public class ProductsController extends AppController {

    public void index() {
        // ...
    }

}

With this implementation, ActiveWeb will automatically map index() method to the following URI:

http://<host>:<port>/products

Controllers annotated with @RESTful, provide a fixed set of methods automatically mapped to different URIs. Let’s see the ones that will be useful for our CRUD example:

Controller method HTTP method URI
CREATE create() POST http://host:port/products
READ ONE show() GET http://host:port/products/{id}
READ ALL index() GET http://host:port/products
UPDATE update() PUT http://host:port/products/{id}
DELETE destroy() DELETE http://host:port/products/{id}

And if we add this set of methods to our ProductsController:

@RESTful
public class ProductsController extends AppController {

    public void index() {
        // code to get all products
    }

    public void create() {
        // code to create a new product
    }

    public void update() {
        // code to update an existing product
    }

    public void show() {
        // code to find one product
    }

    public void destroy() {
        // code to remove an existing product 
    }
}

Before moving on to our logic implementation, we’ll take a quick look at few things that we need to configure.

5. Configuration

ActiveWeb is based mostly on conventions, project structure is an example of that. ActiveWeb projects need to follow a predefined package layout:

src
 |----main
       |----java.app
       |     |----config
       |     |----controllers
       |     |----models
       |----resources
       |----webapp
             |----WEB-INF
             |----views

There’s one specific package that we need to take a look at – app.config.

Inside that package we’re going to create three classes:

public class DbConfig extends AbstractDBConfig {
    @Override
    public void init(AppContext appContext) {
        this.configFile("/database.properties");
    }
}

This class configures database connections using a properties file in the project’s root directory containing the required parameters:

development.driver=com.mysql.jdbc.Driver
development.username=user
development.password=password
development.url=jdbc:mysql://localhost/dbname

This will create the connection automatically replacing what we did in the first line of our mapping test.

The second class that we need to include inside app.config package is:

public class AppControllerConfig extends AbstractControllerConfig {
 
    @Override
    public void init(AppContext appContext) {
        add(new DBConnectionFilter()).to(ProductsController.class);
    }
}

This code will bind the connection that we just configured to our controller.

The third class will configure our app’s context:

public class AppBootstrap extends Bootstrap {
    public void init(AppContext context) {}
}

After creating the three classes, the last thing regarding configuration is creating our web.xml file under webapp/WEB-INF directory:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns=...>

    <filter>
        <filter-name>dispatcher</filter-name>
        <filter-class>org.javalite.activeweb.RequestDispatcher</filter-class>
        <init-param>
            <param-name>exclusions</param-name>
            <param-value>css,images,js,ico</param-value>
        </init-param>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>dispatcher</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

Now that configuration is done, we can go ahead and add our logic.

6. Implementing CRUD Logic

With the DAO-like capabilities provided by our Product class, it’s super simple to add basic CRUD functionality:

@RESTful
public class ProductsController extends AppController {

    private ObjectMapper mapper = new ObjectMapper();    

    public void index() {
        List<Product> products = Product.findAll();
        // ...
    }

    public void create() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        Product p = new Product();
        p.fromMap(payload);
        p.saveIt();
        // ...
    }

    public void update() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        String id = getId();
        Product p = Product.findById(id);
        p.fromMap(payload);
        p.saveIt();
        // ...
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
        // ...
    }

    public void destroy() {
        String id = getId();
        Product p = Product.findById(id);
        p.delete();
        // ...
    }
}

Easy, right? However, this isn’t returning anything yet. In order to do that, we have to create some views.

7. Views

ActiveWeb uses FreeMarker as a templating engine, and all its templates should be located under src/main/webapp/WEB-INF/views.

Inside that directory, we will place our views in a folder called products (same as our controller). Let’s create our first template called _product.ftl:

{
    "id" : ${product.id},
    "name" : "${product.name}"
}

It’s pretty clear at this point that this is a JSON response. Of course, this will only work for one product, so let’s go ahead and create another template called index.ftl:

[<@render partial="product" collection=products/>]

This will basically render a collection named products, with each one formatted by _product.ftl.

Finally, we need to bind the result from our controller to the corresponding view:

@RESTful
public class ProductsController extends AppController {

    public void index() {
        List<Product> products = Product.findAll();
        view("products", products);
        render();
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
        view("product", p);
        render("_product");
    }
}

In the first case, we’re assigning products list to our template collection named also products.

Then, as we’re not specifying any view, index.ftl will be used.

In the second method, we’re assigning product to element product in the view and we’re explicitly saying which view to render.

We could also create a view message.ftl:

{
    "message" : "${message}",
    "code" : ${code}
}

And then call it form any of our ProductsController‘s method:

view("message", "There was an error.", "code", 200);
render("message");

Let’s now see our final ProductsController:

@RESTful
public class ProductsController extends AppController {

    private ObjectMapper mapper = new ObjectMapper();

    public void index() {
        view("products", Product.findAll());
        render().contentType("application/json");
    }

    public void create() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        Product p = new Product();
        p.fromMap(payload);
        p.saveIt();
        view("message", "Successfully saved product id " + p.get("id"), "code", 200);
        render("message");
    }

    public void update() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        p.fromMap(payload);
        p.saveIt();
        view("message", "Successfully updated product id " + id, "code", 200);
        render("message");
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        view("product", p);
        render("_product");
    }

    public void destroy() {
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        p.delete();
        view("message", "Successfully deleted product id " + id, "code", 200);
        render("message");
    }

    @Override
    protected String getContentType() {
        return "application/json";
    }

    @Override
    protected String getLayout() {
        return null;
    }
}

At this point, our application is done and we’re ready to run it.

8. Running the Application

We’ll use Jetty plugin:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.8.v20171121</version>
</plugin>

Find latest jetty-maven-plugin in Maven Central.

And we’re ready, we can run our application:

mvn jetty:run

Let’s create a couple of products:

$ curl -X POST http://localhost:8080/products 
  -H 'content-type: application/json' 
  -d '{"name":"Water"}'
{
    "message" : "Successfully saved product id 1",
    "code" : 200
}
$ curl -X POST http://localhost:8080/products 
  -H 'content-type: application/json' 
  -d '{"name":"Bread"}'
{
    "message" : "Successfully saved product id 2",
    "code" : 200
}

.. read them:

$ curl -X GET http://localhost:8080/products
[
    {
        "id" : 1,
        "name" : "Water"
    },
    {
        "id" : 2,
        "name" : "Bread"
    }
]

.. update one of them:

$ curl -X PUT http://localhost:8080/products/1 
  -H 'content-type: application/json' 
  -d '{"name":"Juice"}'
{
    "message" : "Successfully updated product id 1",
    "code" : 200
}

… read the one that we just updated:

$ curl -X GET http://localhost:8080/products/1
{
    "id" : 1,
    "name" : "Juice"
}

Finally, we can delete one:

$ curl -X DELETE http://localhost:8080/products/2
{
    "message" : "Successfully deleted product id 2",
    "code" : 200
}

9. Conclusion

JavaLite has a lot of tools to help developers get an application up and running in minutes. However, while basing things on conventions results in a cleaner and simpler code, it takes a while to understand naming and location of classes, packages, and files.

This was only an introduction to ActiveWeb and ActiveJDBC, find more documentation on their website and look for our products application in the Github project.

Using JWT with Spring Security OAuth

$
0
0

1. Overview

In this tutorial we’ll discuss how to get our Spring Security OAuth2 implementation to make use of JSON Web Tokens.

We’re also continuing to built on top of the previous article in this OAuth series.

2. Maven Configuration

First, we need to add spring-security-jwt dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-jwt</artifactId>
</dependency>

Note that we need to add spring-security-jwt dependency to both Authorization Server and Resource Server.

3. Authorization Server

Next, we will configure our Authorization Server to use JwtTokenStore – as follows:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                 .accessTokenConverter(accessTokenConverter())
                 .authenticationManager(authenticationManager);
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
}

Note that we used a symmetric key in our JwtAccessTokenConverter to sign our tokens – which means we will need to use the same exact key for the Resources Server as well.

4. Resource Server

Now, let’s take a look at our Resource Server configuration – which is very similar to the config of the Authorization Server:

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }
}

Keep in mind that we’re defining these two servers as entirely separate and independently deployable. That’s the reason we need to declare some of the same beans again here, in the new configuration.

5. Custom Claims in the Token

Let’s now set up some infrastructure to be able to add a few custom claims in the Access Token. The standard claims provided by the framework are all well and good, but most of the time we’ll need some extra information in the token to utilize on the client side.

We’ll define a TokenEnhancer to customize our Access Token with these additional claims.

In the following example, we will add an extra field “organization” to our Access Token – with this CustomTokenEnhancer:

public class CustomTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(
     OAuth2AccessToken accessToken, 
     OAuth2Authentication authentication) {
        Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("organization", authentication.getName() + randomAlphabetic(4));
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
        return accessToken;
    }
}

Then, we’ll wire that into our Authorization Server configuration – as follows:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(
      Arrays.asList(tokenEnhancer(), accessTokenConverter()));

    endpoints.tokenStore(tokenStore())
             .tokenEnhancer(tokenEnhancerChain)
             .authenticationManager(authenticationManager);
}

@Bean
public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
}

With this new configuration up and running – here’s what a token token payload would look like:

{
    "user_name": "john",
    "scope": [
        "foo",
        "read",
        "write"
    ],
    "organization": "johnIiCh",
    "exp": 1458126622,
    "authorities": [
        "ROLE_USER"
    ],
    "jti": "e0ad1ef3-a8a5-4eef-998d-00b26bc2c53f",
    "client_id": "fooClientIdPassword"
}

5.1. Use the Access Token in the JS Client

Finally, we’ll want to make use of the token information over in our AngualrJS client application. We’ll use the angular-jwt library for that.

So what we’re going to do is we’re going to make use of the “organization” claim in our index.html:

<p class="navbar-text navbar-right">{{organization}}</p>

<script type="text/javascript" 
  src="https://cdn.rawgit.com/auth0/angular-jwt/master/dist/angular-jwt.js">
</script>

<script>
var app = angular.module('myApp', ["ngResource","ngRoute", "ngCookies", "angular-jwt"]);

app.controller('mainCtrl', function($scope, $cookies, jwtHelper,...) {
    $scope.organiztion = "";

    function getOrganization(){
    	var token = $cookies.get("access_token");
    	var payload = jwtHelper.decodeToken(token);
    	$scope.organization = payload.organization;
    }
    ...
});

6. Access Extra Claims on Resource Server

But, how can we access that information over on the resource server side?

What we’ll do here is – extract the extra claims from the access token:

public Map<String, Object> getExtraInfo(OAuth2Authentication auth) {
    OAuth2AuthenticationDetails details
      = (OAuth2AuthenticationDetails) auth.getDetails();
    OAuth2AccessToken accessToken = tokenStore
      .readAccessToken(details.getTokenValue());
    return accessToken.getAdditionalInformation();
}

In the following section, we’ll discuss how to add that extra information to our Authentication details by using a custom AccessTokenConverter

6.1. Custom AccessTokenConverter

Let’s create CustomAccessTokenConverter and set Authentication details with access token claims:

@Component
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
        OAuth2Authentication authentication
         = super.extractAuthentication(claims);
        authentication.setDetails(claims);
        return authentication;
    }
}

Note: DefaultAccessTokenConverter used to set Authentication details to Null.

6.2. Configure JwtTokenStore

Next, we’ll configure our JwtTokenStore to use our CustomAccessTokenConverter:

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfigJwt
 extends ResourceServerConfigurerAdapter {

    @Autowired
    private CustomAccessTokenConverter customAccessTokenConverter;

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setAccessTokenConverter(customAccessTokenConverter);
    }
    // ...
}

6.3. Extra Claims available in the Authentication Object

Now that the Authorization Server added some extra claims in the token, we can now access on the Resource Server side, directly in the Authentication object:

public Map<String, Object> getExtraInfo(Authentication auth) {
    OAuth2AuthenticationDetails oauthDetails
      = (OAuth2AuthenticationDetails) auth.getDetails();
    return (Map<String, Object>) oauthDetails
      .getDecodedDetails();
}

6.4. Authentication Details Test

Let’s make sure our Authentication object contains that extra information:

@RunWith(SpringRunner.class)
@SpringBootTest(
  classes = ResourceServerApplication.class, 
  webEnvironment = WebEnvironment.RANDOM_PORT)
public class AuthenticationClaimsIntegrationTest {

    @Autowired
    private JwtTokenStore tokenStore;

    @Test
    public void whenTokenDoesNotContainIssuer_thenSuccess() {
        String tokenValue = obtainAccessToken("fooClientIdPassword", "john", "123");
        OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
        Map<String, Object> details = (Map<String, Object>) auth.getDetails();
 
        assertTrue(details.containsKey("organization"));
    }

    private String obtainAccessToken(
      String clientId, String username, String password) {
 
        Map<String, String> params = new HashMap<>();
        params.put("grant_type", "password");
        params.put("client_id", clientId);
        params.put("username", username);
        params.put("password", password);
        Response response = RestAssured.given()
          .auth().preemptive().basic(clientId, "secret")
          .and().with().params(params).when()
          .post("http://localhost:8081/spring-security-oauth-server/oauth/token");
        return response.jsonPath().getString("access_token");
    }
}

Note: we obtained the access token with extra claims from the Authorization Server, then we read the Authentication object from it which contains extra information “organization” in the details object.

7. Asymmetric KeyPair

In our previous configuration we used symmetric keys to sign our token:

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    return converter;
}

We can also use asymmetric keys (Public and Private keys) to do the signing process.

7.1. Generate JKS Java KeyStore File

Let’s first generate the keys – and more specifically a .jks file – using the command line tool keytool:

keytool -genkeypair -alias mytest 
                    -keyalg RSA 
                    -keypass mypass 
                    -keystore mytest.jks 
                    -storepass mypass

The command will generate a file called mytest.jks which contains our keys -the Public and Private keys.

Also make sure keypass and storepass are the same.

7.2. Export Public Key

Next, we need to export our Public key from generated JKS, we can use the following command to do so:

keytool -list -rfc --keystore mytest.jks | openssl x509 -inform pem -pubkey

A sample response will look like this:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgIK2Wt4x2EtDl41C7vfp
OsMquZMyOyteO2RsVeMLF/hXIeYvicKr0SQzVkodHEBCMiGXQDz5prijTq3RHPy2
/5WJBCYq7yHgTLvspMy6sivXN7NdYE7I5pXo/KHk4nz+Fa6P3L8+L90E/3qwf6j3
DKWnAgJFRY8AbSYXt1d5ELiIG1/gEqzC0fZmNhhfrBtxwWXrlpUDT0Kfvf0QVmPR
xxCLXT+tEe1seWGEqeOLL5vXRLqmzZcBe1RZ9kQQm43+a9Qn5icSRnDfTAesQ3Cr
lAWJKl2kcWU1HwJqw+dZRSZ1X4kEXNMyzPdPBbGmU6MHdhpywI7SKZT7mX4BDnUK
eQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDCzCCAfOgAwIBAgIEGtZIUzANBgkqhkiG9w0BAQsFADA2MQswCQYDVQQGEwJ1
czELMAkGA1UECBMCY2ExCzAJBgNVBAcTAmxhMQ0wCwYDVQQDEwR0ZXN0MB4XDTE2
MDMxNTA4MTAzMFoXDTE2MDYxMzA4MTAzMFowNjELMAkGA1UEBhMCdXMxCzAJBgNV
BAgTAmNhMQswCQYDVQQHEwJsYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAICCtlreMdhLQ5eNQu736TrDKrmTMjsrXjtkbFXj
Cxf4VyHmL4nCq9EkM1ZKHRxAQjIhl0A8+aa4o06t0Rz8tv+ViQQmKu8h4Ey77KTM
urIr1zezXWBOyOaV6Pyh5OJ8/hWuj9y/Pi/dBP96sH+o9wylpwICRUWPAG0mF7dX
eRC4iBtf4BKswtH2ZjYYX6wbccFl65aVA09Cn739EFZj0ccQi10/rRHtbHlhhKnj
iy+b10S6ps2XAXtUWfZEEJuN/mvUJ+YnEkZw30wHrENwq5QFiSpdpHFlNR8CasPn
WUUmdV+JBFzTMsz3TwWxplOjB3YacsCO0imU+5l+AQ51CnkCAwEAAaMhMB8wHQYD
VR0OBBYEFOGefUBGquEX9Ujak34PyRskHk+WMA0GCSqGSIb3DQEBCwUAA4IBAQB3
1eLfNeq45yO1cXNl0C1IQLknP2WXg89AHEbKkUOA1ZKTOizNYJIHW5MYJU/zScu0
yBobhTDe5hDTsATMa9sN5CPOaLJwzpWV/ZC6WyhAWTfljzZC6d2rL3QYrSIRxmsp
/J1Vq9WkesQdShnEGy7GgRgJn4A8CKecHSzqyzXulQ7Zah6GoEUD+vjb+BheP4aN
hiYY1OuXD+HsdKeQqS+7eM5U7WW6dz2Q8mtFJ5qAxjY75T0pPrHwZMlJUhUZ+Q2V
FfweJEaoNB9w9McPe1cAiE+oeejZ0jq0el3/dJsx3rlVqZN+lMhRJJeVHFyeb3XF
lLFCUGhA7hxn2xf3x1JW
-----END CERTIFICATE-----

We take only our Public key and copy it to our resource server src/main/resources/public.txt:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgIK2Wt4x2EtDl41C7vfp
OsMquZMyOyteO2RsVeMLF/hXIeYvicKr0SQzVkodHEBCMiGXQDz5prijTq3RHPy2
/5WJBCYq7yHgTLvspMy6sivXN7NdYE7I5pXo/KHk4nz+Fa6P3L8+L90E/3qwf6j3
DKWnAgJFRY8AbSYXt1d5ELiIG1/gEqzC0fZmNhhfrBtxwWXrlpUDT0Kfvf0QVmPR
xxCLXT+tEe1seWGEqeOLL5vXRLqmzZcBe1RZ9kQQm43+a9Qn5icSRnDfTAesQ3Cr
lAWJKl2kcWU1HwJqw+dZRSZ1X4kEXNMyzPdPBbGmU6MHdhpywI7SKZT7mX4BDnUK
eQIDAQAB
-----END PUBLIC KEY-----

7.3. Maven Configuration

Next, we don’t want the JKS file to be picked up by the maven filtering process – so we’ll make sure to exclude it in the pom.xml:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <excludes>
                <exclude>*.jks</exclude>
            </excludes>
        </resource>
    </resources>
</build>

If we’re using Spring Boot, we need to make sure that our JKS file is added to application classpath via the Spring Boot Maven Plugin – addResources:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <addResources>true</addResources>
            </configuration>
        </plugin>
    </plugins>
</build>

7.4. Authorization Server

Now, we will configure JwtAccessTokenConverter to use our KeyPair from mytest.jks – as follows:

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    KeyStoreKeyFactory keyStoreKeyFactory = 
      new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"), "mypass".toCharArray());
    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
    return converter;
}

7.5. Resource Server

Finally, we need to configure our resource server to use Public key – as follows:

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    Resource resource = new ClassPathResource("public.txt");
    String publicKey = null;
    try {
        publicKey = IOUtils.toString(resource.getInputStream());
    } catch (final IOException e) {
        throw new RuntimeException(e);
    }
    converter.setVerifierKey(publicKey);
    return converter;
}

8. Conclusion

In this quick article we focused on setting up our Spring Security OAuth2 project to use JSON Web Tokens.

The full implementation of this tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.

Viewing all 4752 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>