I've been trying in the last couple of days to setup an embedded Undertow server, with JAX-RS, using RestEasy, and CDI using weld.
No matter what I do, nothing seems to work.
I've read through every possible answer, and demo available I could find; Nothing worked!
The JAX-RS resource:
#Path("/")
#Produces(MediaType.TEXT_PLAIN)
#RequestScoped
public class EchoResource {
#Inject
#Named("upperCase")
private UpperCaseTextProcessing upperCaseTextProcessing;
#Inject
#Named("lowerCase")
private LowerCaseTextProcessing lowerCaseTextProcessing;
#Inject
BeanManager manager;
#GET
public void greet( #Suspended AsyncResponse response, #BeanParam Aggregator queryParams ) {
final Response.ResponseBuilder responseBuilder = Response.ok();
if ( queryParams.async ) {
CompletableFuture.runAsync( () -> {
try {
Thread.sleep( 1500 );
}
catch ( InterruptedException e ) {
e.printStackTrace();
}
responseBuilder.entity( upperCaseTextProcessing.processText( queryParams.message ) );
response.resume( responseBuilder.build() );
} );
}
else {
responseBuilder.entity( upperCaseTextProcessing.processText( queryParams.message ) );
response.resume( responseBuilder.build() );
}
}
public static class Aggregator {
#QueryParam("async")
public boolean async;
#QueryParam("msg")
public String message;
#QueryParam("lower")
#DefaultValue("false")
public boolean lower;
}
}
The "UpperCaseTextProcessing" bean:
#ApplicationScoped
#Named( "upperCase" )
public class UpperCaseTextProcessing implements TextProcessing {
public UpperCaseTextProcessing() {}
#Override
public String processText( String text ) {
return text.toUpperCase();
}
}
I've used http://docs.jboss.org/weld/reference/latest/en-US/html/environments.html#_undertow as a reference
and the injection there works, but there are two things which make this example partially ok for me
The example there is using a simple HttpServlet, and not a proper JAX-RS servlet.
The "BeanManager" is injected, but trying to inject my own object fails miserably (used with #ApplicationScope)
I've setup a complete repo, with tests to ease to process of helping point me to my error.
https://github.com/eladchen/rest-easy-cdi
For bonus points, I've been wondering if it is possible to work with Weld in both contexts SE and EE, and if so, how?
Related
I am writing a Spring Boot Application. I want to audit methods with my annotation #AuditMetod: For example I have method foo() with the annotation:
#AuditMetod(name = "SomeValue")
foo() {...}
I want to handle and audit such methods like this (the simplest example):
auditMethod(Method method) {
if (method.hasAnnotation(AuditMethod.class)) {
System.out.println (method.getName() + " was called at " + new Date())
}
}
upd
Thanks to #Karthikeyan #Swapnil Khante and #misha2048 I understood, that I need to use AOP. But I have 2 problems:
The only method in Aspect class in not being called and I don't see the inscription "----------ASPECT METHOD IS CALLED-----------" in log
How can I check in aspect method what method it is intercepting. To get an instance of Method class.
Now I have the following code:
Controller:
#PostMapping
#LoggingRest(executor = "USER", method = "CREATE", model = "SUBSCRIPTION")
public ResponseEntity<?> create(#Valid #RequestBody SubscriptionRequestDto dto) {
...
}
Aspect:
`#Aspect
#Slf4j
#Component
public class AuditAspect {
#Pointcut(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
log.info("----------ASPECT METHOD IS CALLED------------");
}`
And annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface LoggingRest {
String executor() default "SYSTEM";
String method() default "";
String model() default "";
}
Auditing is a cross-cutting concern and can be handled using AOP.
Another solution would be to use a low-level solution by writing a custom annotation and using a Spring interceptorto write your business logic.
To use the Spring interceptor you will need to implement the HandlerInterceptor interface
Example of the annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Audit {
boolean active() default true;
}
Interceptor example
#Component
public class AuditInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Audit annotation = handlerMethod.getMethodAnnotation(Audit.class);
if (annotation != null && annotation.active()) {
// your business logic
}
}
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
check this interceptor example
I think one of the solutions here, as #Karthikeyan mentioned, is to use Spring AOP.
If you are not aware a brief introduction - spring-aop module implements the aspect oriented programming paradigm. We extract some common functionality, that we generally want to apply to some subset of functions/methods, to an entity called Aspect (see class annotated with #Aspect). This class will contain out cross-cutting functionality - such as auditing, for instance we want to audit the methods execution time, lets say. We just put the code to be executed, the condition, which tell the spring what exact beans methods should be affect by this aspect, see below.
For example, if I can audit the method execution duration with the following very simple example (in my case I said that any public method, returning void inside the Class com.example.stackoverflow.BusinessLogicClass must be inspected by this Aspect):
#SpringBootApplication
#EnableAspectJAutoProxy
public class StackoverflowApplication implements ApplicationRunner {
#Autowired
private BusinessLogicClass businessLogicClass;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
businessLogicClass.test();
}
}
#Aspect
#Component
class MyAspectLogicClass {
#Around("execution(public void com.example.stackoverflow.BusinessLogicClass.*(..))")
public Object hangAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long before = System.currentTimeMillis();
Object returnedValue = proceedingJoinPoint.proceed();
long after = System.currentTimeMillis();
System.out.printf("Retruned in '%s' ms %n", (after - before));
return returnedValue;
}
}
#Component
class BusinessLogicClass {
public void test() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
In my case, I will get the time before method execution, then by the means of
proceedingJoinPoint.proceed() call I delegate the execution to the real method, and then, once I get the response back, I will get the current system time and calculate the execution time, fairly simple.
I hope I have at least directed you somewhere, if you are looking for documentation, this are the resources I suggest you should look for:
https://docs.spring.io/spring-framework/docs/2.5.x/reference/aop.html offical spring doc (stale a bit, but there are some valuable things to learn)
https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html is more fresh doc
Hope it helped :)
The problem was in right annotation. In Aspect class I tried #Around and everything works as I need.
#Aspect
#Slf4j
#Component
public class AuditAspect {
#Around(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
var method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
log.info("----------ASPECT METHOD IS CALLED------------");
}
}
For getting a Method instance I use fallowing code
Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
I'm writing a service that needs to use a different database depending on context (a simple string label). Each database has exactly the same schema. The list of databases is dynamic.
Looking through MyBatis-Guice documentation on multiple data sources, the example is where the list of datasources are known upfront, and each datasource has a different mapper. Similarly, a question found here on SO assumes the same requirements.
As stated, my requirements are much more dynamic and fluid. The idea is to have all the currently known databases (with their connection information) in a config and have that parsed at service startup. Then, dependent upon the context of any incoming requests, the code should pull the SqlSessionFactory for the correct database. All downstream code that uses that SqlSessionFactory is exactly the same - i.e. not dependent on request context. Which means the same mappers are used no matter what database is required.
My MyBatis and Guice knowledge is admittedly very new and limited. However, I've not been able to google anything that shows the MyBatis-Guice equivalent to the multiple environment approach supported by the XML configuration of MyBatis.
I managed to come up with a solution that works for me, so thought I'd share it here. The decision to use Guice had already been made, so there was no wriggle room there.
First, I wrote a MyBatis Guice module for registering a single datasource. It is a PrivateModule so that all the MyBatis classes that get registered for one datasource do not conflict with other registrations for other datasources. It makes use of an internal MyBatisModule implementation because Java doesn't support multiple inheritance. Meaning we can't do public class MyMyBatisModule extends PrivateModule, MyBatisModule {...}.
public class MyMyBatisModule extends PrivateModule {
private final String datasourceLabel;
private final Properies datasourceProperties;
private List< Key<?> > exposedKeys = new ArrayList< Key<?> >();
public MyMyBatisModule( String datasourceLabel, Properties datasourceProperties ) {
this.datasourceLabel = datasourceLabel;
this.datasourceProperties = datasourceProperties;
}
#Override
protected void configure() {
install( new InternalMyMyBatisModule( ) );
for( Key<?> key: keys ) {
expose( key );
}
}
private class InternalMyMyBatisModule extends MyBatisModule {
#Override
protected void initialize( ) {
environmentId( datasourceLabel );
Names.bindProperties( binder(), properties );
install( JdbcHelper.MySQL ); // See JDBC Helper commentary below
bindDataSourceProviderType( C3p0DataSourceProvider.class ); // Choose whichever one you want
bindTransactionFactoryType( JdbcTransactionFactory.class );
// Register your mapper classes here. These mapper classes will have their
// keys exposed from the PrivateModule
//
// i.e.
//
// keys.add( registerMapper( FredMapper.class );
// kets.add( registerMapper( GingerMapper.class );
}
private <T> Key<T> registerMapper( Class<T> mapperClass ) {
Key<T> key = Key.get( mapperClass, Names.named( datasourceLabel ) );
bind( key ).to( mapperClass );
addMapperClass( mapperClass );
return key;
}
}
}
JdbcHeler.MySQL: I've used JdbcHelper.MySQL as a shortcut to map properties to the connection string, and use com.mysql.jdbc.Driver as the JDBC driver. It's declared as:
MySQL("jdbc:mysql://${JDBC.host|localhost}:${JDBC.port|3306}/${JDBC.schema}", "com.mysql.jdbc.Driver"),
Now it's time to register all your datasources. MyBatisModules handles this for us. It requires a map of datasourceLabel to jdbc properties.
public class MyBatisModules extends AbstractModule {
private Map< String, Properties > connectionsProperties;
public MyBatisModules( Map< String, Properties > = new HashMap< String, Properties > connectionsProperties ) {
this.connectionsProperties = connectionsProperties; // consider deep copy if appropriate
}
#Override
protected void configure( ) {
for( Entry< String, Properties > datasourceConnectionProperties : this.connectionsProperties.entrySet() ) {
install( new MyMyBatisModule( datasourceConnectionProperties.getKey(), datasourceConnectionProperties.getValue() ) );
}
bind( MapperRetriever.class ); // See MapperRetriever later
// bind your DAO classes here. By wrapping MyBatis Mapper use in DAO implementations, theoretically we
// can fairly easily change from MyBatis to any other database library just by changing the DAO implementation.
// The rest of our codebase would remain the same.
//
// i.e.
//
// bind( FredDao.class ).to( FredDaoMyBatis.class );
// bind( GingerDao.class).to( GingerDaoMyBatis.class );
}
}
Now we just need some way of getting the right Mapper class (which itself is associated with the right datasource). To do this, we actually need to call a method on the Guice Injector. I don't really like the idea of passing that around, so I wrapped it in MapperRetriever. You need to implement a retrieval method for each of your Mappers.
public class MapperRetriever {
private final Injector injector;
#Inject
public MapperRetriver( Injector injector ) {
this.injector = injector;
}
// The follwing two methods use the example Mappers referenced in the MyMyBatisModule implementation above
public FredMapper getFredMapper( String datasourceLabel ) {
return this.injector.getInstance( Key.get( FredMapper.class, Names.named( datasourceLabel ) ) );
}
public GingerMapper getGingerMapper( String datasourceLabel ) {
return this.injector.getInstance( Key.get( GingerMapper.class, Names.named( datasourceLabel ) ) );
}
}
And an example DAO implementation ...
public interface FredDao {
Fred selectFred( String datasourceLable, String fredId );
}
public class FredDaoMyBatis implements FredDao {
private MapperRetriever mapperRetriever;
#Inject
public FredDaoMyBatis( MapperRetriever mapperRetriever ) {
this.mapperRetriever = mapperRetriever;
}
#Override
public Fred selectFred( String datasourceLabel, String fredId ) {
FredMapper fredMapper = this.mapperRetriever.getFredMapper( datasourceLabel );
return fredMapper.getFred( fredId );
}
}
You can also create a custom SqlSessionFactoryProvider which returns a SqlSessionFactory which delegates to the correct DataSource's SqlSessionFactory. Using a ThreadLocal to determine the underlying SqlSessionFactory.
public class DelegatingSqlSessionFactory implements SqlSessionFactory {
private final Map<String, SqlSessionFactory> factories = new HashMap<>();
public DelegatingSqlSessionFactory(Map<String, DataSource> dataSources) throws ClassNotFoundException {
dataSources.forEach((key, ds) -> {
factories.put(key, createSqlSessionFactory(ds));
});
}
private SqlSessionFactory delegate() {
// Read from a ThreadLocal to determine correct SqlSessionFactory key
String key = findKey();
return factories.get(key);
}
#Override
public SqlSession openSession() {
return delegate().openSession();
}
#Override
public SqlSession openSession(boolean autoCommit) {
return delegate().openSession(autoCommit);
}
#Override
public SqlSession openSession(Connection connection) {
return delegate().openSession(connection);
}
#Override
public SqlSession openSession(TransactionIsolationLevel level) {
return delegate().openSession(level);
}
#Override
public SqlSession openSession(ExecutorType execType) {
return delegate().openSession(execType);
}
#Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return delegate().openSession(execType, autoCommit);
}
#Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return delegate().openSession(execType, level);
}
#Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return delegate().openSession(execType, connection);
}
#Override
public Configuration getConfiguration() {
return delegate().getConfiguration();
}
}
I know we can map a servlet at runtime since servlet api 3.0, that can be achieved as below:
#Override
public void contextInitialized( ServletContextEvent sce ) {
ServletContext sc = sce.getServletContext();
String servletMapping = "/yourURL";
ServletRegistration sr = sc.addServlet( servletMapping, "org.yourdomain.yourclass" );
sr.setInitParameter( "key", "value" );
sr.addMapping( servletMapping );
}
Is there a similar way of doing this with websockets (using javax.websockets.api)?
The Websocket equivalent of ServletContainerInitializer is the ServerApplicationConfig. It only doesn't require a services file, the Websocket API will proactively scan the WAR and JARs in WAR for any classes implementing ServerApplicationConfig interface and use them. You can in getEndpointConfigs() use ServerEndpointConfig.Builder to programmatically build a Websocket endpoint and return it.
Here's a kickoff example, given that YourEndpoint.class represents the Websocket endpoint you'd like to programmatically add, and you'd like to ignore any scanned classes.
public class YourServerApplicationConfig implements ServerApplicationConfig {
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> scannedClasses) {
Set<ServerEndpointConfig> configs = new HashSet<>();
configs.add(ServerEndpointConfig.Builder.create(YourEndpoint.class, "/yourPath").build());
return configs;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scannedClasses) {
return Collections.emptySet();
}
}
I'm designing my REST application architecture using Domain Driven Design and Adapter patter (there are interfaces, and many implementations in the aggregate root). It's all fine as long as don't add HATEOAS to the puzzle. In HATEOAS my value objects (on the bottom of dependency hierarchy) need to depend on resources (in the top layer). This messes up everything. I'm fairly new to HATEOAS so maybe I'm missing something. I'm planning to use Dropwizard and Jersey Declarative Linking.
Here is a diagram of my architecture:
Little clarification - this "Return and attributes types" between interfaces and value objects should actually be "Return and argument types" - It means, that all the interfaces' methods take objects from Value objects module as an arguments and return those objects to the caller.
I can add a piece of code that will show you what's in what module:
REST - JAX-RS Resources
#Component
#Path("/groups")
#Produces(MediaType.APPLICATION_JSON)
public class GroupsResource {
#Autowired
ProcessEngine processEngine; //interface with driver implementation under it
#GET
#Timed
public List<UserGroup> getUserGroups(#Auth BpmUser user) {
return processEngine.getUserGroups(user.id);
}
}
Interface ProcessEngine
public interface ProcessEngine {
void init();
List<UserGroup> getUserGroups(String username);
}
Implementation in drivers module
public class ActivitiProcessEngine implements ProcessEngine {
private org.activiti.engine.ProcessEngine processEngine;
private DataSource dataSource;
private String databaseType;
public ActivitiProcessEngine(String databaseType, DataSource dataSource) {
this.databaseType = databaseType;
this.dataSource = dataSource;
}
#Override
public void init() {
if (processEngine != null)
throw new ProcessEngineAlreadyInitializedException();
try {
processEngine = createProcessEngineConfiguration().buildProcessEngine();
ProcessEngines.registerProcessEngine(processEngine);
} catch (SQLException e) {
throw new ProcessEngineDatabaseException(e);
}
}
#Override
public List<UserGroup> getUserGroups(String username) {
return processEngine
.getIdentityService()
.createGroupQuery()
.groupMember(username)
.list()
.stream()
.map(Group::getId)
.map(UserGroup::new)
.collect(Collectors.toList());
}
...
}
Value object
public class UserGroup {
#JsonProperty
public String name;
//I want to be able add linking to another resources here
public UserGroup(String name){
this.name = name;
}
}
Domain object should never know anything about Controller or any other application logic. So, link controllers to domain object. It will solve your dependency problem.
I have a system (Java with Spring Framework) that exposes 7 different Apache Thrift servlets over HTTP using the TServlet class. Currently they all need their own Servlets, ServletMappings, Processors, Handlers etc. so implementing clients have to also keep an internal list of all the various URLs for the different services.
I understand that Apache Thrift supports multiplexing when using TServer and its derivatives by using TMultiplexingProcessor, however since I am using Spring and my Servlet, Handler and Processor are all Spring Beans that get autowired into one another, I'm unsure how to proceed.
Here's an example of how one of the services gets wired up:
UserServiceHandler.java
#Component
public class UserServiceHandler implements UserService.Iface {
#Override
public User getUser(String userId) throws TException {
// implementation logic goes here
}
}
UserServiceProcessor.java
#Component
public class UserServiceProcessor extends UserService.Processor<UserServiceHandler> {
private UserServiceHandler handler;
#Autowired
public UserServiceProcessor(UserServiceHandler iface) {
super(iface);
handler = iface;
}
public UserServiceHandler getHandler() {
return handler;
}
public void setHandler(UserServiceHandler handler) {
this.handler = handler;
}
}
UserServiceServlet.java
#Component
public class UserServiceServlet extends TServlet {
private UserServiceProcessor processor;
#Autowired
public UserServiceServlet(UserServiceProcessor p) {
super(p, new TBinaryProtocol.Factory());
processor = p;
}
}
Servlet Registration
ServletRegistration.Dynamic userService = servletContext.addServlet("UserServiceServlet", (UserServiceServlet) ctx.getBean("userServiceServlet"));
userService.setLoadOnStartup(1);
userService.addMapping("/api/UserService/*");
// This same block repeated 7 times for each *ServiceServlet with different mappings
I would like to have all 7 service handlers map to a single URL like /api/*. Is this even possible? I suppose I would have to create a single servlet and processor, but I'm unsure what they should look like. My processors extend UserService.Processor and the like.
OK, figured it out. Might not be the best way, so I welcome criticism.
Here were my rough steps:
Keep the handler classes the way they were.
Create a new class that extends TMultiplexedProcessor
Create a new class that extends TServlet
All Processors (e.g. the UserServiceProcessor have a handler property and a corresponding getter and setter
Here is my ApiMultiplexingProcessor:
#Component
public class ApiMultiplexingProcessor extends TMultiplexedProcessor {
UserServiceHandler userServiceHandler;
ReportServiceHandler reportServiceHandler;
// ... more service handlers can go here
#Autowired
public ApiMultiplexingProcessor(UserServiceProcessor userServiceProcessor, ReportServiceProcessor reportServiceProcessor) {
this.registerProcessor("UserService", userServiceProcessor);
this.registerProcessor("ReportService", reportServiceProcessor);
// add more registerProcessor lines here for additional services
userServiceHandler = userServiceProcessor.getHandler();
reportServiceHandler = reportServiceProcessor.getHandler();
// set any additional service handlers here
}
// getters and setters for the handlers
public UserServiceHandler getUserServiceHandler() {
return userServiceHandler;
}
public void setUserServiceHandler(UserServiceHandler userServiceHandler) {
this.userServiceHandler = userServiceHandler;
}
public ReportServiceHandler getReportServiceHandler() {
return reportServiceHandler;
}
public void setReportServiceHandler(ReportServiceHandler reportServiceHandler) {
this.reportServiceHandler = reportServiceHandler;
}
}
So to explain the above a bit, if you add any additional services, you need to add the *ServiceHandler classes as fields on this class, and create the getters and setters etc.
So now that we have that, we can create a new single servlet that will be added to the servlet context.
Here is my ApiServlet:
#Component
public class ApiServlet extends TServlet {
private ApiMultiplexingProcessor processor;
#Autowired
public ApiServlet(ApiMultiplexingProcessor p) {
super(p, new TBinaryProtocol.Factory());
processor = p;
}
}
And then you just add this servlet to the servlet context (from a bean) as before:
ServletRegistration.Dynamic api = servletContext.addServlet("ApiServlet", (ApiServlet) ctx.getBean("apiServlet"));
api.setLoadOnStartup(1);
api.addMapping("/api/*");
// yay now we have a single URL and a single servlet
This all could be helpful to someone else in my situation, so enjoy!
P.S. make sure when adapting your clients you use the TMultiplexedProtocol so that you can pass the service name through when talking to the server e.g.
TTransport transport = new THttpClient(new Uri("https://myapp.com/api/"));
TProtocol protocol = new TBinaryProtocol(transport);
TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "UserService");
UserService.Client userServiceClient = new UserService.Client(mp);