Does Spring-WebFlow provide a way of getting to know the number of flows currently executing ?
I could work around it with a global bean, but maybe WebFlow provides a solution out-of-the-box.
Edit: As requested, here the so called "Global Bean" solution based on a
FlowExecutionListenerAdapter
package your.package;
import org.apache.log4j.Logger;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.definition.StateDefinition;
import org.springframework.webflow.definition.TransitionDefinition;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
public class FlowExecutionListener extends FlowExecutionListenerAdapter {
private static Logger logger = Logger.getLogger(FlowExecutionListener.class);
private int sessionCount = 0;
#Override
public void sessionStarted(final RequestContext context, final FlowSession session) {
super.sessionStarted(context, session);
sessionCount++;
logger.debug("sessionStarted, state: " + session.getState().getId() + ", count: " + sessionCount);
}
#Override
public void sessionEnded(final RequestContext context, final FlowSession session, final String outcome, final AttributeMap output) {
super.sessionEnded(context, session, outcome, output);
sessionCount--;
logger.debug("sessionEnded, state: " + session.getState().getId() + ", count: " + sessionCount);
}
}
The bean must be registered at Spring-level:
<bean id="flowExecutionListener" class="your.package.FlowExecutionListener" />
Edit2:
If you have more than one WebFlow in your application, this would count all the active flows. In case you want to account them separately, you can get the flow's ID with session.getDefinition().getId().
Related
I need to capture all the http/https requests that are going through the browsers of my system using JAVA servlets.
Can I achieve that?
going through the browsers of my system
You can do this is with an implementation of ServletRequestListener::requestInitialized(ServletRequestEvent sre)
The Documentation say:
requestInitialized(ServletRequestEvent sre)
Receives notification that a ServletRequest is about to come into scope of the web application.
The class could look like this:
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Map.Entry;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class RequestListener implements ServletRequestListener {
public RequestListener() {}
public void requestDestroyed(ServletRequestEvent sre) {}
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
System.out.println("Timestamp: " + new Timestamp(System.currentTimeMillis()));
System.out.println("SessionId: " + request.getSession(false));
System.out.println("RequestURL: " + request.getRequestURL());
System.out.println("Method: " + request.getMethod());
System.out.println("Parameters: ");
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
System.out.println(entry.getKey() + " = " + Arrays.asList(entry.getValue()));
}
}
}
In the console you get something like this:
Timestamp: 2017-01-25 19:12:04.36
SessionId: null
RequestURL: https://localhost:8181/jee6/ResponseFilterTest/Fiz
Method: GET
Parameters:
p1 = [v1]
p2 = [v2]
Instead in the console you can store the data in a DB or write to a log.
If you need to differentiate between local and remote requests you can use request.getRemoteAddr(). For local requests it is 127.0.0.1
I have this Apache Felix activator which gets data source service:
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;
import org.DX_57.osgi.SH_27.api.SessionHandle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
public class SessionHandleApp implements BundleActivator {
public static final String DSNAME = "jdbc/Oracle";
public ServiceTracker st;
#Override
public void start(final BundleContext bc) throws Exception {
debug("Activator started");
Filter filter = bc.createFilter("(&" + "(" + Constants.OBJECTCLASS
+ "=" + DataSource.class.getName() + ")" + "(jndi-name="
+ DSNAME + ")" + ")");
st = new ServiceTracker(bc, filter, null) {
#Override
public Object addingService(ServiceReference reference) {
DataSource ds = (DataSource) bc.getService(reference);
try {
debug(ds.getConnection().toString());
SessionHandle sh = new SessionHandleImpl();
sh.setDataSource(ds);
ServiceRegistration registerService = bc.registerService(SessionHandle.class.getName(), sh, new Properties());
} catch (SQLException e) {
}
return super.addingService(reference);
}
#Override
public void removedService(ServiceReference reference,
Object service) {
super.removedService(reference, service);
}
};
st.open();
}
public void stop(BundleContext bc) throws Exception {
boolean ungetService = bc.ungetService(bc.getServiceReference(SessionHandle.class.getName()));
st.close();
}
private void debug(String msg) {
System.out.println("JDBCBundleActivator: " + msg);
}
}
This solution works but legacy aproach with using a database driver classname to configure JDBC does not work well in OSGi.
How I must write a bundle with an activator that initializes the datasource and offers it as a service?
I think you are confused. The above code is not using JDBC driver. It is using JDBC datasource as a service. In GlassFish, the easiest way to create a DataSource service is to use GlassFish administration operation like "asadmin create-jdbc-resource with a JNDI name." Then GlassFish automatically registers it as a DataSource OSGi service with a registration property jndi-name=YourSuppliedJndiName.
You may check Gemini DBAccess project, it exports a DataSourceFactory as an OSGi Service, so you can just use it.
I'm building a web application from an existing project. In the existing project I have a class that contains all my objects and the things I can do with them.
I was wondering what will happen if I had an instance of this class to a servlet as a data member:
When the same user with same session is directed to the servlet that contains this class will it keep it's data or will it regenerate every time?
Will every user/session have a different copy of this member or is it shared?
If data members in servlets don't keep thir state for the same session, then what do you recommend? Maybe activly adding it to the session?
Thanks for your help
Servlets - thus their data members - are shared between all sessions on the server. Thus
When the same user with same session is directed to the servlet that contains this class will it keep it's data or will it regenerate every time?
The data will be kept around (for all users) until you restart the web application.
Will every user/session have a different copy of this member or is it shared?
It is shared.
If data members in servlets don't keep thir state for the same session, then what do you recommend? Maybe activly adding it to the session?
Session specific data should be stored in an HttpSession.
To be sure of this behavior, I wrote a little TestingServlet - I will show you the lifecycle of a servlet and its members. Also supplied; How to work with session variables
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Basic servlet for lifecycle testing
*
* #author powermicha
*
*/
public class TestingServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 4020575563844924588L;
private Logger logger;
private int requestCounter;
#Override
public void init() throws ServletException {
logger = Logger.getLogger("TestingServlet_" + System.currentTimeMillis());
logger.log(Level.INFO, "TestingServlet initialized");
requestCounter = 0;
}
#Override
public void destroy() {
logger.log(Level.INFO, "TestingServlet destroyed");
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int requestsPerSession = incrementRequestsPerSession(req);
String logMessage = "TestingServlet was called " + (++requestCounter) + " times. "
+ requestsPerSession + " times from the same session (ID:"
+ req.getSession().getId() + ")";
logger.log(Level.INFO, logMessage);
// send it to the browser
PrintWriter writer = resp.getWriter();
writer.write(logMessage);
writer.close();
}
private int incrementRequestsPerSession(HttpServletRequest req) {
Integer counter = (Integer) req.getSession().getAttribute("requestsPerSession");
if (counter == null) {
counter = 1;
} else {
counter++;
}
req.getSession().setAttribute("requestsPerSession", counter);
return counter;
}
}
Is there a good way to get the logged in user count in a Java web application that is running in a cluster?
I wrote a simple HttpSessionListener with a static field, but I suppose this doesn't work in cluster. I can see there is a Spring Security solution, but I read in some forums that this is still not ok in cluster.
The product in which I have to implement this user count is trying to be application server independent, currently we support Tomcat, Weblogic and JBoss. At the moment I need a solution for Weblogic 10.3 clusters.
You can maintain the counter in database which will work in cluster env.
A simple tutorial to demonstrate how to determine active users / sessions in a Java Web Application.
package com.hubberspot.javaee.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
#WebListener
public class OnlineUsersCounter implements HttpSessionListener {
private static int numberOfUsersOnline;
public OnlineUsersCounter() {
numberOfUsersOnline = 0;
}
public static int getNumberOfUsersOnline() {
return numberOfUsersOnline;
}
public void sessionCreated(HttpSessionEvent event) {
System.out.println("Session created by Id : " + event.getSession().getId());
synchronized (this) {
numberOfUsersOnline++;
}
}
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("Session destroyed by Id : " + event.getSession().getId());
synchronized (this) {
numberOfUsersOnline--;
}
}
}
Running the below servlet on three different browsers will provide output as : (see fig below)
package com.hubberspot.javaee;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.hubberspot.javaee.listener.OnlineUsersCounter;
// #WebServlet annotation has a initParams field which takes
// in initialization parameters for a servlet.
// #WebInitParam annotation takes in a name and value for the
// initialization parameters for the current Servlet.
#WebServlet(name = "HelloWorldServlet" , urlPatterns = { "/HelloWorldServlet" }
, initParams = { #WebInitParam(name = "user" , value = "Jonty") })
public class HelloWorldServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// sessionCreated method gets executed
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60);
try {
out.println("<html>");
out.println("<body>");
out.println("<h2>Number of Users Online : "
+ OnlineUsersCounter.getNumberOfUsersOnline()
+ "</h2>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
}
Output of the program :
Eclipse Browser ->
Firefox Browser ->
Internet Explorer Browser ->
Console Output ->
For more: http://www.hubberspot.com/2013/09/how-to-determine-active-users-sessions.html
what options do I have to profile a page request in a spring mvc app?
I want to get a breakdown of how long the page request takes, along with the various stages like how long it takes to render the freemarker template, hibernate db calls, etc.
We just accomplished something similar with an interceptor and a custom tag. This solution is "light" enough to be used in production, presents its data as HTML comments at the bottom of the response, and allows you to opt into the more verbose logging with a request parameter. You apply the interceptor below to all request paths you want to profile, and you add the custom tag to the bottom of the desired pages. The placement of the custom tag is important; it should be invoked as close to the end of request processing as possible, as it's only aware of time spent (and objects loaded) prior to its invocation.
package com.foo.web.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class PageGenerationTimeInterceptor extends HandlerInterceptorAdapter {
public static final String PAGE_START_TIME = "page_start_time";
public static final String PAGE_GENERATION_TIME = "page_generation_time";
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
request.setAttribute(PAGE_START_TIME, new Long(System.currentTimeMillis()));
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
Long startTime = (Long) request.getAttribute(PAGE_START_TIME);
if (startTime != null) {
request.setAttribute(PAGE_GENERATION_TIME, new Long(System.currentTimeMillis() - startTime.longValue()));
}
}
}
The custom tag looks for the request attributes, and uses them to compute the handler time, the view time, and the total time. It can also query the current Hibernate session for first-level cache statistics, which can shed some light on how many objects were loaded by the handler and view. If you don't need the Hibernate information, you can delete the big if block.
package com.foo.web.taglib;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TryCatchFinally;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.CollectionKey;
import org.hibernate.engine.EntityKey;
import org.hibernate.stat.SessionStatistics;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.tags.RequestContextAwareTag;
import com.foo.web.interceptor.PageGenerationTimeInterceptor;
public class PageInfoTag extends RequestContextAwareTag implements TryCatchFinally {
private static final long serialVersionUID = -8448960221093136401L;
private static final Logger LOGGER = LogManager.getLogger(PageInfoTag.class);
public static final String SESSION_STATS_PARAM_NAME = "PageInfoTag.SessionStats";
#Override
public int doStartTagInternal() throws JspException {
try {
JspWriter out = pageContext.getOut();
Long startTime = (Long)pageContext.getRequest().getAttribute(PageGenerationTimeInterceptor.PAGE_START_TIME);
Long handlerTime = (Long)pageContext.getRequest().getAttribute(PageGenerationTimeInterceptor.PAGE_GENERATION_TIME);
if (startTime != null && handlerTime != null) {
long responseTime = System.currentTimeMillis() - startTime.longValue();
long viewTime = responseTime - handlerTime;
out.append(String.format("<!-- total: %dms, handler: %dms, view: %dms -->", responseTime, handlerTime, viewTime));
}
if (ServletRequestUtils.getBooleanParameter(pageContext.getRequest(), SESSION_STATS_PARAM_NAME, false)) {
//write another long HTML comment with information about contents of Hibernate first-level cache
ServletContext servletContext = pageContext.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
String[] beans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
SessionFactory.class, false, false);
if (beans.length > 0) {
SessionFactory sessionFactory = (SessionFactory) context.getBean(beans[0]);
Session session = sessionFactory.getCurrentSession();
SessionStatistics stats = session.getStatistics();
Map<String, NamedCount> entityHistogram = new HashMap<String, NamedCount>();
out.append("\n<!-- session statistics:\n");
out.append("\tObject keys (").append(String.valueOf(stats.getEntityCount())).append("):\n");
for (Object obj: stats.getEntityKeys()) {
EntityKey key = (EntityKey)obj;
out.append("\t\t").append(key.getEntityName()).append("#").append(key.getIdentifier().toString()).append("\n");
increment(entityHistogram, key.getEntityName());
}
out.append("\tObject key histogram:\n");
SortedSet<NamedCount> orderedEntityHistogram = new TreeSet<NamedCount>(entityHistogram.values());
for (NamedCount entry: orderedEntityHistogram) {
out.append("\t\t").append(entry.name).append(": ").append(String.valueOf(entry.count)).append("\n");
}
Map<String, NamedCount> collectionHistogram = new HashMap<String, NamedCount>();
out.append("\tCollection keys (").append(String.valueOf(stats.getCollectionCount())).append("):\n");
for (Object obj: stats.getCollectionKeys()) {
CollectionKey key = (CollectionKey)obj;
out.append("\t\t").append(key.getRole()).append("#").append(key.getKey().toString()).append("\n");
increment(collectionHistogram, key.getRole());
}
out.append("\tCollection key histogram:\n");
SortedSet<NamedCount> orderedCollectionHistogram = new TreeSet<NamedCount>(collectionHistogram.values());
for (NamedCount entry: orderedCollectionHistogram) {
out.append("\t\t").append(entry.name).append(": ").append(String.valueOf(entry.count)).append("\n");
}
out.append("-->");
}
}
} catch (IOException e) {
LOGGER.error("Unable to write page info tag");
throw new RuntimeException(e);
}
return Tag.EVAL_BODY_INCLUDE;
}
protected void increment(Map<String, NamedCount> histogram, String key) {
NamedCount count = histogram.get(key);
if (count == null) {
count = new NamedCount(key);
histogram.put(key, count);
}
count.count++;
}
class NamedCount implements Comparable<NamedCount> {
public String name;
public int count;
public NamedCount(String name) {
this.name = name;
count = 0;
}
#Override
public int compareTo(NamedCount other) {
//descending count, ascending name
int compared = other.count - this.count;
if (compared == 0) {
compared = this.name.compareTo(other.name);
}
return compared;
}
}
}
Take a look here:
Profiling with Eclipse and remote profile agents on Linux
Tutorial: Profiling with TPTP and Tomcat
An introduction to profiling Java applications using TPTP
TPTP = Eclipse Test and Performance Tools Platform
More links to the stack:
Open Source Profilers in Java