View Javadoc

1   /* This software was designed and created by Jason Carroll.
2    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
3    * The author can be reached at jcarroll@cowsultants.com
4    * ITracker website: http://www.cowsultants.com
5    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it only under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   */
17  package org.itracker.web.util;
18  
19  import java.io.IOException;
20  
21  import org.apache.log4j.Logger;
22  import org.apache.struts.action.ActionMessage;
23  import org.apache.struts.action.ActionMessages;
24  import org.apache.struts.upload.FormFile;
25  import org.itracker.core.resources.ITrackerResources;
26  import org.itracker.model.Issue;
27  import org.itracker.model.IssueAttachment;
28  import org.itracker.model.Project;
29  import org.itracker.model.User;
30  import org.itracker.services.ConfigurationService;
31  import org.itracker.services.ITrackerServices;
32  import org.itracker.services.IssueService;
33  import org.itracker.services.util.ProjectUtilities;
34  import org.itracker.web.forms.IssueForm;
35   
36  public class AttachmentUtilities {
37      
38      private static final Logger logger = Logger.getLogger(AttachmentUtilities.class);
39      private static boolean initialized = false;
40      private static final String CONTENT_TYPE = "multipart/form-data";
41      private static final String CHAR_ENCODING = "ISO-8859-1";
42      private static final long MAX_FILE_SIZE_KB = 256L;
43      private static final long MAX_TOTAL_FILE_SIZE_KB = 1000000L;
44  
45      private static long maxFileSize = MAX_FILE_SIZE_KB * 1024L;
46      private static long maxTotalFileSize = MAX_TOTAL_FILE_SIZE_KB * 1024L;
47      private static long spaceLeft = 0;
48  
49      
50      /**
51       * 
52       * @deprecated use {@link AttachmentUtilities#validate(FormFile, ITrackerServices)} instead for more detailed messages
53       * @param file
54       * @param services
55       * @return
56       */
57      public static boolean checkFile(FormFile file, ITrackerServices services) {
58      	
59      	return validate(file, services).isEmpty();
60  //    	
61  //    	
62  //        if(! initialized) {
63  //           if(! init(services)) {
64  //              return false;
65  //           }
66  //        }
67  //
68  //        if(file == null) {
69  //            return false;
70  //        }
71  //
72  //        long origFileSize = file.getFileSize();
73  //        if(origFileSize > maxFileSize) {
74  //            logger.info("Cannot save attachment.  File is " + (origFileSize / 1024L) + " kB and max file size is set to " + (maxFileSize / 1024L) + "kB.");
75  //            return false;
76  //        }
77  //
78  //        if((spaceLeft - origFileSize) < 0) {
79  //            logger.info("Cannot save attachment.  Total allocated disk space already used.");
80  //            return false;
81  //        }
82  //        spaceLeft = spaceLeft - origFileSize;
83  //          // @TODO: please check this code and clean up 
84  ////            filename = attachmentDirName + File.separator + filename;
85  //
86  ////            if(logger.isDebugEnabled()) {
87  ////                logger.debug("Attempting to save attachment: " + filename);
88  ////            }
89  //
90  ////            FileOutputStream out = new FileOutputStream(filename);
91  ////            out.write(file.getFileData());
92  ////            out.close();
93  //        return true;
94      }
95      /**
96       * Adds an attachment to issue.
97       * @param issue
98       * @param project
99       * @param user
100      * @param form
101      * @param services
102      * @param messages
103      * @return updated issue 
104      * @throws Exception
105      */
106 	public static Issue addAttachment(Issue issue, Project project, User user,
107 			IssueForm form, ITrackerServices services, ActionMessages messages)  {
108 
109 		if (ProjectUtilities.hasOption(ProjectUtilities.OPTION_NO_ATTACHMENTS,
110 				project.getOptions())) {
111 			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.validate.attachment.disabled", project.getName()));
112 			return issue;
113 		}
114 
115 		FormFile file = form.getAttachment();
116 
117 		if (file == null || file.getFileName().trim().length() < 1) {
118 			logger.info("addAttachment: skipping file " + file);
119 			return issue;
120 		}
121 
122 		String origFileName = file.getFileName();
123 		String contentType = file.getContentType();
124 		int fileSize = file.getFileSize();
125 
126 		String attachmentDescription = form.getAttachmentDescription();
127 
128 		if (null == contentType || 0 >= contentType.length()) {
129 			logger.info("addAttachment: got no mime-type, using default plain-text");
130 			contentType = "text/plain";
131 		}
132 
133 		if (logger.isDebugEnabled()) {
134 			logger.debug("addAttachment: adding file, name: " + origFileName
135 					+ " of type " + file.getContentType() + ", description: "
136 					+ form.getAttachmentDescription() + ". filesize: " + fileSize);
137 		}
138 		ActionMessages validation = AttachmentUtilities.validate(file, services);
139 		if (validation.isEmpty()) {
140 		
141 //		if (AttachmentUtilities.checkFile(file, getITrackerServices())) {
142 			int lastSlash = Math.max(origFileName.lastIndexOf('/'),
143 					origFileName.lastIndexOf('\\'));
144 			if (lastSlash > -1) {
145 				origFileName = origFileName.substring(lastSlash + 1);
146 			}
147 
148 			IssueAttachment attachmentModel = new IssueAttachment(issue,
149 					origFileName, contentType, attachmentDescription, fileSize,
150 					user);
151 			
152 			attachmentModel.setIssue(issue);
153 //			issue.getAttachments().add(attachmentModel);
154 			byte[] fileData;
155 			try {
156 				fileData = file.getFileData();
157 			} catch (IOException e) {
158 				logger.error("addAttachment: failed to get file data", e);
159 				messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.system"));
160 				return issue;
161 			}
162 			if(services.getIssueService()
163 					.addIssueAttachment(attachmentModel, fileData)) {
164 				return services.getIssueService().getIssue(issue.getId());
165 			}
166 			
167 
168 		} else {
169 			if (logger.isDebugEnabled()) {
170 				logger.debug("addAttachment: failed to validate: " + origFileName + ", " + validation);
171 			}
172 			messages.add(validation);
173 		}
174 		return issue;
175 	}
176     
177     public static ActionMessages validate(FormFile file, ITrackerServices services) {
178     	ActionMessages msg = new ActionMessages();
179         if(! initialized) {
180             if(! init(services)) {
181             	msg.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.system"));
182             	return msg;
183             }
184          }
185 
186          if(file == null) {
187              return msg;
188          }
189 
190          long origFileSize = file.getFileSize();
191          if(origFileSize > maxFileSize) {
192              logger.info("Cannot save attachment.  File is " + (origFileSize / 1024L) + " kB and max file size is set to " + (maxFileSize / 1024L) + "kB.");
193 
194  			 msg.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.validate.attachment.size", (Math.round((maxFileSize / 1024L) * 100) / 100) + " " + ITrackerResources.getString("itracker.web.generic.kilobyte")));
195 
196  			 return msg;
197          }
198 
199          if((spaceLeft - origFileSize) < 0) {
200              logger.info("Cannot save attachment.  Total allocated disk space already used.");
201  			 msg.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("itracker.web.error.validate.attachment.quota", (Math.round((maxTotalFileSize / 1024L) * 100) / 100) + " " + ITrackerResources.getString("itracker.web.generic.kilobyte")));
202 
203          }
204          spaceLeft = spaceLeft - origFileSize;
205 
206          return msg;
207      }
208 
209     
210 
211     private static boolean init(ITrackerServices services) {
212         if(! initialized) {
213             try {
214                 ConfigurationService configurationService = services.getConfigurationService();
215                 IssueService issueService = services.getIssueService();
216                 
217                 maxFileSize = configurationService.getLongProperty("max_attachment_size", MAX_FILE_SIZE_KB) * 1024L;
218                 maxTotalFileSize = configurationService.getLongProperty("max_total_attachment_size", MAX_TOTAL_FILE_SIZE_KB) * 1024L;
219                 spaceLeft = maxTotalFileSize - issueService.getAllIssueAttachmentSize();
220 
221                 if(logger.isDebugEnabled()) {
222                     logger.debug("Attachment Properties: MaxAttachmentSize set to " + (maxFileSize / 1024L) + " kB");
223                     logger.debug("Attachment Properties: MaxTotalAttachmentsSize set to " + (maxTotalFileSize / 1024L) + " kB");
224                     logger.debug("Attachment Properties: Current space left is " + (spaceLeft / 1024L) + " kB");
225                 }
226                 initialized = true;
227             } catch(Exception e) {
228                 logger.error("Exception initializing AttachmentUtilities.", e);
229                 throw new Error("Failed to initialize AttachmentUtilities.", e);
230             }
231         }
232         return initialized;
233     }
234 
235 	public static String getCONTENT_TYPE() {
236 		return CONTENT_TYPE;
237 	}
238 
239 	public static String getCHAR_ENCODING() {
240 		return CHAR_ENCODING;
241 	}
242 
243 }