You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@click.apache.org by me...@apache.org on 2009/06/04 14:55:44 UTC

svn commit: r781725 - in /incubator/click/trunk/click: ./ build/ documentation/docs/ examples/ extras/src/org/apache/click/extras/cayenne/

Author: medgar
Date: Thu Jun  4 12:55:43 2009
New Revision: 781725

URL: http://svn.apache.org/viewvc?rev=781725&view=rev
Log:
CLK-559

Modified:
    incubator/click/trunk/click/.classpath
    incubator/click/trunk/click/build/build.properties
    incubator/click/trunk/click/documentation/docs/roadmap-changes.html
    incubator/click/trunk/click/examples/build.xml
    incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/CayenneTemplate.java
    incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/DataContextFilter.java

Modified: incubator/click/trunk/click/.classpath
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/.classpath?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/.classpath (original)
+++ incubator/click/trunk/click/.classpath Thu Jun  4 12:55:43 2009
@@ -15,7 +15,6 @@
 	<classpathentry kind="lib" path="lib/ognl-2.6.9.jar"/>
 	<classpathentry kind="lib" path="lib/log4j-1.2.14.jar"/>
 	<classpathentry kind="var" path="EXAMPLES/ashwood-1.1.jar"/>
-	<classpathentry kind="var" path="EXAMPLES/cayenne-nodeps-2.0.4.jar"/>
 	<classpathentry kind="var" path="EXAMPLES/commons-logging-1.0.4.jar"/>
 	<classpathentry kind="var" path="EXAMPLES/hsqldb-1.8.0.1.jar"/>
 	<classpathentry kind="var" path="EXAMPLES/jstl-1.1.2.jar"/>
@@ -33,5 +32,6 @@
 	<classpathentry kind="lib" path="examples/webapp/WEB-INF/lib/acegi-security-1.0.7.jar"/>
 	<classpathentry kind="lib" path="examples/webapp/WEB-INF/lib/quartz-all-1.6.3.jar"/>
 	<classpathentry kind="lib" path="lib/slf4j-api-1.5.6.jar"/>
+	<classpathentry kind="lib" path="lib/cayenne-server-3.0M5.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>

Modified: incubator/click/trunk/click/build/build.properties
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/build/build.properties?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/build/build.properties (original)
+++ incubator/click/trunk/click/build/build.properties Thu Jun  4 12:55:43 2009
@@ -62,7 +62,6 @@
 geronimo-common-annotations.version=1.1.1
 hsqldb.version=1.8.0.1
 jstl.version=1.1.2
-oro.version=2.0.8
 poi.version=3.0-FINAL
 quartz.version=1.6.3
 slf4j.version=1.5.6

Modified: incubator/click/trunk/click/documentation/docs/roadmap-changes.html
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/documentation/docs/roadmap-changes.html?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/documentation/docs/roadmap-changes.html (original)
+++ incubator/click/trunk/click/documentation/docs/roadmap-changes.html Thu Jun  4 12:55:43 2009
@@ -277,8 +277,13 @@
           [<a target='_blank' href="https://issues.apache.org/click/browse/CLK-552">552</a>].
       </li>
       <li class="change">
-          <a class="external" target="_blank" href="http://code.google.com/p/click-calendar/">Click Calendar</a>
-          version 1.0.1 has been released which fixes a memory leak in the calendar popup
+          Improved Cayenne DataContextFilter, including adding support for LifecycleListener 
+          registration
+          [<a target='_blank' href="https://issues.apache.org/jira/browse/CLK-559">559</a>].
+      </li>
+      <li class="change">
+          Fixed <a class="external" target="_blank" href="http://code.google.com/p/click-calendar/">Click Calendar</a>
+          memory leak in calendar popup with version 1.0.1 released
           [<a target='_blank' href="https://issues.apache.org/jira/browse/CLK-499">499</a>].
       </li>
       <li class="change">

Modified: incubator/click/trunk/click/examples/build.xml
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/examples/build.xml?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/examples/build.xml (original)
+++ incubator/click/trunk/click/examples/build.xml Thu Jun  4 12:55:43 2009
@@ -38,7 +38,6 @@
    <property name="jar.logging" value="commons-logging-${commons-logging.version}.jar"/>
    <property name="jar.poi" value="poi-${poi.version}.jar"/>
    <property name="jar.quartz" value="quartz-all-${quartz.version}.jar"/>
