I'm using slf4j + log4j in java to add logging to my web application. In each logged event I want to print the feature the user is executing and an identifier of the user action.
When my webapp catches the user's request, I generate the identifier and I have access to the feature "name". What is the best way to put these two parameters in every event logged without passing it out to every method log.(info|warn|debug|error)?
I know I can use MDC context to make the parameters visible for the whole thread and print them in the formatter of the logging statement.
log4j.appender.AppLog.layout.ConversionPattern = %d{ddMMyyyyHHmmss}|%X{feature}|%-5p|%t|%l|%X{actionId}|%m%n
But I wanted a more controlled solution. Note that in the example above the feature and actionId aren't printed throught the logging message, but this isn't a requirement.
I would do something like this:
public MyClass {
Logger log = new InterceptedLogger("com.foo.MyClass");
// ...
public void handleUserAction() {
log.info("Action detected !");
// ...
}
}
public InterceptedLogger extends Logger {
private static MyFramework myFrameWork = MyFramework.getInstance(); // or use an IoC to inject the instance for you...
public InterceptedLogger(String name) {
super(name);
}
public void info(Object message) {
if (isInfoEnable()) {
super.info( //
String.format( //
"%s#%s - %s", // this format may be configured externally
myFrameWork.getCurrentUser(), //
myFrameWork.getCurrentAction(), //
message //
));
}
}
// Override other methods as needed
}
Related
I am developing a client-server application in Java using Websocket. Currently, all the client messages are processed using switch-case as shown below.
#OnMessage
public String onMessage(String unscrambledWord, Session session) {
switch (unscrambledWord) {
case "start":
logger.info("Starting the game by sending first word");
String scrambledWord = WordRepository.getInstance().getRandomWord().getScrambledWord();
session.getUserProperties().put("scrambledWord", scrambledWord);
return scrambledWord;
case "quit":
logger.info("Quitting the game");
try {
session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE, "Game finished"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
String scrambledWord = (String) session.getUserProperties().get("scrambledWord");
return checkLastWordAndSendANewWord(scrambledWord, unscrambledWord, session);
}
The server has to process more than 50 different requests from client and that results in more than 50 case statements. And in future, I expect it to grow. Is there any better way to process Websocket messages from client? Or, is this how it is usually done?
I read somewhere about the use of hashtable to avoid long switch-case scenario by mapping to function pointers. Is this possible in Java? Or, is there any better solutions?
Thanks.
After a bit of testing and study, I found two alternatives to avoid long switch case scenario.
Anonymous class method (Strategy pattern)
Reflection with Annotations
Using Anonymous Class
Anonymous class method is the norm and following code shows how to implement it. I used Runnable in this example. If more control is required, create a custom interface.
public class ClientMessageHandler {
private final HashMap<String, Runnable> taskList = new HashMap<>();
ClientMessageHandler() {
this.populateTaskList();
}
private void populateTaskList() {
// Populate the map with client request as key
// and the task performing objects as value
taskList.put("action1", new Runnable() {
#Override
public void run() {
// define the action to perform.
}
});
//Populate map with all the tasks
}
public void onMessageReceived(JSONObject clientRequest) throws JSONException {
Runnable taskToExecute = taskList.get(clientRequest.getString("task"));
if (taskToExecute == null)
return;
taskToExecute.run();
}
}
Major drawback of this method is object creation. Say, we have 100 different tasks to perform. This Anonymous class approach will result in creating 100 objects for a single client. Too much object creation is not affordable for my application, where there will be more than 5,000 active concurrent connections. Have a look at this article http://blogs.microsoft.co.il/gilf/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements/
Reflection with Annotation
I really like this approach. I created a custom annotation to represent the tasks performed by methods. There is no overhead of object creation, like in Strategy pattern method, as tasks are performed by a single class.
Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TaskAnnotation {
public String value();
}
The code given below maps the client request keys to the methods which process the task. Here, map is instantiated and populated only once.
public static final HashMap<String, Method> taskList = new HashMap<>();
public static void main(String[] args) throws Exception {
// Retrieves declared methods from ClientMessageHandler class
Method[] classMethods = ClientMessageHandler.class.getDeclaredMethods();
for (Method method : classMethods) {
// We will iterate through the declared methods and look for
// the methods annotated with our TaskAnnotation
TaskAnnotation annot = method.getAnnotation(TaskAnnotation.class);
if (annot != null) {
// if a method with TaskAnnotation is found, its annotation
// value is mapped to that method.
taskList.put(annot.value(), method);
}
}
// Start server
}
Now finally, our ClientMessageHandler class looks like the following
public class ClientMessageHandler {
public void onMessageReceived(JSONObject clientRequest) throws JSONException {
// Retrieve the Method corresponding to the task from map
Method method = taskList.get(clientRequest.getString("task"));
if (method == null)
return;
try {
// Invoke the Method for this object, if Method corresponding
// to client request is found
method.invoke(this);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
logger.error(e);
}
}
#TaskAnnotation("task1")
public void processTaskOne() {
}
#TaskAnnotation("task2")
public void processTaskTwo() {
}
// Methods for different tasks, annotated with the corresponding
// clientRequest code
}
Major drawback of this approach is the performance hit. This approach is slow compared to Direct Method calling approach. Moreover, many articles are suggesting to stay away from Reflection, unless we are dealing with dynamic programming.
Read these answers to know more about reflection What is reflection and why is it useful?
Reflection performance related articles
Faster alternatives to Java's reflection
https://dzone.com/articles/the-performance-cost-of-reflection
FINAL RESULT
I continue to use switch statements in my application to avoid any performance hit.
As mentioned in the comments, one of websockets drawback is that you'll to specify the communication protocol yourself. AFAIK, the huge switch is the best option. To improve code readability and maintenance, I'll suggest to use encoders and decoders. Then, your problem becomes: how should I design my messages?
Your game looks like Scrabble. I don't know how to play Scrabble so let's take the example of card game with money. Let's assume you have three types of actions:
Global action (join table, leave table ...)
Money action (place bet, split bet, ...)
Card action (draw card, etc)
Then your messages can look like
public class AbstractAction{
// not relevant for global action but let's put that aside for the example
public abstract void endTurn();
}
public class GlobalAction{
// ...
}
public class MoneyAction{
enum Action{
PLACE_BET, PLACE_MAX_BET, SPLIT_BET, ...;
}
private MoneyAction.Action action;
// ...
}
public class CardAction{
// ...
}
Once your decoder and encoders are properly defined, your switch would be easier to read and easier to maintain. In my project, the code would look like this:
#ServerEndPoint(value = ..., encoders = {...}, decoders = {...})
public class ServerEndPoint{
#OnOpen
public void onOpen(Session session){
// ...
}
#OnClose
public void onClose(Session session){
// ...
}
#OnMessage
public void onMessage(Session session, AbstractAction action){
// I'm checking the class here but you
// can use different check such as a
// specific attribute
if(action instanceof GlobalAction){
// do some stuff
}
else if (action instanceof CardAction){
// do some stuff
}
else if (action instance of MoneyAction){
MoneyAction moneyAction = (MoneyAction) action;
switch(moneyAction.getAction()){
case PLACE_BET:
double betValue = moneyAction.getValue();
// do some stuff here
break;
case SPLIT_BET:
doSomeVeryComplexStuff(moneyAction);
break;
}
}
}
private void doSomeVeryComplexStuff(MoneyAction moneyAction){
// ... do something very complex ...
}
}
I prefer this approach because:
The messages design can leverage your entities design (if you are using JPA behind)
As messages are not plain text anymore but objects, enumerations can be used and enumerations are very powerful in this kind of switch-case situation. With the same logic but in a lesser extend, class abstraction can be useful as well
The ServerEndPoint class only handles communication. The business logic is handled out of this class, either directly in Messages classes or in some EJB. Because of this split, code maintenance is much easier
Bonus: #OnMessage method can be read as a summary of the protocol but details should not be displayed here. Each case must contain few lines only.
I prefer avoid using Reflection: it'll ruin your code readability, in the specific scenario of websocket
To go further beyond code readability, maintenance and efficiency, you can use a SessionHandler to intercept some CDI event if this can improve your code. I gave an example in this answer. If you need a more advanced example, Oracle provides a great tutorial about it. It might help you to improve your code.
In my JEE application, running on glassfish 3, I have the following situation:
MyFacade class
#Interceptors(SomeInterceptor.class)
public void delete(Flag somethingForTheInterceptor, String idToDelete) {
.......
}
#Interceptors(SomeInterceptor.class)
public void update(Flag somethingForTheInterceptor, MyStuff newStuff) {
.......
}
The variable somethingForTheInterceptor is not used in these methods, it is only used in the interceptor:
SomeInterceptor class
#AroundInvoke
public Object userMayAccessOutlet(InvocationContext ctx) throws Exception {
Flag flag = extractParameterOfType(Arrays.asList(ctx.getParameters()), Flag.class);
// some checks on the flag
}
Somehow it doesn't feel good to have a parameter that is not used in the method. Is there another way to "send" somethingForTheInterceptor to the interceptor?
UPDATE: The callers of delete() and update() have different ways of calculating the somethingForTheInterceptor variable. And this is not a constant. The information needed to calculate it is in the REST call. But the 2 REST methods have different input objects so it is not enough to inject the http request.
These are the callers:
MyResource class
#DELETE
#Path("/delete/{" + ID + "}")
public Response delete(#PathParam(ID) final String id) {
Flag flag = calculateFlagForInterceptor(id);
facade.delete(flag, id);
}
#POST
#Path("/update")
#Consumes(MediaType.APPLICATION_JSON + RestResourceConstants.CHARSET_UTF_8)
public Response update(final WebInputDTO updateDetails) throws ILeanException {
Flag flag = calculateFlagForInterceptor(updateDetails);
facade.update(flag, convertToMyStuff(updateDetails));
}
I was thinking - is it possible for the methods in the Resource to set the flag in some kind of Context, that can be later injected in the Interceptor?
In Java EE, Interceptors allow to add pre and post processings to a method.
So, the context of the Interceptor execution is the context of the method.
I was thinking - is it possible for the methods in the Resource to set
the flag in some kind of Context, that can be later injected in the
Interceptor?
Staless Service should be privileged when you may. So, you should avoid storing data on the server (ThreadLocal, Session, etc..).
The information needed to calculate it is
in the REST call.
Why ?
A Rest controller has no vocation to do computations and logic.
To solve your problem, are you sure you could not move the flag computation in your interceptor ?
By enhancing the interceptor responsibilities, you would have not need anly longer to transit the flag :
#AroundInvoke
public Object userMayAccessOutlet(InvocationContext ctx) throws Exception {
Flag flag = calculFlag(Arrays.asList(ctx.getParameters()));
// some checks on the flag
}
We are using Guice in our project for DI. Currently we have some configurations(properties) that we load a t server startup from a file. These are then bound to all the components & used for all the requests.
But now, we have multiple property files & load them at startup. These configurations can be different per REST(Jersey) request as they depend on the input.
So, we need to bind these configurations dynamically for each request. I looked into Guice API for #RequestScoped, but did not find anything specificallyu helpful.
There are few questions similar to this, but no luck yet. Can you please help me with this.
I'm providing 2 ways of doing this and both are request scoped.
Using HttpServletRequest, for classes where you can Inject request object.
Using ThreadLocal, Generic way. It can be used in any class.
(NOTE: This method wouldn't work if your creating new threads in your code and want to access the value. In which case you'll have to pass the values through Objects to those threads)
I meant something like this:
public class RequestFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
List listOfConfig = //load Config;
request.setAttribute("LOADED_CONFIG",listOfConfig);
// If you want to access this value at some place where Request object cannot be injected (like in service layers, etc.) Then use below ThreadLocals.
ThreadLocalWrapper.getInstance().get().add("adbc"); // In general add your config here, instead of abdc.
}
}
My ThreadLocalWrapper looks like this:
public class ThreadLocalWrapper {
private static ThreadLocal<List<String>> listOfStringLocals; // You can modify this to a list of Object or an Object by itself.
public static synchronized ThreadLocal<List<String>> getInstance() {
if (listOfStringLocals == null) {
listOfStringLocals = new ThreadLocal<List<String>>() {
#Override
protected List<String> initialValue() {
return new ArrayList<String>();
}
};
}
return listOfStringLocals;
}
}
To Access the value:
In Controller - Inject HttpServletRequest Object and do getAttribute() to get the value. Since HttpServletRequest Object is requestScoped, you can set the loaded config. into this and access it in your controller's using request Object again.
In Any other part of the code - If HttpServletRequest is not available then you can always use the ThreadLocal example shown. To access this value.
public class GuiceTransactionImpl implements GuiceTransaction {
private String value = "";
public GuiceTransactionImpl(String text) {
value = text;
}
#Override
public String returnSuccess() {
return value + " Thread Local Value " + ThreadLocalWrapper.getInstance().get();
}
}
In a project using Struts2 (2.3.20) I would like to run through the
configured actions (name, class, namespace, method) at application startup.
I'm using
Struts 2.3.20
struts-spring-plugin
struts-convention-plugin
For reference: I've done some work with beans and Struts injection before so not entirely fresh on this, but I'm stuck solving the problem stated here.
Any pointers on how to obtain this would be appreciated.
Further explanation
Reading Andrea's answer below I see I need to explain what I need.
I'm building a application menu builder feature for the application. My plan is to obtain the action configurations and build a tree of "menu nodes" from information in annotations on selected action classes and methods.
My problem with the code from the config-browser is that the Configuration (xwork) doesn't seem to be available outside of Struts components. Since this is an application startup task it doesn't really fit Struts' MVC component model. I'd like to put the menu building initialization in a ServletContextListener.
Fake example
Per request here is just the connection actionconfig <-> annotation <-> my_custom_menu. From this I could produce a menu structure provided from the annotations on action classes and methods.
public class ActionMenuBuilderListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent arg0) {
List<ActionCfg> actions = Struts.getConfiguredActions(); // thisi is where I'd like some help
for(ActionCfg action : actions) {
MenuAnnotation annotation = getAnnotationFromMethodOrClass(action);
if(annotation != null) {
addMenuItem(action, annotation);
}
}
}
}
Here ActionCfgis whatever class Struts would return for action configuration, Struts.getConfiguredActions() would be one or more calls to Struts components and addMenu(...) is where I add a menu item node to my structure. The structure is later the target from JSP-s to build menus.
I don't know how much more code to write.
My sollution
For completness I thought I'll include what came out of this.
First, I to plugged in into Struts through this
ServletContextListnere:
public class ActionMenuBuilderListener implements
ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent arg0) {
}
#Override
public void contextInitialized(ServletContextEvent event) {
ActionMenuDispatcherListener listener =
new ActionMenuDispatcherListener();
ServletContext context = event.getServletContext();
listener.setServletContext(context);
Dispatcher.addDispatcherListener(listener);
}
}
Then, I wrote the DispatcherListener:
public class ActionMenuDispatcherListener implements DispatcherListener {
private ServletContext servletContext;
...
#Override
public void dispatcherInitialized(Dispatcher dispatcher) {
Map<String, PackageConfig> packages = dispatcher
.getConfigurationManager().getConfiguration()
.getPackageConfigs();
Map<String, Map<String, ActionConfig>> runtimeActionConfigs = dispatcher
.getConfigurationManager().getConfiguration()
.getRuntimeConfiguration().getActionConfigs();
for (String packageKey : runtimeActionConfigs.keySet()) {
Map<String, ActionConfig> actionConfigs = runtimeActionConfigs
.get(packageKey);
for (String actionKey : actionConfigs.keySet()) {
ActionConfig actionConfig = actionConfigs.get(actionKey);
PackageConfig packageConfig = packages.get(actionConfig
.getPackageName());
if (packageConfig != null) {
String actionName = actionConfig.getName();
String namespace = packageConfig.getNamespace();
try {
ActionMenu methodAnnotation = getMethodAnnotation(actionConfig);
if (methodAnnotation != null) {
String annotationInfo = methodAnnotation.value();
log.debug("[{}, {}, {}]", namespace, actionName,
annotationInfo);
}
} catch (ClassNotFoundException e) {
log.error("{}: {}", e.getClass().getSimpleName(),
e.getMessage());
}
}
}
}
}
protected ActionMenu getMethodAnnotation(ActionConfig actionConfig)
throws ClassNotFoundException {
String className = actionConfig.getClassName();
String methodName = actionConfig.getMethodName();
Class<?> actionClass = Class.forName(className);
try {
Method method = actionClass.getDeclaredMethod(methodName, null);
ActionMenu annotation = method.getAnnotation(ActionMenu.class);
return annotation;
} catch (NoSuchMethodException | SecurityException e) {
// log.error("{}: {}", e.getClass().getSimpleName(),
// e.getMessage());
}
return null;
}
}
Just in case someone else is thinking along those line :)
First of all you need to hook into application initialization process after the configurations are loaded and parsed. One of the ways is to implement DispatcherListener which you need to add to the Dispatcher. This you can do in ServletContextListener#contextInitialized method.
The second piece of the puzzle is to get action configurations. This is pretty simple because the instance of the Dispatcher is passed as argument into dispatcherInitialized method. To get all current action configurations get RuntimeConfiguration which holds data in Map<String, Map<String, ActionConfig>>, where the first map key is package namespace, the second map key is action name and ActionConfig holds all info about action. Since you need a class name then use getClassName() method of it.
public class ActionMenuBuilderListener implements ServletContextListener,DispatcherListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
Dispatcher.addDispatcherListener(this);
}
#Override
public void dispatcherInitialized(Dispatcher du) {
Map<String, Map<String, ActionConfig>> runtimeActionConfigs = du
.getConfigurationManager().getConfiguration().getRuntimeConfiguration()
.getActionConfigs();
}
// other methods
}
And of course don't forget to register your listener in web.xml.
You are free of building this thing for your personal growth, but beware that it already exist.
It is called Config Browser Plugin (struts2-config-browser-plugin-2.3.20.jar).
It is included by default with the Maven archetypes, and you must remember of removing it before going in production.
Once imported it is available at the URL:
//www.SERVER_NAME.com:8080/WEBAPP_NAME/config-browser/actionNames
It gives you the exact informations you are looking for: actions, methods, results, parameters, mappings etc. and it looks like this:
I am new to Java World.
We have a Java application where it gives a specific type of exception. Is there any way, we can have log4j to react to specific way. Having own appender for something like MQ connection exception, we need to send email to specific group.
We are in the process of customizing a Java out of the application which intern uses MQ and through exception which we need to email.
I am actually looking for how the appender will look like
Yes, you're on the right track. Implement your own Appender and only log things that match what you want to log.
Alternatively, use an existing appender (e.g. SMTPAppender) and implement/utilize an existing Filter to limit what is sent there.
If you mean that you want to append an event only when it contains a certain class of exception, you could write a filter. Something along these lines (untested code!):
public final class ExceptionFilter extends org.apache.log4j.spi.Filter {
private volatile String type;
public void setType(String type) {
this.type = type;
}
public String getType()
return type;
}
public int decide(LoggingEvent evt) {
Throwable t = evt.getThrowableInformation().getThrowable();
if ((t != null) && t.getName().equals(type))
return NEUTRAL;
else
return DENY;
}
}