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">
+ * <filter>
+ * <filter-name><span class="blue">data-context-filter</span></filter-name>
+ * <filter-class><span class="red">org.apache.click.extras.cayenne.DataContextFilter</span></filter-class>
+ * <init-param>
+ * <param-name><font color="blue">lifecycle-listener</font></param-name>
+ * <param-value><font color="red">com.mycorp.service.AuditListener</font></param-value>
+ * </init-param>
+ * </filter> </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;