Listing of Source filetrans/AdminUtilClientToServerFileTransfer.java
package se.entra.phantom.server.rconsole;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import se.entra.phantom.server.VirtualCUserWindow;
import se.entra.phantom.server.VirtualComponentAdapter;
import se.entra.phantom.server.VirtualControl;
import se.entra.phantom.server.VirtualPanel;
import se.entra.phantom.server.VirtualSessionManager;
import se.entra.phantom.server.VirtualUserWindowInterface;

/**
 * This class handles the transfer of an arbitrary file from the client to the server
 */
public class AdminUtilClientToServerFileTransfer extends VirtualComponentAdapter implements AdminFileTransferListener
{
  /**
   * The session manager.
   */
  private final VirtualSessionManager vsm;

  /**
   * String for message boxes.
   */
  private final String messageHeader;

  /**
   * String for error messages.
   */
  private final String errorMessageHeader;

  /**
   * The output stream.
   */
  private BufferedOutputStream fileOutputStream;

  /**
   * Download in progress flag.
   */
  private boolean inProgress;

  /**
   * Cancel flag.
   */
  private boolean doCancel;

  /**
   * The server file VirtualControl.
   */
  private final VirtualControl serverFileControl;

  /**
   * The server side file.
   */
  private File srvFile;

  /**
   * Bytes downloaded so far.
   */
  private int currentSize;

  ///

  /**
   * Constructor
   */
  public AdminUtilClientToServerFileTransfer(VirtualPanel vp)
    {
    vsm=vp.getVirtualSessionManager();
    vp.setListener(this);

    // Hide the file transfer user window.
    vp.setVisible("FILETRAN",false);
    vp.setText("MESSAGE","Progress indicator:");
    vp.setText("PROGRESS","0");

    serverFileControl =vp.getControlFromID("SRVFILE");
    messageHeader     ="Client-to-server file transer";
    errorMessageHeader="Error during file transfer";
    }

  /**
   * Push buttons and menu items generates this event when selected.
   */
  @Override
  public void onAction(VirtualPanel vp,String controlID)
    {
    if      ( controlID.equals("CANCEL"  ) )  onPanelClosing(vp);
    else if ( controlID.equals("CLTBUTT" ) )  selectSourceFile(vp);
    else if ( controlID.equals("SRVBUTT" ) )  new AdminConfigSelectFile(vsm,serverFileControl,null);
    else if ( controlID.equals("TRANSFER") )  performTransfer(vp);
    }

  /**
   * Method called when the 'TRANSFER' button is pressed
   */
  private void performTransfer(VirtualPanel vp)
    {
    // Check access rights.
    final String srvPath=vp.getText("SRVFILE");
    try
      {
      AdminConfigFileManager.checkAccessRights(srvPath);
      }
    catch(final IOException e)
      {
      vp.messageBox(MB_OK,ICON_CRITICAL,"Error checking the specified server file: "+e, messageHeader);
      return;
      }

    // Get that userWindow!
    final VirtualUserWindowInterface vu=((VirtualCUserWindow)(vp.getControlFromID("FILETRAN"))).getPeer();
    final AdminFileTransferInterface userWindow=(AdminFileTransferInterface)vu;
    final String cltPath=vp.getText("CLNTFILE");
    srvFile=new File(srvPath);
    String cfpEnding="";
    String sfpEnding="";

    int index=cltPath.lastIndexOf('.');
    if ( index>=0 )
      cfpEnding=cltPath.substring(index);
    index=srvPath.lastIndexOf('.');
    if ( index>0 )
      sfpEnding=srvPath.substring(index);

    // Validation.
    if ( srvFile.exists() && !srvFile.canWrite() )
      {
      vp.messageBox(MB_OK,ICON_WARNING,"The specified server file is write protected!",messageHeader);
      return;
      }

    if ( !srvFile.isFile() && srvFile.exists() )
      {
      vp.messageBox(MB_OK,ICON_WARNING,"The specified server file is not valid!",messageHeader);
      return;
      }

    if ( cltPath.isEmpty() || srvPath.isEmpty() )
      {
      vp.messageBox(MB_OK,ICON_WARNING,"Please specify both a target and a source file.",messageHeader);
      return;
      }

    if ( !cfpEnding.equals(sfpEnding) )
      {
      final int answer=vp.messageBox(MB_YESNO,ICON_WARNING,
                               "Please note that You are about to save the file with a different extension than the original file on the server.\n\n"+
                               "Do You want to continue?",
                                messageHeader);
      if ( answer!=MBID_YES )
        return;
      }

    if ( srvFile.exists() )
      {
      if ( vp.messageBox(MB_YESNO,ICON_QUESTION,
                         srvFile.getAbsolutePath()+" already exists.\n\nDo You want to replace it?",
                         messageHeader)!=MBID_YES )
        return;
      }

    vp.setEnabled("TRANSFER",false);
    vp.setEnabled("CLTBUTT",false);
    vp.setEnabled("SRVBUTT",false);
    vp.setText("PROGRESS","-1");
    doCancel=false;
    inProgress=true;
    currentSize=0;
    userWindow.initiateFileTransfer(this,cltPath);
    }

