How to measure HTTP-Session Size? - session

Is there some effective and accurate way to track the size of a particular session in a servlet based application?

Java doesn't have a sizeof() method like C (see this post for more information) so you generally can't get the size of anything in Java. However, you can track what goes into and is removed from the session with a HttpSessionAttributeListener (link is JavaEE 8 and below). This will give you some visibility into the number of attributes and, to an extent, the amount of memory being used. Something like:
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
#WebListener
public class MySessionAttributeListener implements HttpSessionAttributeListener {
#Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println( "the attribute \"" + event.getName() + "\" with the value \"" + event.getValue() + "\" has been added" );
}
#Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.our.println( "the attribute \"" + event.getName() + "\" with the value \"" + event.getValue() + "\" has been removed" );
}
#Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println( "the attribute \"" + event.getName() + "\" with the value \"" + event.getValue() + "\" has been replaced" );
}
}

Related

Spring Aspect to log exceptions [duplicate]

This question already has an answer here:
Exception handling and after advice
(1 answer)
Closed 1 year ago.
I added aspect like below in my spring-boot REST API to log calls to all methods in package "com.leanring.sprint" like so:
#Aspect
#Component
public class LogAdvice {
Logger logger = LoggerFactory.getLogger(LogAdvice.class);
#Pointcut(value = "execution(* com.learning.spring.*.*.*(..))")
public void pointCut() {
}
#Around("pointCut()")
public Object appLogger(ProceedingJoinPoint jp) throws Throwable {
ObjectMapper mapper = new ObjectMapper();
String methodName = jp.getSignature().getName();
String className = jp.getTarget().getClass().toString();
Object[] args = jp.getArgs();
logger.info("Start call: " + className + ":" + methodName + "()" + " with arguments: " + mapper.writeValueAsString(args));
Object object = jp.proceed();
logger.info("End call: " + className + ":" + methodName + "()" + " returned: " + mapper.writeValueAsString(object));
return object;
}
}
This is working fine, but I would also like it to be able to log any exceptions that could occur when a method is called.
How do I do that?
I suppose you could add another #AfterThrowing advice using the same pointcut or wrap jp.proceed(); inside a try-catch block.

GWT & Java EE SessionScoped bean not persisting

I'm playing w/ EE and want to persist a user session state. I have the session bean here:
#Stateful(mappedName = "UserSessionState")
#Named("UserSessionState")
#SessionScoped
#StatefulTimeout(value = 5, unit = TimeUnit.MINUTES)
public class UserSessionState implements Serializable
{
private boolean hasPlayerId = false;
private String playerId = "";
public void setRandomPlayerId()
{
playerId = UUID.uuid();
hasPlayerId = true;
}
public boolean hasPlayerId()
{
return hasPlayerId;
}
public String getPlayerId()
{
return playerId;
}
}
And a servlet here (GameState is an Application Scoped bean that is working as expected, CustomExtendedHttpServlet is just a simple extension of HttpServlet)
public class NewUserJoined extends CustomExtendedHttpServlet
{
#Inject
protected GameState gameState;
#Inject
protected UserSessionState user;
#Override
protected String doGetImpl(HttpServletRequest request, HttpServletResponse response, UserContext userLoginContext)
{
if (!user.hasPlayerId())
{
user.setRandomPlayerId();
}
String userId = user.getPlayerId();
if (!gameState.hasUser(userId))
{
gameState.addUser(userId, user);
return "Hi, your ID is: " + user.getPlayerId() + ", there are " + gameState.getUserCount() + " other players here";
}
else
{
return user.getPlayerId() + " you're already in the game, there are: " + gameState.getUserCount() + " other players here";
}
}
}
I'm not sure what's going on, but whenever I call the New User Joined servlet from the same HTTP session, I get this response on the first call (as expected):
"Hi, your ID is: , there are 1 other players here"
Repeating the same servlet call in the same session gives me the same message:
"Hi, your ID is: , there are 2 other players here"
...
It looks like a new instance of User Session State is getting created over and over. Am I doing this correctly?
EDIT 1: Here the code I use to send a request. It appears I'm getting a new session ID with each request, what could cause that?
RequestCallback callback = new RequestCallback()
{
#Override
public void onResponseReceived(Request request, Response response)
{
log(response.getText());
}
#Override
public void onError(Request request, Throwable exception)
{
log(
"Response Error | "
+ "Exception: " + exception);
}
};
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, SERVLET_URL);
rb.setCallback(callback);
try
{
rb.send();
}
catch (RequestException e)
{
log("Response Error | "
+ "Exception: " + e);
}
Figured out the issue,
Turns out I had an old workaround in the GWT client that was changing the host to get around a CORS issue. Because the response didn't match up to the origin, the cookie wasn't getting sent with future servlet GET calls.
Have you tried a call to request.getSession(true) to make sure an EE HTTPSession is established here?

