001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * 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. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018: /*
019: * Created on Jun 18, 2004
020: */
021: package org.apache.roller.business.hibernate;
022:
023: import java.io.StringReader;
024: import org.hibernate.Criteria;
025: import org.hibernate.HibernateException;
026: import org.hibernate.Session;
027: import org.hibernate.criterion.Expression;
028: import org.apache.roller.RollerException;
029: import org.apache.roller.pojos.Assoc;
030: import org.apache.roller.pojos.BookmarkData;
031: import org.apache.roller.pojos.FolderAssoc;
032: import org.apache.roller.pojos.FolderData;
033: import org.apache.roller.pojos.WebsiteData;
034: import java.util.Iterator;
035: import java.util.LinkedList;
036: import java.util.List;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039: import org.jdom.Document;
040: import org.jdom.Element;
041: import org.jdom.input.SAXBuilder;
042: import org.apache.roller.business.BookmarkManager;
043: import org.apache.roller.business.RollerFactory;
044: import org.apache.roller.util.Utilities;
045:
046: /**
047: * Hibernate implementation of the BookmarkManager.
048: */
049: public class HibernateBookmarkManagerImpl implements BookmarkManager {
050:
051: static final long serialVersionUID = 5286654557062382772L;
052:
053: private static Log log = LogFactory
054: .getLog(HibernateBookmarkManagerImpl.class);
055:
056: private HibernatePersistenceStrategy strategy = null;
057:
058: /**
059: * @param pstrategy
060: * @param roller
061: */
062: public HibernateBookmarkManagerImpl(
063: HibernatePersistenceStrategy strat) {
064: log.debug("Instantiating Hibernate Bookmark Manager");
065:
066: this .strategy = strat;
067: }
068:
069: public void saveBookmark(BookmarkData bookmark)
070: throws RollerException {
071: this .strategy.store(bookmark);
072:
073: // update weblog last modified date. date updated by saveWebsite()
074: RollerFactory.getRoller().getUserManager().saveWebsite(
075: bookmark.getWebsite());
076: }
077:
078: public BookmarkData getBookmark(String id) throws RollerException {
079: BookmarkData bd = (BookmarkData) strategy.load(id,
080: BookmarkData.class);
081: // TODO: huh? why do we do this?
082: if (bd != null)
083: bd.setBookmarkManager(this );
084: return bd;
085: }
086:
087: public void removeBookmark(BookmarkData bookmark)
088: throws RollerException {
089: this .strategy.remove(bookmark);
090:
091: // update weblog last modified date. date updated by saveWebsite()
092: RollerFactory.getRoller().getUserManager().saveWebsite(
093: bookmark.getWebsite());
094: }
095:
096: //------------------------------------------------------------ Folder CRUD
097:
098: public void saveFolder(FolderData folder) throws RollerException {
099:
100: if (isDuplicateFolderName(folder)) {
101: throw new RollerException("Duplicate folder name");
102: }
103:
104: this .strategy.store(folder);
105:
106: // update weblog last modified date. date updated by saveWebsite()
107: RollerFactory.getRoller().getUserManager().saveWebsite(
108: folder.getWebsite());
109: }
110:
111: public void removeFolder(FolderData folder) throws RollerException {
112:
113: this .strategy.remove(folder);
114:
115: // update weblog last modified date. date updated by saveWebsite()
116: RollerFactory.getRoller().getUserManager().saveWebsite(
117: folder.getWebsite());
118: }
119:
120: /**
121: * Retrieve folder and lazy-load it's sub-folders and bookmarks.
122: */
123: public FolderData getFolder(String id) throws RollerException {
124: return (FolderData) strategy.load(id, FolderData.class);
125: }
126:
127: //------------------------------------------------------------ Operations
128:
129: public void importBookmarks(WebsiteData website, String folderName,
130: String opml) throws RollerException {
131:
132: String msg = "importBookmarks";
133: try {
134: // Build JDOC document OPML string
135: SAXBuilder builder = new SAXBuilder();
136: StringReader reader = new StringReader(opml);
137: Document doc = builder.build(reader);
138:
139: FolderData newFolder = getFolder(website, folderName);
140: if (newFolder == null) {
141: newFolder = new FolderData(getRootFolder(website),
142: folderName, folderName, website);
143: this .strategy.store(newFolder);
144: }
145:
146: // Iterate through children of OPML body, importing each
147: Element body = doc.getRootElement().getChild("body");
148: Iterator iter = body.getChildren().iterator();
149: while (iter.hasNext()) {
150: Element elem = (Element) iter.next();
151: importOpmlElement(website, elem, newFolder);
152: }
153:
154: } catch (Exception ex) {
155: throw new RollerException(ex);
156: }
157: }
158:
159: // convenience method used when importing bookmarks
160: // NOTE: this method does not commit any changes, that is done by importBookmarks()
161: private void importOpmlElement(WebsiteData website, Element elem,
162: FolderData parent) throws RollerException {
163: String text = elem.getAttributeValue("text");
164: String title = elem.getAttributeValue("title");
165: String desc = elem.getAttributeValue("description");
166: String url = elem.getAttributeValue("url");
167: //String type = elem.getAttributeValue("type");
168: String xmlUrl = elem.getAttributeValue("xmlUrl");
169: String htmlUrl = elem.getAttributeValue("htmlUrl");
170:
171: title = null != title ? title : text;
172: desc = null != desc ? desc : title;
173: xmlUrl = null != xmlUrl ? xmlUrl : url;
174: url = null != htmlUrl ? htmlUrl : url;
175:
176: if (elem.getChildren().size() == 0) {
177: // Leaf element. Store a bookmark
178: // Currently bookmarks must have at least a name and HTML url to be stored. Previous logic was
179: // trying to skip invalid ones, but was letting ones with an xml url and no html url through
180: // which could result in a db exception.
181: // TODO: Consider providing error feedback instead of silently skipping the invalid bookmarks here.
182: if (null != title && null != url) {
183: BookmarkData bd = new BookmarkData(parent, title, desc,
184: url, xmlUrl, new Integer(0), new Integer(100),
185: null);
186: parent.addBookmark(bd);
187: // TODO: maybe this should be saving the folder?
188: this .strategy.store(bd);
189: }
190: } else {
191: // Store a folder
192: FolderData fd = new FolderData(parent, title, desc, parent
193: .getWebsite());
194: this .strategy.store(fd);
195:
196: // Import folder's children
197: Iterator iter = elem.getChildren("outline").iterator();
198: while (iter.hasNext()) {
199: Element subelem = (Element) iter.next();
200: importOpmlElement(website, subelem, fd);
201: }
202: }
203: }
204:
205: //----------------------------------------------------------------
206: public void moveFolderContents(FolderData src, FolderData dest)
207: throws RollerException {
208:
209: if (dest.descendentOf(src)) {
210: throw new RollerException(
211: "ERROR cannot move parent folder into it's own child");
212: }
213:
214: try {
215: // Add to destination folder
216: LinkedList deleteList = new LinkedList();
217: Iterator srcBookmarks = src.getBookmarks().iterator();
218: while (srcBookmarks.hasNext()) {
219: BookmarkData bd = (BookmarkData) srcBookmarks.next();
220: deleteList.add(bd);
221:
222: BookmarkData movedBd = new BookmarkData();
223: movedBd.setData(bd);
224: movedBd.setId(null);
225:
226: dest.addBookmark(movedBd);
227: this .strategy.store(movedBd);
228: }
229:
230: // Remove from source folder
231: Iterator deleteIter = deleteList.iterator();
232: while (deleteIter.hasNext()) {
233: BookmarkData bd = (BookmarkData) deleteIter.next();
234: src.removeBookmark(bd);
235: // TODO: this won't conflict with the bookmark we store above right?
236: this .strategy.remove(bd);
237: }
238:
239: } catch (Exception ex) {
240: throw new RollerException(ex);
241: }
242: }
243:
244: //----------------------------------------------------------------
245: public void removeFolderContents(FolderData src)
246: throws RollerException {
247:
248: // just go through the folder and remove each bookmark
249: Iterator srcBookmarks = src.getBookmarks().iterator();
250: while (srcBookmarks.hasNext()) {
251: BookmarkData bd = (BookmarkData) srcBookmarks.next();
252: this .strategy.remove(bd);
253: }
254: }
255:
256: //---------------------------------------------------------------- Queries
257:
258: public FolderData getFolder(WebsiteData website, String folderPath)
259: throws RollerException {
260: return getFolderByPath(website, null, folderPath);
261: }
262:
263: public String getPath(FolderData folder) throws RollerException {
264: if (null == folder.getParent()) {
265: return "/";
266: } else {
267: String parentPath = getPath(folder.getParent());
268: parentPath = "/".equals(parentPath) ? "" : parentPath;
269: return parentPath + "/" + folder.getName();
270: }
271: }
272:
273: public FolderData getFolderByPath(WebsiteData website,
274: FolderData folder, String path) throws RollerException {
275: final Iterator folders;
276: final String[] pathArray = Utilities.stringToStringArray(path,
277: "/");
278:
279: if (folder == null && (null == path || "".equals(path.trim()))) {
280: throw new RollerException("Bad arguments.");
281: }
282:
283: if (path.trim().equals("/")) {
284: return getRootFolder(website);
285: } else if (folder == null || path.trim().startsWith("/")) {
286: folders = getRootFolder(website).getFolders().iterator();
287: } else {
288: folders = folder.getFolders().iterator();
289: }
290:
291: while (folders.hasNext()) {
292: FolderData possibleMatch = (FolderData) folders.next();
293: if (possibleMatch.getName().equals(pathArray[0])) {
294: if (pathArray.length == 1) {
295: return possibleMatch;
296: } else {
297: String[] subpath = new String[pathArray.length - 1];
298: System.arraycopy(pathArray, 1, subpath, 0,
299: subpath.length);
300:
301: String pathString = Utilities.stringArrayToString(
302: subpath, "/");
303: return getFolderByPath(website, possibleMatch,
304: pathString);
305: }
306: }
307: }
308:
309: // The folder did not match and neither did any subfolders
310: return null;
311: }
312:
313: //----------------------------------------------- FolderAssoc CRUD
314:
315: public FolderAssoc retrieveFolderAssoc(String id)
316: throws RollerException {
317: return (FolderAssoc) strategy.load(id, FolderAssoc.class);
318: }
319:
320: public void release() {
321: }
322:
323: /**
324: * @see org.apache.roller.model.BookmarkManager#retrieveBookmarks(
325: * org.apache.roller.pojos.FolderData, boolean)
326: */
327: public List getBookmarks(FolderData folder, boolean subfolders)
328: throws RollerException {
329: try {
330: Session session = ((HibernatePersistenceStrategy) strategy)
331: .getSession();
332: List bookmarks = new LinkedList();
333: if (subfolders) {
334: // get bookmarks in subfolders
335: Criteria assocsQuery = session
336: .createCriteria(FolderAssoc.class);
337: assocsQuery
338: .add(Expression.eq("ancestorFolder", folder));
339: Iterator assocs = assocsQuery.list().iterator();
340: while (assocs.hasNext()) {
341: FolderAssoc assoc = (FolderAssoc) assocs.next();
342: Criteria bookmarksQuery = session
343: .createCriteria(BookmarkData.class);
344: bookmarksQuery.add(Expression.eq("folder", assoc
345: .getFolder()));
346: Iterator bookmarkIter = bookmarksQuery.list()
347: .iterator();
348: while (bookmarkIter.hasNext()) {
349: BookmarkData entry = (BookmarkData) bookmarkIter
350: .next();
351: bookmarks.add(entry);
352: }
353: }
354: }
355:
356: // get bookmarks in folder
357: Criteria bookmarksQuery = session
358: .createCriteria(BookmarkData.class);
359: bookmarksQuery.add(Expression.eq("folder", folder));
360: Iterator bookmarkIter = bookmarksQuery.list().iterator();
361: while (bookmarkIter.hasNext()) {
362: BookmarkData bookmark = (BookmarkData) bookmarkIter
363: .next();
364: bookmarks.add(bookmark);
365: }
366: return bookmarks;
367: } catch (HibernateException e) {
368: throw new RollerException(e);
369: }
370: }
371:
372: public FolderData getRootFolder(WebsiteData website)
373: throws RollerException {
374: if (website == null)
375: throw new RollerException("website is null");
376: try {
377: Session session = ((HibernatePersistenceStrategy) strategy)
378: .getSession();
379: Criteria criteria = session
380: .createCriteria(FolderAssoc.class);
381: criteria.createAlias("folder", "f");
382: criteria.add(Expression.eq("f.website", website));
383: criteria.add(Expression.isNull("ancestorFolder"));
384: criteria.add(Expression.eq("relation", FolderAssoc.PARENT));
385: List results = criteria.list();
386: if (results.size() > 1) {
387: // Should not have more than one root
388: throw new RollerException(
389: "More than one root folder found for website "
390: + website.getId());
391: } else if (results.size() == 1) {
392: // Return root
393: return ((FolderAssoc) results.get(0)).getFolder();
394: }
395: return null;
396: } catch (HibernateException e) {
397: throw new RollerException(e);
398: }
399: }
400:
401: public List getAllFolders(WebsiteData website)
402: throws RollerException {
403: if (website == null)
404: throw new RollerException("Website is null");
405:
406: try {
407: Session session = ((HibernatePersistenceStrategy) strategy)
408: .getSession();
409: Criteria criteria = session
410: .createCriteria(FolderData.class);
411: criteria.add(Expression.eq("website", website));
412: return criteria.list();
413: } catch (HibernateException e) {
414: throw new RollerException(e);
415: }
416:
417: }
418:
419: /**
420: * @see org.apache.roller.model.BookmarkManager#isDuplicateFolderName(org.apache.roller.pojos.FolderData)
421: */
422: public boolean isDuplicateFolderName(FolderData folder)
423: throws RollerException {
424: // ensure that no sibling folders share the same name
425: boolean isNewFolder = (folder.getId() == null);
426: FolderData parent = isNewFolder ? (FolderData) folder
427: .getNewParent() : folder.getParent();
428:
429: if (null != parent) {
430: List sameNames;
431: try {
432: Session session = ((HibernatePersistenceStrategy) strategy)
433: .getSession();
434: Criteria criteria = session
435: .createCriteria(FolderAssoc.class);
436: criteria.createAlias("folder", "f");
437: criteria.add(Expression.eq("f.name", folder.getName()));
438: criteria.add(Expression.eq("ancestorFolder", parent));
439: criteria.add(Expression.eq("relation", Assoc.PARENT));
440: sameNames = criteria.list();
441: } catch (HibernateException e) {
442: throw new RollerException(e);
443: }
444: // If we got some matches
445: if (sameNames.size() > 0) {
446: // if we're saving a new folder, any matches are dups
447: if (isNewFolder)
448: return true;
449: // otherwise it's a dup it isn't the same one (one match with the same id).
450: if (!(sameNames.size() == 1 && folder.getId().equals(
451: ((FolderAssoc) sameNames.get(0)).getFolder()
452: .getId())))
453: return true;
454: }
455: }
456: return false;
457: }
458:
459: /**
460: * @see org.apache.roller.model.BookmarkManager#getFolderParentAssoc(
461: * org.apache.roller.pojos.FolderData)
462: */
463: public Assoc getFolderParentAssoc(FolderData folder)
464: throws RollerException {
465: try {
466: Session session = ((HibernatePersistenceStrategy) strategy)
467: .getSession();
468: Criteria criteria = session
469: .createCriteria(FolderAssoc.class);
470: criteria.add(Expression.eq("folder", folder));
471: criteria.add(Expression.eq("relation", Assoc.PARENT));
472: List parents = criteria.list();
473: if (parents.size() > 1) {
474: throw new RollerException("ERROR: more than one parent");
475: } else if (parents.size() == 1) {
476: return (Assoc) parents.get(0);
477: } else {
478: return null;
479: }
480: } catch (HibernateException e) {
481: throw new RollerException(e);
482: }
483: }
484:
485: /**
486: * @see org.apache.roller.model.BookmarkManager#getFolderChildAssocs(
487: * org.apache.roller.pojos.FolderData)
488: */
489: public List getFolderChildAssocs(FolderData folder)
490: throws RollerException {
491: try {
492: Session session = ((HibernatePersistenceStrategy) strategy)
493: .getSession();
494: Criteria criteria = session
495: .createCriteria(FolderAssoc.class);
496: criteria.add(Expression.eq("ancestorFolder", folder));
497: criteria.add(Expression.eq("relation", Assoc.PARENT));
498: return criteria.list();
499: } catch (HibernateException e) {
500: throw new RollerException(e);
501: }
502: }
503:
504: /**
505: * @see org.apache.roller.model.BookmarkManager#getAllFolderDecscendentAssocs(
506: * org.apache.roller.pojos.FolderData)
507: */
508: public List getAllFolderDecscendentAssocs(FolderData folder)
509: throws RollerException {
510: try {
511: Session session = ((HibernatePersistenceStrategy) strategy)
512: .getSession();
513: Criteria criteria = session
514: .createCriteria(FolderAssoc.class);
515: criteria.add(Expression.eq("ancestorFolder", folder));
516: return criteria.list();
517: } catch (HibernateException e) {
518: throw new RollerException(e);
519: }
520: }
521:
522: /**
523: * @see org.apache.roller.model.BookmarkManager#getFolderAncestorAssocs(
524: * org.apache.roller.pojos.FolderData)
525: */
526: public List getFolderAncestorAssocs(FolderData folder)
527: throws RollerException {
528: try {
529: Session session = ((HibernatePersistenceStrategy) strategy)
530: .getSession();
531: Criteria criteria = session
532: .createCriteria(FolderAssoc.class);
533: criteria.add(Expression.eq("folder", folder));
534: return criteria.list();
535: } catch (HibernateException e) {
536: throw new RollerException(e);
537: }
538: }
539:
540: /**
541: * @see org.apache.roller.model.BookmarkManager#isFolderInUse(org.apache.roller.pojos.FolderData)
542: */
543: public boolean isFolderInUse(FolderData folder)
544: throws RollerException {
545: try {
546: // We consider a folder to be "in use" if it contains any bookmarks or has
547: // any children.
548:
549: // We first determine the number of bookmark entries.
550: // NOTE: This seems to be an attempt to optimize, rather than just use getBookmarks(),
551: // but I'm not sure that this optimization is really worthwhile, and it ignores
552: // caching in the case that the (lazy) getBookmarks has been done already. --agangolli
553: // TODO: condider changing to just use getBookmarks().size()
554:
555: Session session = ((HibernatePersistenceStrategy) strategy)
556: .getSession();
557: Criteria criteria = session
558: .createCriteria(BookmarkData.class);
559: criteria.add(Expression.eq("folder", folder));
560: criteria.setMaxResults(1);
561: int entryCount = criteria.list().size();
562:
563: // Return true if we have bookmarks or (, failing that, then checking) if we have children
564: return (entryCount > 0 || folder.getFolders().size() > 0);
565: } catch (HibernateException e) {
566: throw new RollerException(e);
567: }
568: }
569:
570: public boolean isDescendentOf(FolderData child, FolderData ancestor)
571: throws RollerException {
572: boolean ret = false;
573: try {
574: Session session = ((HibernatePersistenceStrategy) strategy)
575: .getSession();
576: Criteria criteria = session
577: .createCriteria(FolderAssoc.class);
578: criteria.add(Expression.eq("folder", child));
579: criteria.add(Expression.eq("ancestorFolder", ancestor));
580: ret = criteria.list().size() > 0;
581: } catch (HibernateException e) {
582: throw new RollerException(e);
583: }
584: return ret;
585: }
586: }
|