001: /*
002: * Copyright (c) 2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017:
018: package org.jpublish.module.cayenne;
019:
020: import com.anthonyeden.lib.config.Configuration;
021: import org.apache.cayenne.CayenneException;
022: import org.apache.cayenne.access.DataContext;
023: import org.apache.cayenne.conf.DefaultConfiguration;
024: import org.apache.cayenne.conf.ServletUtil;
025: import org.apache.cayenne.util.ResourceLocator;
026: import org.apache.cayenne.util.WebApplicationResourceLocator;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.jpublish.JPublishModule;
030: import org.jpublish.SiteContext;
031: import org.jpublish.action.ActionWrapper;
032: import org.jpublish.action.PathAction;
033:
034: import javax.servlet.ServletContext;
035: import javax.sql.DataSource;
036: import java.util.HashMap;
037: import java.util.List;
038: import java.util.Map;
039:
040: /**
041: * The Cayenne module
042: *
043: * @author <a href="mailto:florin.patrascu@gmail.com">Florin T.PATRASCU</a>
044: * @since $Revision$ (created: Sep 22, 2007 10:50:57 AM)
045: */
046: public class JPCayenneModule implements JPublishModule {
047: public static final String JPCAYENNE_SERVICE_NAME = "jpCayenneService";
048: public static final String JPCAYENNE_DATA_CONTEXT = "jpCayenne_DC";
049: public static final String JPCAYENNE_OBJECT_CONTEXT = "jpCayenne_OC";
050: public static final String JPCAYENNE_DATA_OBJECT_UTILS = "DataObjectUtils"; // I am not sure we need this one
051: public static final String JPCAYENNE__UTILS = "jpCayenneUtils";
052:
053: private static final Log log = LogFactory
054: .getLog(JPCayenneModule.class);
055:
056: private static final String NAME = "JPCayenne Module";
057: private static final String VERSION = "v0.1b";
058: private static final String DESCRIPTION = "Cayenne ORM support for JPublish";
059: private static final String CAYENNE_VERSION = "Cayenne "
060: + CayenneException.getExceptionLabel();
061:
062: private SiteContext site;
063: private Map actions = new HashMap(5);
064:
065: private Map jpCayenneUtils = new HashMap(5);
066: /**
067: * Automatically rollback any changes to the DataContext at the end of
068: * each request, the default value is true.
069: * <p/>
070: * This option is only useful for sessionScope DataObjects.
071: */
072: private boolean autoRollback = true;
073:
074: /**
075: * Maintain user HttpSession scope DataContext object, the default value is
076: * true. If sessionScope is false then a new DataContext object will be
077: * created for each request.
078: */
079: private boolean sessionScope = true;
080:
081: /**
082: * Create DataContext objects using the shared cache.
083: */
084: private boolean sharedCache = true;
085:
086: private boolean debugEnabled = false;
087:
088: //protected org.apache.cayenne.conf.Configuration configuration;
089: DefaultConfiguration conf;
090: protected DataSource dataSource;
091:
092: /**
093: * Initialize the module. This corresponds with the
094: * Servlet.init() method, except that it includes a reference
095: * to the JPublish SiteContext.
096: *
097: * @param site The SiteContext
098: * @param config The configuration object
099: * @throws Exception
100: */
101: public void init(SiteContext site, Configuration config)
102: throws Exception {
103: log.info(NAME + " starting for: "
104: + site.getServletContext().getServletContextName());
105: this .site = site;
106:
107: String cayenneConfigPath = config.getChildValue(
108: "cayenne-config-path", "WEB-INF");
109: log.info("Initializing the " + CAYENNE_VERSION
110: + "framework from: " + cayenneConfigPath);
111:
112: // create new shared configuration
113: conf = new DefaultConfiguration(
114: org.apache.cayenne.conf.Configuration.DEFAULT_DOMAIN_FILE,
115: createLocator(site.getServletContext(),
116: cayenneConfigPath));
117: org.apache.cayenne.conf.Configuration
118: .initializeSharedConfiguration(conf);
119:
120: String value = config.getChildValue("auto-rollback", "true");
121: autoRollback = "true".equalsIgnoreCase(value);
122:
123: value = config.getChildValue("session-scope", "true");
124: sessionScope = "true".equalsIgnoreCase(value);
125:
126: value = config.getChildValue("shared-cache", "true");
127: sharedCache = "true".equalsIgnoreCase(value);
128:
129: value = config.getChildValue("debug", "false");
130: debugEnabled = "true".equalsIgnoreCase(value);
131:
132: String msg = "Cayenne DataContext initialized with: auto-rollback="
133: + autoRollback
134: + ", session-scope="
135: + sessionScope
136: + ", shared-cache=" + sharedCache;
137:
138: log.info(msg);
139:
140: //jpCayenneUtils.put(JPCAYENNE_DATA_OBJECT_UTILS,
141: // ClassUtilities.loadClass("org.apache.cayenne.DataObjectUtils"));
142:
143: log.info("Mapping Cayenne support...");
144: List urls = config.getChild("cayenne-enabled-urls")
145: .getChildren();
146: if (urls != null && !urls.isEmpty()) {
147: for (int i = 0; i < urls.size(); i++) {
148: Configuration url = (Configuration) urls.get(i);
149: String path = url.getAttribute("path");
150: if (path != null) {
151: ActionWrapper aw;
152: boolean ro = url.getAttribute("readonly", "false")
153: .equalsIgnoreCase("true");
154: if (ro) {
155: aw = new ActionWrapper(
156: new PathAction(
157: path,
158: new CayenneReadOnlySupportAction(
159: this )), config);
160: } else {
161: aw = new ActionWrapper(new PathAction(path,
162: new CayenneSupportBeforeAction(this )),
163: config);
164: // add a post-evaluate action for all the R/W paths
165: site
166: .getActionManager()
167: .getPostEvaluationActions()
168: .add(
169: new ActionWrapper(
170: new PathAction(
171: path,
172: new CayenneSupportAfterAction(
173: this )),
174: config));
175: }
176:
177: site.getActionManager().getPathActions().add(aw);
178: log.info("... added "
179: + (ro ? "read-only" : "read-write")
180: + " support for: " + path);
181: }
182: }
183: } else {
184: log
185: .info(" ... the 'cayenne-enabled-urls' node contains no mappings. "
186: + "Cayenne support will be unavailable to the web requests.");
187:
188: }
189: //todo implement a ShutDown action
190:
191: //populate the Application with a shared DataContext
192: DataContext dataContext = (DataContext) site
193: .getAttribute(ServletUtil.DATA_CONTEXT_KEY);
194:
195: if (dataContext == null) {
196: dataContext = DataContext
197: .createDataContext(isSharedCache());
198: site
199: .setAttribute(ServletUtil.DATA_CONTEXT_KEY,
200: dataContext);
201: if (isDebugEnabled()) {
202: log
203: .info("Created an Application wide DataContext with shared-cache="
204: + isSharedCache());
205: }
206: }
207:
208: DataContext.bindThreadDataContext(dataContext);
209:
210: site.setAttribute(JPCayenneModule.JPCAYENNE_SERVICE_NAME,
211: new JPCayenneService());
212: log.info(this .toString() + " started.");
213: }
214:
215: /**
216: * Get a map of defined actions.
217: *
218: * @return The defined actions
219: */
220: public Map getDefinedActions() {
221: return actions;
222: }
223:
224: public static String getModuleDescription() {
225: return DESCRIPTION;
226: }
227:
228: public SiteContext getSite() {
229: return site;
230: }
231:
232: /**
233: * Invoked when the module is destroyed. This corresponds to the
234: * Servlet.destroy() method.
235: */
236: public void destroy() {
237: log.info("Shutting down the Cayenne configuration ....");
238: if (conf != null) {
239: conf.shutdown();
240: }
241: }
242:
243: /**
244: *
245: * @return the Cayenne configuration used by this module
246: */
247: public DefaultConfiguration getCayenneConfiguration() {
248: return conf;
249: }
250:
251: /**
252: * A helper method to create default ResourceLocator.
253: *
254: * @param context the Servlet context
255: * @param cayenneConfigPath the path to the cayenne configuration file (e.g: WEB-INF)
256: * @return a resourceLocator object
257: */
258: protected static ResourceLocator createLocator(
259: ServletContext context, String cayenneConfigPath) {
260: WebApplicationResourceLocator locator = new WebApplicationResourceLocator();
261: locator.setSkipAbsolutePath(true);
262: locator.setSkipClasspath(false);
263: locator.setSkipCurrentDirectory(true);
264: locator.setSkipHomeDirectory(true);
265:
266: locator.setServletContext(context);
267: if (cayenneConfigPath != null
268: && cayenneConfigPath.trim().length() > 0) {
269: locator.addFilesystemPath(cayenneConfigPath.trim());
270: }
271: return locator;
272: }
273:
274: public boolean isAutoRollback() {
275: return autoRollback;
276: }
277:
278: public boolean isSessionScope() {
279: return sessionScope;
280: }
281:
282: public boolean isSharedCache() {
283: return sharedCache;
284: }
285:
286: public boolean isDebugEnabled() {
287: return debugEnabled;
288: }
289:
290: public Map getJPCayenneUtils() {
291: return jpCayenneUtils;
292: }
293:
294: public String toString() {
295: return NAME + " " + VERSION;
296: }
297: }
|