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