Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    File Upload short file name (bug? / possible RFE)

    Hi Isomorphic,

    Version: SmartGWTEE 4.1

    We had a situation using com.isomorphic.servlet.ISCFileItem where we needed to get the short filename, without path on the server side.

    Unfortunately, IE 8 sends the whole path such that ISCFileItem.getFileName() returns something like c:\path\to\myfile.xls. If the server is UNIX/Linux then it is hard to know what to do since this is a valid UNIX file name. Developing locally on Windows we could create a File in Java to get the short file name or path. FireFox sends myfile.xls to the server so only IE is the problem.

    Our use case was that we have files to upload where the filename X23C.txt for example has data inside X23C and we need to know that so we can delete data on load rather than peek inside the file or do something less than optimal.

    We tried ISCFileItem.getShortFileName() and it returns null.

    This next code shows a form with a file item - not totally code complete. Basically we get the short file name and pass it as a parameter of the request. Ideally the FileItem field would capture the short file name.


    Code:
    import com.ray.gwt.util.FileUtils;
    import com.smartgwt.client.widgets.form.fields.FileItem;
    // most imports omitted
    
    public UploadForm extends Form {
    
    	public UploadForm(String title) {
    		super(title);
    		this.setEncoding(Encoding.MULTIPART);
    		this.setDataSource(DataSource.get("ExcelUpload"));				            
            	FileItem excelFile = new FileItem("excelFile", "Import " + title);
            	excelFile.setWidth(300);
            	excelFile.setWrapTitle(true);
            	excelFile.setType("binary");
    
    		IButton importButton = new ImportButton();
    		importButton.addClickHandler(new ClickHandler() {
    			@Override
    			public void onClick(ClickEvent event) {
    				Object file = uploadForm.getValue("excelFile");
    				if ( file != null) {
    					String shortFileName = FileUtils.getShortFileName((String) file);
    					GWT.log("Short File: " + shortFileName);
    					
    					Map<String, Object> paramMap = new HashMap<String, Object>();
    					paramMap.put("fileName", "excelFile"); // for field name
    					paramMap.put("shortFileName", shortFileName);  // added to FileItemBean
    
    					DSRequest req = new DSRequest();
    					req.setOperationId("importSapKsh3");
    					req.setIgnoreTimeout(true);
    					req.setData(paramMap);
    
    					form.saveData(new DSCallback() {
    						@Override
    						public void execute(DSResponse response, Object rawData, DSRequest request) {
    							// code omiited
    						}
    					}, req);
    				}
    			}
    		});
    		toolbarItem.setButtons(importButton, resetButton);
            	this.setFields(excelFile, toolbarItem);
    	}
    }
    This next code is the utility we created to get the shortFileName using core GWT not SmartGWT. Probably a better way but...

    Code:
    package com.ray.gwt.util;
    
    import com.google.gwt.user.client.Window.Navigator;
    
    /**
     * Some useful File methods for GWT.
     *
     * @author ekr
     */
    final public class FileUtils {
      
      /** So no one can instantiate it */
      private FileUtils() {}
        
      /**
       * Return the file name without the extension.
       * 
       * @param fileName - a filename such as foo.txt
       * @return - e.g. foo
       */
      public static String getBaseFileName(final String fileName) {
        final int extensionDot = fileName.lastIndexOf('.');
        return extensionDot != -1 ? fileName.substring(0, extensionDot) : fileName;
      }
      
      /**
       * Get the short filename only handles Win and UNIX for now.
       * @param fileName - a full filename such as c:\work\foo.txt or /work/foo.txt
       * @return - e.g. foo.txt
       */
      public static String getShortFileName(String fileName) {
        String platform = Navigator.getPlatform();
        String fileSep = platform.equals("Win32") ? "\\" : "/";
        int lastIndex = fileName.lastIndexOf(fileSep);
        return lastIndex != -1 ? fileName.substring(lastIndex + 1) : fileName;
      } 
    }
    Then we have a little helper class on the server side to deal with the ISCFileItem.

    Code:
    public class FileItemBean {
    	private static final String FILE_NAME_FIELD = "fileName";
    	private final String fileFieldName;
    	private final ISCFileItem file;
    	private final DSRequest dsRequest;
    	private final String shortFileName;
    	private final long fileSize;
    	private InputStream is;
    	
    	public FileItemBean(DSRequest dsRequest) {
    	  this.dsRequest = dsRequest;
    		this.fileFieldName = DmiUtils.getValue(dsRequest, FILE_NAME_FIELD); // form field
    		this.shortFileName = DmiUtils.getValue(dsRequest, "shortFileName"); // if passed in Request
    		try {
    			this.file = dsRequest.getUploadedFile(fileFieldName);
    		} catch (Exception e) {
    			throw new RuntimeException("Unable to get File: " +
    					fileFieldName + " for form field: " + FILE_NAME_FIELD, e);
    		}
    		this.fileSize = file!=null ? file.getSize() : 0;
    		this.is = file.getInputStream();
    	}
    }
    We get the shortFileName from the request as shown above. Ideally, SC would pass the shortFileName across and make it available in the ISCFileItem.getShortFileName() method.

    Thanks,
    Eric

    #2
    Sorry, we're not really following this - different browsers send different values, so it seems like regardless, you should add code that looks for the last forward or backslash?

    Comment


      #3
      Hi Isomorphic,

      It wasn't quite clear what I was talking about but I also wanted to put some code so you could se want I was doing.

      I thought since ISCFileItem has a method getShortFileName, I assumed that it would have a value and not be null. I have found a solution to pass the shortFileName across in the application I was working on so that is good.

      I'm wasn't sure if there was a way to enhance or standardize SmartGwt so I wanted to point this out in case it might be useful.

      I did some reading and it seems, like you point out that different browsers do different things. If you wanted to change or add to SmartGWT then maybe the shortFileName could be passed on form submittal and ISCFileItem could pick it up.

      Thanks,
      Eric

      Comment


        #4
        I guess what we're not clear on is - the shortFileName is something you can just calculate from the full fileName, right? So why bother sending it from client to server?

        Comment


          #5
          Hi Isomorphic,

          Thank-you for following up.

          If the client is Windows using IE and sends c:\foo\bar.txt.
          I get c:\foo\bar.txt on the server.

          Code:
          // server side possible way the deal with filenames
          File file = new File("c:\foo\bar.txt");
          
          String shortFileName = file.getName(); 
          // UNIX server result: c:\foo\bar.txt
          // windows server result: bar.txt
          Backslash is allowed in Unix file names so we don't get bar.txt as expected. We could guess or do some sort of heuristics (pattern match) but a deterministic way is to know what platform the file is being sent from and deal with it on the client.

          What I did I think was the safest way - user's can do weird things so I don't want to leave any holes. I also don't want to make client or server platform assumptions. So to me, a logical thing to do was to pass the filename from the client to the server. I also found on the web someone else using an onSubmit function to add the short file name to a form field for exactly the same purpose. Lost the reference other wise I'd include it.

          Do you know why ISCFileItem has the getShortFileName() method?
          I'm not sure anyone else has tried to use that method or would need to use the filename on the server for some reason.

          Windows IE does have a feature to turn off passing file path.

          Eric

          Comment


            #6
            Do you know why ISCFileItem has the getShortFileName() method?
            It's an undocumented, internal method related to automatic file persistence in SQL/JPA/Hibernate. You shouldn't be calling it.

            More broadly, obtaining the last path segment of a file name is an extremely trivial task (substring+lastIndexOf("/")); it doesn't make much sense to use that you'd bother to do this client-side and try to find a special means of conveying the value to the server. Just compute it server side.

            Comment


              #7
              In my opinion you need to know the Operating system to reliably parse the filename out of the pathname because you know the separator which is system dependent. I didn't consider finding the client OS on the server via the request somehow. That's it, no worries.

              Comment


                #8
                Right, if you find it necessary to sniff the separator (may not matter depending on what characters you actually allow in the filename you save), the client and server have basically the same information (user agent string).

                Comment

                Working...
                X