  /**
   * Method used to initiate a file selection on the client
   */
  private void selectSourceFile(VirtualPanel vp)
    {
    final VirtualUserWindowInterface vu=((VirtualCUserWindow)(vp.getControlFromID("FILETRAN"))).getPeer();
    final AdminFileTransferInterface ft=(AdminFileTransferInterface)vu;

    if ( !ft.selectFileForTransfer(this) )
      {
      vp.messageBox(MB_OK,ICON_WARNING,"Selection of file to transfer failed.",errorMessageHeader);
      close(vp);
      }
    }

  /**
   * A file has been selected on the client side in the dialog box (or canceled if file name is null).
   */
  @Override
  public void onFileSelected(VirtualPanel vp,AdminFileTransferInterface ft,String fileName,int size)
    {
    if ( fileName==null || doCancel )
      return;
    vp.setText("CLNTFILE",fileName);
    }

  /**
   * A piece of the download data of a file (data is null when canceled).
   */
  @Override
  public void onFileDownload(VirtualPanel vp,AdminFileTransferInterface ft,int totalSize,byte [] data)
    {
    // Create new output stream if not created.
    if ( fileOutputStream==null )
      {
      try
        {
        fileOutputStream=new BufferedOutputStream(new FileOutputStream(srvFile));
        }
      catch(final IOException e)
        {
        vp.messageBox(MB_OK,ICON_WARNING,"The specified server file is not valid!",errorMessageHeader);
        close(vp);
        return;
        }
      catch(final Exception e)
        {
        vp.messageBox(MB_OK,ICON_WARNING,"Server file transfer error: "+e+").",errorMessageHeader);
        close(vp);
        return;
        }
      }

    // Add the new data.
    final int cc=data.length;
    currentSize+=cc;
    try
      {
      fileOutputStream.write(data);
      }
    catch(final IOException e)
      {
      vp.messageBox(MB_OK,ICON_WARNING,"Error trying to write to file: "+e+").",errorMessageHeader);
      close(vp);
      return;
      }

    // Check if the entire file has been downloaded.
    if ( currentSize<totalSize )
      {
      // Calculate percentage of download.
      final long progress=100L*currentSize/totalSize;
      vp.setText("PROGRESS",Long.toString(progress));
      if ( !ft.continueFileTransfer() )
        {
        ft.closeFileTransfer();
        vp.messageBox(MB_OK,ICON_CRITICAL,"File transfer couldn't be continued.",messageHeader);
        close(vp);
        return;
        }
      vsm.commitChanges(false);
      return;
      }
    downloadComplete(vp,ft);
    }

