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