package com.vaadin.server;
import java.io.File;
-import java.io.PrintWriter;
import java.io.Serializable;
-import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class ApplicationContext implements HttpSessionBindingListener,
Serializable {
- /**
- * Interface for listening to transaction events. Implement this interface
- * to listen to all transactions between the client and the application.
- *
- */
- public static interface TransactionListener extends Serializable {
-
- /**
- * Invoked at the beginning of every transaction.
- *
- * The transaction is linked to the context, not the application so if
- * you have multiple applications running in the same context you need
- * to check that the request is associated with the application you are
- * interested in. This can be done looking at the application parameter.
- *
- * @param application
- * the Application object.
- * @param transactionData
- * the Data identifying the transaction.
- */
- public void transactionStart(Application application,
- Object transactionData);
-
- /**
- * Invoked at the end of every transaction.
- *
- * The transaction is linked to the context, not the application so if
- * you have multiple applications running in the same context you need
- * to check that the request is associated with the application you are
- * interested in. This can be done looking at the application parameter.
- *
- * @param applcation
- * the Application object.
- * @param transactionData
- * the Data identifying the transaction.
- */
- public void transactionEnd(Application application,
- Object transactionData);
-
- }
-
- protected Collection<ApplicationContext.TransactionListener> listeners = Collections
- .synchronizedList(new LinkedList<ApplicationContext.TransactionListener>());
-
protected final HashSet<Application> applications = new HashSet<Application>();
protected WebBrowser browser = new WebBrowser();
private transient WrappedSession session;
- /**
- * Adds a transaction listener to this context. The transaction listener is
- * called before and after each each request related to this session except
- * when serving static resources.
- *
- * The transaction listener must not be null.
- *
- * @see com.vaadin.service.ApplicationContext#addTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
- */
- public void addTransactionListener(
- ApplicationContext.TransactionListener listener) {
- if (listener != null) {
- listeners.add(listener);
- }
- }
-
- /**
- * Removes a transaction listener from this context.
- *
- * @param listener
- * the listener to be removed.
- * @see ApplicationContext.TransactionListener
- */
- public void removeTransactionListener(
- ApplicationContext.TransactionListener listener) {
- listeners.remove(listener);
- }
-
- /**
- * Sends a notification that a transaction is starting.
- *
- * @param application
- * The application associated with the transaction.
- * @param request
- * the HTTP or portlet request that triggered the transaction.
- */
- protected void startTransaction(Application application, Object request) {
- ArrayList<ApplicationContext.TransactionListener> currentListeners;
- synchronized (listeners) {
- currentListeners = new ArrayList<ApplicationContext.TransactionListener>(
- listeners);
- }
- for (ApplicationContext.TransactionListener listener : currentListeners) {
- listener.transactionStart(application, request);
- }
- }
-
- /**
- * Sends a notification that a transaction has ended.
- *
- * @param application
- * The application associated with the transaction.
- * @param request
- * the HTTP or portlet request that triggered the transaction.
- */
- protected void endTransaction(Application application, Object request) {
- LinkedList<Exception> exceptions = null;
-
- ArrayList<ApplicationContext.TransactionListener> currentListeners;
- synchronized (listeners) {
- currentListeners = new ArrayList<ApplicationContext.TransactionListener>(
- listeners);
- }
-
- for (ApplicationContext.TransactionListener listener : currentListeners) {
- try {
- listener.transactionEnd(application, request);
- } catch (final RuntimeException t) {
- if (exceptions == null) {
- exceptions = new LinkedList<Exception>();
- }
- exceptions.add(t);
- }
- }
-
- // If any runtime exceptions occurred, throw a combined exception
- if (exceptions != null) {
- final StringBuffer msg = new StringBuffer();
- for (Exception e : exceptions) {
- if (msg.length() == 0) {
- msg.append("\n\n--------------------------\n\n");
- }
- msg.append(e.getMessage() + "\n");
- final StringWriter trace = new StringWriter();
- e.printStackTrace(new PrintWriter(trace, true));
- msg.append(trace.toString());
- }
- throw new RuntimeException(msg.toString());
- }
- }
-
/**
* @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
*/
(ResourceResponse) response);
} else {
Application application = null;
- boolean transactionStarted = false;
boolean requestStarted = false;
boolean applicationRunning = false;
startApplication(request, application, applicationContext);
applicationRunning = true;
- /*
- * Transaction starts. Call transaction listeners. Transaction
- * end is called in the finally block below.
- */
- applicationContext.startTransaction(application, request);
- transactionStarted = true;
-
/* Notify listeners */
// Finds the window within the application
// Notifies transaction end
try {
- if (transactionStarted) {
- ((PortletApplicationContext2) application.getContext())
- .endTransaction(application, request);
+ if (requestStarted) {
+ ((PortletRequestListener) application).onRequestEnd(
+ request, response);
+
}
} finally {
- try {
- if (requestStarted) {
- ((PortletRequestListener) application)
- .onRequestEnd(request, response);
+ CurrentInstance.clearAll();
- }
- } finally {
- CurrentInstance.clearAll();
-
- PortletSession session = request
- .getPortletSession(false);
- if (session != null) {
- requestTimer.stop(getApplicationContext(session));
- }
+ PortletSession session = request.getPortletSession(false);
+ if (session != null) {
+ requestTimer.stop(getApplicationContext(session));
}
}
}
}
Application application = null;
- boolean transactionStarted = false;
boolean requestStarted = false;
boolean applicationRunning = false;
startApplication(request, application, webApplicationContext);
applicationRunning = true;
- /*
- * Transaction starts. Call transaction listeners. Transaction end
- * is called in the finally block below.
- */
- webApplicationContext.startTransaction(application, request);
- transactionStarted = true;
-
/* Handle the request */
if (requestType == RequestType.FILE_UPLOAD) {
// UI is resolved in communication manager
// Notifies transaction end
try {
- if (transactionStarted) {
- ((ServletApplicationContext) application.getContext())
- .endTransaction(application, request);
-
+ if (requestStarted) {
+ ((HttpServletRequestListener) application).onRequestEnd(
+ request, response);
}
-
} finally {
- try {
- if (requestStarted) {
- ((HttpServletRequestListener) application)
- .onRequestEnd(request, response);
- }
- } finally {
- CurrentInstance.clearAll();
+ CurrentInstance.clearAll();
- HttpSession session = request.getSession(false);
- if (session != null) {
- requestTimer.stop(getApplicationContext(session));
- }
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ requestTimer.stop(getApplicationContext(session));
}
}
+++ /dev/null
-package com.vaadin.tests.server;
-
-import static org.easymock.EasyMock.createMock;
-
-import java.lang.Thread.UncaughtExceptionHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Properties;
-import java.util.Random;
-
-import javax.servlet.http.HttpSession;
-
-import junit.framework.TestCase;
-
-import org.easymock.EasyMock;
-
-import com.vaadin.Application;
-import com.vaadin.Application.ApplicationStartEvent;
-import com.vaadin.server.ApplicationContext;
-import com.vaadin.server.DeploymentConfiguration;
-import com.vaadin.server.ServletApplicationContext;
-
-public class TransactionListenersConcurrency extends TestCase {
-
- /**
- * This test starts N threads concurrently. Each thread creates an
- * application which adds a transaction listener to the context. A
- * transaction is then started for each application. Some semi-random delays
- * are included so that calls to addTransactionListener and
- * WebApplicationContext.startTransaction are mixed.
- *
- */
- public void testTransactionListeners() throws Exception {
- final List<Throwable> exceptions = new ArrayList<Throwable>();
-
- HttpSession session = createSession();
- final ServletApplicationContext context = ServletApplicationContext
- .getApplicationContext(session);
- List<Thread> threads = new ArrayList<Thread>();
-
- for (int i = 0; i < 5; i++) {
- Thread t = new Thread(new Runnable() {
-
- @Override
- public void run() {
- Application app = new Application() {
-
- @Override
- public void init() {
- // Sleep 0-1000ms so another transaction has time to
- // start before we add the transaction listener.
- try {
- Thread.sleep((long) (1000 * new Random()
- .nextDouble()));
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- getContext().addTransactionListener(
- new DelayTransactionListener(2000));
- }
-
- };
-
- // Start the application so the transaction listener is
- // called later on.
- try {
- DeploymentConfiguration dc = EasyMock
- .createMock(DeploymentConfiguration.class);
- EasyMock.expect(dc.isProductionMode()).andReturn(true);
- EasyMock.expect(dc.getInitParameters()).andReturn(
- new Properties());
- EasyMock.replay(dc);
-
- app.start(new ApplicationStartEvent(new URL(
- "http://localhost/"), dc, context));
- } catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- try {
- // Call the transaction listener using reflection as
- // startTransaction is protected.
-
- Method m = ApplicationContext.class.getDeclaredMethod(
- "startTransaction", Application.class,
- Object.class);
- m.setAccessible(true);
- m.invoke(context, app, null);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- });
-
- threads.add(t);
- t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
-
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- if (e.getCause() != null) {
- e = e.getCause();
- }
- exceptions.add(e);
- }
- });
- }
-
- // Start the threads and wait for all of them to finish
- for (Thread t : threads) {
- t.start();
- }
- int running = threads.size();
-
- while (running > 0) {
- for (Iterator<Thread> i = threads.iterator(); i.hasNext();) {
- Thread t = i.next();
- if (!t.isAlive()) {
- running--;
- i.remove();
- }
- }
- }
-
- for (Throwable t : exceptions) {
- if (t instanceof InvocationTargetException) {
- t = t.getCause();
- }
- if (t != null) {
- t.printStackTrace(System.err);
- fail(t.getClass().getName());
- }
- }
-
- System.out.println("Done, all ok");
-
- }
-
- /**
- * Creates a HttpSession mock
- *
- */
- private static HttpSession createSession() {
- HttpSession session = createMock(HttpSession.class);
- EasyMock.expect(
- session.getAttribute(ServletApplicationContext.class.getName()))
- .andReturn(null).anyTimes();
- session.setAttribute(
- EasyMock.eq(ServletApplicationContext.class.getName()),
- EasyMock.anyObject());
-
- EasyMock.replay(session);
- return session;
- }
-
- /**
- * A transaction listener that just sleeps for the given amount of time in
- * transactionStart and transactionEnd.
- *
- */
- public static class DelayTransactionListener implements
- ApplicationContext.TransactionListener {
-
- private int delay;
-
- public DelayTransactionListener(int delay) {
- this.delay = delay;
- }
-
- @Override
- public void transactionStart(Application application,
- Object transactionData) {
- try {
- Thread.sleep(delay);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- }
-
- @Override
- public void transactionEnd(Application application,
- Object transactionData) {
- try {
- Thread.sleep(delay);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- }
- }
-
-}
+++ /dev/null
-package com.vaadin.tests.applicationcontext;
-
-import com.vaadin.Application;
-import com.vaadin.server.ApplicationContext;
-import com.vaadin.server.ApplicationContext.TransactionListener;
-import com.vaadin.tests.components.TestBase;
-import com.vaadin.tests.util.Log;
-
-public class RemoveTransactionListener extends TestBase {
-
- private final Log log = new Log(10);
-
- @Override
- protected void setup() {
- // Add one listener that will remove itself from within transactionEnd
- getMainWindow().getApplication().getContext()
- .addTransactionListener(new TransactionListener() {
- @Override
- public void transactionStart(Application application,
- Object transactionData) {
- }
-
- @Override
- public void transactionEnd(Application application,
- Object transactionData) {
- removeListener(this);
- log.log("Listener removed in transactionEnd");
- }
- });
-
- // Add one listener that will remove itself from within transactionStart
- getMainWindow().getApplication().getContext()
- .addTransactionListener(new TransactionListener() {
- @Override
- public void transactionStart(Application application,
- Object transactionData) {
- removeListener(this);
- log.log("Listener removed in transactionStart");
- }
-
- @Override
- public void transactionEnd(Application application,
- Object transactionData) {
- }
- });
-
- // Add one listener to verify that all listeners are called, as thrown
- // ConcurrentModificationException causes subsequent listeners to be
- // ignored
- getMainWindow().getApplication().getContext()
- .addTransactionListener(new TransactionListener() {
- @Override
- public void transactionStart(Application application,
- Object transactionData) {
- log.log("transactionStart from last listener");
- }
-
- @Override
- public void transactionEnd(Application application,
- Object transactionData) {
- log.log("transactionEnd from last listener");
- }
- });
-
- addComponent(log);
- }
-
- private void removeListener(TransactionListener l) {
- ApplicationContext context = getMainWindow().getApplication()
- .getContext();
- context.removeTransactionListener(l);
- }
-
- @Override
- protected String getDescription() {
- return "Tests that a transaction listener can be removed from within the listener.";
- }
-
- @Override
- protected Integer getTicketNumber() {
- return Integer.valueOf(7065);
- }
-
-}