001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Jun 17, 2005
014: * @author Marc Batchelor
015: *
016: */
017:
018: package org.pentaho.repository.content;
019:
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.OutputStream;
023: import java.io.Reader;
024: import java.text.MessageFormat;
025: import java.util.Date;
026: import java.util.Iterator;
027: import java.util.List;
028:
029: import javax.activation.FileDataSource;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.hibernate.Query;
034: import org.hibernate.Session;
035: import org.pentaho.core.repository.IContentItem;
036: import org.pentaho.core.repository.content.ContentException;
037: import org.pentaho.core.system.PentahoBase;
038: import org.pentaho.core.system.PentahoSystem;
039: import org.pentaho.messages.MessageUtil;
040: import org.pentaho.messages.Messages;
041: import org.pentaho.repository.HibernateUtil;
042: import org.pentaho.repository.ISearchable;
043: import org.pentaho.util.UUIDUtil;
044:
045: public class ContentItem extends PentahoBase implements IContentItem,
046: ISearchable {
047: public static final int ClassVersionNumber = 2;
048:
049: private static final long serialVersionUID = 823604019645900631L;
050:
051: private static final Log logger = LogFactory
052: .getLog(ContentItem.class);
053:
054: private String id; // Required
055:
056: private ContentLocation parent; // Required
057:
058: private String path; // Derived
059:
060: private String name; // Required
061:
062: private String title; // required
063:
064: private String mimeType; // Required
065:
066: private String url; // Optional
067:
068: private String extension; // Required
069:
070: private ContentItemFile latestFile;
071:
072: private OutputStream outputStream = null;
073:
074: private int revision = -1; // Hibernate Revision
075:
076: private int writeMode; // Indicates whether this kind of file is versioned
077:
078: private int latestVersionNum; // This is now defunct. Don't bother using this anymore
079:
080: private static final String PATH_BUILDER = "{0}/{1}"; //$NON-NLS-1$
081:
082: private static final String[] SearchableColumns = { "name", //$NON-NLS-1$
083: "title", //$NON-NLS-1$
084: "path" }; //$NON-NLS-1$
085:
086: private static final String SearchableTable = "org.pentaho.repository.content.ContentItem"; //$NON-NLS-1$
087:
088: private static final String SearchablePhraseNamedQuery = "org.pentaho.repository.content.ContentItem.itemSearcher"; //$NON-NLS-1$
089:
090: /* Constructor for Hibernate */
091:
092: protected ContentItem() {
093: }
094:
095: /**
096: * Constructor
097: *
098: * @param cntId
099: * @param theParent
100: * @param theName
101: * @param title
102: * @param mType
103: * @param url
104: */
105: protected ContentItem(String cntId, ContentLocation theParent,
106: String theName, String title, String mType,
107: String extension, String url, int writeMode) {
108: name = theName;
109: mimeType = mType;
110: parent = theParent;
111: id = cntId;
112: String extnSep = "."; //$NON-NLS-1$
113: if (!extension.startsWith(extnSep)) {
114: this .extension = extnSep + extension;
115: } else {
116: this .extension = extension;
117: }
118: this .title = title;
119: this .url = url;
120: this .path = MessageUtil.formatMessage(PATH_BUILDER, parent
121: .getDirPath(), this .getName());
122: this .writeMode = writeMode;
123: }
124:
125: public List getMessages() {
126: return null;
127: }
128:
129: protected ContentItemFile newContentFile(String actionName) {
130: String fileGuid = UUIDUtil.getUUIDAsString();
131: String fileName = fileGuid + this .getExtension();
132: ContentItemFile theFile = new ContentItemFile(this , fileGuid,
133: parent.getDirPath(), fileName, actionName);
134: this .latestFile = theFile;
135: HibernateUtil.makePersistent(theFile);
136: return theFile;
137: }
138:
139: public InputStream getInputStream() throws ContentException {
140: ContentItemFile cif = getLatestFile();
141: if (this .latestFile == null) {
142: throw new ContentException(
143: Messages
144: .getErrorString(
145: "CONTITEM.ERROR_0001_NO_EXISTING_FILES", this .getName())); //$NON-NLS-1$
146: }
147: return cif.getInputStream();
148: }
149:
150: public FileDataSource getDataSource() {
151: ContentItemFile cif = getLatestFile();
152: if (this .latestFile == null) {
153: throw new ContentException(
154: Messages
155: .getErrorString(
156: "CONTITEM.ERROR_0001_NO_EXISTING_FILES", this .getName())); //$NON-NLS-1$
157: }
158:
159: String fullPath = PentahoSystem
160: .getApplicationContext()
161: .getFileOutputPath(
162: "system/content/" + cif.getOsPath() + "/" + cif.getId() + extension); //$NON-NLS-1$ //$NON-NLS-2$
163: FileDataSource dataSource = new FileDataSource(fullPath);
164: return dataSource;
165: }
166:
167: public Reader getReader() throws ContentException {
168: ContentItemFile cif = getLatestFile();
169: if (this .latestFile == null) {
170: throw new ContentException(
171: Messages
172: .getErrorString(
173: "CONTITEM.ERROR_0002_NO_EXISTING_FILES", this .getName())); //$NON-NLS-1$
174: }
175: return cif.getReader();
176: }
177:
178: public OutputStream getOutputStream(String actionName)
179: throws IOException {
180: outputStream = null;
181: if (actionName == null) {
182: throw new IllegalArgumentException(
183: Messages
184: .getErrorString("CONTITEM.ERROR_0006_ACTION_NAME_CANNOT_BE_NULL")); //$NON-NLS-1$
185: }
186: switch (getWriteMode()) {
187: case WRITEMODE_KEEPVERSIONS: {
188: ContentItemFile cif = newContentFile(actionName);
189: outputStream = cif.getOutputStream(false);
190: return outputStream;
191: }
192: case WRITEMODE_OVERWRITE: {
193: ContentItemFile cif = getLatestFile();
194: if (cif == null) {
195: cif = newContentFile(actionName);
196: }
197: if (cif != null) {
198: outputStream = cif.getOutputStream(true);
199: return outputStream;
200: }
201: throw new IOException(
202: Messages
203: .getErrorString("CONTITEM.ERROR_0004_OUTPUT_STREAM_NOT_AVAILABLE")); //$NON-NLS-1$
204: }
205: case WRITEMODE_APPEND: {
206: ContentItemFile cif = getLatestFile();
207: if (cif == null) {
208: cif = newContentFile(actionName);
209: }
210: if (cif != null) {
211: outputStream = cif.getOutputStream(true, true);
212: return outputStream;
213: }
214: throw new IOException(
215: Messages
216: .getErrorString("CONTITEM.ERROR_0004_OUTPUT_STREAM_NOT_AVAILABLE")); //$NON-NLS-1$
217: }
218: default: {
219: throw new ContentException(
220: Messages
221: .getErrorString(
222: "CONTITEM.ERROR_0003_BAD_WRITE_MODE", Integer.toString(getWriteMode()))); //$NON-NLS-1$
223: }
224: }
225: }
226:
227: public void closeOutputStream() {
228: if (outputStream != null) {
229: try {
230: outputStream.close();
231: } catch (IOException e) {
232: error(
233: Messages
234: .getErrorString("ContentItem.ERROR_0001_CLOSE_OUTPUT_STREAM"), e); //$NON-NLS-1$
235: }
236: }
237: }
238:
239: public String getActionName() {
240: return this .getLatestFile() != null ? this .getLatestFile()
241: .getActionName() : null;
242: }
243:
244: public String getFileId() {
245: return this .getLatestFile() != null ? this .getLatestFile()
246: .getId() : null;
247: }
248:
249: public long getFileSize() {
250: return this .getLatestFile() != null ? this .getLatestFile()
251: .getFileSize() : -1;
252: }
253:
254: public Date getFileDateTime() {
255: return this .getLatestFile() != null ? this .getLatestFile()
256: .getFileDateTime() : null;
257: }
258:
259: /**
260: * @return Returns the writeMode.
261: */
262: public int getWriteMode() {
263: return writeMode;
264: }
265:
266: /**
267: * @param writeMode
268: * The writeMode to set.
269: */
270: public void setWriteMode(int writeMode) {
271: this .writeMode = writeMode;
272: }
273:
274: /**
275: * equals override for Hibernate
276: *
277: * @see java.lang.Object#equals(java.lang.Object)
278: */
279: public boolean equals(Object other) {
280: if (this == other) {
281: return true;
282: }
283: if (!(other instanceof ContentItem)) {
284: return false;
285: }
286: final ContentItem that = (ContentItem) other;
287: return this .getId().equals(that.getId());
288: }
289:
290: /**
291: * hashcode override for Hibernate
292: *
293: * @see java.lang.Object#hashCode()
294: */
295: public int hashCode() {
296: return getId().hashCode();
297: }
298:
299: /**
300: * @return Returns the extension.
301: */
302: public String getExtension() {
303: return extension;
304: }
305:
306: /**
307: * @param extension
308: * The extension to set.
309: */
310: public void setExtension(String extension) {
311: this .extension = extension;
312: }
313:
314: /**
315: * @return Returns the latestFile.
316: */
317: protected ContentItemFile getLatestFile() {
318: if (latestFile == null) {
319: Session session = HibernateUtil.getSession();
320: Query qry = session
321: .createQuery("from ContentItemFile cif where cif.parent = :contentParent and cif.fileDateTime = (select max(fileDateTime) from ContentItemFile where parent = :contentParent2) "); //$NON-NLS-1$
322: qry.setParameter("contentParent", this ); //$NON-NLS-1$
323: qry.setParameter("contentParent2", this ); //$NON-NLS-1$
324: try {
325: this .latestFile = (ContentItemFile) qry.uniqueResult();
326: } catch (org.hibernate.TransientObjectException ignored) {
327: // The object doesn't exist in Hibernate yet - that's
328: // OK, there's no reason for this exception to escape
329: // from this method. We are purposely swallowing
330: // the exception and returning null...
331: this .latestFile = null;
332: }
333: }
334: return this .latestFile;
335: }
336:
337: /**
338: * @param latestFile
339: * The latestFile to set.
340: */
341: public void setLatestFile(ContentItemFile latestFile) {
342: this .latestFile = latestFile;
343: }
344:
345: /**
346: * @deprecated
347: * @return Returns the latestVersionNum. Don't set or get this value any more - retained for backward compatibility.
348: */
349: public int getLatestVersionNum() {
350: return latestVersionNum;
351: }
352:
353: /**
354: * @deprecated
355: * @param latestVersionNum
356: * The latestVersionNum to set. Don't set or get this value any more - retained for backward compatibility.
357: */
358: public void setLatestVersionNum(int latestVersionNum) {
359: this .latestVersionNum = latestVersionNum;
360: }
361:
362: /**
363: * @return Returns the revision.
364: */
365: public int getRevision() {
366: return revision;
367: }
368:
369: /**
370: * @param revision
371: * The revision to set.
372: */
373: public void setRevision(int revision) {
374: this .revision = revision;
375: }
376:
377: public void removeVersion(ContentItemFile cif) {
378: try {
379: cif.deleteOsFile();
380: } catch (Exception ex) {
381: logger
382: .error(
383: Messages
384: .getErrorString(
385: "CONTITEM.ERROR_0005_COULD_NOT_DELETE_OS_FILE", cif.getCompleteFileName()), ex); //$NON-NLS-1$
386: }
387: HibernateUtil.makeTransient(cif);
388:
389: if (latestFile == null
390: || latestFile.getId().equals(cif.getId())) {
391: this .latestFile = null;
392: // Get the now latest file from the DB and sets the variable.
393: this .getLatestFile();
394: }
395: }
396:
397: public void removeVersion(String fileId) {
398: Iterator it = getFileVersions().iterator();
399: ContentItemFile cif;
400: while (it.hasNext()) {
401: cif = (ContentItemFile) it.next();
402: if (fileId.equalsIgnoreCase(cif.getId())) {
403: removeVersion(cif);
404: break;
405: }
406: }
407: }
408:
409: /**
410: * Removes all version files.
411: */
412: public void removeAllVersions() {
413: Iterator it = getFileVersions().iterator();
414: ContentItemFile cif;
415: while (it.hasNext()) {
416: cif = (ContentItemFile) it.next();
417: cif.deleteOsFile();
418: HibernateUtil.makeTransient(cif);
419: }
420: this .latestFile = null;
421: }
422:
423: /*
424: * Accessors
425: */
426:
427: /**
428: * @return Returns the parent.
429: */
430: public ContentLocation getParent() {
431: return parent;
432: }
433:
434: /**
435: * @param theParent
436: * The parent to set.
437: */
438: public void setParent(ContentLocation theParent) {
439: this .parent = theParent;
440: }
441:
442: /**
443: * @return Returns the name.
444: */
445: public String getName() {
446: return name;
447: }
448:
449: /**
450: * @param fName
451: * The name to set.
452: */
453: public void setName(String fName) {
454: this .name = fName;
455: }
456:
457: /**
458: * @return Returns the id.
459: */
460: public String getId() {
461: return id;
462: }
463:
464: /**
465: * @param id
466: * The id to set.
467: */
468: public void setId(String id) {
469: this .id = id;
470: }
471:
472: /**
473: * @return Returns the mimeType.
474: */
475: public String getMimeType() {
476: return mimeType;
477: }
478:
479: /**
480: * @param mimeType
481: * The mimeType to set.
482: */
483: public void setMimeType(String mimeType) {
484: this .mimeType = mimeType;
485: }
486:
487: /**
488: * @return Returns the url.
489: */
490: public String getUrl() {
491: return url;
492: }
493:
494: /**
495: * @param url
496: * The url to set.
497: */
498: public void setUrl(String url) {
499: this .url = url;
500: }
501:
502: /**
503: * @return Returns the path.
504: */
505: public String getPath() {
506: return path;
507: }
508:
509: /**
510: * @param path
511: * The path to set.
512: */
513: public void setPath(String path) {
514: this .path = path;
515: }
516:
517: /**
518: * @return Returns the fileVersions.
519: */
520: public List getFileVersions() {
521: Session session = HibernateUtil.getSession();
522: Query qry = session
523: .createQuery("from ContentItemFile cif where cif.parent = :contentParent order by cif.fileDateTime"); //$NON-NLS-1$
524: qry.setParameter("contentParent", this ); //$NON-NLS-1$
525: return qry.list();
526: }
527:
528: /**
529: * @return Returns the title.
530: */
531: public String getTitle() {
532: return title;
533: }
534:
535: /**
536: * @param title
537: * The title to set.
538: */
539: public void setTitle(String title) {
540: this .title = title;
541: }
542:
543: /**
544: * @return Returns the log.
545: */
546: public Log getLogger() {
547: return logger;
548: }
549:
550: /* ISearchable Needs */
551: public String[] getSearchableColumns() {
552: return SearchableColumns;
553: }
554:
555: public String getSearchableTable() {
556: return SearchableTable;
557: }
558:
559: public String getPhraseSearchQueryName() {
560: return SearchablePhraseNamedQuery;
561: }
562:
563: public void makeTransient() {
564: this .removeAllVersions();
565: HibernateUtil.makeTransient(this );
566: }
567:
568: public String toString() {
569: return MessageFormat
570: .format(
571: "{0}, {1}, {2}", new String[] { this .getTitle(), this .getPath(), this .getMimeType() }); //$NON-NLS-1$
572: }
573:
574: }
|