  /**
   * Used when server-to-client file transfer
   */
  @Override
  public void onTargetFileSelected(VirtualPanel vp,AdminFileTransferInterface ft,String directory)
    {
    }

  /**
   * Used when server-to-client file transfer
   */
  @Override
  public void onFileUploadComplete(VirtualPanel vp,AdminFileTransferInterface ft)
    {
    }

  /**
   * Returns the list of all files or directories in the requested directory.
   */
  @Override
  public void onDirectoryList(VirtualPanel vp,AdminFileTransferInterface ft,AdminConfigFileTransferItem [] files)
    {
    }

  /**
   * Called when the client is ready for next chunk of data
   */
  @Override
  public void onFileUpload(VirtualPanel vp, AdminFileTransferInterface ft)
    {
    }

  /**
   * Called whenever a file transfer error occurs.
   */
  @Override
  public void onFileTransferError(VirtualPanel vp,AdminFileTransferInterface ft,String errorMessage)
    {
    vp.messageBox(MB_OK,ICON_WARNING,errorMessage,errorMessageHeader);
    close(vp);
    return;
    }

  /**
   * Called when to cancel/close
   */
  private void close(VirtualPanel vp)
    {
    if ( fileOutputStream!=null )
      {
      try { fileOutputStream.close(); }
      catch(final IOException e2) {}
      fileOutputStream=null;
      }

    if ( !inProgress )
      vsm.stopSession(vp.getPanelSession().getIndex());
    else
      {
      // Get that userWindow!
      final VirtualUserWindowInterface vu=((VirtualCUserWindow)(vp.getControlFromID("FILETRAN"))).getPeer();
      final AdminFileTransferInterface userWindow=(AdminFileTransferInterface)vu;
      userWindow.closeFileTransfer();
      vp.setEnabled("TRANSFER",true);
      vp.setEnabled("CLTBUTT",true);
      vp.setEnabled("SRVBUTT",true);
      vp.setText("PROGRESS","0");
      inProgress=false;
      doCancel=true;
      }
    }

  /**
   * Called when the close button of a panel is pressed,
   * but before any other processing has been done. If this
   * function returns false, the application close object
   * will be called (if defined), otherwise a faked key-press
   * of the Escape key is performed. If these two actions
   * failed (because there is no close object or no button or
   * menu item is connected to the Escape key), then the
   * function <code>onPanelClose</code> is called.
   *
   * @return  true  to cancel all default processing.
   */
  @Override
  public boolean onPanelClosing(VirtualPanel vp)
    {
    if ( inProgress )
      vp.messageBox(MB_OK,ICON_WARNING,
                    "The file transfer was cancelled. The created file is corrupt.",
                    errorMessageHeader);
    doCancel=true;
    close(vp);
    return true;
    }

  /**
   * Called to inform the listener that the panel is destroyed.
   *
   * <p>Closes any currently opened file transfer.
   */
  @Override
  public void onPanelDestroy(VirtualPanel panel)
    {
    if ( fileOutputStream!=null )
      {
      try { fileOutputStream.close(); }
      catch(final IOException e2) {}
      fileOutputStream=null;
      }
    }

  /**
   * Called from onFileDownload when the download is complete
   */
  private void downloadComplete(VirtualPanel vp,AdminFileTransferInterface ft)
    {
    inProgress=false;
    ft.closeFileTransfer();
    if ( fileOutputStream!=null )
      {
      try { fileOutputStream.close(); }
      catch(final Exception e){}
      fileOutputStream=null;
      }
    vp.setText("PROGRESS","100");
    vp.setText("MESSAGE","The file transfer has completed succefully, press 'OK' to continue");
    vp.messageBox(MB_OK,ICON_INFORMATION,"The file transfer has completed succefully, press 'OK' to continue","Transfer complete");
    vp.setEnabled("TRANSFER",true);
    vp.setEnabled("CLTBUTT",true);
    vp.setEnabled("SRVBUTT",true);
    }
}