001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
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.
015: */
016: package org.kuali.core.service.impl;
017:
018: import java.io.BufferedInputStream;
019: import java.io.BufferedOutputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.util.List;
026:
027: import org.apache.commons.lang.StringUtils;
028: import org.apache.log4j.Logger;
029: import org.kuali.RiceConstants;
030: import org.kuali.core.bo.Attachment;
031: import org.kuali.core.bo.Note;
032: import org.kuali.core.bo.PersistableBusinessObject;
033: import org.kuali.core.service.AttachmentService;
034: import org.kuali.core.service.KualiConfigurationService;
035: import org.kuali.core.util.Guid;
036: import org.springframework.transaction.annotation.Transactional;
037:
038: /**
039: * Attachment service implementation
040: */
041: @Transactional
042: public class AttachmentServiceImpl implements AttachmentService {
043: private static Logger LOG = Logger
044: .getLogger(AttachmentServiceImpl.class);
045:
046: private KualiConfigurationService kualiConfigurationService;
047:
048: /**
049: * @see org.kuali.core.service.DocumentAttachmentService#createAttachment(java.lang.String, java.lang.String, int,
050: * java.io.InputStream, Document)
051: */
052: public Attachment createAttachment(
053: PersistableBusinessObject parent, String uploadedFileName,
054: String mimeType, int fileSize, InputStream fileContents,
055: String attachmentTypeCode) throws IOException {
056: LOG.debug("starting to create attachment for document: "
057: + parent.getObjectId());
058: if (parent == null) {
059: throw new IllegalArgumentException(
060: "invalid (null or uninitialized) document");
061: }
062: if (StringUtils.isBlank(uploadedFileName)) {
063: throw new IllegalArgumentException(
064: "invalid (blank) fileName");
065: }
066: if (StringUtils.isBlank(mimeType)) {
067: throw new IllegalArgumentException(
068: "invalid (blank) mimeType");
069: }
070: if (fileSize <= 0) {
071: throw new IllegalArgumentException(
072: "invalid (non-positive) fileSize");
073: }
074: if (fileContents == null) {
075: throw new IllegalArgumentException(
076: "invalid (null) inputStream");
077: }
078:
079: String uniqueFileNameGuid = new Guid().toString();
080: String fullPathUniqueFileName = getDocumentDirectory(parent
081: .getObjectId())
082: + File.separator + uniqueFileNameGuid;
083:
084: writeInputStreamToFileStorage(fileContents,
085: fullPathUniqueFileName);
086:
087: // create DocumentAttachment
088: Attachment attachment = new Attachment();
089: attachment.setAttachmentIdentifier(uniqueFileNameGuid);
090: attachment.setAttachmentFileName(uploadedFileName);
091: attachment.setAttachmentFileSize(new Long(fileSize));
092: attachment.setAttachmentMimeTypeCode(mimeType);
093: attachment.setAttachmentTypeCode(attachmentTypeCode);
094:
095: LOG.debug("finished creating attachment for document: "
096: + parent.getObjectId());
097: return attachment;
098: }
099:
100: private void writeInputStreamToFileStorage(
101: InputStream fileContents, String fullPathUniqueFileName)
102: throws IOException {
103: File fileOut = new File(fullPathUniqueFileName);
104: FileOutputStream streamOut = null;
105: BufferedOutputStream bufferedStreamOut = null;
106: try {
107: streamOut = new FileOutputStream(fileOut);
108: bufferedStreamOut = new BufferedOutputStream(streamOut);
109: int c;
110: while ((c = fileContents.read()) != -1) {
111: bufferedStreamOut.write(c);
112: }
113: } finally {
114: bufferedStreamOut.close();
115: streamOut.close();
116: }
117: }
118:
119: public void moveAttachmentsWherePending(List notes, String objectId) {
120: for (Object obj : notes) {
121: Note note = (Note) obj;
122: Attachment attachment = note.getAttachment();
123: if (attachment != null) {
124: try {
125: moveAttachmentFromPending(attachment, objectId);
126: } catch (IOException e) {
127: throw new RuntimeException(
128: "Problem moving pending attachment to final directory");
129:
130: }
131: }
132: }
133: }
134:
135: private void moveAttachmentFromPending(Attachment attachment,
136: String objectId) throws IOException {
137: //This method would probably be more efficient if attachments had a pending flag
138: String fullPendingFileName = getPendingDirectory()
139: + File.separator + attachment.getAttachmentIdentifier();
140: File pendingFile = new File(fullPendingFileName);
141:
142: if (pendingFile.exists()) {
143: BufferedInputStream bufferedStream = null;
144: FileInputStream oldFileStream = null;
145: String fullPathNewFile = getDocumentDirectory(objectId)
146: + File.separator
147: + attachment.getAttachmentIdentifier();
148: try {
149: oldFileStream = new FileInputStream(pendingFile);
150: bufferedStream = new BufferedInputStream(oldFileStream);
151: writeInputStreamToFileStorage(bufferedStream,
152: fullPathNewFile);
153: } finally {
154:
155: bufferedStream.close();
156: oldFileStream.close();
157: //this has to come after the close
158: pendingFile.delete();
159:
160: }
161: }
162:
163: }
164:
165: public void deleteAttachmentContents(Attachment attachment) {
166: String fullPathUniqueFileName = getDocumentDirectory(attachment
167: .getNote().getRemoteObjectIdentifier())
168: + File.separator + attachment.getAttachmentIdentifier();
169: File attachmentFile = new File(fullPathUniqueFileName);
170: attachmentFile.delete();
171: }
172:
173: private String getPendingDirectory() {
174: return this .getDocumentDirectory("");
175: }
176:
177: private String getDocumentDirectory(String objectId) {
178: // Create a directory; all ancestor directories must exist
179: File documentDirectory = new File(
180: getDocumentFileStorageLocation(objectId));
181: if (!documentDirectory.exists()) {
182: boolean success = documentDirectory.mkdir();
183: if (!success) {
184: throw new RuntimeException(
185: "Could not generate directory for File at: "
186: + documentDirectory.getAbsolutePath());
187: }
188: }
189: return documentDirectory.getAbsolutePath();
190: }
191:
192: /**
193: * /* (non-Javadoc)
194: *
195: * @see org.kuali.core.service.DocumentAttachmentService#retrieveAttachmentContents(org.kuali.core.document.DocumentAttachment)
196: */
197: public InputStream retrieveAttachmentContents(Attachment attachment)
198: throws IOException {
199: //refresh to get Note object in case it's not there
200: if (attachment.getNoteIdentifier() != null) {
201: attachment.refreshNonUpdateableReferences();
202: }
203:
204: String parentDirectory = "";
205: if (attachment.getNote() != null) {
206: parentDirectory = attachment.getNote()
207: .getRemoteObjectIdentifier();
208: }
209:
210: return new BufferedInputStream(new FileInputStream(
211: getDocumentDirectory(parentDirectory) + File.separator
212: + attachment.getAttachmentIdentifier()));
213: }
214:
215: private String getDocumentFileStorageLocation(String objectId) {
216: String location = null;
217: if (StringUtils.isEmpty(objectId)) {
218: location = kualiConfigurationService
219: .getPropertyString(RiceConstants.ATTACHMENTS_PENDING_DIRECTORY_KEY);
220: } else {
221: location = kualiConfigurationService
222: .getPropertyString(RiceConstants.ATTACHMENTS_DIRECTORY_KEY)
223: + File.separator + objectId;
224: }
225: return location;
226: }
227:
228: /**
229: * @see org.kuali.core.service.AttachmentService#deletePendingAttachmentsModifiedBefore(long)
230: */
231: public void deletePendingAttachmentsModifiedBefore(
232: long modificationTime) {
233: String pendingAttachmentDirName = getPendingDirectory();
234: if (StringUtils.isBlank(pendingAttachmentDirName)) {
235: throw new RuntimeException(
236: "Blank pending attachment directory name");
237: }
238: File pendingAttachmentDir = new File(pendingAttachmentDirName);
239: if (!pendingAttachmentDir.exists()) {
240: throw new RuntimeException(
241: "Pending attachment directory does not exist");
242: }
243: if (!pendingAttachmentDir.isDirectory()) {
244: throw new RuntimeException(
245: "Pending attachment directory is not a directory! "
246: + pendingAttachmentDir.getAbsolutePath());
247: }
248:
249: File[] files = pendingAttachmentDir.listFiles();
250: for (File file : files) {
251: if (!file.getName().equals("placeholder.txt")) {
252: if (file.lastModified() < modificationTime) {
253: file.delete();
254: }
255: }
256: }
257:
258: }
259:
260: /**
261: * Gets the configService attribute.
262: * @return Returns the configService.
263: */
264: public KualiConfigurationService getKualiConfigurationService() {
265: return kualiConfigurationService;
266: }
267:
268: /**
269: * Sets the configService attribute value.
270: * @param configService The configService to set.
271: */
272: public void setKualiConfigurationService(
273: KualiConfigurationService configService) {
274: this.kualiConfigurationService = configService;
275: }
276: }
|