001: package org.emforge.wiki.providers.hibernateprovider;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.sql.Timestamp;
007: import java.util.Collection;
008: import java.util.Date;
009: import java.util.Iterator;
010: import java.util.LinkedList;
011: import java.util.List;
012: import java.util.Properties;
013:
014: import org.apache.commons.logging.Log;
015: import org.apache.commons.logging.LogFactory;
016: import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
017: import org.springframework.transaction.PlatformTransactionManager;
018: import org.springframework.transaction.TransactionStatus;
019: import org.springframework.transaction.support.TransactionCallbackWithoutResult;
020: import org.springframework.transaction.support.TransactionTemplate;
021:
022: import com.ecyrd.jspwiki.FileUtil;
023: import com.ecyrd.jspwiki.NoRequiredPropertyException;
024: import com.ecyrd.jspwiki.QueryItem;
025: import com.ecyrd.jspwiki.WikiEngine;
026: import com.ecyrd.jspwiki.WikiPage;
027: import com.ecyrd.jspwiki.WikiProvider;
028: import com.ecyrd.jspwiki.attachment.Attachment;
029: import com.ecyrd.jspwiki.providers.ProviderException;
030: import com.ecyrd.jspwiki.providers.WikiAttachmentProvider;
031:
032: /*
033: * History:
034: *
035: * 2007-07-08 Ray Initial released.
036: */
037:
038: /**
039: * Provides a hibernate-based repository for Wiki attachments.
040: * It is a simple wrapper of AttachmentProviderService, and conver the mapping bean with wiki Attachment.
041: * <p/>
042: *
043: * @author Ray Linn
044: *
045: */
046: public class HibernateAttachmentProvider extends HibernateDaoSupport
047: implements WikiAttachmentProvider {
048: protected final Log log = LogFactory.getLog(getClass());
049:
050: private WikiEngine wikiEngine = null;
051: private TransactionTemplate transactionTemplate;
052:
053: public void setTxManager(PlatformTransactionManager txManager) {
054: transactionTemplate = new TransactionTemplate(txManager);
055: }
056:
057: public int getAttachmentCount() {
058: int result = 0;
059:
060: Iterator<?> it = this .getHibernateTemplate().find(
061: "select count(*) from AttachmentDO a").iterator();
062:
063: if (it.hasNext()) {
064: result = ((Long) it.next()).intValue();
065: }
066:
067: return result;
068: }
069:
070: /*
071: * (non-Javadoc)
072: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#putAttachmentData(com.ecyrd.jspwiki.attachment.Attachment, java.io.InputStream)
073: */
074: public void putAttachmentData(final Attachment att,
075: final InputStream dataStream) throws ProviderException,
076: IOException {
077: // transaction is required here since some databases (like PgSQL)
078: // required transactions for working with blobs
079: transactionTemplate
080: .execute(new TransactionCallbackWithoutResult() {
081:
082: protected void doInTransactionWithoutResult(
083: TransactionStatus status) {
084: ByteArrayOutputStream baos = new ByteArrayOutputStream();
085: try {
086: FileUtil.copyContents(dataStream, baos);
087: } catch (IOException ex) {
088: logger.error(
089: "Cannot copy attachment contents",
090: ex);
091: return;
092: }
093:
094: byte[] data = baos.toByteArray();
095:
096: // get new version
097: int version = 1;
098: AttachmentDO latest = getLatestVersion(att
099: .getParentName(), att.getFileName());
100: if (latest != null) {
101: version = latest.getVersion() + 1;
102: }
103:
104: // convert attachment to data object
105: AttachmentDO bean = new AttachmentDO();
106: bean.setVersion(version);
107: bean.setAuthor(att.getAuthor());
108: bean.setFilename(att.getFileName());
109: bean.setParentName(att.getParentName());
110:
111: if (att.getLastModified() != null) {
112: bean.setLastModified(att.getLastModified());
113: } else {
114: bean.setLastModified(new Timestamp(System
115: .currentTimeMillis()));
116: }
117:
118: bean.setNotes((String) att
119: .getAttribute(WikiPage.CHANGENOTE));
120: bean.setDataAsByteArray(data);
121: bean.setLength(data.length);
122: getHibernateTemplate().saveOrUpdate(bean);
123: }
124: });
125: }
126:
127: /*
128: * (non-Javadoc)
129: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#getAttachmentData(com.ecyrd.jspwiki.attachment.Attachment)
130: */
131: public InputStream getAttachmentData(final Attachment att)
132: throws ProviderException, IOException {
133: // for getAttachmentData we cannot use transaction here - since input stream should be
134: // used inside the transaction. So, caller should organize transactions by itself
135: InputStream stream = null;
136: AttachmentDO bean = null;
137:
138: if (att.getVersion() == WikiProvider.LATEST_VERSION) {
139: bean = getLatestVersion(att.getParentName(), att
140: .getFileName());
141: } else {
142: bean = findAttachment(att.getParentName(), att
143: .getFileName(), att.getVersion());
144: }
145:
146: if (bean != null && bean.getData() != null) {
147: stream = bean.getDataInputStream();
148: }
149:
150: return stream;
151: }
152:
153: /*
154: * (non-Javadoc)
155: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#listAttachments(com.ecyrd.jspwiki.WikiPage)
156: */
157: public Collection<Attachment> listAttachments(WikiPage page)
158: throws ProviderException {
159: List<Attachment> result = new LinkedList<Attachment>();
160: List<AttachmentDO> attachments = findAttachments(page.getName());
161:
162: //convert the AttachmentBean to Attachment
163: for (AttachmentDO bean : attachments) {
164: result.add(this .convert(bean));
165: }
166:
167: return result;
168: }
169:
170: /*
171: * (non-Javadoc)
172: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#findAttachments(com.ecyrd.jspwiki.QueryItem[])
173: */
174: @SuppressWarnings("unchecked")
175: public Collection findAttachments(QueryItem[] query) {
176: return new LinkedList(); // TODO
177: }
178:
179: /*
180: * (non-Javadoc)
181: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#listAllChanged(java.util.Date)
182: */
183: public List<Attachment> listAllChanged(Date timestamp)
184: throws ProviderException {
185: List<Attachment> result = new LinkedList<Attachment>();
186: List<AttachmentDO> attachments = findAttachments(timestamp);
187:
188: //convert the AttachmentBean to Attachment
189: for (AttachmentDO bean : attachments) {
190: result.add(this .convert(bean));
191: }
192:
193: return result;
194: }
195:
196: /*
197: * (non-Javadoc)
198: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#getAttachmentInfo(com.ecyrd.jspwiki.WikiPage, java.lang.String, int)
199: */
200: public Attachment getAttachmentInfo(WikiPage page, String name,
201: int version) throws ProviderException {
202: AttachmentDO bean = null;
203: if (version == LATEST_VERSION) {
204: bean = getLatestVersion(page.getName(), name);
205: } else {
206: bean = findAttachment(page.getName(), name, version);
207: }
208:
209: return this .convert(bean);
210: }
211:
212: /*
213: * (non-Javadoc)
214: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#getVersionHistory(com.ecyrd.jspwiki.attachment.Attachment)
215: */
216: public List<Attachment> getVersionHistory(Attachment att) {
217: List<Attachment> result = new LinkedList<Attachment>();
218: List<AttachmentDO> attachments = findAttachments(att
219: .getParentName(), att.getFileName());
220:
221: //convert the AttachmentBean to Attachment
222: for (AttachmentDO bean : attachments) {
223: result.add(this .convert(bean));
224: }
225:
226: return result;
227: }
228:
229: /*
230: * (non-Javadoc)
231: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#deleteVersion(com.ecyrd.jspwiki.attachment.Attachment)
232: */
233: public void deleteVersion(Attachment att) throws ProviderException {
234: AttachmentDO bean = null;
235: if (att.getVersion() == LATEST_VERSION) {
236: bean = getLatestVersion(att.getParentName(), att
237: .getFileName());
238: } else {
239: bean = findAttachment(att.getParentName(), att
240: .getFileName(), att.getVersion());
241: }
242:
243: getHibernateTemplate().delete(bean);
244: getHibernateTemplate().flush();
245: }
246:
247: /*
248: * (non-Javadoc)
249: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#deleteAttachment(com.ecyrd.jspwiki.attachment.Attachment)
250: */
251: public void deleteAttachment(Attachment att)
252: throws ProviderException {
253: List<AttachmentDO> attachments = findAttachments(att
254: .getParentName(), att.getFileName());
255:
256: getHibernateTemplate().deleteAll(attachments);
257: }
258:
259: /*
260: * (non-Javadoc)
261: * @see com.ecyrd.jspwiki.providers.WikiAttachmentProvider#moveAttachmentsForPage(java.lang.String, java.lang.String)
262: */
263: public void moveAttachmentsForPage(String oldParent,
264: String newParent) throws ProviderException {
265: List<AttachmentDO> attachments = findAttachments(oldParent);
266:
267: //convert the AttachmentBean to Attachment
268: for (AttachmentDO bean : attachments) {
269: bean.setParentName(newParent);
270: }
271: getHibernateTemplate().saveOrUpdateAll(attachments);
272: }
273:
274: /*
275: * (non-Javadoc)
276: * @see com.ecyrd.jspwiki.WikiProvider#initialize(com.ecyrd.jspwiki.WikiEngine, java.util.Properties)
277: */
278: public void initialize(WikiEngine engine, Properties properties)
279: throws NoRequiredPropertyException, IOException {
280: log.info("Initializing HibernateAttachmentProvider");
281: this .wikiEngine = engine;
282: int count = this .getAttachmentCount();
283: log.info("Attachment count at startup: " + count);
284: }
285:
286: /*
287: * (non-Javadoc)
288: * @see com.ecyrd.jspwiki.WikiProvider#getProviderInfo()
289: */
290: public String getProviderInfo() {
291: return "Hibernate attachment provider";
292: }
293:
294: private Attachment convert(AttachmentDO attc) {
295: if (attc != null) {
296: Attachment att = new Attachment(this .getEngine(), attc
297: .getParentName(), attc.getFilename());
298: att.setSize(attc.getLength());
299: // use Java Date for friendlier comparisons with other dates
300: att.setLastModified(attc.getLastModified());
301: att.setAuthor(attc.getAuthor());
302: att.setAttribute(WikiPage.CHANGENOTE, attc.getNotes());
303: att.setVersion(attc.getVersion());
304: return att;
305: }
306:
307: return null;
308: }
309:
310: private WikiEngine getEngine() {
311: return this .wikiEngine;
312: }
313:
314: /** Find latest Version of Attachment */
315: protected AttachmentDO getLatestVersion(String pageName,
316: String filename) {
317: List<AttachmentDO> attachments = findAttachments(pageName,
318: filename);
319:
320: if (attachments.size() > 0) {
321: return attachments.get(0);
322: } else {
323: return null;
324: }
325: }
326:
327: /** Find all attchments for specified name
328: *
329: * @param pageName
330: * @param filename
331: * @return
332: */
333: @SuppressWarnings("unchecked")
334: protected List<AttachmentDO> findAttachments(String pageName,
335: String filename) {
336: return this
337: .getHibernateTemplate()
338: .findByNamedParam(
339: "from AttachmentDO att where att.parentName=:pageName and att.filename=:filename order by att.version desc",
340: new String[] { "pageName", "filename" },
341: new Object[] { pageName, filename });
342: }
343:
344: /**
345: * get info for a given page/attachment/version
346: * @param the name of the page
347: * @param the filename of the attachment
348: * @param the version of the attachment
349: * @return the attachment information collection
350: */
351: @SuppressWarnings("unchecked")
352: protected AttachmentDO findAttachment(String pageName,
353: String filename, int version) {
354: List<AttachmentDO> attachments = this
355: .getHibernateTemplate()
356: .findByNamedParam(
357: "from AttachmentDO att where att.parentName=:pageName and att.filename=:filename and att.version=:version",
358: new String[] { "pageName", "filename",
359: "version" },
360: new Object[] { pageName, filename, version });
361:
362: if (attachments.size() > 0) {
363: if (attachments.size() > 1) {
364: log.warn("More then one attachment found for "
365: + pageName + "/" + filename + " version "
366: + version);
367: }
368:
369: return attachments.get(0);
370: } else {
371: return null;
372: }
373: }
374:
375: /**
376: * get list of attachments for a given page grouped by filename in descending order of version number
377: * @param the name of the page
378: * @return the attachment information collection
379: */
380: @SuppressWarnings("unchecked")
381: protected List<AttachmentDO> findAttachments(String pageName) {
382: return this
383: .getHibernateTemplate()
384: .findByNamedParam(
385: "from AttachmentDO att where att.parentName=:pageName and att.version in (select max(att2.version) from AttachmentDO att2 where att2.parentName=:pageName and att2.filename = att.filename group by att2.filename)",
386: "pageName", pageName);
387: }
388:
389: /**
390: * get list of attachment changed since the given date
391: * @param timestamp
392: * @return the attachment information collection
393: */
394: @SuppressWarnings("unchecked")
395: protected List<AttachmentDO> findAttachments(Date timestamp) {
396: return this
397: .getHibernateTemplate()
398: .findByNamedParam(
399: "from AttachmentDO att where att.lastModified>:datetime order by att.lastModified",
400: "datetime", timestamp);
401: }
402:
403: }
|