001    /* 
002     * Copyright 2008-2009 the original author or authors.
003     * The contents of this file are subject to the Mozilla Public License
004     * Version 1.1 (the "License"); you may not use this file except in
005     * compliance with the License. You may obtain a copy of the License at
006     * http://www.mozilla.org/MPL/
007     *
008     * Software distributed under the License is distributed on an "AS IS"
009     * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
010     * License for the specific language governing rights and limitations
011     * under the License.
012     */
013     
014    package com.mtgi.io;
015    
016    import java.io.EOFException;
017    import java.io.File;
018    import java.io.FileInputStream;
019    import java.io.FileOutputStream;
020    import java.io.IOException;
021    import java.io.ObjectInputStream;
022    import java.io.ObjectOutputStream;
023    import java.io.Serializable;
024    
025    /**
026     * A custom data transfer class that serializes data from a local file to an ObjectOutputStream,
027     * which is then stored in a temporary file (rather than memory) on read.  Useful for returning large
028     * files from RMI methods (e.g. JMX operations).
029     */
030    public class RelocatableFile implements Serializable {
031    
032            private static final long serialVersionUID = 6034331005472005195L;
033            private transient File localPath;
034            
035            public RelocatableFile(File localPath) {
036                    this.localPath = localPath;
037            }
038            
039            /** get the local path where the file data is stored */
040            public File getLocalFile() {
041                    return localPath;
042            }
043    
044            /** return the absolute path of the local data file */
045            @Override
046            public String toString() {
047                    return localPath.getAbsolutePath();
048            }
049            
050            private void writeObject(ObjectOutputStream out) 
051                    throws IOException 
052            {
053                    out.writeUTF(localPath.getName());
054                    out.writeLong(localPath.length());
055                    
056                    byte[] xfer = new byte[4096];
057                    FileInputStream fis = new FileInputStream(localPath);
058                    try {
059                            for (int read = fis.read(xfer); read >= 0; read = fis.read(xfer))
060                                    out.write(xfer, 0, read);
061                    } finally {
062                            fis.close();
063                    }
064            }
065            
066            private void readObject(ObjectInputStream in) 
067                    throws IOException, ClassNotFoundException 
068            {
069                    String remote = in.readUTF();
070                    String ext = ".data";
071                    int dot = remote.lastIndexOf('.');
072                    if (dot > 0) {
073                            ext = remote.substring(dot);
074                            remote = remote.substring(0, dot);
075                    }
076                    localPath = File.createTempFile(remote, ext);
077                    
078                    FileOutputStream fos = new FileOutputStream(localPath);
079                    try {
080                            long length = in.readLong();
081                            byte[] xfer = new byte[4096];
082                            while (length > 0) {
083                                    int read = in.read(xfer, 0, (int)Math.min(xfer.length, length));
084                                    if (read < 0)
085                                            throw new EOFException("Unexpected EOF (" + length + " bytes remaining)");
086                                    fos.write(xfer, 0, read);
087                                    length -= read;
088                            }
089                    } finally {
090                            fos.close();
091                    }
092            }
093    }