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.shim;
022:
023: import com.methodhead.aikp.AutoIntKeyPersistable;
024:
025: import org.apache.commons.beanutils.DynaClass;
026: import org.apache.commons.beanutils.DynaProperty;
027: import org.apache.commons.beanutils.BasicDynaClass;
028: import java.util.Map;
029: import java.util.HashMap;
030: import java.util.List;
031: import java.util.Iterator;
032: import java.util.Collections;
033: import com.methodhead.persistable.Persistable;
034: import com.methodhead.persistable.PersistableException;
035: import com.methodhead.persistable.Key;
036: import com.methodhead.sitecontext.SiteContextCapable;
037: import com.methodhead.sitecontext.SiteContext;
038: import org.apache.commons.lang.StringUtils;
039:
040: /**
041: * A Page. The following fields are defined:
042: * <ul>
043: * <li><tt>int id = 0</tt></li>
044: * <li><tt>int sitecontext_id = 0</tt></li>
045: * <li><tt>String title = ""</tt></li>
046: * <li><tt>String alttitle = ""</tt></li>
047: * <li><tt>String aliasname = ""</tt></li>
048: * <li><tt>String template = ""</tt></li>
049: * <li><tt>boolean hidden = false</tt></li>
050: * <li><tt>String metadescription = ""</tt></li>
051: * <li><tt>String metakeywords = ""</tt></li>
052: * </ul>
053: */
054: public class Page extends AutoIntKeyPersistable implements
055: SiteContextCapable, Comparable {
056:
057: private static DynaClass dynaClass_ = null;
058: private static DynaClass panelDynaClass_ = null;
059:
060: static {
061: DynaProperty[] dynaProperties = new DynaProperty[] {
062: new DynaProperty("id", Integer.class),
063: new DynaProperty("sitecontext_id", Integer.class),
064: new DynaProperty("title", String.class),
065: new DynaProperty("alttitle", String.class),
066: new DynaProperty("aliasname", String.class),
067: new DynaProperty("template", String.class),
068: new DynaProperty("hidden", Boolean.class),
069: new DynaProperty("metadescription", String.class),
070: new DynaProperty("metakeywords", String.class) };
071:
072: dynaClass_ = new BasicDynaClass("shim_page", Page.class,
073: dynaProperties);
074:
075: dynaProperties = new DynaProperty[] {
076: new DynaProperty("page_id", Integer.class),
077: new DynaProperty("name", String.class),
078: new DynaProperty("module", String.class) };
079:
080: panelDynaClass_ = new BasicDynaClass("shim_panel",
081: Persistable.class, dynaProperties);
082: }
083:
084: // constructors /////////////////////////////////////////////////////////////
085:
086: public Page() {
087: super (dynaClass_);
088: init();
089: }
090:
091: public Page(DynaClass dynaClass) {
092: super (dynaClass);
093: init();
094: }
095:
096: // constants ////////////////////////////////////////////////////////////////
097:
098: // classes //////////////////////////////////////////////////////////////////
099:
100: // methods //////////////////////////////////////////////////////////////////
101:
102: protected void init() {
103: setInt("id", 0);
104: setInt("sitecontext_id", 0);
105: setString("title", "");
106: setString("alttitle", "");
107: setString("aliasname", "");
108: setString("template", "");
109: setBoolean("hidden", false);
110: setString("metadescription", "");
111: setString("metakeywords", "");
112: }
113:
114: public String toString() {
115: return getString("title");
116: }
117:
118: public int compareTo(Object o) {
119:
120: if (o == null)
121: return 1;
122:
123: if (!Page.class.isInstance(o))
124: return 1;
125:
126: Page p = (Page) o;
127:
128: return getString("title").toLowerCase().compareTo(
129: p.getString("title").toLowerCase());
130: }
131:
132: /**
133: * Returns the current site context for this object, throwing an exception if
134: * it hasn't been set.
135: */
136: public SiteContext getSiteContext() {
137: if (siteContext_ == null)
138: throw new ShimException("Site context has not been set.");
139:
140: return siteContext_;
141: }
142:
143: /**
144: * Implements <tt>SiteContextCapable.setSiteContext()</tt>.
145: */
146: public void setSiteContext(SiteContext siteContext) {
147:
148: siteContext_ = siteContext;
149: }
150:
151: /**
152: * Returns an alias name for <tt>title</tt> by converting it to lower case
153: * and removing any whitespace or special characters; if a page exists with
154: * the alias, a number is appended and incremented until a unique alias is
155: * calculated.
156: */
157: protected void setDefaultAliasName() {
158:
159: String title = getString("title");
160:
161: //
162: // blank title?
163: //
164: if (StringUtils.isBlank(title))
165: throw new ShimException(
166: "Can't set default alias name for empty title.");
167:
168: //
169: // convert to lower case
170: //
171: String alias = title.toLowerCase();
172:
173: //
174: // strip out non-alphanumeric characters
175: //
176: StringBuffer buf = new StringBuffer();
177:
178: for (int i = 0; i < alias.length(); i++) {
179: char c = alias.charAt(i);
180:
181: if (Character.isLetterOrDigit(c))
182: buf.append(c);
183: }
184:
185: alias = buf.toString();
186:
187: //
188: // make sure it hasn't already been used
189: //
190: Page p = new Page();
191: p.setSiteContext(getSiteContext());
192:
193: try {
194: p.loadForAlias(alias);
195:
196: //
197: // did we find ourself?
198: //
199: if (p.getInt("id") != getInt("id")) {
200:
201: //
202: // try to find an alternative
203: //
204: String tmp = alias;
205: for (int i = 2; true; i++) {
206: alias = tmp + i;
207:
208: try {
209: p.loadForAlias(alias);
210: } catch (PersistableException e) {
211: break;
212: }
213: }
214: }
215: } catch (PersistableException e) {
216: //
217: // no such page
218: //
219: }
220:
221: setString("aliasname", alias);
222: }
223:
224: /**
225: * Adds a panel to the page.
226: */
227: public void addPanel(Panel panel) {
228:
229: if (panels_.containsKey(panel.getName()))
230: throw new ShimException("Page already has panel \""
231: + panel.getName() + "\"");
232:
233: panels_.put(panel.getName(), panel);
234: }
235:
236: /**
237: * Deletes any panels associated with this page from the database.
238: */
239: private void deletePanels() {
240: Persistable.deleteAll(panelDynaClass_, "page_id="
241: + getInt("id"));
242: }
243:
244: /**
245: * Saves any panels associated with this site context to the database.
246: */
247: private void savePanels() {
248: Persistable p = new Persistable(panelDynaClass_);
249: p.setInt("page_id", getInt("id"));
250:
251: for (Iterator iter = panels_.values().iterator(); iter
252: .hasNext();) {
253: Panel panel = (Panel) iter.next();
254: p.set("name", panel.getName());
255: p.set("module", panel.getModuleClass());
256: p.saveNew();
257: }
258: }
259:
260: /**
261: * Loads any panels associated with this site context from the database.
262: */
263: private void loadPanels() {
264: panels_.clear();
265:
266: List l = Persistable.loadAll(panelDynaClass_, "page_id="
267: + getInt("id"), "name");
268:
269: for (Iterator iter = l.iterator(); iter.hasNext();) {
270: Persistable p = (Persistable) iter.next();
271: Panel panel = new Panel();
272: panel.setName(p.getString("name"));
273: panel.setModuleClass(p.getString("module"));
274: panels_.put(panel.getName(), panel);
275: }
276: }
277:
278: /**
279: * Instantiates modules for each panel and calls their <tt>init()</tt>
280: * method.
281: */
282: private void initPanels() {
283: for (Iterator iter = panels_.values().iterator(); iter
284: .hasNext();) {
285: Panel panel = (Panel) iter.next();
286:
287: Module module = null;
288: try {
289: module = (Module) Class.forName(panel.getModuleClass())
290: .newInstance();
291: } catch (Exception e) {
292: throw new ShimException(
293: "Unexpected exception while instantiating module \""
294: + panel.getModuleClass() + "\":"
295: + e.toString());
296: }
297:
298: module.init(this , panel.getName());
299:
300: panel.setModule(module);
301: }
302: }
303:
304: public void saveNew() {
305:
306: setInt("sitecontext_id", getSiteContext().getInt("id"));
307:
308: //
309: // save
310: //
311: super .saveNew();
312: savePanels();
313: }
314:
315: public void load(Key key) {
316:
317: //
318: // load needs only the id, but to enforce a call to setSiteContext(), make
319: // sure the site context has been set
320: //
321: super .load(key.getWhereClause() + " AND sitecontext_id="
322: + getSiteContext().getInt("id"));
323:
324: loadPanels();
325: }
326:
327: public void save() {
328: super .save();
329: deletePanels();
330: savePanels();
331: }
332:
333: /**
334: * Deletes any modules associated with this page using {@link Module#destroy
335: * Module.destroy()} and deletes the page; be sure to call {@link #loadFull
336: * loadFull()} before calling this method.
337: */
338: public void delete() {
339:
340: for (Iterator iter = getPanels().values().iterator(); iter
341: .hasNext();) {
342: Panel panel = (Panel) iter.next();
343: panel.getModule().destroy();
344: }
345:
346: deletePanels();
347: super .delete();
348: }
349:
350: /**
351: * Loads the page and any modules referenced by its panels. {@link
352: * Module#init init()} is called for each module during this operation.
353: */
354: public void loadFull(Key key) {
355:
356: load(key);
357: initPanels();
358: }
359:
360: /**
361: * Loads the page for <tt>alias</tt> and any modules referenced by its
362: * panels. {@link Module#init init()} is called for each module during this
363: * operation.
364: */
365: public void loadFullForAlias(String alias) {
366:
367: loadForAlias(alias);
368: initPanels();
369: }
370:
371: /**
372: * Loads all pages in the system; a shallow load is performed.
373: */
374: public List loadAll() {
375: List l = loadAll(dynaClass_, "sitecontext_id="
376: + getSiteContext().getInt("id"), "title");
377:
378: //
379: // set the site context for each page
380: //
381: for (Iterator iter = l.iterator(); iter.hasNext();) {
382: Page p = (Page) iter.next();
383: p.setSiteContext(getSiteContext());
384: }
385:
386: //
387: // sort the pages
388: //
389: Collections.sort(l);
390:
391: return l;
392: }
393:
394: /**
395: * Loads the page for <tt>alias</tt>, returning <tt>true</tt> if the page was
396: * found.
397: */
398: public void loadForAlias(String alias) {
399:
400: super .load("sitecontext_id=" + getSiteContext().getInt("id")
401: + " AND aliasname=" + getSqlLiteral(alias));
402:
403: loadPanels();
404: }
405:
406: /**
407: * Copies the page and all of its modules.
408: */
409: public Page copy() {
410:
411: Page copy = new Page();
412:
413: copy.setSiteContext(getSiteContext());
414: copy.setString("title", getString("title"));
415: copy.setString("alttitle", getString("alttitle"));
416: copy.setDefaultAliasName();
417: copy.setString("template", getString("template"));
418: copy.setBoolean("hidden", getBoolean("hidden"));
419: copy.setString("metadescription", getString("metadescription"));
420: copy.setString("metakeywords", getString("metakeywords"));
421:
422: for (Iterator iter = getPanels().values().iterator(); iter
423: .hasNext();) {
424: Panel panel = (Panel) iter.next();
425: copy.addPanel((Panel) panel.clone());
426: }
427:
428: copy.saveNew();
429:
430: for (Iterator iter = getPanels().values().iterator(); iter
431: .hasNext();) {
432: Panel panel = (Panel) iter.next();
433: panel.getModule().copyTo(copy);
434: }
435:
436: return copy;
437: }
438:
439: // properties ///////////////////////////////////////////////////////////////
440:
441: /**
442: * Returns a map of {@link Panel}s.
443: */
444: public Map getPanels() {
445: return panels_;
446: }
447:
448: // attributes ///////////////////////////////////////////////////////////////
449:
450: protected Map panels_ = new HashMap();
451:
452: protected SiteContext siteContext_ = null;
453: }
|