I'm using Sitebricks with Guice to implement REST service and I have a set of methods like this:
#Get
#At("/:version/har/mostRecentEntry/assertResponseTimeWithin")
public Reply<?> doSomething(#Named("version") int version, Request<String> request) {
// Validation logic for request parameters ...
// Extracting parameters (converting url params to domain area objects)
// Actual business logic
}
Which leads to a lot of copy/pasted code.
I'm looking for some way to separate common validating & extracting data logic from request parameters. Probably I can use AOP to do it, but maybe there's easier way Sitebricks provides?
A few considerations:
Google's Sitebricks project is dead
official site is down (sitebricks.org)
last Github commit - 2015
My recommendation is to not build anything with that framework.
You should definitely consider alternatives for implementing REST services (e.g. SpringBoot).
maybe there's easier way Sitebricks provides?
That being said, Sitebricks doesn't seem to offer validation out of the box.
The code you can find related to validation in Sitebrick is:
#ImplementedBy(AlwaysValidationValidator.class)
public interface SitebricksValidator {
Set<? extends ConstraintViolation<?>> validate(Object object);
}
and this:
public class AlwaysValidationValidator implements SitebricksValidator {
#Override
public Set<? extends ConstraintViolation<?>> validate(Object object) {
return null; //unfinished
}
}
This is unfinished implementation!
Your best option is to use javax validation in a standalone setup.
This includes hibernate-validator + javax expression language - reference implementation of JSR 380. It has a lot of build in constraints (e.g. #NotNull, #Size etc.) and is extensible - you can create your own constraints implementing the right interfaces (the AOP part is handled by the framework).
A more simple alternative is Guava's PreConditions.
Related
I'm still quite new to microservices and have a few basic architectural questions that I can't get solved right now.
I'm using the Quarkus framework with the standard extensions like quarkus-resteasy and quarkus-rest-client for the realization.
The scenario:
I have an example of a "Persistence" service that I want to externally populate with data via a REST call in a dedicated Maven project.
#Path("/api/persistence")
#Products(MediaType.APPLICATION_JSON)
public class Persistence{
#Inject
EntityManager entityManager;
#POST
#Transactional
public Response create(PostDto postDto) {
Post post = toPostMapper.toResource(postDto);
entityManager.persist(post);
return Response.ok(postDto).status(201).build();
}
}
At the same time I would like to have a microservice DataGenerator which generates the corresponding data and passes it to the Persistence Service.
My problem : API sharing
Both services were created as Maven projects.
According to the tutorials I found the correct way would be to declare an interface (here called PersistenceApi) in the DataGenerator project like this
#Path("/api/persistence")
#Products(MediaType.APPLICATION_JSON)
#RegisterRestClient
public interface PersistenceApi {
#POST
#Transactional
public Response create(PostDto post) ;
}
This interface is then integrated into the DataGenerator service via #Inject, which leads to the following exemplary service.
#RequestScoped
#Path("/api/datagenerator")
#Products("application/json")
#Consumes("application/json")
public class DataGenerator{
#Inject
#RestClient
PersistenceApi persistenceApi
#POST
public void getPostExamplePostToPersistence() {
PostDto post = new PostDto();
post.setTitle("Find me in db in persistence-service")
persistenceApi.create(post);
}
}
I have the PersistenceService running locally on port 8181 and have added the following entry in the application.properties of the DataGenerator project so that the service can be found.
furnace.collection.item.service.PersistenceApi/mp-rest/url=http://localhost:8181
furnace.collection.item.service.PersistenceApi/mp-rest/scope=javax.inject.Singleton
I find it "wrong" to declare the interface in my DataGenerator, because at this point I don't notice when the api provided by the Persistence service changes. Accordingly one could come up with the idea to position the interface in the Persistence service, which is then implemented by my concrete Persistence implementation and leads to the following code.
#Path("/api/persistence")
#Products(MediaType.APPLICATION_JSON)
#RegisterRestClient
public class PersistenceApiImpl implements PersistenceApi {
#Inject
EntityManager entityManager;
#POST
#Transactional
public Response create(PostDto fruit) {
Post post = toPostMapper.toResource(fruit);
entityManager.persist(post);
return Response.ok(fruit).status(201).build();
}
}
In order to use them in my DataGenerator project, I would have to include the Persistence project as a dependency in my DataGenerator project, which sounds like a "monolith with extra steps" to me and therefore feels wrong in terms of "separation of concerns".
I have tried the following approach:
I created another Maven project called PersistenceApi which only contains the corresponding PersistenceApi. This PersistenceApi project was then included as a dependency in both the "Persistence" and "DataGenerator" projects. In the "Persistence"-Project I implement the service from the example above and try to address the corresponding interface in the "DataGenerator"-Project via #Inject.
Unfortunately this does not work. When I'm building the service, I get the message that the required dependency PersistenceApi, which I want to include via #Inject in the DataGenerator service, cannot be injected in the form of an UnsatisfiedResolutionException.
Now my questions:
I don't see what I'm missing here. Could you help me?
Is this kind of API-sharing with dedicated Api projects a viable way or is the "monolith with extra steps" approach really the way to go?
Thank you in advance.
Thats a common problem with microservices. Like in the book "Microservices: Grundlagen flexibler Softwarearchitekturen" by Eberhard Wolff (I saw that you are German too) i follow the idea that microservices should have the same coupling like the teams developing them and like the organization your developing it for(have a look at Conway's law). Therefore services of mostly independent teams should be developed independly and the api changes of one service should not affect another at the time of the update.
If you develop both services in your team then i think you can couple them the way you are doing it because you dont have to work together with other teams and there will be no huge overhead. Note that you will be forced to release both services together. If that is always ok for you then save your time and do it your way, if not have a look at API-Versioning:
I use api versioning so the old api is still reachable under "v1/" and the new one under "v2/". This way the team behind the other microservice has enough time to update their service.
Have a look at Domain-driven Design for different ways of integrating bounded contexts (=services) and the coupling consequences. Without API-Versioning you are forced to a partnership and you need to release together. Maybe you prefer Customer-Supplier or even conformist.
To test compatibility between both services have a look at consumer driven contracts and Pact. You can also generate open api files and track their changes but that will only help to notify people about changes.
I'm designing software with different components, that need to communicate with each other through a REST interface.
I've seen and implemented solutions, where the different components of the software (deployed on the same cluster) would communicate by declaring and injecting EJB beans. This way, it's really easy to standardize the communication by defining common interfaces and DTOs in a separate .jar dependency.
This level of comfort and standardization is what I'd like to achieve with RESTful services, between Java-based components of my software.
Imagine something like this:
Let's say, I have a REST Client (C) and a REST Server (S).
I'd like to be able to communicate between them, via a common interface, which is implemented in S and called by C. This common interface is in an API component (I).
It would mean that I would have an interface:
#RestController
#RequestMapping("/rest/user")
public class UserController {
#GetMapping("list")
ResponseEntity<List<UsersModel>> getUserList(OAuth2LoginAuthenticationToken token);
}
In C it could be used like:
public class Sg {
private final UserController userController;
...
public void method(OAuth2LoginAuthenticationToken token) {
...
userController.getUserList(token);
...
}
}
Lastly, in S:
public class UserControllerImpl implements UserController {
#Override
public ResponseEntity<List<UsersModel>> getUserList(OAuth2LoginAuthenticationToken token) {
...
}
}
The only configuration needed is to tell the client the context root (and host address) of the server, everything else is present in the common interface in the form of annotations.
Since not all components are necessarily Java-based, it is important for the REST resource to be callable in a typical REST-like way, so those Java remote service calling mechanics are out of consideration.
I was looking into JAX-RS, which seems promising, but is missing a couple of features that would be nice. For example, there isn't a common interface telling the client which endpoint on the server can the REST resource be found, neither are the method names, etc. AFAIK, on the client, you can only call the method representing the HTTP method of the request, which is a bummer.
Am I out of my mind with this spec? I'm not really experienced with REST services yet, so I don't really know if I'm speaking of something that is out of the REST services scope. Is there an already existing solution to the problem I face?
After more thorough research, I found that RESTeasy already has a solution for this.
You need to use the ProxyBuilder to create a proxy of your interface and that's it.
We have several legacy java-services with RMI-api, implemented by the old JRMP approach requiring 'rmic' pre-compilation.
As part of migrating everything to latest JDK,
I am also trying to rewrite the RMI stuff to the more current approach, where the implementation-classes extend from UnicastRemoteObject, thus getting rid of the rmic pre-compilation step.
Following a simple example, like here:
https://www.mkyong.com/java/java-rmi-hello-world-example/
but I have not been able to find such example with commit/rollback transaction-logic.
In the current legacy-code, all transaction-logic is handled in a single, common method invokeObject() in the JRMP container-code that will intercept all RMI api-calls in one place,
and will simply commit if the RMI-call is successful, or rollback if an Exception was thrown.
I haven't been able to figure out how to do this in the new approach with no JRMP container present.
Obviously, I do not want to code commit/rollback-logic into every single api-method (there are many dozens of them),
but still keep that uniform logic in one place.
Any advice, hints, references, etc, how to intercept all RMI-calls in a single point to implement the transaction-logic?
To begin with, I agree with #df778899 the solution he provides is a robust solution. Although,I will give you an alternative choice if you don't want to work with spring framework and you want to dig it further.
Interceptors provide a powerful and flexible design include invocation monitoring, logging, and message routing. In some sense, the key value you are looking is a kind of RMI-level AOP (aspect-oriented programming) support
Generally speaking:
it is not fair to ask RMI to directly support such capabilities as it
is only a basic remote method invocation primitive, while CORBA ORB is
at a layer close to what the J2EE EJB (Enterprise JavaBean) container
offers. In the CORBA specification, service context is directly
supported at the IIOP level (GIOP, or General Inter-Orb Protocol) and
integrated with the ORB runtime. However, for RMI/IIOP, it is not easy
for applications to utilize the underlying IIOP service-context
support, even when the protocol layer does have such support. At the
same time, such support is not available when RMI/JRMP (Java Remote
Method Protocol) is used. As a result, for RMI-based distributed
applications that do not use, or do not have to use, an ORB or EJB
container environment, the lack of such capabilities limits the
available design choices, especially when existing applications must
be extended to support new infrastructure-level functions. Modifying
existing RMI interfaces often proves undesirable due to the
dependencies between components and the huge impact to client-side
applications. The observation of this RMI limitation leads to the
generic solution that I describe in this article
Despite all the above
The solution is based on Java reflection techniques and some common
methods for implementing interceptors. More importantly, it defines an
architecture that can be easily integrated into any RMI-based
distributed application design.
The solution below is demonstrated through an example implementation that supports the transparent passing of transaction-context data, such as a transaction ID (xid), with RMI. The solution contains the following three important components:
RMI remote interface naming-function encapsulation and interceptor plug-in
Service-context propagation mechanism and server-side interface support
Service-context data structure and transaction-context propagation support
The implementation assumes that RMI/IIOP is used. However, it by no
means implies that this solution is only for RMI/IIOP. In fact, either
RMI/JRMP or RMI/IIOP can be used as the underlying RMI environments,
or even a hybrid of the two environments if the naming service
supports both
Naming-function encapsulation
First we encapsulate the naming function that provides the RMI remote
interface lookup, allowing interceptors to be transparently plugged
in. Such an encapsulation is always desirable and can always be found
in most RMI-based applications. The underlying naming resolution
mechanism is not a concern here; it can be anything that supports JNDI
(Java Naming and Directory Interface). In this example, to make the
code more illustrative, we assume all server-side remote RMI
interfaces inherit from a mark remote interface ServiceInterface,
which itself inherits from the Java RMI Remote interface. Figure
shows the class diagram, which is followed by code snippets that I
will describe further
RMI invocation interceptor
To enable the invocation interceptor, the original RMI stub reference
acquired from the RMI naming service must be wrapped by a local proxy.
To provide a generic implementation, such a proxy is realized using a
Java dynamic proxy API. In the runtime, a proxy instance is created;
it implements the same ServiceInterface RMI interface as the wrapped
stub reference. Any invocation will be delegated to the stub
eventually after first being processed by the interceptor. A simple
implementation of an RMI interceptor factory follows the class diagram
shown in Figure
package rmicontext.interceptor;
public interface ServiceInterfaceInterceptorFactoryInterface {
ServiceInterface newInterceptor(ServiceInterface serviceStub, Class serviceInterfaceClass) throws Exception;
}
package rmicontext.interceptor;
public class ServiceInterfaceInterceptorFactory
implements ServiceInterfaceInterceptorFactoryInterface {
public ServiceInterface newInterceptor(ServiceInterface serviceStub, Class serviceInterfaceClass)
throws Exception {
ServiceInterface interceptor = (ServiceInterface)
Proxy.newProxyInstance(serviceInterfaceClass.getClassLoader(),
new Class[]{serviceInterfaceClass},
new ServiceContextPropagationInterceptor(serviceStub)); // ClassCastException
return interceptor;
}
}
package rmicontext.interceptor;
public class ServiceContextPropagationInterceptor
implements InvocationHandler {
/**
* The delegation stub reference of the original service interface.
*/
private ServiceInterface serviceStub;
/**
* The delegation stub reference of the service interceptor remote interface.
*/
private ServiceInterceptorRemoteInterface interceptorRemote;
/**
* Constructor.
*
* #param serviceStub The delegation target RMI reference
* #throws ClassCastException as a specified uncaught exception
*/
public ServiceContextPropagationInterceptor(ServiceInterface serviceStub)
throws ClassCastException {
this.serviceStub = serviceStub;
interceptorRemote = (ServiceInterceptorRemoteInterface)
PortableRemoteObject.narrow(serviceStub, ServiceInterceptorRemoteInterface.class);
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
// Skip it for now ...
}
}
To complete the ServiceManager class, a simple interface proxy cache is implemented:
package rmicontext.service;
public class ServiceManager
implements ServiceManagerInterface {
/**
* The interceptor stub reference cache.
* <br><br>
* The key is the specific serviceInterface sub-class and the value is the interceptor stub reference.
*/
private transient HashMap serviceInterfaceInterceptorMap = new HashMap();
/**
* Gets a reference to a service interface.
*
* #param serviceInterfaceClassName The full class name of the requested interface
* #return selected service interface
*/
public ServiceInterface getServiceInterface(String serviceInterfaceClassName) {
// The actual naming lookup is skipped here.
ServiceInterface serviceInterface = ...;
synchronized (serviceInterfaceInterceptorMap) {
if (serviceInterfaceInterceptorMap.containsKey(serviceInterfaceClassName)) {
WeakReference ref = (WeakReference) serviceInterfaceInterceptorMap.get(serviceInterfaceClassName);
if (ref.get() != null) {
return (ServiceInterface) ref.get();
}
}
try {
Class serviceInterfaceClass = Class.forName(serviceInterfaceClassName);
ServiceInterface serviceStub =
(ServiceInterface) PortableRemoteObject.narrow(serviceInterface, serviceInterfaceClass);
ServiceInterfaceInterceptorFactoryInterface factory = ServiceInterfaceInterceptorFactory.getInstance();
ServiceInterface serviceInterceptor =
factory.newInterceptor(serviceStub, serviceInterfaceClass);
WeakReference ref = new WeakReference(serviceInterceptor);
serviceInterfaceInterceptorMap.put(serviceInterfaceClassName, ref);
return serviceInterceptor;
} catch (Exception ex) {
return serviceInterface; // no interceptor
}
}
}
}
You can find more details in the following guideline here. It is important to understand all this above if you desire to make it from scratch, in contrast with Spring-AOP Framework robust solution.In addition,I think you will find very interesting the Spring Framework plain source code for implementing an RmiClientInterceptor. Take another look here also.
You might consider using Spring with RMI. It offers a simplified way to use transactions. You just set some persistence settings from the #EnableTransactionManagement annotation and it manages transactions for you at a point defined by #Transactional. It can be a class or methods of a class.
example code here
The explanation is in the project README.
I don't know if you've already considered this, one possibility that would fit well with the dual requirement of RMI and transactional boundaries is clearly Spring. An example of Spring Remoting is here.
The #Transactional annotation is very widely used for declarative transaction management - Spring will automatically wrap your bean in an AOP transaction advisor.
These two would then fit together well, for example with a single transactional bean that could be exported as a remote service.
The Spring Remoting link above is based around Spring Boot, which is an easy way to get started. By default Boot would want to bring in an embedded server to the environment, though this can be disabled. Equally there are other options like a standalone AnnotationConfigApplicationContext, or a WebXmlApplicationContext within an existing web application.
Naturally with a question asking for recommendations, there will an element of opinion in any reply - I would be disappointed not to see some other suggestions shortly.
This one seems relatively straightforward. I'm messing around with composed annotations, and I'm trying to do the following:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Path("")
public #interface TestAnnotation {
#AliasFor(annotation = Path.class, attribute = "value")
String path();
}
This does not work. When I use it like so:
#Path("")
public class MyResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#TestAnnotation(path = "/things")
public void postIt(Thing myThing) {
// Do various things and then return a Response
}
}
...I receive a 405 in return. If I do this:
// Remove class-level #Path
// #Path("")
public class MyResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#TestAnnotation(path = "/things")
public void postIt(Thing myThing) {
// Do various things and then return a Response
}
}
...I receive a 404 in return.
There is just something about #Path or the fact that #Path has a required value attribute that results in this just not functioning, and I have no idea how to remedy it.
After further experimentation and research, it would appear that what I am trying to do is literally not possible.
A follow-up attempt was made to utilize Jackson's #JsonView and expose it through my composed annotation via Spring's #AliasFor, and this also failed to function.
I spent some time thinking about how annotations work and considering peeskillet's comments about compilation vs. processing, and I have come to the conclusion that both Jersey and Jackson must use annotation processors that basically just call "Method.isAnnotationPresent()" for detection of relevant annotations. Spring's #AliasFor most likely does not compile nor weave the aliased meta-annotations into the byte-code of the target methods, and thus they are not found by the processors.
My personal solution to this problem was to drop JAX-RS entirely and use Spring's #RequestMapping, which can be aliased in a composed annotation, and to just accept that Jackson's #JsonView simply can't be integrated into a composed annotation.
Obviously, this is not an ideal solution for most people, especially those with large, already established systems. In such situations, it is more likely that the idea of composed annotations will be abandoned long before JAX-RS.
So if anyone has some more insight into the problem, or someone directly from the Spring team wants to chime in, feel free.
Essentially, I have a MessageBodyWriter that writes objects as JSON, and I'd like to be able to control some aspects of the output based on which resource method handled the request. However, the default lifecycle of #Provider classes is singleton (one per JVM), so I can't inject an instance of some configuration object. This leaves me with 2 obvious workarounds:
Use custom annotations: Each call to writeTo(...) includes the list of annotations on the method that was invoked, so I could check for the existence of some annotation. However, JAX-RS methods are already pretty laden with metaprogramming.
Use a ThreadLocal property map: Assuming one request per thread, but this approach breaks encapsulation a bit. The resource methods needs to be aware that there is some other class out there, looking for this map.
Is there a way to change the lifecycle of the Provider itself? I am using Jersey.
Not sure why you need a MessageBodyWriter Provider with per-request basis. If you just want to distinguish which methods are with JSON ouput and which are not, then jersey-json does already support.
And although the #Provider is singleton. You still can use per-request object within it like below.
#Provider
public class StViewProcessor implements ViewProcessor<ST> {
......
#Context
HttpServletRequest request;
public void writeTo(ST st, Viewable viewable, OutputStream out)
throws IOException {
System.out.println(request.getRequestURI());
...
}
}
And if you want to inject your instance per request, you can have a look at PerRequestTypeInjectableProvider. Here is a link about it.
The JAX-RS 1.1 spec requires that implementations support singleton providers and allows support for other lifecycles but doesn't suggest anything else along those lines. As far as I'm aware, pure Jersey doesn't support anything beyond singletons. With the jersey-spring contrib module, you get support for using Spring as Jersey's IoC container (where it gets its resource and provider instances from). I know Spring supports multiple lifecycles, including request, but I'm not sure if support for that is built into jersey-spring.