Spring Aop logging line number incorrect

I am using spring aop to do logging for my application :
I have before after and afterthrowing advice configured but the line numbers that I see is not of the target class but that of the class used for logging
How can I solve this
Below is my configuration
Spring xml :
<aop:aspectj-autoproxy proxy-target-class="false" />
Class used for logging :
package com.digilegal.services.ahc.logging;
import java.lang.reflect.Modifier;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
#Aspect
public class AHCLogging {
#Before("execution(* com.digilegal.services..*.*(..))")
public void logBefore(JoinPoint joinPoint) {
Logger log = Logger.getLogger(joinPoint.getTarget().getClass());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
if (!Modifier.isPrivate(signature.getModifiers())
&& !signature.getName().startsWith("get")
&& !signature.getName().startsWith("set")
&& !signature.getName().startsWith("is")) {
log.trace("ENTER METHOD ::"
+ signature.getReturnType().getSimpleName() + " "
+ signature.getName() + "("
+ paramterType(signature.getParameterTypes()) + ")");
}
}
#After("execution(* com.digilegal.services..*.*(..))")
public void logAfter(JoinPoint joinPoint) {
Logger log = Logger.getLogger(joinPoint.getTarget().getClass());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
if (!Modifier.isPrivate(signature.getModifiers())
&& !signature.getName().startsWith("get")
&& !signature.getName().startsWith("set")
&& !signature.getName().startsWith("is")) {
log.trace("EXIT METHOD ::"
+ signature.getReturnType().getSimpleName() + " "
+ signature.getName() + "("
+ paramterType(signature.getParameterTypes()) + ")");
}
}
#AfterThrowing(pointcut = "execution(* com.digilegal.services..*.* (..))",throwing= "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
Logger log = Logger.getLogger(joinPoint.getTarget().getClass());
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
if (!Modifier.isPrivate(signature.getModifiers())
&& !signature.getName().startsWith("get")
&& !signature.getName().startsWith("set")
&& !signature.getName().startsWith("is")) {
log.error("EXCEPTION IN METHOD ::"
+ signature.getReturnType().getSimpleName() + " "
+ signature.getName() + "("
+ paramterType(signature.getParameterTypes()) + ")");
log.error("Exception",error);
}
}
private String paramterType(Class<?>[] classes) {
StringBuffer buffer = new StringBuffer();
String returnValue = "";
for (Class<?> string : classes) {
buffer.append(Modifier.toString(string.getModifiers()));
buffer.append(" ");
buffer.append(string.getSimpleName());
buffer.append(",");
}
returnValue = buffer.toString();
if (returnValue.trim().length() > 0) {
returnValue = returnValue.substring(0, returnValue.length() - 1);
}
return returnValue;
}
}
Am I missing something or is it suppose to be like this
Thanks
Nirav
I think this is not specifically a Spring AOP problem but just the way Log4j works, see Javadoc for PatternLayout:
L
Used to output the line number from where the logging request was issued.
WARNING Generating caller location information is extremely slow and should be avoided unless execution speed is not an issue.
So my recommendation is to use a pattern layout without line number and use Spring AOP's capability of determining line numbers, roughly like this:
joinPoint.getSourceLocation().getLine()

Deserializing an interface using Gson?

