001: package org.emforge.wiki.providers.hibernateprovider;
002:
003: import java.io.IOException;
004: import java.util.Collection;
005: import java.util.Date;
006: import java.util.Iterator;
007: import java.util.LinkedList;
008: import java.util.List;
009: import java.util.Properties;
010: import java.util.TreeSet;
011:
012: import org.apache.commons.logging.Log;
013: import org.apache.commons.logging.LogFactory;
014: import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
015:
016: import com.ecyrd.jspwiki.NoRequiredPropertyException;
017: import com.ecyrd.jspwiki.QueryItem;
018: import com.ecyrd.jspwiki.SearchMatcher;
019: import com.ecyrd.jspwiki.SearchResult;
020: import com.ecyrd.jspwiki.SearchResultComparator;
021: import com.ecyrd.jspwiki.WikiEngine;
022: import com.ecyrd.jspwiki.WikiPage;
023: import com.ecyrd.jspwiki.WikiProvider;
024: import com.ecyrd.jspwiki.providers.ProviderException;
025: import com.ecyrd.jspwiki.providers.VersioningProvider;
026: import com.ecyrd.jspwiki.providers.WikiPageProvider;
027:
028: public class HibernatePageProvider extends HibernateDaoSupport
029: implements WikiPageProvider, VersioningProvider, WikiProvider {
030: protected final Log log = LogFactory.getLog(getClass());
031: private WikiEngine wikiEngine = null;
032: private int continuationEditMinutes = 0;
033:
034: /*
035: * (non-Javadoc)
036: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#putPageText(com.ecyrd.jspwiki.WikiPage, java.lang.String)
037: */
038: public void putPageText(WikiPage page, String text)
039: throws ProviderException {
040: String previousAuthor = "";
041: Date previousModified = new Date(0L);
042:
043: //int version = 0;
044: PageDO latest = getLatestVersion(page.getName());
045:
046: if (latest != null) {
047: // version = latest.getVersion();
048: previousModified = latest.getDatetime();
049: previousAuthor = latest.getAuthor();
050: }
051:
052: // If same author and saved again within continuationEditTimeout, save by
053: // directly overwriting current version.
054: // Create version, if not in continuationEdit, or if migrating, or if
055: // page is non-existant
056: boolean isDifferentAuthor = (page.getAuthor() == null)
057: || page.getAuthor().equals("")
058: || !page.getAuthor().equals(previousAuthor);
059:
060: boolean isContinuationEditTimeExpired = System
061: .currentTimeMillis() > (this
062: .getContinuationEditTimeout() + previousModified
063: .getTime());
064:
065: boolean createVersion = !pageExists(page.getName())
066: || isDifferentAuthor || isContinuationEditTimeExpired;
067:
068: if (createVersion) {
069: // Insert page
070: if (!pageExists(page.getName())) {
071: page.setVersion(1);
072: } else {
073: page.setVersion(page.getVersion() + 1);
074: }
075:
076: if (page.getLastModified() != null) {
077: page.setLastModified(page.getLastModified());
078: } else {
079: page.setLastModified(new Date());
080: }
081:
082: log.debug("Create page version: " + page);
083:
084: PageDO bean = this .convert(page);
085: bean.setContent(text);
086: saveOrUpdate(bean);
087: }
088: }
089:
090: /*
091: * (non-Javadoc)
092: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#pageExists(java.lang.String)
093: */
094: public boolean pageExists(String pagename) {
095: return getLatestVersion(pagename) != null;
096: }
097:
098: /*
099: * (non-Javadoc)
100: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#findPages(com.ecyrd.jspwiki.QueryItem[])
101: */
102: @SuppressWarnings("unchecked")
103: public Collection<SearchResult> findPages(QueryItem[] query) {
104: Collection<SearchResult> result = new TreeSet<SearchResult>(
105: new SearchResultComparator());
106: SearchMatcher matcher = new SearchMatcher(getEngine(), query);
107:
108: try {
109: for (PageDO page : findPages()) {
110: String pagetext = page.getContent();
111: SearchResult comparison = matcher.matchPageContent(page
112: .getName(), pagetext);
113:
114: if (comparison != null) {
115: result.add(comparison);
116: }
117: }
118: } catch (IOException e) {
119: log.error(e.toString());
120: }
121:
122: return result;
123: }
124:
125: /*
126: * (non-Javadoc)
127: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getPageInfo(java.lang.String, int)
128: */
129: public WikiPage getPageInfo(String pagename, int version)
130: throws ProviderException {
131: WikiPage p = null;
132:
133: if (version == WikiPageProvider.LATEST_VERSION) {
134: p = convert(getLatestVersion(pagename));
135: } else {
136: p = convert(findPage(pagename, version));
137: }
138:
139: return p;
140: }
141:
142: /*
143: * (non-Javadoc)
144: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getAllPages()
145: */
146: public Collection<WikiPage> getAllPages() throws ProviderException {
147: LinkedList<WikiPage> result = new LinkedList<WikiPage>();
148: // get latest versions
149: List<PageDO> pages = findPages();
150:
151: // convert them to wiki pages
152: for (PageDO page : pages) {
153: WikiPage wikipage = this .convert(page);
154:
155: result.add(wikipage);
156: }
157:
158: return result;
159: }
160:
161: /*
162: * (non-Javadoc)
163: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getAllChangedSince(java.util.Date)
164: */
165: public Collection<WikiPage> getAllChangedSince(Date timestamp) {
166: LinkedList<WikiPage> result = new LinkedList<WikiPage>();
167: List<PageDO> pages = findPages(timestamp);
168:
169: // convert them to wiki pages
170: for (PageDO page : pages) {
171: WikiPage wikipage = this .convert(page);
172:
173: result.add(wikipage);
174: }
175:
176: return result;
177: }
178:
179: /*
180: * (non-Javadoc)
181: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getPageCount()
182: */
183: public int getPageCount() {
184: int count = 0;
185: Iterator<?> it = this .getHibernateTemplate().find(
186: "select count(name) from PageDO p group by p.name")
187: .iterator();
188: if (it.hasNext())
189: count = ((Long) it.next()).intValue();
190: return count;
191: }
192:
193: /*
194: * (non-Javadoc)
195: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getVersionHistory(java.lang.String)
196: */
197: public List<WikiPage> getVersionHistory(String pagename)
198: throws ProviderException {
199: LinkedList<WikiPage> result = new LinkedList<WikiPage>();
200: List<PageDO> pages = findPages(pagename);
201:
202: // convert them to wiki pages
203: for (PageDO page : pages) {
204: WikiPage wikipage = this .convert(page);
205:
206: result.add(wikipage);
207: }
208:
209: return result;
210: }
211:
212: /*
213: * (non-Javadoc)
214: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#getPageText(java.lang.String, int)
215: */
216: public String getPageText(String pagename, int version)
217: throws ProviderException {
218: if (version == WikiPageProvider.LATEST_VERSION) {
219: PageDO current = getLatestVersion(pagename);
220:
221: if (current != null) {
222: return current.getContent();
223: } else {
224: return null;
225: }
226: } else {
227: PageDO page = findPage(pagename, version);
228:
229: if (page != null) {
230: return page.getContent();
231: } else {
232: return null;
233: }
234: }
235: }
236:
237: /*
238: * (non-Javadoc)
239: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#deleteVersion(java.lang.String, int)
240: */
241: public void deleteVersion(String pageName, int version)
242: throws ProviderException {
243: PageDO page = findPage(pageName, version);
244:
245: this .getHibernateTemplate().delete(page);
246: this .getHibernateTemplate().flush();
247: }
248:
249: /*
250: * (non-Javadoc)
251: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#deletePage(java.lang.String)
252: */
253: public void deletePage(String page) throws ProviderException {
254: List<PageDO> col = this .findPages(page);
255:
256: if (col.size() > 0) {
257: logger.debug("deleting " + col.size()
258: + " records from database.");
259: this .getHibernateTemplate().deleteAll(col);
260: }
261:
262: this .getHibernateTemplate().flush();
263: }
264:
265: /*
266: * (non-Javadoc)
267: * @see com.ecyrd.jspwiki.providers.WikiPageProvider#movePage(java.lang.String, java.lang.String)
268: */
269: public void movePage(String from, String to)
270: throws ProviderException {
271: logger.info("Changing the title from " + from + " to " + to);
272:
273: List<PageDO> result = findPages(from);
274:
275: for (PageDO page : result) {
276: page.setName(to);
277: }
278: logger.info("Total " + result.size() + " records are changed");
279: getHibernateTemplate().saveOrUpdateAll(result);
280: getHibernateTemplate().flush();
281: }
282:
283: /*
284: * (non-Javadoc)
285: * @see com.ecyrd.jspwiki.WikiProvider#initialize(com.ecyrd.jspwiki.WikiEngine, java.util.Properties)
286: */
287: public void initialize(WikiEngine engine, Properties prop)
288: throws NoRequiredPropertyException, IOException {
289: log.debug("Initializing HibernatePageProvider");
290: this .wikiEngine = engine;
291:
292: int count = getPageCount();
293: log.info("Page count at startup: " + count);
294: }
295:
296: /*
297: * (non-Javadoc)
298: * @see com.ecyrd.jspwiki.WikiProvider#getProviderInfo()
299: */
300: public String getProviderInfo() {
301: return "Hibernate Page Provider";
302: }
303:
304: /*
305: * (non-Javadoc)
306: * @see com.ecyrd.jspwiki.providers.VersioningProvider#pageExists(java.lang.String, int)
307: */
308: public boolean pageExists(String pagename, int version) {
309: if (version == WikiPageProvider.LATEST_VERSION) {
310: return getLatestVersion(pagename) != null;
311: } else {
312: return findPage(pagename, version) != null;
313: }
314: }
315:
316: protected WikiEngine getEngine() {
317: return this .wikiEngine;
318: }
319:
320: /** Convert database object to WikiPage
321: *
322: * @param page
323: * @return
324: */
325: protected WikiPage convert(PageDO page) {
326: if (page == null) {
327: return null;
328: }
329:
330: WikiPage wikipage = new WikiPage(this .getEngine(), page
331: .getName());
332: wikipage.setVersion(page.getVersion());
333: wikipage.setLastModified(page.getDatetime());
334: wikipage.setAuthor(page.getAuthor());
335: wikipage.setAttribute(WikiPage.CHANGENOTE, page.getNotes());
336:
337: return wikipage;
338: }
339:
340: /** Convert wikiPage to database object
341: *
342: * @param wikipage
343: * @return
344: */
345: protected PageDO convert(WikiPage wikipage) {
346: if (wikipage == null) {
347: return null;
348: }
349:
350: PageDO page = new PageDO();
351: page.setVersion(wikipage.getVersion());
352: page.setName(wikipage.getName());
353: page.setDatetime(wikipage.getLastModified());
354: page.setNotes((String) wikipage
355: .getAttribute(WikiPage.CHANGENOTE));
356: page.setAuthor(wikipage.getAuthor());
357:
358: return page;
359: }
360:
361: public int getContinuationEditTimeout() {
362: return this .continuationEditMinutes * 60 * 1000;
363: }
364:
365: public void setContinuationEditTimeout(int interval) {
366: this .continuationEditMinutes = interval;
367: }
368:
369: /** saves or updates page into database */
370: protected void saveOrUpdate(PageDO page) {
371: this .getHibernateTemplate().merge(page);
372: // need to make flush to be able find this page via find (called later in WikiEngine)
373: this .getHibernateTemplate().flush();
374: }
375:
376: /** returns latest version for page
377: *
378: * @param pageName
379: * @return
380: */
381: protected PageDO getLatestVersion(String pageName) {
382: List<PageDO> pages = findPages(pageName);
383: if (pages.size() > 0) {
384: return pages.get(0);
385: } else {
386: return null;
387: }
388: }
389:
390: /** Find pages by name
391: *
392: * @param pageName
393: * @return
394: */
395: @SuppressWarnings("unchecked")
396: protected List<PageDO> findPages(String pageName) {
397: return this
398: .getHibernateTemplate()
399: .findByNamedParam(
400: "from PageDO p where p.name=:pageName order by p.version desc",
401: "pageName", pageName);
402: }
403:
404: /** Find page by name and version
405: *
406: * It should be only one page with specified name and version
407: * @param pageName
408: * @param version
409: * @return
410: */
411: @SuppressWarnings("unchecked")
412: protected PageDO findPage(String pageName, int version) {
413: List<PageDO> pages = this
414: .getHibernateTemplate()
415: .findByNamedParam(
416: "from PageDO p where p.name=:pageName and p.version=:version",
417: new String[] { "pageName", "version" },
418: new Object[] { pageName, version });
419:
420: if (pages.size() > 0) {
421: if (pages.size() > 1) {
422: log.warn("Two pages found for name " + pageName
423: + " and version " + version);
424: }
425:
426: return pages.get(0);
427: } else {
428: return null;
429: }
430: }
431:
432: /** Returns latests versions for all pages
433: *
434: * @return
435: */
436: @SuppressWarnings("unchecked")
437: protected List<PageDO> findPages() {
438: return this
439: .getHibernateTemplate()
440: .find(
441: "from PageDO p where p.version in (select max(p2.version) from PageDO p2 group by p2.name)");
442: }
443:
444: /** get latest version of every page CHANGE_TIME since the given date
445: *
446: * @param date
447: * @return
448: */
449: @SuppressWarnings("unchecked")
450: protected List<PageDO> findPages(Date date) {
451: return this
452: .getHibernateTemplate()
453: .findByNamedParam(
454: "from PageDO p where p.datetime>:datetime and p.version=(select max(p2.version) from PageDO p2 group by p2.name)",
455: "datetime", date);
456: }
457:
458: }
|