-   <property name="jar.oro" value="oro-${oro.version}.jar"/>
    <property name="jar.servlet" value="servlet-api-${servlet-api.version}.jar"/>
    <property name="jar.spring" value="spring-${spring.version}.jar"/>
    <property name="jar.standard" value="standard-${standard.version}.jar"/>

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/CayenneTemplate.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/CayenneTemplate.java?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/CayenneTemplate.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/CayenneTemplate.java Thu Jun  4 12:55:43 2009
@@ -20,10 +20,12 @@
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.BaseContext;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataObject;
 import org.apache.cayenne.DataObjectUtils;
@@ -69,8 +71,19 @@
      * @param dataObjectClass the data object class to create and register
      * @return the new registered data object
      */
+    protected DataObject newObject(Class dataObjectClass) {
+        return (DataObject) getDataContext().newObject(dataObjectClass);
+    }
+
+    /**
+     * Instantiates new object and registers it with itself. Object class must
+     * have a default constructor.
+     *
+     * @param dataObjectClass the data object class to create and register
+     * @return the new registered data object
+     */
     protected DataObject createAndRegisterNewObject(Class dataObjectClass) {
-        return getDataContext().createAndRegisterNewObject(dataObjectClass);
+        return (DataObject) getDataContext().newObject(dataObjectClass);
     }
 
     /**
@@ -150,11 +163,11 @@
      */
     protected DataContext getDataContext() {
         try {
-            return DataContext.getThreadDataContext();
+            return (DataContext) BaseContext.getThreadObjectContext();
 
         } catch (IllegalStateException ise) {
             DataContext dataContext = DataContext.createDataContext();
-            DataContext.bindThreadDataContext(dataContext);
+            BaseContext.bindThreadObjectContext(dataContext);
             return dataContext;
         }
     }
@@ -228,14 +241,14 @@
                     + objEntity.getName());
         }
 
-        List pkAttributes = dbEntity.getPrimaryKey();
+        Collection pkAttributes = dbEntity.getPrimaryKeys();
         if (pkAttributes.size() != 1) {
             throw new CayenneRuntimeException("PK contains "
                     + pkAttributes.size()
                     + " columns, expected 1.");
         }
 
-        DbAttribute attr = (DbAttribute) pkAttributes.get(0);
+        DbAttribute attr = (DbAttribute) pkAttributes.iterator().next();
 
         return attr.getName();
     }

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/DataContextFilter.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/DataContextFilter.java?rev=781725&r1=781724&r2=781725&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/DataContextFilter.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/cayenne/DataContextFilter.java Thu Jun  4 12:55:43 2009
@@ -19,24 +19,30 @@
 package org.apache.click.extras.cayenne;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.Iterator;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
-import org.apache.click.util.HtmlStringBuffer;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
+import org.apache.cayenne.BaseContext;
+import org.apache.cayenne.LifecycleListener;
 import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.conf.Configuration;
 import org.apache.cayenne.conf.ServletUtil;
+import org.apache.cayenne.map.LifecycleEvent;
+import org.apache.cayenne.reflect.LifecycleCallbackRegistry;
+import org.apache.click.service.ConfigService;
+import org.apache.click.service.LogService;
+import org.apache.click.util.ClickUtils;
+import org.apache.click.util.HtmlStringBuffer;
+import org.apache.commons.lang.StringUtils;
 
 /**
  * Provides a servlet filter which binds DataContext objects to the request.
@@ -73,6 +79,27 @@
  * However when web applications which share a database you should probably
  * disable this option by setting the <tt>shared-cache</tt> init parameter to false.
  *
+ * <h3>Lifecycle Listener</h3>
+ *
+ * You can register a data domain
+ * <a href="http://cayenne.apache.org/doc/api/org/apache/cayenne/LifecycleListener.html">LifecycleListener</a>
+ * class to listen to persistent object lifecycle events. Please see the
+ * Cayenne <a href="http://cayenne.apache.org/doc/lifecycle-callbacks.html">Lifecycle Callbacks</a>
+ * documentation for more details.
+ * <p/>
+ * To configure a Livecycle Listener simply specify the class name of the listener
+ * class as a filter init parameter. For example:
+ *
+ * <pre class="codeConfig">
+ *   &lt;filter&gt;
+ *     &lt;filter-name&gt;<span class="blue">data-context-filter</span>&lt;/filter-name&gt;
+ *     &lt;filter-class&gt;<span class="red">org.apache.click.extras.cayenne.DataContextFilter</span>&lt;/filter-class&gt;
+ *     &lt;init-param&gt;
+ *       &lt;param-name&gt;<font color="blue">lifecycle-listener</font>&lt;/param-name&gt;
+ *       &lt;param-value&gt;<font color="red">com.mycorp.service.AuditListener</font>&lt;/param-value&gt;
+ *     &lt;/init-param&gt;
+ *   &lt;/filter&gt; </pre>
+ *
  * <h3>Configuration Examples</h3>
  *
  * An example data context filter configuration in the web application's
@@ -157,6 +184,15 @@
      */
     protected boolean autoRollback = true;
 