I'm trying to use Gson with an interface:
public interface Photo {
public int getWidth();
}
public class DinosaurPhoto implements Photo {
...
}
public class Wrapper {
private Photo mPhoto; // <- problematic
}
...
Wrapper wrapper = new Wrapper();
wrapper.setPhoto(new DinosaurPhoto());
Gson gson = new Gson();
String raw = gson.toJson(wrapper);
// Throws an error since "Photo" can't be deserialized as expected.
Wrapper deserialized = gson.fromJson(raw, Wrapper.class);
Since the Wrapper class has a member variable that is of type Photo, how do I go about deserializing it using Gson?
Thanks
Custom deserialization is necessary.
Depending on the larger problem to be solved, either a ["type adapter"] 1 or a "type hierarchy adapter" should be used. The type hierarchy adapter "is to cover the case when you want the same representation for all subtypes of a type".
Simply put, you can't do that with GSON.
I was troubled by the same problem when I stumbled upon Jackson.
With it it is very easy:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
And then you can go about de/serializing your Java objects and interfaces without having to write additional custom de/serializers, annotaions and really no added code whatsoever.
This was not a part of the question, but may prove useful if you decide to port from Gson to Jackson.
Gson supports private fields by default but for Jackson you have to include this in your code.
mapper.setVisibilityChecker(g.getVisibilityChecker().with(Visibility.ANY));
Sample implementation for your code in main:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.setVisibilityChecker(g.getVisibilityChecker().with(Visibility.ANY));
Wrapper wrapper = new Wrapper();
wrapper.setPhoto(new DinosaurPhoto());
String wrapper_json = mapper.writeValueAsString(wrapper);
Wrapper wrapper_from_json = mapper.readValue(wrapper_json,Wrapper.class);
Gson promised they will work on this problem in future versions, but they haven't solved it so far.
If this is very important for you application I would suggest that you port to Jackson.
I have built a primitive interface shim generator by way of compiling a groovy properties class to interoperate with a GWT Autobeans model. this is a really rough method to sidestep the ASM/cglib learning curve for now. background on this: with Autobeans, you may only use interfaces, and the sun.* proxies are incapable of gson interop for all the access attempts I have experimented with. BUT, when groovy classloader is local to GsonBuilder, things get a tiny bit easier. note, this fails unless the gsonBuilder registration is actually called from within the groovy itself.
to access the shim factory create one as a singleton names JSON_SHIM and call
JSON_SHIM.getShim("{}",MyInterface.class)
to register if needed and create a [blank] instance. if you have interfaces in your interfaces, you must pre-register those too ahead of use. this is just enough magic to use flat Autobeans with gson, not a whole framework.
there is no groovy code in this generator, so someone with javassist-foo can repeat the experiment.
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
import groovy.lang.GroovyClassLoader;
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
public class GroovyGsonShimFactory {
private Map<Class, Method> shimMethods = new LinkedHashMap<>();
private void generateGroovyProxy(Class ifaceClass) {
String shimClassName = ifaceClass.getSimpleName() + "$Proxy";
String ifaceClassCanonicalName = ifaceClass.getCanonicalName();
String s = "import com.google.gson.*;\n" +
"import org.apache.commons.beanutils.BeanUtils;\n" +
"import java.lang.reflect.*;\n" +
"import java.util.*;\n\n" +
"public class "+shimClassName+" implements "+ifaceClassCanonicalName+" {\n" ;
{
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(ifaceClass);
for (PropertyDescriptor p : propertyDescriptors) {
String name = p.getName();
String tname = p.getPropertyType().getCanonicalName();
s += "public " + tname + " " + name + ";\n";
s += " " + p.getReadMethod().toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "") + "{return " + name + ";};\n";
Method writeMethod = p.getWriteMethod();
if (writeMethod != null)
s += " " + writeMethod.toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "").replace(")", " v){" + name + "=v;};") + "\n\n";
}
}
s+= " public static "+ifaceClassCanonicalName+" fromJson(String s) {\n" +
" return (" +ifaceClassCanonicalName+
")cydesign.strombolian.server.ddl.DefaultDriver.gson().fromJson(s, "+shimClassName+".class);\n" +
" }\n" +
" static public interface foo extends InstanceCreator<"+ifaceClassCanonicalName+">, JsonSerializer<"+ifaceClassCanonicalName+">, JsonDeserializer<"+ifaceClassCanonicalName+"> {}\n" +
" static {\n" +
" cydesign.strombolian.server.ddl.DefaultDriver.builder().registerTypeAdapter("+ifaceClassCanonicalName+".class, new foo() {\n" +
" public "+ifaceClassCanonicalName+" deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n" +
" return context.deserialize(json, "+shimClassName+".class);\n" +
" }\n" +
"\n" +
" public "+ifaceClassCanonicalName+" createInstance(java.lang.reflect.Type type) {\n" +
" try {\n" +
" return new "+shimClassName+"();\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace(); \n" +
" }\n" +
" return null;\n" +
" }\n" +
"\n" +
" #Override\n" +
" public JsonElement serialize("+ifaceClassCanonicalName+" src, Type typeOfSrc, JsonSerializationContext context) {\n" +
" LinkedHashMap linkedHashMap = new LinkedHashMap();\n" +
" try {\n" +
" BeanUtils.populate(src, linkedHashMap);\n" +
" return context.serialize(linkedHashMap);\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace(); \n" +
" }\n" +
"\n" +
" return null;\n" +
" }\n" +
" });\n" +
" }\n\n" +
"};";
System.err.println("" + s);
ClassLoader parent = DefaultDriver.class.getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
final Class gClass = loader.parseClass(s);
try {
Method shimMethod = gClass.getMethod("fromJson", String.class);
shimMethods.put(ifaceClass, shimMethod);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public <T> T getShim(String json, Class<T> ifaceClass) {
if (!shimMethods.containsKey(ifaceClass))
generateGroovyProxy(ifaceClass);
T shim = null;//= gson().shimMethods(json, CowSchema.class);
try {
shim = (T) shimMethods.get(ifaceClass).invoke(null, json);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return shim;
}
}

Wicket key event -> get key!

one more question:
I created an inputfield and added an AjaxFormComponentUpdatingBehavior ("onkeyup"). Now I want to execute some code only if the right key (space-key) is pressed.
How am I able to get the last pressed key? I thought it would be stored in the target attribute but I couldn't find it there... Is there any easy way to solve this problem?
Thx guys!
CU Sylvus
You should not use an AjaxFormComponentUpdatingBehavior if you want to capture keys. This behavior is reserved for actions that update the form component model. I would probably try to do it in javascript alone, especially if you are using a javascript framework like mootools or prototype. Here is some sample code for mootools (no need to send this to the server):
this.add(new TextField<String>("textField").add(new AbstractBehavior(){
private static final long serialVersionUID = 1L;
private Component component;
#Override
public void bind(final Component component){
this.component = component.setOutputMarkupId(true);
}
#Override
public void renderHead(final IHeaderResponse response){
response.renderOnDomReadyJavascript(
"$('" + this.component.getMarkupId() + "')" +
".addEvent('keyup',function(event){" +
"if(' '==event.key){" +
"alert('you pressed space!!!')" +
"}" +
"}" +
");");
};
}));
if no js library is available, here's a wicket-only solution:
#Override
public void renderHead(final IHeaderResponse response){
response.renderJavascriptReference(WicketEventReference.INSTANCE);
response.renderOnDomReadyJavascript("Wicket.Event.add('"
+ this.component.getMarkupId()
+ "',onkeyup',function(event){" + "if(' '==event.key){"
+ "alert('you pressed space!!!')" + "}" + "}" + ");");
};
but this does not deal with cross-browser issues in event handling
I found the solution, thanks to Google and Firebug.
searchInput.add(new AbstractBehavior() {
private static final long serialVersionUID = 1L;
private Component component;
#Override
public void bind(final Component component) {
this.component = component.setOutputMarkupId(true);
}
#Override
public void renderHead(final IHeaderResponse response) {
response.renderJavascriptReference(WicketEventReference.INSTANCE);
response.renderOnDomReadyJavascript("document.getElementById('" +
this.component.getMarkupId() + "').onkeyup=function(event){\n" +
"if(32==event.keyCode){\n" + "alert('you pressed space!!!')" + "\n}" +
"}");
}
});

Resources