How to implement the API/SPI Pattern in Java? - java

I am creating a framework that exposes an API for developers to use:
public interface MyAPI {
public void doSomeStuff();
public int getWidgets(boolean hasRun);
}
All the developers should have to do is code their projects against these API methods. I also want them to be able to place different "drivers"/"API bindings" on the runtime classpath (the same way JDBC or SLF4J work) and have the API method calls (doSomeStuff(), etc.) operate on different 3rd party resources (files, servers, whatever). Thus the same code and API calls will map to operations on different resources depending on what driver/binding the runtime classpath sees (i.e. myapi-ftp, myapi-ssh, myapi-teleportation).
How do I write (and package) an SPI that allows for such runtime binding, and then maps MyAPI calls to the correct (concrete) implementation? In other words, if myapi-ftp allows you to getWidgets(boolean) from an FTP server, how would I could this up (to make use of both the API and SPI)?
Bonus points for concrete, working Java code example! Thanks in advance!

Take a look at the java.util.ServiceLoader class.
In general, the idea is this:
API Jar
Supply the interface
Use the ServiceLoader class to lookup the implementation
Binding/Driver Jar
Implement the interface
Create the file META-INF/ and specify the classname that implements it
There's a good example right in the javadocs:
http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html
API Jar
package com.foo;
public interface FooInterface { ... }
public class FooInterfaceFactory {
public static FooInterface newFooInstance() {
ServiceLoader<FooInterface> loader = ServiceLoader.load(FooInterface.class);
Iterator<FooInterface> it = loader.iterator();
// pick one of the provided implementations and return it.
}
Binding Jar
package com.myfoo;
public class MyFooImpl implements FooInterface { ... }
META-INF/com.foo.FooInterface
com.myfoo.MyFooImpl
EDIT
SPI Example
public interface FooSpi {
void accepts(String url);
FooInterface getFooInstance();
}
public class FooInterfaceFactory {
public static FooInterface getFooInterfaceInstance(String url) {
ServiceLoader<FooSpi> loader = ServiceLoader.load(FooSpi.class);
Iterator<FooSpi> it = loader.iterator();
while (it.hasNext()) {
FooSpi fooSpi = it.next();
if (fooSpi .accepts(url)) {
return fooSpi.getFooInstance();
}
}
return null;
}
}
And of course, change the filename to com.foo.FooSpi and provide an implementation of FooSpi. That will allow you to segregate the public API from the Spi interface.
If you want to hide the accepts method, you could always have a second interface which is your public API, and t

Well you know that API are what clients use, and SPI is what your library use internally.
You shall have classes which implement your API classes, which depend on SPI interfaces, and have some implementations for your SPI.
Most of the time SPI interfaces contain low level methods (abstraction for direct working with FTP, SSH and... in your example), and your library provides higher level operations for your clients.
Maybe your SPI interfaces would be such as:
public interface ProtocolSPI {
boolean isCompatibleWithUrl(String url);
Handle connect(String url, Map<String, Object> parameters);
int readData(Handle handle, byte[] bytes);
void writeData(Handle handle, byte[] bytes, int startIndex, int length);
void closeHandle(Handle handle);
}
and you have code which depends on this interface for working with replaceable part.
You may have a ProtocolSPIFactory which uses java.util.ServiceLoader to find available implementations of your ProtocolSPI (in the class-path), then instantiates them and by calling isCompatibleWithUrl finds out which implementation to use for a specific url.

Related

Selecting Implementation of Interface based on the Parameter passed

I have a Parent interface.
public interface Parent{...}
And two classes that implement this interface.
public class ChildA implements Parent {...}
public class ChildB implements Parent {...}
Now I want to create an object of the child based on the parameter passed. Something like this,
Parent instance1 = Parent.getChild("Key1");
Currently, I am achieving this by using hashmaps.
static Map<String,Class<?>> map = new HashMap<String,Class<?>>();
static void init() throws ClassNotFoundException {
map.put("Key1",Class.forName("ChildA"));
map.put("Key2",Class.forName("ChildB"));
}
static Parent getChild(String key) throws InstantiationException, IllegalAccessException {
return (Parent) map.get(key).newInstance();
}
But the issue here is every time I implement a new child I will have to add it in the Parent init method. So is there any cleaner way to do this? Something like adding the information of the key to the child itself,
public class ChildA implements Parent {
private String key = "Key1";
...
So that when from the parent class I call getChild it refers to the respective Child.
Basically I am asking for a way to dynamically refer to a child of the parent based on the parameter passed.
You can use the service provider mechanism. This works best when actively using Java’s module system as then, the necessary parts are even integrated into the Java language.
The module containing the Parent interface must export its package, if implementations in other modules should be possible. Then, a module which wants to look up implementations of the interface must have a
uses yourpackage.Parent;
directive in its module-info. A module providing implementations must have a directive like
provides yourpackage.Parent with yourpackage.ChildA, yourpackage.ChildB;
in its module-info. It’s possible to use the interface and provide implementations within the same module. This might also be the module containing the declaration of the interface. In that case, it’s even possible to use the mechanism within a single module only and not to export the interface at all.
The compiler will already check that the specified implementation classes are public, have a public no-arg constructor, and truly implement the service interface. The implementations do not need to reside in an exported package; it’s possible that the interface is the only way to access an implementation from another module.
Since the compiler pre-checks the required invariants, you don’t need to deal with the issues inherent to Reflection. For example, you don’t need to declare or handle InstantiationException or IllegalAccessException.
A simple setup could be
module-info
module ExampleApp {
uses yourpackage.Parent;
provides yourpackage.Parent with yourpackage.ChildA, yourpackage.ChildB;
}
yourpackage/Parent
package yourpackage;
public interface Parent {
}
yourpackage/TheKey
package yourpackage;
import java.lang.annotation.*;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface TheKey {
String value();
}
yourpackage/ChildA
package yourpackage;
#TheKey("Key1")
public class ChildA implements Parent {
}
yourpackage/ChildB
package yourpackage;
#TheKey("Key2")
public class ChildB implements Parent {
}
independentpackage/UsingTheInterfaces
package independentpackage;
import java.util.ServiceLoader;
import yourpackage.Parent;
import yourpackage.TheKey;
public class UsingTheInterfaces {
public static void main(String[] args) {
Parent p = getChild("Key1");
System.out.println(p);
}
static Parent getChild(String key) {
return ServiceLoader.load(Parent.class).stream()
.filter(p -> {
TheKey keyAnno = p.type().getAnnotation(TheKey.class);
return keyAnno != null && keyAnno.value().equals(key);
})
.findAny()
.map(ServiceLoader.Provider::get)
.orElse(null); // decide how to handle absent keys
}
}
As said, when you have an exports yourpackage; directive, implementations can be provided by other modules and the ServiceLoader will discover those implementations dynamically for all modules present at runtime. The using module does not need to know them at compile time.
There is a predecessor mechanism for older Java versions not having a module system, which is also handled by ServiceLoader in a backwards compatible manner. Those providers have to be packaged in a jar file containing a file META-INF/services/yourpackage.Parent containing a list of all classes within the jar file implementing the interface. Before Java 9, the ServiceLoader also lacks the Stream API support that allowed to query the annotations before instantiating the implementation. You can only use the Iterator that will already instantiate the classes and return an instance.
One way to avoid unnecessary overhead with the old API, is to split the interface into a service provider interface and an actual service interface. The provider interface will supply meta information and act as a factory for actual service implementations. Compare with the relationship between CharsetProvider and Charset or FileSystemProvider and FileSystem. These examples also demonstrate that the service provider mechanism is already widely used. More examples can be found in the java.base module documentation.
This was just an overview; the API documentation of ServiceLoader contains more details about the mechanism.
Option 1: I suggest you to use a simple factory class like this one:
public class ChildFactory {
public static Parent getChild(String key) throws ClassNotFoundException {
if (key.equals("Key1"))
return new ChildA();
if (key.equals("key2"))
return new ChildB();
throw new ClassNotFoundException();
}
}
These are the reasons:
Simple and easy to extend: the class does only one thing, create objects
Don't use the deprecated newInstance()
Clean the interface Parent from static "factory" methods
Option 2: define a function that given the key it returns the class name and use it to create the instance:
public class ChildFactory {
public static Parent getChild(String key) {
String className = childClassNameFor(key);
return (Parent) Class.forName("my.package."+className).newInstance();
}
private static String childClassNameFor(String key) {
return "Child" + key;
}
}
And then you can use it like this:
Parent p = ChildFactory.getChild("A");

How can i restrict my clients with selected methods from the class?

Let's say I have 1 complete class with around 20 methods which provide different functionalities.
Now we have multiple clients using this class, but we want them to have restricted access.
For e.g. -
Client 1 - Gets access to method1/m3/m5/m7/m9/m11
Client 2 - Gets access to method2/m4/m6/m8/m10/m12
Is there any way I can restrict this access?
One solution which I thought:
Create 2 new classes extending Parent class and override methods which are not accessible and throw Exception from them.
But then if 3rd client with different requirement, we have to create new subclass for them.
Is there any other way to do this?
Create 2 new classes extending Parent class and override methods which
are not accessible and throw Exception from them. But then if 3rd
client with different requirement, we have to create new subclass for
them.
It is a bad solution because it violates Polymorphism and the Liskov Substitution Principle. This way will make your code less clear.
At first, you should think about your class, are you sure that it isn't overloaded by methods? Are you sure that all of those methods relate to one abstraction? Perhaps, there is a sense to separate methods to different abstractions and classes?
If there is a point in the existence of those methods in the class then you should use different interfaces to different clients. For example, you can make two interfaces for each client
interface InterfaceForClient1 {
public void m1();
public void m3();
public void m5();
public void m7();
public void m9();
public void m11();
}
interface InterfaceForClient2 {
public void m2();
public void m4();
public void m6();
public void m8();
public void m10();
public void m12();
}
And implement them in your class
class MyClass implements InterfaceForClient1, InterfaceForClient2 {
}
After it, clients must use those interfaces instead of the concrete implementation of the class to implement own logic.
You can create an Interface1 which defines methods only for Client1, and an Interface2 which defines methods only for Client2. Then, your class implements Interface1 and Interface2.
When you declare Client1 you can do something like: Interface1 client1.
With this approach, client1 can accesses only methods of this interface.
I hope this will help you.
The other answers already present the idiomatic approach. Another idea is a dynamic proxy decorating the API with an access check.
In essence, you generate a proxy API that has additional checks on method calls to implement a form of Access Control.
Example Implementation:
package com.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
#FunctionalInterface
public interface ACL<P, Q> {
boolean allowed(P accessor, Q target, Method method, Object[] args);
class ACLException extends RuntimeException {
ACLException(String message) {
super(message);
}
}
#SuppressWarnings("unchecked")
default Q protect(P accessor, Q delegate, Class<Q> dType) {
if (!dType.isInterface()) {
throw new IllegalArgumentException("Delegate type must be an Interface type");
}
final InvocationHandler handler = (proxy, method, args) -> {
if (allowed(accessor, delegate, method, args)) {
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
} else {
throw new ACLException("Access denies as per ACL");
}
};
return (Q) Proxy.newProxyInstance(dType.getClassLoader(), new Class[]{dType}, handler);
}
}
Example Usage:
package com.example;
import java.lang.reflect.Method;
public class Main {
interface API {
void doAlpha(int arg);
void doBeta(String arg);
void doGamma(Object arg);
}
static class MyAPI implements API {
#Override
public void doAlpha(int arg) {
System.out.println("Alpha");
}
#Override
public void doBeta(String arg) {
System.out.println("Beta");
}
#Override
public void doGamma(Object arg) {
System.out.println("Gamma");
}
}
static class AlphaClient {
void use(API api) {
api.doAlpha(100);
api.doBeta("100");
api.doGamma(this);
}
}
public static class MyACL implements ACL<AlphaClient, API> {
#Override
public boolean allowed(AlphaClient accessor, API target, Method method, Object[] args) {
final String callerName = accessor.getClass().getName().toLowerCase();
final String methodName = method.getName().toLowerCase().replace("do", "");
return callerName.contains(methodName);
}
}
public static void main(String[] args) {
final MyACL acl = new MyACL();
final API api = new MyAPI();
final AlphaClient client = new AlphaClient();
final API guardedAPI = acl.protect(client, api, API.class);
client.use(guardedAPI);
}
}
Notes:
The accessor does not have to be the client object itself, it can be a string key or token that helps ACL identify the client.
The ACL implementation here is rudimentary, more interesting ones could be One that reads ACL from some file or One that uses method and client annotations as rules.
If you don't want to define an interface for API class, consider a tool like javassist to directly proxy a class.
Consider other popular Aspect Oriented Programming solutions
You should create one super class with all the methods and then provide Client specific implementations in their corresponding sub classes extending from the super class defined earlier.
If there are methods which are common implementation for all clients, leave their implementations to the super class.
It seems like you are a bit confused about the purpose of Classes and Interfaces. As far as I know, an Interface is a contract defining which functionality a piece of software provides. This is from official java tutorial:
There are a number of situations in software engineering when it is
important for disparate groups of programmers to agree to a "contract"
that spells out how their software interacts. Each group should be
able to write their code without any knowledge of how the other
group's code is written. Generally speaking, interfaces are such
contracts.
Then you can write a Class which implements this Interface/contract, that is, provides the code that actually perform what was specified. The List interface and the ArrayList class are both an example of this.
Interfaces and Classes have access modifiers, but they aren't designed to specify permissions to specific clients. They specify what is visible for other piece of software depending the location where it is defined: Class, Package, Subclass, World. For example, a private method can be accessed only inside the class where it is defined.
From official Java tutorial again:
Access level modifiers determine whether other classes can use a
particular field or invoke a particular method. There are two levels
of access control:
At the top level—public, or package-private (no explicit modifier).
At the member level—public, private, protected, or package-private (no
explicit modifier).
Maybe you want something more powerful like Access Control List (ACL).
Your question is a little unclear, leading to different possible answers. I'll try to cover some of the possible areas:
Object encapsulation
If your goal is to provide interfaces to different clients that only provide certain functionality or a specific view there are several solutions. Which matches best depends on the purpose of your class:
Refactoring
The question somehow suggests that your class is responsible for different tasks. That might be an indicator, that you could tear it apart into distinct classes that provide the different interfaces.
Original
class AllInOne {
A m1() {}
B m2() {}
C m3() {}
}
client1.useClass(allInOneInstance);
client2.useClass(allInOneInstance);
client3.useClass(allInOneInstance);
Derived
class One {
A m1() {}
}
class Two {
B m2() {}
}
class Three {
C m3() {}
}
client1.useClass(oneInstance);
client2.useClass(twoInstance);
client3.useClass(threeInstance);
Interfaces
If you choose to keep the class together (there might be good reasons for it), you could have the class implement interfaces that model the view required by different clients. By passing instances of the appropriate interface to the clients they will not see the full class interface:
Example
class AllInOne implements I1, I2, I3 {
...
}
interface I1 {
A m1();
}
But be aware that clients will still be able to cast to the full class like ((AllInOne) i1Instance).m2().
Inheritance
This was already outline in other answers. I'll therefore skip this here. I don't think this is a good solution as it might easily break in a lot of scenarios.
Delegation
If casting is a risk to you, you can create classes that only offer the desired interface and delegate to the actual implementation:
Example
class Delegate1 {
private AllInOne allInOne;
public A m1() {
return allInOne.m1();
}
}
Implementing this can be done in various ways and depends on your environment like explicit classes, dynamic proxies , code generation, ...
Framework
If you are using an Application Framework like Spring you might be able to use functionality from this Framework.
Aspects
AOP allows you to intercept method calls and therefor apply some access control logic there.
Security
Please note that all of the above solutions will not give you actual security. Using casts, reflection or other techniques will still allow clients to obtain access to the full functionality.
If you require stronger access limitations there are techniques that I will just briefly outline as they might depend on your environment and are more complex.
Class Loader
Using different class loaders you can make sure that parts of your code have no access to class definitions outsider their scope (used e.g. in tomcat to isolate different deployments).
SecurityManager
Java offers possibilities to implement your own SecurityManager this offers ways to add some extra level of access checking.
Custom build Security
Of course you can add your own access checking logic. Yet I don't think this will be a viable solution for in JVM method access.

Update a New Java Library Without Affecting Existing Systems

Suppose I have created a library and distribute all over the company and it use in every project.
Library is 1.0 and Suppose I have a interface Componentble.
public interface Componentble {
public String getComponentId();
}
I had done some modification and updated the jar for 1.1 and Componentble interface modified as follows.
public interface Componentble {
public String getComponentId();
public Componentble getParentComponent();
}
When this jar applied to existing project it will gives compile errors.
I want to do this modifications and update the jar. but case is it should not affect to existing projects.
What is the best way to do this.
Create ComponentbleV2 and in new project ask to use ComponentbleV2 not Componentble.
Or Create custom class loader and do what need.
The answer what i want is how we can do api modification and apply to existing project with out any compilation issue for existing projects.
One way to do this is by annotating the method(s) in your old interface with #Deprecated and explaining in the javadocs what to use instead.
For more documentation on that, see Oracle documentation on #Deprecated
For the sake of backwards compatibility, you're going to have to keep both interfaces for now. This might require a bit of customization in the implementation of the interfaces. In a while, after you've been through a couple more versions, you can remove the old interface.
Make sure to properly document your deprecated methods, so that the developers who use it know what to use instead and where to find it.
From Java 8 on you can provide default implementations for interface methods. They were invented exactly for your problem.
public interface Componentble {
public String getComponentId();
public default Componentble getParentComponent() {
return null;
}
}
Two interfaces
There is no need to deprecate the old one.
Create two interfaces where the new one extends the old one.
public interface Componentble {
public String getComponentId();
}
and
public interface ComponentbleWithStructure extends Componentble {
public Componentble getParentComponent();
}
Implementing a interface should imply that the implementer follows the contract of that interface.
This way you know that any class implementing both has been remade to fit the new contract and the ones implementing only the old still follows the old contract.
Example of use:
void doStuff(Componentble component){
if(component instanceof ComponentbleWithStructure){
Componentble parent=((ComponentbleWithStructure)component).getParentComponent();
....
}
....
}
Default implementation
The java8 way is only useful when it is possible to express the new functionality using the old interface. For example if you have a service that can look up parents you could write.
public interface Componentble {
public String getComponentId();
public default Componentble getParentComponent() {
return ParentLookUpService.getParent(getComponentId());
}
}
This way you will know that all instances using the new interface have a correct implementation.

How can I override a method of an anonymous generic class?

I am working on GWT project with JDK7. It has two entryPoints (two clients) that are located in separate packages of the project. Clients share some code that is located in /common package, which is universal and accessible to both by having the following line in their respective xml-build files:
<source path='ui/common' />
Both clients have their own specific implementations of the Callback class which serves their running environments and performs various actions in case of failure or success. I have the following abstract class that implements AsyncCallback interface and then gets extended by its respective client.
public abstract class AbstractCallback<T> implements AsyncCallback<T> {
public void handleSuccess( T result ) {}
...
}
Here are the client's classes:
public class Client1Callback<T> extends AbstractCallback<T> {...}
and
public class Client2Callback<T> extends AbstractCallback<T> {...}
In the common package, that also contains these callback classes, I am working on implementing the service layer that serves both clients. Clients use the same back-end services, just handle the results differently. Based on the type of the client I want to build a corresponding instance of AbstractCallback child without duplicating anonymous class creation for each call. I am going to have many declarations that will look like the following:
AsyncCallback<MyVO> nextCallback = isClient1 ?
new Client1Callback<MyVO>("ABC") {
public void handleSuccess(MyVO result) {
doThatSameAction(result);
}
}
:
new Client2Callback<MyVO>("DEF") {
public void handleSuccess(MyVO result) {
doThatSameAction(result);
}
};
That will result in a very verbose code.
The intent (in pseudo-code) is to have the below instead:
AsyncCallback<MyVO> nextCallback = new CallbackTypeResolver.ACallback<MyVO>(clientType, "ABC"){
public void handleSuccess(MyVO result) {
doThatSameAction(result);
}
};
I was playing with the factory pattern to get the right child instance, but quickly realized that I am not able to override handleSuccess() method after the instance is created.
I think the solution may come from one of the two sources:
Different GWT way of dealing with custom Callback implementations, lets call it alternative existent solution.
Java generics/types juggling magic
I can miss something obvious, and would appreciate any advice.
I've read some articles here and on Oracle about types erasure for generics, so I understand that my question may have no direct answer.
Refactor out the handleSuccess behavior into its own class.
The handleSuccess behavior is a separate concern from what else is going on in the AsyncCallback classes; therefore, separate it out into a more useful form. See Why should I prefer composition over inheritance?
Essentially, by doing this refactoring, you are transforming an overridden method into injected behavior that you have more control over. Specifically, you would have instead:
public interface SuccessHandler<T> {
public void handleSuccess(T result);
}
Your callback would look something like this:
public abstract class AbstractCallback<T> implements AsyncCallback<T> {
private final SuccessHandler<T> handler; // Inject this in the constructor
// etc.
// not abstract anymore
public void handleSuccess( T result ) {
handler.handleSuccess(result);
}
}
Then your pseudocode callback creation statement would be something like:
AsyncCallback<MyVO> nextCallback = new CallbackTypeResolver.ACallback<MyVO>(
clientType,
"ABC",
new SuccessHandler<MyVO>() {
public void handleSuccess(MyVO result) {
doThatSameMethod(result);
}
});
The implementations of SuccessHandler don't have to be anonymous, they can be top level classes or even inner classes based on your needs. There's a lot more power you can do once you're using this injection based framework, including creating these handlers with automatically injected dependencies using Gin and Guice Providers. (Gin is a project that integrates Guice, a dependency injection framework, with GWT).

What is the right way to organize Jersey resources using inheritance and generics?

I'm developing an app with Jersey where I have many resources. Although main functionality of these resources varies, they share lots of common methods (like list, read, update and etc). The app runs on Google App Engine and uses Guice for dependency injection.
My first approach was to have a generic AbstactResource which contains all common logic, and it's respectively extended by all other resources which add their required custom methods.
public class AbstractResource<T> {
#GET
public ListPage<T> list(#QueryParam("limit") Integer limit,
#QueryParam("start") Integer start) {
// ... implementation
}
#GET
#Path("/{id}")
public T get(#PathParam("id") Long id) {
// ... implementation
}
And sample resource looks like:
public class TenantResource extends AbstractResource<Tenant> {
// custom resource related methods here
}
Everything works fine in this case. The problems appear when I add one more level of abstraction. Let's say if I want to store history and changelogs only for some of my resources. I've created one more abstract class extending AbstractResource called AudiatableResource which adds the required functionality.
public abstract class AuditableResource<T extends AuditableModel>
extends AbstractResource {
// here I override update and create methods to save changelogs
}
As you see the type parameter in this case has changed (now it extends AuditableModel).
New concrete resources will look like:
public class PropertyResource extends AuditableResource<Tenant> {
// custom resource related methods here
}
In this case everything still works, but this time I'm getting lots of warning messages on start-up:
WARNING: Return type T of method public T com.pkg.AbstractResource.get(java.lang.Long) is not resolvable to a concrete type
WARNING: Return type T of method public T com.pkg.AbstractResource.getNew() is not resolvable to a concrete type
WARNING: Return type com.pkg.data.ListPage<T> of method public com.pkg.ListPage<T> com.pkg.AbstractResource.list(java.lang.Integer,java.lang.Integer) is not resolvable to a concrete type
I really wonder if this approach is correct using Jersey and if I can just ignore this messages. It would be interesting to know how resources are organized in cases when there are large number of them.
One way to go is to separate the definition of the resources from the implementation.
Have very simple resource classes, defining the different services you want to offer. This way, the API you expose through rest is easily located and audited. The different methods are probably delegates to an implementation class
Implement the business logic of your resources in the implementations, where you might want to use inheritance to factor common behavior.
The reason you get those messages at runtime is that jersey uses runtime information about types in the resource. Generic type information being erased at compile time, it cannot get the actual return type of the generic class methods. If you provide a REST "facade" to your implementation, you can make this explicit.
public class Facade {
private final PropertyResource propertyResource;
public Facade() {
propertyResource = new PropertyResource();
}
#GET
#Path("somepath")
public Tenant something() {
return propertyResource.something();
}
}

Categories

Resources