001: /*
002: * Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
003: *
004: * This file is part of TransferCM.
005: *
006: * TransferCM is free software; you can redistribute it and/or modify it under the
007: * terms of the GNU General Public License as published by the Free Software
008: * Foundation; either version 2 of the License, or (at your option) any later
009: * version.
010: *
011: * TransferCM is distributed in the hope that it will be useful, but WITHOUT ANY
012: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
013: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
014: * details.
015: *
016: * You should have received a copy of the GNU General Public License along with
017: * TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
018: * Fifth Floor, Boston, MA 02110-1301 USA
019: */
020:
021: package com.methodhead.sitecontext;
022:
023: import java.sql.SQLException;
024: import java.sql.ResultSet;
025: import javax.servlet.http.HttpServletRequest;
026:
027: import com.methodhead.persistable.ConnectionSingleton;
028: import com.methodhead.persistable.Persistable;
029: import com.methodhead.persistable.PersistableException;
030: import com.methodhead.persistable.Key;
031: import com.methodhead.MhfException;
032: import com.methodhead.event.Event;
033: import com.methodhead.aikp.IntKey;
034: import com.methodhead.aikp.AutoIntKeyPersistable;
035:
036: import java.util.List;
037: import java.util.ArrayList;
038: import java.util.Iterator;
039: import java.util.Collections;
040:
041: import org.apache.commons.beanutils.DynaClass;
042: import org.apache.commons.beanutils.DynaProperty;
043: import org.apache.commons.beanutils.BasicDynaClass;
044: import org.apache.log4j.Logger;
045: import org.apache.commons.lang.exception.ExceptionUtils;
046:
047: /**
048: * A SiteContext. The following fields are defined:
049: * <ul>
050: * <li><tt>int id = 0</tt></li>
051: * <li><tt>int path = ""</tt></li>
052: * </ul>
053: */
054: public class SiteContext extends AutoIntKeyPersistable implements
055: Comparable {
056:
057: private static DynaClass dynaClass_ = null;
058: private static DynaClass domainDynaClass_ = null;
059:
060: static {
061: DynaProperty[] dynaProperties = new DynaProperty[] {
062: new DynaProperty("id", Integer.class),
063: new DynaProperty("path", String.class) };
064:
065: dynaClass_ = new BasicDynaClass("mh_sitecontext",
066: SiteContext.class, dynaProperties);
067:
068: dynaProperties = new DynaProperty[] {
069: new DynaProperty("sitecontext_id", Integer.class),
070: new DynaProperty("name", String.class),
071: new DynaProperty("rank", Integer.class) };
072:
073: domainDynaClass_ = new BasicDynaClass("mh_domain",
074: Persistable.class, dynaProperties);
075: }
076:
077: // constructors /////////////////////////////////////////////////////////////
078:
079: public SiteContext() {
080: super (dynaClass_);
081: init();
082: }
083:
084: public SiteContext(DynaClass dynaClass) {
085: super (dynaClass);
086: init();
087: }
088:
089: // constants ////////////////////////////////////////////////////////////////
090:
091: public static final String SITECONTEXT_KEY = "com.methodhead.sitecontext.SITECONTEXT_KEY";
092:
093: public static final String DEFAULTDOMAIN = "DEFAULT";
094:
095: // classes //////////////////////////////////////////////////////////////////
096:
097: // methods //////////////////////////////////////////////////////////////////
098:
099: /**
100: * Returns a human-readable representation of this site context.
101: */
102: public String toString() {
103: if (domains_.isEmpty())
104: return "SiteContext (no domains)";
105:
106: if ("".equals(getString("path")))
107: return (String) domains_.get(0);
108:
109: return domains_.get(0) + "/" + getString("path");
110: }
111:
112: /**
113: * Returns <tt>true</tt> if <tt>o</tt> is a <tt>SiteContext</tt> and has the
114: * same id as this object.
115: */
116: public boolean equals(Object o) {
117:
118: if ((o != null) && (o instanceof SiteContext))
119: return ((SiteContext) o).getInt("id") == getInt("id");
120:
121: return false;
122: }
123:
124: /**
125: * Returns this site context's id.
126: */
127: public int hashCode() {
128: return getInt("id");
129: }
130:
131: /**
132: * Compares this site context using the name of the first domain, if any, and
133: * then any path.
134: */
135: public int compareTo(Object o) {
136:
137: if (!(o instanceof SiteContext))
138: return -1;
139:
140: SiteContext sc = (SiteContext) o;
141:
142: if (getDomains().size() == 0) {
143: if (sc.getDomains().size() > 0)
144: return -1;
145: else
146: return getString("path")
147: .compareTo(sc.getString("path"));
148: } else {
149: if (sc.getDomains().size() == 0)
150: return 1;
151: else {
152: if (getDomains().get(0).equals(sc.getDomains().get(0)))
153: return getString("path").compareTo(
154: sc.getString("path"));
155: else
156: return ((String) getDomains().get(0)).compareTo(sc
157: .getDomains().get(0));
158: }
159: }
160: }
161:
162: /**
163: * Initializes site context fields.
164: */
165: protected void init() {
166: setInt("id", 0);
167: setString("path", "");
168: }
169:
170: /**
171: * Deletes any domains associated with this site context from the database.
172: */
173: private void deleteDomains() {
174: Persistable.deleteAll(domainDynaClass_, "sitecontext_id="
175: + getInt("id"));
176: }
177:
178: /**
179: * Saves any domains associated with this site context to the database.
180: */
181: private void saveDomains() {
182: Persistable p = new Persistable(domainDynaClass_);
183: p.setInt("sitecontext_id", getInt("id"));
184:
185: int i = 0;
186: for (Iterator iter = domains_.iterator(); iter.hasNext();) {
187: p.set("name", iter.next());
188: p.setInt("rank", i++);
189: p.saveNew();
190: }
191: }
192:
193: /**
194: * Loads any domains associated with this site context from the database.
195: */
196: private void loadDomains() {
197: domains_.clear();
198:
199: List l = Persistable.loadAll(domainDynaClass_,
200: "sitecontext_id=" + getInt("id"), "rank");
201:
202: for (Iterator iter = l.iterator(); iter.hasNext();) {
203: Persistable p = (Persistable) iter.next();
204: domains_.add(p.get("name"));
205: }
206: }
207:
208: public void saveNew() {
209: super .saveNew();
210: saveDomains();
211: }
212:
213: public void save() {
214: super .save();
215: deleteDomains();
216: saveDomains();
217: }
218:
219: public void load(Key key) {
220: super .load(key);
221: loadDomains();
222: }
223:
224: /**
225: * Loads the context for <tt>domain</tt> and <tt>path</tt>, returning
226: * <tt>true</tt> if it was successfully loaded, or <tt>false</tt> if no such
227: * context exists.
228: */
229: public boolean loadForDomainAndPath(String domain, String path) {
230:
231: String sql = "SELECT " + " sc.id AS id " + "FROM "
232: + " mh_sitecontext AS sc " + "LEFT JOIN "
233: + " mh_domain AS d ON "
234: + " d.sitecontext_id = sc.id " + "WHERE "
235: + " sc.path=" + getSqlLiteral(path) + " AND "
236: + " d.name=" + getSqlLiteral(domain) + " ";
237:
238: ResultSet rs = null;
239: try {
240: rs = ConnectionSingleton.runQuery(sql);
241:
242: if (!rs.next()) {
243: return false;
244: }
245:
246: load(new IntKey(rs.getInt("id")));
247:
248: return true;
249: } catch (SQLException e) {
250: String msg = "Loading SiteContext for domain \"" + domain
251: + "\" and path \"" + path + "\". "
252: + ExceptionUtils.getStackTrace(e);
253: logger_.error(msg);
254: throw new RuntimeException(msg);
255: } finally {
256: ConnectionSingleton.close(rs);
257: }
258: }
259:
260: /**
261: * Deletes this site context and any events associated with it.
262: */
263: public void delete() {
264: deleteDomains();
265: Event event = new Event();
266: event.setSiteContext(this );
267: event.deleteAll();
268: super .delete();
269: }
270:
271: /**
272: * Returns the default site context, creating it in the database if
273: * necessary. The default context always has id <tt>0</tt>. If this method
274: * ends up creating the default context, it won't create any domains for it,
275: * nor will it set a path.
276: */
277: public static SiteContext getDefaultContext() {
278: SiteContext siteContext = new SiteContext();
279:
280: try {
281: siteContext.load(new IntKey(0));
282: } catch (PersistableException e) {
283: //
284: // can't use saveNew() because this is a aikp and that will result in an
285: // id other than 0; we have to manually insert the context
286: //
287: String sql = "INSERT INTO " + " mh_sitecontext " + "( "
288: + " id, " + " path ) " + "VALUES ( " + " 0, "
289: + " '' " + ")";
290:
291: try {
292: ConnectionSingleton.runUpdate(sql);
293: } catch (SQLException se) {
294: throw new PersistableException(
295: "Unexpected SQLException: " + se.getMessage());
296: }
297:
298: siteContext.getDomains().add(DEFAULTDOMAIN);
299: siteContext.save();
300: }
301:
302: return siteContext;
303: }
304:
305: /**
306: * Sets the site context in the session.
307: */
308: public static void setContext(HttpServletRequest request,
309: SiteContext context) {
310:
311: request.getSession().setAttribute(SITECONTEXT_KEY, context);
312: }
313:
314: /**
315: * Gets the site context, looking first in the session, then in the request
316: * (NEEDS UNIT TESTING). Returns <tt>null</tt> if no site context is found.
317: */
318: public static SiteContext getContext(HttpServletRequest request) {
319:
320: SiteContext context = (SiteContext) request.getSession()
321: .getAttribute(SITECONTEXT_KEY);
322:
323: if (context == null) {
324: context = (SiteContext) request
325: .getAttribute(SITECONTEXT_KEY);
326: }
327:
328: return context;
329: }
330:
331: /**
332: * Loads all site contexts in the database, sorted according to the order
333: * specified by {@link #compareTo compareTo()}.
334: */
335: public static List loadAll() {
336: List list = loadAll(dynaClass_, null, null);
337:
338: for (Iterator iter = list.iterator(); iter.hasNext();) {
339: SiteContext sc = (SiteContext) iter.next();
340: sc.load(new IntKey(sc.getInt("id")));
341: }
342:
343: Collections.sort(list);
344:
345: return list;
346: }
347:
348: // properties ///////////////////////////////////////////////////////////////
349:
350: /**
351: * Returns the site context's domains as a list of <tt>String</tt>s.
352: */
353: public List getDomains() {
354: return domains_;
355: }
356:
357: // attributes ///////////////////////////////////////////////////////////////
358:
359: protected List domains_ = new ArrayList();
360:
361: private static Logger logger_ = Logger.getLogger(SiteContext.class);
362: }
|