001    package echopoint.tucana;
002    
003    import echopoint.tucana.event.DownloadFailEvent;
004    import echopoint.tucana.event.DownloadFinishEvent;
005    import echopoint.tucana.event.DownloadStartEvent;
006    import static nextapp.echo.webcontainer.ClientProperties.BROWSER_INTERNET_EXPLORER;
007    import nextapp.echo.webcontainer.Connection;
008    import nextapp.echo.webcontainer.ContentType;
009    import nextapp.echo.webcontainer.Service;
010    import nextapp.echo.webcontainer.UserInstance;
011    import nextapp.echo.webcontainer.WebContainerServlet;
012    
013    import javax.servlet.http.HttpServletResponse;
014    import java.io.IOException;
015    import java.io.OutputStream;
016    
017    /**
018     * Services requests to download files.
019     *
020     * @author Echo File Transfer Library
021     * @version $Id: DownloadService.java 116 2009-02-19 00:23:08Z sptrakesh $
022     */
023    public class DownloadService implements Service
024    {
025      static final String SERVICE_ID = "echopoint.tucana.DownloadService";
026    
027      private static final String HTTPS = "https";
028    
029      private static final String PARAMETER_DOWNLOAD_UID = "duid";
030    
031      private static final String[] URL_PARAMETERS = new String[]{ PARAMETER_DOWNLOAD_UID };
032    
033      private static final DownloadService INSTANCE = new DownloadService();
034    
035      /** Installs the service in the registry. */
036      public static void install()
037      {
038        WebContainerServlet.getServiceRegistry().add( INSTANCE );
039      }
040    
041      /** Don't instantiate externally */
042      private DownloadService() {}
043    
044      /**
045       * Creates a URI from which to download the file.
046       *
047       * @param userInstance the user instance of the user downloading.
048       * @param downloadId the id of the download command.
049       * @return the download URI.
050       */
051      public String createUri( UserInstance userInstance, String downloadId )
052      {
053        return userInstance.getServiceUri(
054            this, URL_PARAMETERS, new String[]{ downloadId } );
055      }
056    
057      /** Returns the service id. */
058      public String getId()
059      {
060        return SERVICE_ID;
061      }
062    
063      /** Returns the service version. */
064      public int getVersion()
065      {
066        return DO_NOT_CACHE;
067      }
068    
069      /**
070       * Handles a service request.
071       *
072       * @param conn the connection.
073       */
074      public void service( Connection conn ) throws IOException
075      {
076        final UserInstance userInstance = conn.getUserInstance();
077        if ( userInstance == null )
078        {
079          serviceBadRequest( conn, "No container available." );
080          return;
081        }
082    
083        final String downloadId =
084            conn.getRequest().getParameter( PARAMETER_DOWNLOAD_UID );
085        if ( downloadId == null )
086        {
087          serviceBadRequest( conn, "Download UID not specified." );
088          return;
089        }
090    
091        final DownloadCommand download =
092            DownloadCommandPeer.getAndRemoveDownload( downloadId );
093        if ( download == null )
094        {
095          serviceBadRequest( conn, "Download UID is not valid." );
096          return;
097        }
098    
099        service( conn, download );
100      }
101    
102      /**
103       * Internal processing to handle the download request.
104       *
105       * @param conn the connection.
106       * @param download the download command.
107       * @throws IOException If errors are encountered while writing to the output
108       * stream of the connection.
109       */
110      private void service( Connection conn, DownloadCommand download )
111          throws IOException
112      {
113        final OutputStream out = conn.getOutputStream();
114        final DownloadProvider provider = download.getProvider();
115        final HttpServletResponse response = conn.getResponse();
116    
117        if ( provider.getFileName() == null )
118        {
119          response.setHeader(
120              "Content-Disposition", provider.getContentDisposition() );
121        }
122        else
123        {
124          response.setHeader( "Content-Disposition",
125              provider.getContentDisposition() +
126                  "; filename=\"" + provider.getFileName() + "\"" );
127        }
128    
129        if ( provider.getSize() > 0 )
130        {
131          response.setHeader( "Content-Length", String.valueOf( provider.getSize() ) );
132        }
133    
134        final String contentType = provider.getContentType();
135        if ( contentType == null )
136        {
137          response.setContentType( "application/octet-stream" );
138        }
139        else
140        {
141          response.setContentType( provider.getContentType() );
142        }
143    
144        try
145        {
146          download.notifyCallback( new DownloadStartEvent( download, provider ) );
147    
148          // Fix for IE and https connections
149          if ( HTTPS.equals( conn.getRequest().getScheme() ) &&
150            conn.getUserInstance().getClientProperties().getBoolean( BROWSER_INTERNET_EXPLORER ) )
151          {
152            response.setHeader( "Cache-Control", "" );
153            response.setHeader( "Pragma", "" );
154          }
155    
156          provider.writeFile( out );
157          download.notifyCallback( new DownloadFinishEvent( download, provider ) );
158        }
159        catch ( Exception e )
160        {
161          download.notifyCallback( new DownloadFailEvent( download, provider, e ) );
162        }
163      }
164    
165      /**
166       * Sets the response status indicating that a bad request was made to this
167       * service.
168       *
169       * @param conn the connection.
170       * @param message the error message.
171       */
172      private void serviceBadRequest( Connection conn, String message )
173      {
174        conn.getResponse().setStatus( HttpServletResponse.SC_BAD_REQUEST );
175        conn.setContentType( ContentType.TEXT_PLAIN );
176        conn.getWriter().write( message );
177      }
178    
179      /**
180       * Returns an instance for public use.
181       *
182       * @return an instance for public use.
183       */
184      public static DownloadService getInstance()
185      {
186        return INSTANCE;
187      }
188    }