+    /** The Cayenne DataDomain. */
+    protected DataDomain dataDomain;
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    protected FilterConfig filterConfig = null;
+
     /**
      * Maintain user HttpSession scope DataContext object, the default value is
      * true. If sessionScope is false then a new DataContext object will be
@@ -167,8 +203,10 @@
     /** Create DataContext objects using the shared cache. */
     protected boolean sharedCache = true;
 
-    /** The DataContextFilter logger. */
-    protected Logger logger = Logger.getLogger(getClass());
+    /** The Click log service. */
+    protected LogService logger;
+
+    // --------------------------------------------------------- Public Methods
 
     /**
      * Initialize the shared Cayenne configuration. If the
@@ -177,12 +215,16 @@
      * @see Filter#init(FilterConfig)
      *
      * @param config the filter configuration
-     * @throws ServletException if an initialization error occurs
+     * @throws RuntimeException if an initialization error occurs
      */
-    public synchronized void init(FilterConfig config) throws ServletException {
+    public synchronized void init(FilterConfig config) {
+
+        filterConfig = config;
 
         ServletUtil.initializeSharedConfiguration(config.getServletContext());
 
+        dataDomain = Configuration.getSharedConfiguration().getDomain();
+
         String value = null;
 
         value = config.getInitParameter("auto-rollback");
@@ -200,17 +242,41 @@
             sharedCache = "true".equalsIgnoreCase(value);
         }
 
-        String msg = "DataContextFilter initialized with: auto-rollback="
-            + autoRollback + ", session-scope=" + sessionScope
-            + ", shared-cache=" + sharedCache;
+        String classname = config.getInitParameter("lifecycle-listener");
+
+        if (StringUtils.isNotEmpty(classname)) {
+            try {
+                Class listenerClass = ClickUtils.classForName(classname);
+
+                LifecycleCallbackRegistry registry =
+                    dataDomain.getEntityResolver().getCallbackRegistry();
+
+                LifecycleListener lifecycleListener = (LifecycleListener)
+                    listenerClass.newInstance();
 
-        logger.info(msg);
+                if (registry.isEmpty(LifecycleEvent.POST_LOAD)) {
+                    registry.addDefaultListener(lifecycleListener);
+
+                } else {
+                    String message =
+                        "Could not get LifecycleCallbackRegistry from domain: "
+                        + dataDomain.getName();
+                    throw new RuntimeException(message);
+                }
+
+            } catch (Exception e) {
+                String message =
+                    "Could not configure LifecycleCallbackRegistry: " + classname;
+                throw new RuntimeException(message, e);
+            }
+        }
     }
 
     /**
      * Destroy the DataContextFilter.
      */
     public void destroy() {
+        this.filterConfig = null;
     }
 
     /**
@@ -227,6 +293,12 @@
     public void doFilter(ServletRequest request, ServletResponse response,
             FilterChain chain) throws IOException, ServletException {
 
+        if (logger == null) {
+             ServletContext servletContext = getFilterConfig().getServletContext();
+             ConfigService configService = ClickUtils.getConfigService(servletContext);
+             logger = configService.getLogService();
+        }
+
         // Obtain the users DataContext
         DataContext dataContext = getDataContext((HttpServletRequest) request);
 
@@ -235,30 +307,50 @@
         }
 
         // Bind DataContext to the request thread
-        DataContext.bindThreadDataContext(dataContext);
+        BaseContext.bindThreadObjectContext(dataContext);
 
         try {
             chain.doFilter(request, response);
 
         } finally {
+            BaseContext.bindThreadObjectContext(null);
+
             if (logger.isDebugEnabled() && dataContext.hasChanges()) {
                 logger.debug("Uncommitted data objects:");
 
-                Collection uncommitted = dataContext.uncommittedObjects();
-                for (Iterator i = uncommitted.iterator(); i.hasNext();) {
-                    logger.debug("   " + i.next());
+                for (Object uncommitted : dataContext.uncommittedObjects()) {
+                    logger.debug("   " + uncommitted);
                 }
             }
 
             if (autoRollback) {
                 dataContext.rollbackChanges();
             }
-
-            DataContext.bindThreadDataContext(null);
         }
     }
 
     /**
+     * Set filter configuration. This function is equivalent to init and is
+     * required by Weblogic 6.1.
+     *
+     * @param filterConfig the filter configuration object
+     */
+    public void setFilterConfig(FilterConfig filterConfig) {
+        init(filterConfig);
+    }
+
+    /**
+     * Return filter config. This is required by Weblogic 6.1
+     *
+     * @return the filter configuration
+     */
+    public FilterConfig getFilterConfig() {
+        return filterConfig;
+    }
+
+    // ------------------------------------------------------ Protected Methods
+
+    /**
      * Return a DataContext instance. If the DataContextFilter is configured
      * to associate the DataContext with the session (which is the default
      * behaviour), the DataContext will be bound to the users session. If
@@ -268,46 +360,57 @@
      * If this filter is configured with <tt>create-each-request</tt> to be true
      * then a new DataContext will be created for each request and the DataContext
      * will not be bound to the session.
-     * <p/>
-     * If this filter is configured with <tt>use-shared-cache</tt> to be true
-     * (which is the default behaviour) this method will create DataContext objects
-     * using the Cayenne shared cache, otherwise they will not use the shared cache.
      *
      * @param request the page request
      * @return the DataContext object
      */
