1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.asynchronousupload.service;
35
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.Enumeration;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.UUID;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46
47 import javax.servlet.http.HttpServletRequest;
48 import javax.servlet.http.HttpServletResponse;
49 import javax.servlet.http.HttpSession;
50
51 import org.apache.commons.collections.CollectionUtils;
52 import org.apache.commons.fileupload.FileItem;
53 import org.apache.commons.lang3.ArrayUtils;
54 import org.apache.commons.lang3.StringUtils;
55
56 import fr.paris.lutece.plugins.asynchronousupload.util.JSONUtils;
57 import fr.paris.lutece.portal.service.util.AppException;
58 import fr.paris.lutece.portal.service.util.AppLogService;
59 import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
60 import net.sf.json.JSON;
61 import net.sf.json.JSONArray;
62 import net.sf.json.JSONObject;
63 import net.sf.json.JSONSerializer;
64
65
66
67
68 public abstract class AbstractAsynchronousUploadHandler implements IAsyncUploadHandler
69 {
70 protected static final String PARAM_CUSTOM_SESSION_ID = "CUSTOM_SESSION";
71 private static final String PARAMETER_FIELD_NAME = "fieldname";
72 private static final String PARAMETER_FIELD_INDEX = "field_index";
73 private static final String PARAMETER_HANDLER = "asynchronousupload.handler";
74 private static final String UPLOAD_SUBMIT_PREFIX = "_upload_submit_";
75 private static final String UPLOAD_DELETE_PREFIX = "_upload_delete_";
76 private static final String UPLOAD_CHECKBOX_PREFIX = "_upload_checkbox_";
77 private static final String KEY_FORM_ERROR = "form_error";
78 private static final String KEY_FILE_SIZE = "fileSize";
79 private static final String KEY_FILE_NAME = "fileName";
80 private static final String KEY_FIELD_NAME = "field_name";
81 private static final String KEY_FILES = "files";
82 private static final String HEADER_CONTENT_RANGE = "Content-Range";
83 private static final String REGEXP_CONTENT_RANGE_HEADER = "bytes (\\d*)-(\\d*)\\/(\\d*)";
84
85 @Override
86 public void process( HttpServletRequest request, HttpServletResponse response, Map<String, Object> map, List<FileItem> listFileItemsToUpload )
87 {
88 map.clear( );
89 String strFieldName = request.getParameter( PARAMETER_FIELD_NAME );
90
91 if ( StringUtils.isBlank( strFieldName ) )
92 {
93 throw new AppException( "id entry is not provided for the current file upload" );
94 }
95
96 if ( CollectionUtils.isNotEmpty( listFileItemsToUpload ) )
97 {
98 String strError = canUploadFiles( request, strFieldName, listFileItemsToUpload, request.getLocale( ) );
99 if ( strError == null )
100 {
101
102 if ( isManagePartialContent( ) && isRequestContainsPartialContent( request ) )
103 {
104 if ( listFileItemsToUpload.size( ) == 1 )
105 {
106 addFileItemToPartialUploadedFilesList( listFileItemsToUpload.get( 0 ), strFieldName, request );
107 if ( isRequestContainsLastPartialContent( request ) )
108 {
109 PartialFileItemGroup/PartialFileItemGroup.html#PartialFileItemGroup">PartialFileItemGroup partialFileItemGroup = new PartialFileItemGroup(
110 getListPartialUploadedFiles( strFieldName, request.getSession( ) ) );
111 addFileItemToUploadedFilesList( partialFileItemGroup, strFieldName, request );
112 }
113 }
114 else
115 {
116 AppLogService.error( "AbstractAsynchronousUploadHandler.process : -Chunk files with multiple file selected do not deal" );
117 map.put( KEY_FORM_ERROR, "Chunk files with multiple file selected do not deal" );
118 }
119 }
120 else
121 {
122 for ( FileItem fileItem : listFileItemsToUpload )
123 {
124 addFileItemToUploadedFilesList( fileItem, strFieldName, request );
125 }
126 }
127 }
128 else
129 {
130 map.put( KEY_FORM_ERROR, strError );
131 }
132 }
133 map.put( KEY_FIELD_NAME, strFieldName );
134
135 List<FileItem> fileItemsSession = getListUploadedFiles( strFieldName, request.getSession( ) );
136 List<Map<String, Object>> listJsonFileMap = new ArrayList<>( );
137 map.put( KEY_FILES, listJsonFileMap );
138
139 for ( FileItem fileItem : fileItemsSession )
140 {
141 Map<String, Object> jsonFileMap = new HashMap<>( );
142 jsonFileMap.put( KEY_FILE_NAME, fileItem.getName( ) );
143 jsonFileMap.put( KEY_FILE_SIZE, fileItem.getSize( ) );
144 listJsonFileMap.add( jsonFileMap );
145 }
146
147 }
148
149
150
151
152
153
154
155
156 public String getUploadAction( HttpServletRequest request )
157 {
158 Enumeration<String> enumParamNames = request.getParameterNames( );
159
160 while ( enumParamNames.hasMoreElements( ) )
161 {
162 String paramName = enumParamNames.nextElement( );
163
164 if ( paramName.startsWith( getUploadSubmitPrefix( ) ) || paramName.startsWith( getUploadDeletePrefix( ) ) )
165 {
166 return paramName;
167 }
168 }
169
170 return null;
171 }
172
173
174
175
176 @Override
177 public void doRemoveFile( HttpServletRequest request, String strFieldName )
178 {
179 if ( hasRemoveFlag( request, strFieldName ) )
180 {
181 HttpSession session = request.getSession( false );
182
183 if ( session != null )
184 {
185
186
187 String strPrefix = getUploadCheckboxPrefix( ) + strFieldName;
188
189
190 Enumeration<String> enumParamNames = request.getParameterNames( );
191 List<Integer> listIndexes = new ArrayList<>( );
192
193 while ( enumParamNames.hasMoreElements( ) )
194 {
195 String strParamName = enumParamNames.nextElement( );
196 String strParamValue = request.getParameter( strParamName );
197
198 if ( strParamValue.startsWith( strPrefix ) )
199 {
200
201 listIndexes.add( Integer.parseInt( strParamValue.substring( strPrefix.length( ) ) ) );
202 }
203 }
204
205 Collections.sort( listIndexes );
206 Collections.reverse( listIndexes );
207
208 for ( int nIndex : listIndexes )
209 {
210 removeFileItem( strFieldName, session, nIndex );
211 }
212 }
213 }
214 }
215
216
217
218
219 @Override
220 public String doRemoveUploadedFile( HttpServletRequest request, String strFieldName, List<Integer> listIndexesFilesToRemove )
221 {
222 if ( StringUtils.isBlank( strFieldName ) )
223 {
224 return JSONUtils.buildJsonErrorRemovingFile( request ).toString( );
225 }
226
227 if ( CollectionUtils.isNotEmpty( listIndexesFilesToRemove ) )
228 {
229
230 JSON jsonFieldIndexes = JSONSerializer.toJSON( listIndexesFilesToRemove );
231
232 if ( !jsonFieldIndexes.isArray( ) )
233 {
234 return JSONUtils.buildJsonErrorRemovingFile( request ).toString( );
235 }
236
237 JSONArray jsonArrayFieldIndexers = (JSONArray) jsonFieldIndexes;
238 int [ ] tabFieldIndex = new int [ jsonArrayFieldIndexers.size( )];
239
240 for ( int nIndex = 0; nIndex < jsonArrayFieldIndexers.size( ); nIndex++ )
241 {
242 try
243 {
244 tabFieldIndex [nIndex] = Integer.parseInt( jsonArrayFieldIndexers.getString( nIndex ) );
245 }
246 catch( NumberFormatException nfe )
247 {
248 return JSONUtils.buildJsonErrorRemovingFile( request ).toString( );
249 }
250 }
251
252
253 Arrays.sort( tabFieldIndex );
254 ArrayUtils.reverse( tabFieldIndex );
255
256 List<FileItem> fileItemsSession = getListUploadedFiles( strFieldName, request.getSession( ) );
257
258 List<FileItem> listItemsToRemove = new ArrayList<>( listIndexesFilesToRemove.size( ) );
259
260 for ( int nFieldIndex : tabFieldIndex )
261 {
262 if ( fileItemsSession.size( ) == 1 && nFieldIndex > 0 )
263 {
264 nFieldIndex = nFieldIndex - 1;
265 }
266 listItemsToRemove.add( fileItemsSession.get( nFieldIndex ) );
267 removeFileItem( strFieldName, request.getSession( ), nFieldIndex );
268 }
269 }
270
271 JSONObject json = new JSONObject( );
272 json.element( JSONUtils.JSON_KEY_SUCCESS, JSONUtils.JSON_KEY_SUCCESS );
273
274 json.accumulateAll( JSONUtils.getUploadedFileJSON( getListUploadedFiles( strFieldName, request.getSession( ) ) ) );
275 json.element( JSONUtils.JSON_KEY_FIELD_NAME, strFieldName );
276
277 return json.toString( );
278 }
279
280
281
282
283 @Override
284 public boolean hasRemoveFlag( HttpServletRequest request, String strFieldName )
285 {
286 return StringUtils.isNotEmpty( request.getParameter( getUploadDeletePrefix( ) + strFieldName ) );
287 }
288
289
290
291
292 @Override
293 public boolean isInvoked( HttpServletRequest request )
294 {
295 return StringUtils.equals( getHandlerName( ), request.getParameter( PARAMETER_HANDLER ) );
296 }
297
298
299
300
301 @Override
302 public boolean hasAddFileFlag( HttpServletRequest request, String strFieldName )
303 {
304 return StringUtils.isNotEmpty( request.getParameter( getUploadSubmitPrefix( ) + strFieldName ) );
305 }
306
307
308
309
310 @Override
311 public void addFilesUploadedSynchronously( HttpServletRequest request, String strFieldName )
312 {
313 if ( request instanceof MultipartHttpServletRequest && hasAddFileFlag( request, strFieldName ) )
314 {
315 MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
316 List<FileItem> listFileItem = multipartRequest.getFileList( strFieldName );
317
318 if ( CollectionUtils.isNotEmpty( listFileItem ) )
319 {
320 for ( FileItem fileItem : listFileItem )
321 {
322 if ( ( fileItem.getSize( ) > 0L ) && StringUtils.isNotEmpty( fileItem.getName( ) ) )
323 {
324 addFileItemToUploadedFilesList( fileItem, strFieldName, request );
325 }
326 }
327 }
328 }
329 }
330
331
332
333
334 @Override
335 public String getUploadSubmitPrefix( )
336 {
337 return getHandlerName( ) + UPLOAD_SUBMIT_PREFIX;
338 }
339
340
341
342
343 @Override
344 public String getUploadDeletePrefix( )
345 {
346 return getHandlerName( ) + UPLOAD_DELETE_PREFIX;
347 }
348
349
350
351
352 @Override
353 public String getUploadCheckboxPrefix( )
354 {
355 return getHandlerName( ) + UPLOAD_CHECKBOX_PREFIX;
356 }
357
358
359
360
361 @Override
362 public byte [ ] doRetrieveUploadedFile( HttpServletRequest request )
363 {
364 String strFieldName = request.getParameter( PARAMETER_FIELD_NAME );
365 String strFieldIndex = request.getParameter( PARAMETER_FIELD_INDEX );
366 int intFieldIndex;
367 FileItem itemToDownload = null;
368 if ( StringUtils.isNotEmpty( strFieldIndex ) && StringUtils.isNumeric( strFieldIndex ) )
369 {
370 intFieldIndex = Integer.parseInt( request.getParameter( PARAMETER_FIELD_INDEX ) );
371 List<FileItem> fileItemsSession = getListUploadedFiles( strFieldName, request.getSession( ) );
372 itemToDownload = fileItemsSession.get( intFieldIndex );
373 }
374 if ( itemToDownload == null )
375 {
376 return new byte [ 0];
377 }
378 return itemToDownload.get( );
379 }
380
381
382
383
384 @Override
385 public List<FileItem> getListPartialUploadedFiles( String strFieldName, HttpSession session )
386 {
387 AppLogService.error( "the Upload Handler do not manage partial content files " );
388 return new ArrayList<>( );
389 }
390
391
392
393
394 @Override
395 public void addFileItemToPartialUploadedFilesList( FileItem fileItem, String strFieldName, HttpServletRequest request )
396 {
397 AppLogService.error( "the Upload Handler do not manage partial content files " );
398 }
399
400
401
402
403
404 @Override
405 public boolean isManagePartialContent( )
406 {
407
408 return false;
409 }
410
411
412
413
414 @Override
415 public void removeAllFileItem( HttpSession session )
416 {
417 }
418
419
420
421
422
423
424
425
426 private boolean isRequestContainsPartialContent( HttpServletRequest request )
427 {
428 return request.getHeader( HEADER_CONTENT_RANGE ) != null;
429
430 }
431
432
433
434
435
436
437
438 private boolean isRequestContainsLastPartialContent( HttpServletRequest request )
439 {
440
441 boolean bLastPartialContent = false;
442 String strContentRange = request.getHeader( HEADER_CONTENT_RANGE );
443 Pattern r = Pattern.compile( REGEXP_CONTENT_RANGE_HEADER );
444 Matcher m = r.matcher( strContentRange );
445
446 if ( m.find( ) )
447 {
448
449 String strLatsBytes = m.group( 2 );
450 String strTotalBytes = m.group( 3 );
451 int nTotalBytes = Integer.parseInt( strTotalBytes );
452 int nLastBytes = Integer.parseInt( strLatsBytes );
453 if ( nTotalBytes - nLastBytes == 1 )
454 {
455 bLastPartialContent = true;
456
457 }
458
459 }
460 return bLastPartialContent;
461 }
462
463 protected String getCustomSessionId( HttpSession session )
464 {
465 String sessionId = (String) session.getAttribute( PARAM_CUSTOM_SESSION_ID );
466 if ( sessionId == null )
467 {
468 sessionId = UUID.randomUUID( ).toString( );
469 session.setAttribute( PARAM_CUSTOM_SESSION_ID, sessionId );
470 }
471 return sessionId;
472 }
473
474 @Override
475 public void removeFileItem( String strFieldName, HttpSession session, int nIndex )
476 {
477
478 List<FileItem> uploadedFiles = getListUploadedFiles( strFieldName, session );
479
480 if ( ( uploadedFiles != null ) && !uploadedFiles.isEmpty( ) && ( uploadedFiles.size( ) > nIndex ) )
481 {
482
483 FileItem fileItem = uploadedFiles.remove( nIndex );
484 fileItem.delete( );
485 }
486 }
487 }