I'm trying to create a custom Appender that will persist logs to the database using JPA.
The thing is that I'm using PersistenceContext attribute like this
package com.foobar.logging;
import com.foobar.model.SysLog;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.MDC;
import org.apache.log4j.spi.LoggingEvent;
import javax.ejb.Stateless;
#Stateless
public class LogManager extends AppenderSkeleton {
#PersistenceContext(unitName = "primary")
private EntityManager em;
#Override
protected void append(LoggingEvent le) {
SysLog log = new SysLog();
log.setDescripcion(le.getMessage().toString());
if (MDC.get("IdUsuario") != null) {
log.setIdUsuario(MDC.get("IdUsuario").toString());
}
log.setSysAccionLog(null);
this.em.persist(log);
}
#Override
public void close() {
}
#Override
public boolean requiresLayout() {
return false;
}
}
Now when I'm deploying the WAR to JBoss AS 7.1, it fails, and I get the error:
java.lang.VerifyError: class com.foobar.logging.LogManager$Proxy$_$$_Weld$Proxy$ overrides final method getName.()Ljava/lang/String;
How can I use CDI to inject my EntityManager inside an AppenderSkeleton? Has anyone accomplished JPA persistance in an AppenderSkeleton using CDI?
I also tried not using CDI, but since every other object in my app uses it (JAX-RS classes), it collapses.
EJBs are proxies. AppenderSkeleton has a getName method that is final. I think for your use case, you need to implement Appender directly. This will avoid the bean method getName
However, I have to question the idea of trying to make an appendar an EJB. How are you instantiating it?
Related
I'm trying to print a message after the application startup with #PostConstruct, but nothing is printed.
package dev.renansouza.server;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
I have read that #PostConstruct is Lazy. Does this mean that I need to do
something else for this to work?
You can also use #EventListener annotation to acheive what you what, if using #PostConstruct is not that important to you.
For example in your case, you can add following code in any class to listen for application startup event.
#EventListener
void onStartup(ServerStartupEvent event) {
println("Hey, I work from anywhere in project..")
}
Code shared above is in Groovy
Keep in mind, the event listener added in main application class is usually called first from what I have observed.
The problem (aka feature) is, as you already mentioned, the lazy loading.
I see two solutions:
You have to do something to cause that bean to be initialized.
Change the scope of the bean from #Singleton to #Context
Micronaut has a few built-in scopes (see https://docs.micronaut.io/latest/guide/index.html#scopes) and the documentation of #Context states (see https://docs.micronaut.io/latest/api/io/micronaut/context/annotation/Context.html)
Context scope indicates that the classes life cycle is bound to that of the BeanContext and it should be initialized and shutdown during startup and shutdown of the underlying BeanContext.
Micronaut by default treats all Singleton bean definitions as lazy and will only load them on demand. By annotating a bean with #Context you can ensure that the bean is loaded at the same time as the context.
package dev.renansouza.server;
import javax.annotation.PostConstruct;
import io.micronaut.context.annotation.Context;
#Context
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
See the project at https://github.com/jeffbrown/renansouzapostconstruct.
https://github.com/jeffbrown/renansouzapostconstruct/blob/master/src/main/java/renansouzapostconstruct/ServerService.java
package renansouzapostconstruct;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
#Singleton
public class ServerService {
#PostConstruct
public void print() {
System.out.println("Hello!");
}
}
https://github.com/jeffbrown/renansouzapostconstruct/blob/master/src/main/java/renansouzapostconstruct/DemoController.java
package renansouzapostconstruct;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.HttpStatus;
#Controller("/demo")
public class DemoController {
private ServerService serverService;
public DemoController(ServerService serverService) {
this.serverService = serverService;
}
#Get("/")
public HttpStatus index() {
return HttpStatus.OK;
}
}
When you start the app you won't see the message printed to standard out because the service bean won't have been initialized. Send a request to http://localhost:8080/demo/ and then you will see the message printed to stdout.
I hope that helps.
I'm developing an SDK, which will be used to create additional applications for batch processing. There is core-a-api module, which holds interface Client
public interface Client {
void send();
}
and core-a-impl which holds couple implementations for Client interface - HttpClient and TcpClient.
Also, there is one more core module core-b-impl, which uses a particular instance of Client interface.
public class SendingTasklet implements Tasklet {
#Autowired
private Client client
public void process() {
client.send();
}
}
What instance should be created (HttpClient or SftpClient) should be decided by the user, who creates an application using SDK. He also needs to have an ability to create its own implementation for Client and use it in SendingTasklet. A user from core dependencies can see only interfaces from -api modules. For dependency injection, I'm using Spring. All beans for particular modules are created in each module separately. The user created beans are created in user's configuration class
#Configuration
public class UsersApplicationConf {
#Bean
public Client client {
return new UsersClient();
}
}
The issue is, that somehow without exposing -impl module details for user application, he should be able to decide what Client implementation can be used from the core provided implementations or he should be able to pass one of its own.
The first thought was to use qualifiers when injecting into SendingTasklet, but then you need to create a separate instance variable for each implementation in SendingTasklet and this is not very good because if there would be more implementations for Client interface it would be required to change SendingTasklet as well. And also the problem, that user should somehow decide wich implementation to use persists.
What I did, I exposed core-a-impl for client's application. So in his configuration, he can decide what instance to create for Client interface.
#Configuration
public class UsersApplicationConf {
#Bean
public Client client {
return new HttpClient();
}
}
But this is not very smart as well and I'm thinking is there any other way how to solve this issue?
You can use strategy or factory pattern as mentioned here but personally I would go with JSR 330 that you can find an example here , below code block for spring example:
package spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static spring.Spring.Platform;
#Configuration
#ComponentScan
public class Spring {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Spring.class);
}
#Autowired
#Platform(Platform.OperatingSystems.ANDROID)
private MarketPlace android;
#Autowired
#Platform(Platform.OperatingSystems.IOS)
private MarketPlace ios;
#PostConstruct
public void qualifyTheTweets() {
System.out.println("ios:" + this.ios);
System.out.println("android:" + this.android);
}
// the type has to be public!
#Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE,
ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public static #interface Platform {
OperatingSystems value();
public static enum OperatingSystems {
IOS,
ANDROID
}
}
}
interface MarketPlace {
}
#Component
#Platform(Platform.OperatingSystems.IOS)
class AppleMarketPlace implements MarketPlace {
#Override
public String toString() {
return "apple";
}
}
#Component
#Platform(Platform.OperatingSystems.ANDROID)
class GoogleMarketPlace implements MarketPlace {
#Override
public String toString() {
return "android";
}
}
Edit: I didnt test the code but I have used javax.inject.Qualifier
with CDI if this code doesnt work let me know I will update with
correct combination and imports
Ive Added Spring annotation's to my code
but when connecting via visual vm the method "myExample()" isn't showing in the JMX bean list
My code :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
#Component
#ManagedResource
public class MyClass {
#Autowired
private Example exampleService;
#ManagedAttribute
public String myExample() {
return exampleService.getSomething().toString();
}
}
any idea why this is happening ?
You should use #ManagedOperation instead. #ManagedAttribute is for a getter / setter methods only.
I've got a session scoped CDI bean, and I need to somehow access the HttpServletRequest object in this bean's #PostConstruct method. Is it possible? I've tried to Inject such an object, but it results in:
WELD-001408 Unsatisfied dependencies for type [HttpServletRequest] with qualifiers [#Default] at injection point [[field] #Inject ...]
As I understood while googling, the Seam framework has such a functionality, but I have a standard Java EE application on a GlassFish server.
Is it even possible to somehow pass the request to a CDI bean's #PostConstruct method?
As per your comment, you want access to the user principal. You can just inject it like this: #Inject Principal principal; or #Resource Principal principal;, see Java EE 6 Tutorial.
Update
I'll answer your direct question. In Java EE 7 (CDI 1.1) injection of HttpServletRequest is supported out of the box. In Java EE 6 (CDI 1.0) however, this is not supported out of the box. To get it working, include the class below into your web-app:
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#Produces
private ServletRequest obtain() {
return SERVLET_REQUESTS.get();
}
}
Note: Tested only on GlassFish 3.1.2.2
When using the code from rdcrng be aware of the following:
* The producer-method obtain is dependent-scoped, thus is only called once for application scoped beans (and will resolve to problems for every other request except the first)
* You can solve this with #RequestScoped
* When RequestScoped annotated, you will only get a proxy, and thus you cannot cas it to HttpServletRequest. So you maybe want a producer for HttpServletRequest.
Also note: As per CDI specification link passage 3.6, java ee beans are NOT consideres managed beans. Thus you will end up with two instances of CDIServletRequestProducingListener - one managed by the Java EE container, one managed by the CDI-container. It only works because SERVLET_REQUESTS is static.
Following the modified code for your convenience.
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<ServletRequest>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#RequestScoped
#Produces
private HttpServletRequest obtainHttp() {
ServletRequest servletRequest = SERVLET_REQUESTS.get();
if (servletRequest instanceof HttpServletRequest) {
return (HttpServletRequest) servletRequest;
} else {
throw new RuntimeException("There is no HttpServletRequest avaible for injection");
}
}
}
I am using spring with aspect-j annotation support to allow for an #Loggable annotation. This allows automatic logging on a class based on the configuration.
I am wondering if I can somehow use this annotation to expose an slf4j Logger variable into the class for direct use, so that I don't have to do something to the effect of:
Logger logger = LoggerFactory.getLogger(MyClass.class);
It would be nice if the above was implicitly available due to the annotation and I could just go about doing logger.debug("..."); without the declaration. I'm not sure if this is even possible.
You can use the BeanPostProcessor interface, which is called by the ApplicationContext for all created beans, so you have the chance to fill the appropriate properties.
I created a simple implementation, which does that:
import java.lang.reflect.Field;
import java.util.List;
import net.vidageek.mirror.dsl.Mirror;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
#Component
public class LoggerPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
List<Field> fields = new Mirror().on(bean.getClass()).reflectAll().fields();
for (Field field : fields) {
if (Logger.class.isAssignableFrom(field.getType()) && new Mirror().on(field).reflect().annotation(InjectLogger.class) != null) {
new Mirror().on(bean).set().field(field).withValue(LoggerFactory.getLogger(bean.getClass()));
}
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
You don't have to do any complex registration step, since the ApplicationContext is capable of recognizing BeanPostProcessor instances and automatically register them.
The #InjectLogger annotation is:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectLogger {
}
And then you can easily use the annotation:
public static #InjectLogger Logger LOGGER;
...
LOGGER.info("Testing message");
I used the Mirror library to find the annotated fields, but obviously you may perform a manual lookup in order to avoid this additional dependency.
It's actually a nice idea to avoid repeated code, and even small issues that come from copying and paste the Logger definitions from other classes, like when we forget to change the class parameter, which leads to wrong logs.
You can't do it with an aspect, but lombok can help you in a, in my opinion, elegant way. See #Log annotation.
I think the solution from #Redder is a great way of doing this. However, I didn't want to include the Mirror library so I wrote an implementation of LoggerPostProcessor that uses the Java reflect library instead. Here it is:
package com.example.spring.postProcessor;
import com.example.annotation.InjectLogger;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
#Component
public class LoggerPostProcessor implements BeanPostProcessor {
private static Logger logger = LoggerFactory.getLogger(LoggerPostProcessor.class);
/* (non-Javadoc)
* #see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
List<Field> fields = Arrays.asList(bean.getClass().getDeclaredFields());
for (Field field : fields) {
if (Logger.class.isAssignableFrom(field.getType()) && field.getAnnotation(InjectLogger.class) != null) {
logger.debug("Attempting to inject a SLF4J logger on bean: " + bean.getClass());
if (field != null && (field.getModifiers() & Modifier.STATIC) == 0) {
field.setAccessible(true);
try {
field.set(bean, LoggerFactory.getLogger(bean.getClass()));
logger.debug("Successfully injected a SLF4J logger on bean: " + bean.getClass());
} catch (IllegalArgumentException e) {
logger.warn("Could not inject logger for class: " + bean.getClass(), e);
} catch (IllegalAccessException e) {
logger.warn("Could not inject logger for class: " + bean.getClass(), e);
}
}
}
}
return bean;
}
/* (non-Javadoc)
* #see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
I want to make some improvements to #Redder's solution.
First - we can omit introduction of new annotation #Log, instead we
can use Spring's #Autowired annotation with 'required' flag set to
'false' to make Spring not to check that bean was injected or not
(because, we will inject it later).
Second - use Spring's ReflectionUtils API that provides all
needed methods for field discovering and manipulation, so we don't need additional external dependencies.
Here an example (in Java 8, but can be rewritten in Java 7/6/etc., also slf4j facade is used but it can be replaced with any other logger):
#Component
public class LoggerPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Logger logger = getLogger(bean.getClass());
doWithFields(bean.getClass(), field -> {
makeAccessible(field);
setField(field, bean, logger);
}, field -> field.isAnnotationPresent(Autowired.class) && Logger.class.equals(field.getType()));
return bean;
}
...
}
...
//logger injection candidate
#Autowired(required = false)
private Logger log;
Since I got this as the first result when trying to do the same thing in CDI (JSR 299: Context and Dependency Injection), this link shows the straightforward way to do this using CDI (and also an alternative using Spring):
Basically, you only need to inject:
class MyClass {
#Inject private Log log;
And have a logger factory like so:
#Singleton
public class LoggerFactory implements Serializable {
private static final long serialVersionUID = 1L;
static final Log log = LogFactory.getLog(LoggerFactory.class);
#Produces Log createLogger(InjectionPoint injectionPoint) {
String name = injectionPoint.getMember().getDeclaringClass().getName();
log.debug("creating Log instance for injecting into " + name);
return LogFactory.getLog(name);
}
}
I found that I needed to add transient to the injected log so that I did not get a passivating scope exception in my session scoped beans:
#Named()
#SessionScoped()
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private transient Log log;
Herald provides a very simple BeanPostProcessor which does all the magic for you. You can annotate any field of Spring bean with a #Log annotation to let Herald inject suitable logger in this field.
Supported logging frameworks:
JavaTM 2 platform's core logging framework
Apache Commons Logging
Simple Logging Facade for Java (SLF4J)
SLF4J Extended logger
Logback
Apache Log4j
Apache Log4j 2
JBoss Logging
Syslog4j
Syslog4j fork from Graylog
Fluent Logger for Java
It is also possible to add other logging frameworks.
Github repo: https://github.com/vbauer/herald