Example – restricting callers

In this section, we will develop a sample library with two methods. The hello() method prints hello to the standard output. The callMe() method accepts Runnable as an argument and runs it. The first method, however, is restricted. It executes only if the caller is purely outside of the library. It throws IllegalCallerException if the caller obtained the control in a way that the library was called out, presumably via the second method invoking the passed Runnable. The implementation of the API is simple:

package packt.java9.deep.stackwalker.myrestrictivelibrary;
public class RestrictedAPI {
public void hello() {
CheckEligibility.itIsNotCallBack();
System.out.println("hello");
}
public void callMe(Runnable cb) {
cb.run();
}
}

The code that performs the eligibility checking is implemented in a separate class to keep things simple; we will examine that code later in this section. First, let's review the main code used to start our demonstration:

package packt.java9.deep.stackwalker.externalcode;
import packt.java9.deep.stackwalker.myrestrictivelibrary.RestrictedAPI;

public class DirectCall {
public static void main(String[] args) {
RestrictedAPI api = new RestrictedAPI();
api.hello();
api.callMe(() -> { api.hello();
});
}
}

This code creates an instance of our API class and then directly invokes the hello() method. It should work and should print the characters hello onscreen. The next code line asks the callMe() method to call back Runnable provided in the form of a Lambda expression. In this case, the call will fail, because the caller is outside but was called from inside the library.

Let's now look at how the eligibility check is implemented:

package packt.java9.deep.stackwalker.myrestrictivelibrary;
import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE;

public class CheckEligibility {
private static final String packageName
= CheckEligibility.class.getPackageName();
private static boolean notInLibrary(StackWalker.StackFrame f) {
return !inLibrary(f);
}

private static boolean inLibrary(StackWalker.StackFrame f) {
return f.getDeclaringClass().getPackageName()
.equals(packageName);
}

public static void itIsNotCallBack() {
boolean eligible = StackWalker
.getInstance(RETAIN_CLASS_REFERENCE)
.walk(s -> s.dropWhile(CheckEligibility::inLibrary)
.dropWhile(CheckEligibility::notInLibrary)
.count() == 0
);
if (!eligible) {
throw new IllegalCallerException();
}
}
}

The itIsNotCallBack() method is the one called from the hello() method. This method creates StackWalker and invokes the walk() method. The argument of the walk() method is a function that converts Stream of StackFrame objects to some other value that the walk() method will return.

At first, this argument setting might seem complex and difficult to understand. It would be more logical to return Stream that provides the StackFrame objects instead of forcing the caller to define a function that will get this as an argument.

The sample code uses a Lambda expression to define the function as an argument to the walk() method. The argument to the Lambda expression is the stream. Since the first element of this stream is the actual call, we drop it. Because these calls should also be refused if the caller is not eligible even though the call to the hello() method was through some other class and method that is already inside the library, we drop all elements from the frame that belong to classes inside the package of the CheckEligibility class. This package is packt.java9.deep.stackwalker.myrestrictivelibrary and in the code, this string is stored in the packageName field. The resulting stream contains only the StackFrame objects that are from outside of the library. We drop these also until the stream exhausts or until we find StackFrame that again belongs to the library. If all the elements were dropped, we are good. In this case, the result of count() is zero. If we find a class in StackFrame that belongs to the library, it means that the outside code was called from the library and, in this case, we have to refuse to work. In this case, the variable eligible will be false and we throw an exception, as depicted in the following screenshot:

Class in library found by StackFrame
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset