1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  *  The Contents of this file are made available subject to the terms of
4*cdf0e10cSrcweir  *  the BSD license.
5*cdf0e10cSrcweir  *
6*cdf0e10cSrcweir  *  Copyright 2000, 2010 Oracle and/or its affiliates.
7*cdf0e10cSrcweir  *  All rights reserved.
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  *  Redistribution and use in source and binary forms, with or without
10*cdf0e10cSrcweir  *  modification, are permitted provided that the following conditions
11*cdf0e10cSrcweir  *  are met:
12*cdf0e10cSrcweir  *  1. Redistributions of source code must retain the above copyright
13*cdf0e10cSrcweir  *     notice, this list of conditions and the following disclaimer.
14*cdf0e10cSrcweir  *  2. Redistributions in binary form must reproduce the above copyright
15*cdf0e10cSrcweir  *     notice, this list of conditions and the following disclaimer in the
16*cdf0e10cSrcweir  *     documentation and/or other materials provided with the distribution.
17*cdf0e10cSrcweir  *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
18*cdf0e10cSrcweir  *     contributors may be used to endorse or promote products derived
19*cdf0e10cSrcweir  *     from this software without specific prior written permission.
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*cdf0e10cSrcweir  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*cdf0e10cSrcweir  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*cdf0e10cSrcweir  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25*cdf0e10cSrcweir  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*cdf0e10cSrcweir  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*cdf0e10cSrcweir  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28*cdf0e10cSrcweir  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29*cdf0e10cSrcweir  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30*cdf0e10cSrcweir  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31*cdf0e10cSrcweir  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*cdf0e10cSrcweir  *
33*cdf0e10cSrcweir  *************************************************************************/
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir // JDK API
36*cdf0e10cSrcweir import java.io.IOException;
37*cdf0e10cSrcweir import java.io.PrintWriter;
38*cdf0e10cSrcweir import java.io.File;
39*cdf0e10cSrcweir import java.io.FileInputStream;
40*cdf0e10cSrcweir import java.io.BufferedInputStream;
41*cdf0e10cSrcweir import java.util.Enumeration;
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir // Servlet API
44*cdf0e10cSrcweir import javax.servlet.ServletException;
45*cdf0e10cSrcweir import javax.servlet.http.HttpServlet;
46*cdf0e10cSrcweir import javax.servlet.http.HttpServletRequest;
47*cdf0e10cSrcweir import javax.servlet.http.HttpServletResponse;
48*cdf0e10cSrcweir import javax.servlet.ServletOutputStream;
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir // Helper API
51*cdf0e10cSrcweir import com.oreilly.servlet.MultipartRequest;
52*cdf0e10cSrcweir import com.oreilly.servlet.MultipartResponse;
53*cdf0e10cSrcweir import com.oreilly.servlet.ServletUtils;
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir // UNO API
56*cdf0e10cSrcweir import com.sun.star.bridge.XUnoUrlResolver;
57*cdf0e10cSrcweir import com.sun.star.uno.XComponentContext;
58*cdf0e10cSrcweir import com.sun.star.uno.UnoRuntime;
59*cdf0e10cSrcweir import com.sun.star.frame.XComponentLoader;
60*cdf0e10cSrcweir import com.sun.star.frame.XStorable;
61*cdf0e10cSrcweir import com.sun.star.util.XCloseable;
62*cdf0e10cSrcweir import com.sun.star.beans.PropertyValue;
63*cdf0e10cSrcweir import com.sun.star.beans.XPropertySet;
64*cdf0e10cSrcweir import com.sun.star.lang.XComponent;
65*cdf0e10cSrcweir import com.sun.star.lang.XMultiComponentFactory;
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir 
68*cdf0e10cSrcweir /** This class implements a http servlet in order to convert an incoming document
69*cdf0e10cSrcweir  * with help of a running OpenOffice.org and to push the converted file back
70*cdf0e10cSrcweir  * to the client.
71*cdf0e10cSrcweir  */
72*cdf0e10cSrcweir public class ConverterServlet extends HttpServlet {
73*cdf0e10cSrcweir     /** Specifies the temporary directory on the web server.
74*cdf0e10cSrcweir      */
75*cdf0e10cSrcweir     private String stringWorkingDirectory =
76*cdf0e10cSrcweir     System.getProperty( "java.io.tmpdir" ).replace( '\\', '/' );
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir     /** Specifies the host for the office server.
79*cdf0e10cSrcweir      */
80*cdf0e10cSrcweir     private String stringHost = "localhost";
81*cdf0e10cSrcweir 
82*cdf0e10cSrcweir     /** Specifies the port for the office server.
83*cdf0e10cSrcweir      */
84*cdf0e10cSrcweir     private String stringPort = "2083";
85*cdf0e10cSrcweir 
86*cdf0e10cSrcweir     /** Called by the server (via the service method) to allow a servlet to handle
87*cdf0e10cSrcweir      * a POST request. The file from the client will be uploaded to the web server
88*cdf0e10cSrcweir      * and converted on the web server and after all pushed to the client.
89*cdf0e10cSrcweir      * @param request Object that contains the request the client has made of the servlet.
90*cdf0e10cSrcweir      * @param response Object that contains the response the servlet sends to the client.
91*cdf0e10cSrcweir      * @throws ServletException If the request for the POST could not be handled.
92*cdf0e10cSrcweir      * @throws IOException If an input or output error is detected when the servlet handles the request.
93*cdf0e10cSrcweir      */
94*cdf0e10cSrcweir     protected void doPost( HttpServletRequest request,
95*cdf0e10cSrcweir                            HttpServletResponse response) throws ServletException, java.io.IOException {
96*cdf0e10cSrcweir         try {
97*cdf0e10cSrcweir             // If necessary, add a slash to the end of the string.
98*cdf0e10cSrcweir             if ( !stringWorkingDirectory.endsWith( "/" ) ) {
99*cdf0e10cSrcweir                 stringWorkingDirectory += "/";
100*cdf0e10cSrcweir             }
101*cdf0e10cSrcweir 
102*cdf0e10cSrcweir             // Construct a MultipartRequest to help read the information.
103*cdf0e10cSrcweir             // Pass in the request, a directory to save files to, and the
104*cdf0e10cSrcweir             // maximum POST size we should attempt to handle.
105*cdf0e10cSrcweir             MultipartRequest multipartrequest =
106*cdf0e10cSrcweir                 new MultipartRequest( request, stringWorkingDirectory, 5 * 1024 * 1024 );
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir             // Getting all file names from the request
109*cdf0e10cSrcweir             Enumeration files = multipartrequest.getFileNames();
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir             // Every received file will be converted to the specified type
112*cdf0e10cSrcweir             while (files.hasMoreElements()) {
113*cdf0e10cSrcweir                 // Getting the name from the element
114*cdf0e10cSrcweir                 String stringName = (String)files.nextElement();
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir                 // Getting the filename from the request
117*cdf0e10cSrcweir                 String stringFilename =
118*cdf0e10cSrcweir                     multipartrequest.getFilesystemName( stringName );
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir                 // Converting the given file on the server to the specified type and
121*cdf0e10cSrcweir                 // append a special extension
122*cdf0e10cSrcweir                 File cleanupFile = null;
123*cdf0e10cSrcweir                 String stringSourceFile = stringWorkingDirectory + stringFilename;
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir                 try {
126*cdf0e10cSrcweir                     String stringConvertedFile = convertDocument(stringSourceFile,
127*cdf0e10cSrcweir                         multipartrequest.getParameter( "converttype" ),
128*cdf0e10cSrcweir                         multipartrequest.getParameter( "extension" ));
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir                     String shortFileName = stringConvertedFile.substring(
131*cdf0e10cSrcweir                         stringConvertedFile.lastIndexOf('/') + 1);
132*cdf0e10cSrcweir 
133*cdf0e10cSrcweir                     // Set the response header
134*cdf0e10cSrcweir                     // Set the filename, is used when the file will be saved (problem with mozilla)
135*cdf0e10cSrcweir                     response.addHeader( "Content-Disposition",
136*cdf0e10cSrcweir                                         "attachment; filename=" + shortFileName);
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir                     // Constructing the multi part response to the client
139*cdf0e10cSrcweir                     MultipartResponse multipartresponse = new MultipartResponse(response);
140*cdf0e10cSrcweir 
141*cdf0e10cSrcweir                     // Is the convert type HTML?
142*cdf0e10cSrcweir                     if ( ( multipartrequest.getParameter( "converttype" ).equals(
143*cdf0e10cSrcweir                                "swriter: HTML (StarWriter)" ) )
144*cdf0e10cSrcweir                          || ( multipartrequest.getParameter( "converttype" ).equals(
145*cdf0e10cSrcweir                                   "scalc: HTML (StarCalc)" ) ) ) {
146*cdf0e10cSrcweir                         // Setting the content type of the response being sent to the client
147*cdf0e10cSrcweir                         // to text
148*cdf0e10cSrcweir                         multipartresponse.startResponse( "text/html" );
149*cdf0e10cSrcweir                     } else {
150*cdf0e10cSrcweir                         // Setting the content type of the response being sent to the client
151*cdf0e10cSrcweir                         // to application/octet-stream so that file will open a dialog box
152*cdf0e10cSrcweir                         // at the client in order to save the converted file
153*cdf0e10cSrcweir                         multipartresponse.startResponse( "application/octet-stream" );
154*cdf0e10cSrcweir                     }
155*cdf0e10cSrcweir 
156*cdf0e10cSrcweir                     // Pushing the converted file to the client
157*cdf0e10cSrcweir                     ServletUtils.returnFile( stringConvertedFile,
158*cdf0e10cSrcweir                                              response.getOutputStream() );
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir                     // Finishing the multi part response
161*cdf0e10cSrcweir                     multipartresponse.finish();
162*cdf0e10cSrcweir 
163*cdf0e10cSrcweir                     // clean up the working directory
164*cdf0e10cSrcweir                     cleanupFile = new File(stringConvertedFile);
165*cdf0e10cSrcweir                     if ( cleanupFile.exists() )
166*cdf0e10cSrcweir                         cleanupFile.delete();
167*cdf0e10cSrcweir 
168*cdf0e10cSrcweir                 } catch (Exception exc) {
169*cdf0e10cSrcweir                     response.setContentType( "text/html;charset=8859-1" );
170*cdf0e10cSrcweir                     PrintWriter out = response.getWriter();
171*cdf0e10cSrcweir 
172*cdf0e10cSrcweir                     exc.printStackTrace();
173*cdf0e10cSrcweir 
174*cdf0e10cSrcweir                     out.println( "<html><head>" );
175*cdf0e10cSrcweir                     out.println( " <title>" + "SDK Converter Servlet" + "</title>" );
176*cdf0e10cSrcweir                     out.println( "</head>" );
177*cdf0e10cSrcweir                     out.println( "<body><br><p>");
178*cdf0e10cSrcweir                     out.println( "<b>Sorry, the conversion failed!</b></p>");
179*cdf0e10cSrcweir                     out.println( "<p><b>Error Mesage:</b><br>" + exc.getMessage() + "<br>");
180*cdf0e10cSrcweir                     exc.printStackTrace(out);
181*cdf0e10cSrcweir                     out.println( "</p></body><html>");
182*cdf0e10cSrcweir                 }
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir                 // clean up the working directory
185*cdf0e10cSrcweir                 cleanupFile = new File(stringSourceFile);
186*cdf0e10cSrcweir                 if ( cleanupFile.exists() )
187*cdf0e10cSrcweir                     cleanupFile.delete();
188*cdf0e10cSrcweir             }
189*cdf0e10cSrcweir         }
190*cdf0e10cSrcweir         catch (Exception exception) {
191*cdf0e10cSrcweir             System.err.println( exception.toString() );
192*cdf0e10cSrcweir         }
193*cdf0e10cSrcweir     }
194*cdf0e10cSrcweir 
195*cdf0e10cSrcweir     /** This method converts a document to a given type by using a running
196*cdf0e10cSrcweir      * OpenOffice.org and saves the converted document to the specified
197*cdf0e10cSrcweir      * working directory.
198*cdf0e10cSrcweir      * @param stringDocumentName The full path name of the file on the server to be converted.
199*cdf0e10cSrcweir      * @param stringConvertType Type to convert to.
200*cdf0e10cSrcweir      * @param stringExtension This string will be appended to the file name of the converted file.
201*cdf0e10cSrcweir      * @return The full path name of the converted file will be returned.
202*cdf0e10cSrcweir      * @see stringWorkingDirectory
203*cdf0e10cSrcweir      */
204*cdf0e10cSrcweir     private String convertDocument( String stringDocumentName,
205*cdf0e10cSrcweir                                     String stringConvertType,
206*cdf0e10cSrcweir                                     String stringExtension)
207*cdf0e10cSrcweir         throws Exception
208*cdf0e10cSrcweir     {
209*cdf0e10cSrcweir         String stringConvertedFile = "";
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir         // Converting the document to the favoured type
212*cdf0e10cSrcweir //         try {
213*cdf0e10cSrcweir             // Composing the URL
214*cdf0e10cSrcweir             String stringUrl = "file:///" + stringDocumentName;
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir             /* Bootstraps a component context with the jurt base components
217*cdf0e10cSrcweir                registered. Component context to be granted to a component for running.
218*cdf0e10cSrcweir                Arbitrary values can be retrieved from the context. */
219*cdf0e10cSrcweir             XComponentContext xcomponentcontext =
220*cdf0e10cSrcweir                 com.sun.star.comp.helper.Bootstrap.createInitialComponentContext( null );
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir             /* Gets the service manager instance to be used (or null). This method has
223*cdf0e10cSrcweir                been added for convenience, because the service manager is a often used
224*cdf0e10cSrcweir                object. */
225*cdf0e10cSrcweir             XMultiComponentFactory xmulticomponentfactory =
226*cdf0e10cSrcweir                 xcomponentcontext.getServiceManager();
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir             /* Creates an instance of the component UnoUrlResolver which
229*cdf0e10cSrcweir                supports the services specified by the factory. */
230*cdf0e10cSrcweir             Object objectUrlResolver =
231*cdf0e10cSrcweir                 xmulticomponentfactory.createInstanceWithContext(
232*cdf0e10cSrcweir                     "com.sun.star.bridge.UnoUrlResolver", xcomponentcontext );
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir             // Create a new url resolver
235*cdf0e10cSrcweir             XUnoUrlResolver xurlresolver = ( XUnoUrlResolver )
236*cdf0e10cSrcweir                 UnoRuntime.queryInterface( XUnoUrlResolver.class,
237*cdf0e10cSrcweir                                            objectUrlResolver );
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir             // Resolves an object that is specified as follow:
240*cdf0e10cSrcweir             // uno:<connection description>;<protocol description>;<initial object name>
241*cdf0e10cSrcweir             Object objectInitial = xurlresolver.resolve(
242*cdf0e10cSrcweir                 "uno:socket,host=" + stringHost + ",port=" + stringPort +
243*cdf0e10cSrcweir                 ";urp;StarOffice.ServiceManager" );
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir             // Create a service manager from the initial object
246*cdf0e10cSrcweir             xmulticomponentfactory = ( XMultiComponentFactory )
247*cdf0e10cSrcweir                 UnoRuntime.queryInterface( XMultiComponentFactory.class, objectInitial );
248*cdf0e10cSrcweir 
249*cdf0e10cSrcweir             // Query for the XPropertySet interface.
250*cdf0e10cSrcweir             XPropertySet xpropertysetMultiComponentFactory = ( XPropertySet )
251*cdf0e10cSrcweir                 UnoRuntime.queryInterface( XPropertySet.class, xmulticomponentfactory );
252*cdf0e10cSrcweir 
253*cdf0e10cSrcweir             // Get the default context from the office server.
254*cdf0e10cSrcweir             Object objectDefaultContext =
255*cdf0e10cSrcweir                 xpropertysetMultiComponentFactory.getPropertyValue( "DefaultContext" );
256*cdf0e10cSrcweir 
257*cdf0e10cSrcweir             // Query for the interface XComponentContext.
258*cdf0e10cSrcweir             xcomponentcontext = ( XComponentContext ) UnoRuntime.queryInterface(
259*cdf0e10cSrcweir                 XComponentContext.class, objectDefaultContext );
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir             /* A desktop environment contains tasks with one or more
262*cdf0e10cSrcweir                frames in which components can be loaded. Desktop is the
263*cdf0e10cSrcweir                environment for components which can instanciate within
264*cdf0e10cSrcweir                frames. */
265*cdf0e10cSrcweir             XComponentLoader xcomponentloader = ( XComponentLoader )
266*cdf0e10cSrcweir                 UnoRuntime.queryInterface( XComponentLoader.class,
267*cdf0e10cSrcweir                                            xmulticomponentfactory.createInstanceWithContext(
268*cdf0e10cSrcweir                                                "com.sun.star.frame.Desktop", xcomponentcontext ) );
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir             // Preparing properties for loading the document
271*cdf0e10cSrcweir             PropertyValue propertyvalue[] = new PropertyValue[ 1 ];
272*cdf0e10cSrcweir             // Setting the flag for hidding the open document
273*cdf0e10cSrcweir             propertyvalue[ 0 ] = new PropertyValue();
274*cdf0e10cSrcweir             propertyvalue[ 0 ].Name = "Hidden";
275*cdf0e10cSrcweir             propertyvalue[ 0 ].Value = new Boolean(true);
276*cdf0e10cSrcweir 
277*cdf0e10cSrcweir             // Loading the wanted document
278*cdf0e10cSrcweir             Object objectDocumentToStore =
279*cdf0e10cSrcweir                 xcomponentloader.loadComponentFromURL(
280*cdf0e10cSrcweir                     stringUrl, "_blank", 0, propertyvalue );
281*cdf0e10cSrcweir 
282*cdf0e10cSrcweir             // Getting an object that will offer a simple way to store a document to a URL.
283*cdf0e10cSrcweir             XStorable xstorable =
284*cdf0e10cSrcweir                 ( XStorable ) UnoRuntime.queryInterface( XStorable.class,
285*cdf0e10cSrcweir                                                          objectDocumentToStore );
286*cdf0e10cSrcweir 
287*cdf0e10cSrcweir             // Preparing properties for converting the document
288*cdf0e10cSrcweir             propertyvalue = new PropertyValue[ 2 ];
289*cdf0e10cSrcweir             // Setting the flag for overwriting
290*cdf0e10cSrcweir             propertyvalue[ 0 ] = new PropertyValue();
291*cdf0e10cSrcweir             propertyvalue[ 0 ].Name = "Overwrite";
292*cdf0e10cSrcweir             propertyvalue[ 0 ].Value = new Boolean(true);
293*cdf0e10cSrcweir             // Setting the filter name
294*cdf0e10cSrcweir             propertyvalue[ 1 ] = new PropertyValue();
295*cdf0e10cSrcweir             propertyvalue[ 1 ].Name = "FilterName";
296*cdf0e10cSrcweir             propertyvalue[ 1 ].Value = stringConvertType;
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir             // Appending the favoured extension to the origin document name
299*cdf0e10cSrcweir             int index = stringUrl.lastIndexOf('.');
300*cdf0e10cSrcweir             if ( index >= 0 ) {
301*cdf0e10cSrcweir                 stringConvertedFile = stringUrl.substring(0, index) + "." + stringExtension;
302*cdf0e10cSrcweir             } else {
303*cdf0e10cSrcweir                 stringConvertedFile = stringUrl + "." + stringExtension;
304*cdf0e10cSrcweir             }
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir             // Storing and converting the document
307*cdf0e10cSrcweir             xstorable.storeAsURL( stringConvertedFile, propertyvalue );
308*cdf0e10cSrcweir 
309*cdf0e10cSrcweir             XCloseable xcloseable = (XCloseable)UnoRuntime.queryInterface( XCloseable.class,xstorable );
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir             // Closing the converted document
312*cdf0e10cSrcweir             if ( xcloseable != null )
313*cdf0e10cSrcweir                 xcloseable.close(false);
314*cdf0e10cSrcweir             else {
315*cdf0e10cSrcweir                 // If Xcloseable is not supported (older versions,
316*cdf0e10cSrcweir                 // use dispose() for closing the document
317*cdf0e10cSrcweir                 XComponent xComponent = ( XComponent ) UnoRuntime.queryInterface(
318*cdf0e10cSrcweir                     XComponent.class, xstorable );
319*cdf0e10cSrcweir                 xComponent.dispose();
320*cdf0e10cSrcweir             }
321*cdf0e10cSrcweir 
322*cdf0e10cSrcweir //         }
323*cdf0e10cSrcweir //         catch( Exception exception ) {
324*cdf0e10cSrcweir //             exception.printStackTrace();
325*cdf0e10cSrcweir //             return( "" );
326*cdf0e10cSrcweir //         }
327*cdf0e10cSrcweir 
328*cdf0e10cSrcweir         if ( stringConvertedFile.startsWith( "file:///" ) ) {
329*cdf0e10cSrcweir             // Truncating the beginning of the file name
330*cdf0e10cSrcweir             stringConvertedFile = stringConvertedFile.substring( 8 );
331*cdf0e10cSrcweir         }
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir         // Returning the name of the converted file
334*cdf0e10cSrcweir         return stringConvertedFile;
335*cdf0e10cSrcweir     }
336*cdf0e10cSrcweir }
337