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 Dec 21, 2006
014: * @author James Dixon
015: *
016: */
017:
018: package org.pentaho.repository.content;
019:
020: import org.pentaho.core.output.BaseOutputHandler;
021: import org.pentaho.core.repository.IContentItem;
022: import org.pentaho.core.repository.IContentLocation;
023: import org.pentaho.core.repository.IContentRepository;
024: import org.pentaho.core.system.PentahoSystem;
025: import org.pentaho.messages.Messages;
026: import org.pentaho.util.logging.Logger;
027:
028: public class ContentRepositoryOutputHandler extends BaseOutputHandler {
029:
030: private static final byte[] lock = new byte[0];
031:
032: public IContentItem getFileOutputContentItem() {
033:
034: String contentRef = getContentRef();
035: // get an output stream to hand to the caller
036: IContentRepository contentRepository = PentahoSystem
037: .getContentRepository(getSession());
038: if (contentRepository == null) {
039: Logger
040: .error(
041: this .getClass().getName(),
042: Messages
043: .getErrorString("RuntimeContext.ERROR_0024_NO_CONTENT_REPOSITORY")); //$NON-NLS-1$
044: return null;
045: }
046: String extension = ""; //$NON-NLS-1$
047: int idx1 = contentRef.lastIndexOf("."); //$NON-NLS-1$
048: if (idx1 != -1) {
049: extension = contentRef.substring(idx1);
050: } else {
051: idx1 = contentRef.length();
052: }
053: String extensionFolder = extension;
054: if (extensionFolder.startsWith(".")) { //$NON-NLS-1$
055: extensionFolder = extensionFolder.substring(1);
056: }
057: int idx2 = contentRef.lastIndexOf("/"); //$NON-NLS-1$
058: String outputFolder = ""; //$NON-NLS-1$
059: String itemName = contentRef;
060: if (idx2 != -1) {
061: outputFolder = contentRef.substring(0, idx2);
062: }
063: itemName = contentRef.substring(idx2 + 1, idx1);
064: String contentPath = outputFolder
065: + "/" + itemName + "/" + extensionFolder; //$NON-NLS-1$ //$NON-NLS-2$
066: IContentItem contentItem = null;
067: //
068: // Synchronizing solves a nasty race condition when
069: // multiple simultaneous threads ask Hibernate if a
070: // specific Location/Item exists. In all cases, the
071: // answer will be no, so they all create the corresponding
072: // object and tell Hibernate to save it. The end-result is
073: // exceptions thrown from the database for key-constraint violations.
074: // Synchronizing down to the create of the item will make sure
075: // that all pending saves get persistent.
076: //
077: synchronized (lock) {
078: // Find the location if it's already there.
079: IContentLocation contentLocation = null;
080: try {
081: contentLocation = contentRepository
082: .getContentLocationByPath(contentPath);
083: } catch (Exception ex) {
084: Logger
085: .debug(this .getClass().getName(), contentPath,
086: ex);
087: }
088: if (contentLocation == null) {
089: // Logger.debug(this.getClass().getName(),"******** New Location: " + contentPath + " - Thread: " + Thread.currentThread().getName()); //$NON-NLS-1$ //$NON-NLS-2$
090: contentLocation = contentRepository.newContentLocation(
091: contentPath, contentRef, contentRef,
092: getSolutionName(), true);
093: }
094: if (contentLocation == null) {
095: Logger
096: .error(
097: this .getClass().getName(),
098: Messages
099: .getErrorString("RuntimeContext.ERROR_0025_INVALID_CONTENT_LOCATION")); //$NON-NLS-1$
100: return null;
101: }
102: // TODO support content expiration
103:
104: // TODO make the write mode based on the output definition
105:
106: // Get the content item from the location - if it's there.
107: try {
108: contentItem = contentLocation
109: .getContentItemByName(getInstanceId());
110: } catch (Exception ex) {
111: Logger.debug(this .getClass().getName(),
112: getInstanceId(), ex);
113: }
114: if (contentItem == null) { // DM - Need to keep versions so each report
115: // in a burst gets saved
116: contentItem = contentLocation.newContentItem(
117: getInstanceId(), contentRef, extension,
118: getMimeType(), null,
119: IContentItem.WRITEMODE_KEEPVERSIONS);
120: }
121: }
122: return contentItem;
123: }
124:
125: }
|