-    protected synchronized DataContext getDataContext(HttpServletRequest request) {
-
-        HttpSession session = null;
-        DataContext dataContext = null;
+    protected DataContext getDataContext(HttpServletRequest request) {
 
         if (sessionScope) {
-            session = request.getSession(true);
-            dataContext = (DataContext) session.getAttribute(ServletUtil.DATA_CONTEXT_KEY);
+            HttpSession session = request.getSession(true);
+
+            DataContext dataContext = (DataContext)
+                session.getAttribute(ServletUtil.DATA_CONTEXT_KEY);
+
+            if (dataContext == null) {
+                synchronized (session) {
+                    dataContext = createDataContext();
+
+                    session.setAttribute(ServletUtil.DATA_CONTEXT_KEY, dataContext);
+                }
+            }
+
+            return dataContext;
+
+        } else {
+            return createDataContext();
         }
+    }
 
-        if (dataContext == null) {
-            dataContext = DataContext.createDataContext(sharedCache);
+    /**
+     * Return a new DataContex instance using a shared cache if the filter is
+     * configured with <tt>use-shared-cache</tt>, otherwise the DataContext
+     * will not use a shared cache.
+     *
+     * @return the DataContext object
+     */
+    protected DataContext createDataContext() {
+        DataContext dataContext = dataDomain.createDataContext(sharedCache);
 
+        if (logger.isTraceEnabled()) {
+            HtmlStringBuffer buffer = new HtmlStringBuffer();
+            buffer.append("DataContext created with ");
             if (sessionScope) {
-                session.setAttribute(ServletUtil.DATA_CONTEXT_KEY, dataContext);
+                buffer.append("session scope");
+            } else {
+                buffer.append("request scope");
             }
-
-            if (logger.isDebugEnabled()) {
-                HtmlStringBuffer buffer = new HtmlStringBuffer();
-                buffer.append("DataContext created with ");
-                if (sessionScope) {
-                    buffer.append("session scope");
-                } else {
-                    buffer.append("request scope");
-                }
-                if (sharedCache) {
-                    buffer.append(" and shared cache.");
-                } else {
-                    buffer.append(".");
-                }
-                logger.debug(buffer);
+            if (sharedCache) {
+                buffer.append(" and shared cache.");
+            } else {
+                buffer.append(".");
             }
+            logger.trace(buffer);
         }
 
         return dataContext;