1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
53
54
55
56
57 public static boolean checkFile(FormFile file, ITrackerServices services) {
58
59 return validate(file, services).isEmpty();
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 }
95
96
97
98
99
100
101
102
103
104
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
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
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 }