001    /* ************************************************************************
002     *
003     *  The Contents of this file are made available subject to the terms of
004     *  the BSD license.
005     *  
006     *  Copyright (c) 2003 by Sun Microsystems, Inc.
007     *  Modifications Copyright (c) 2005 by Marko Karppinen & Co. LLC
008     *  All rights reserved.
009     *
010     *  Redistribution and use in source and binary forms, with or without
011     *  modification, are permitted provided that the following conditions
012     *  are met:
013     *  1. Redistributions of source code must retain the above copyright
014     *     notice, this list of conditions and the following disclaimer.
015     *  2. Redistributions in binary form must reproduce the above copyright
016     *     notice, this list of conditions and the following disclaimer in the
017     *     documentation and/or other materials provided with the distribution.
018     *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
019     *     contributors may be used to endorse or promote products derived
020     *     from this software without specific prior written permission.
021     *
022     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
023     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
024     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
025     *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
026     *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
027     *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
028     *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
029     *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
030     *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
031     *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
032     *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033     *     
034     *************************************************************************/
035    
036    /*
037     * This file is derived by hsivonen from a file that came with the 
038     * following note (dollar signs stripped):
039     *
040     *  RCSfile: ConverterServlet.java,v 
041     *
042     *  Revision: 1.6 
043     *
044     *  last change: Author: hr  Date: 2003/06/30 15:53:49 
045     */
046    
047    package fi.karppinen.ooo;
048    
049    import java.io.File;
050    
051    import org.apache.log4j.Logger;
052    
053    import com.sun.star.beans.PropertyValue;
054    import com.sun.star.beans.XPropertySet;
055    import com.sun.star.bridge.XUnoUrlResolver;
056    import com.sun.star.comp.helper.Bootstrap;
057    import com.sun.star.document.XDocumentInfo;
058    import com.sun.star.document.XDocumentInfoSupplier;
059    import com.sun.star.document.XDocumentInsertable;
060    import com.sun.star.frame.XComponentLoader;
061    import com.sun.star.frame.XStorable;
062    import com.sun.star.lang.Locale;
063    import com.sun.star.lang.XComponent;
064    import com.sun.star.lang.XMultiComponentFactory;
065    import com.sun.star.lang.XMultiServiceFactory;
066    import com.sun.star.text.XText;
067    import com.sun.star.text.XTextCursor;
068    import com.sun.star.text.XTextDocument;
069    import com.sun.star.uno.UnoRuntime;
070    import com.sun.star.uno.XComponentContext;
071    
072    /**
073     * Converts an HTML file into PDF, OOo Writer, MS Word or RTF formats by inserting 
074     * it into an OOo Writer template.
075     * 
076     * @version $Id: Converter.java,v 1.1 2006/10/30 20:00:08 hsivonen Exp $
077     * @author hr
078     * @author hsivonen
079     */
080    public class Converter {
081        private static final Logger log4j = Logger.getLogger(Converter.class);
082        
083        /**
084         * Specifies the host for the office server.
085         */
086        private String stringHost = "localhost";
087    
088        /**
089         * Specifies the port for the office server.
090         */
091        private String stringPort = "8100";
092    
093        public static void main(String[] args) throws Exception {
094            try {
095                new Converter().convertTextWithInsert(new File(args[0]), new File(args[1]), new File(args[2])); 
096            } finally {
097                System.exit(0);
098            }
099        }
100    
101        /**
102         * Performs the conversion. The target format is sniffed from the target file name.
103         * 
104         * @param template The template
105         * @param htmlDoc The document to convert
106         * @param target The destination file
107         * @throws Exception
108         */
109        public synchronized void convertTextWithInsert(File template, File htmlDoc, File target) throws Exception {
110    
111            String templateUrl = template.toURL().toString();
112    
113            String htmlUrl = htmlDoc.toURL().toString();
114    
115            String stringConvertedFile = target.toURL().toString();
116    
117            String targetName = target.getName();
118            
119            int index = targetName.lastIndexOf('.');
120            
121            if(index < 0) {
122                throw new IllegalArgumentException("No filename extension");
123            }
124            
125            String extension = targetName.substring(index + 1);
126            
127            String stringConvertType = null;
128            
129            if("sxw".equals(extension)) {
130                stringConvertType = "StarOffice XML (Writer)";
131            } else if("doc".equals(extension)) {
132                stringConvertType = "MS Word 97";
133            } else if("rtf".equals(extension)) {
134                stringConvertType = "Rich Text Format";
135            } else if("pdf".equals(extension)) {
136                stringConvertType = "writer_pdf_Export";
137            } else {
138                throw new IllegalArgumentException("Unsupported filename extension: " + extension);
139            }
140    
141            /*
142             * Bootstraps a component context with the jurt base components
143             * registered. Component context to be granted to a component for
144             * running. Arbitrary values can be retrieved from the context.
145             */
146            XComponentContext xcomponentcontext = Bootstrap.createInitialComponentContext(null);
147    
148            /*
149             * Gets the service manager instance to be used (or null). This
150             * method has been added for convenience, because the service
151             * manager is a often used object.
152             */
153            XMultiComponentFactory xmulticomponentfactory = xcomponentcontext.getServiceManager();
154    
155            /*
156             * Creates an instance of the component UnoUrlResolver which
157             * supports the services specified by the factory.
158             */
159            Object objectUrlResolver = xmulticomponentfactory.createInstanceWithContext(
160                    "com.sun.star.bridge.UnoUrlResolver", xcomponentcontext);
161    
162            // Create a new url resolver
163            XUnoUrlResolver xurlresolver = (XUnoUrlResolver) UnoRuntime.queryInterface(
164                    XUnoUrlResolver.class, objectUrlResolver);
165    
166            // Resolves an object that is specified as follow:
167            // uno:<connection description>;<protocol description>;<initial
168            // object name>
169            Object objectInitial = xurlresolver.resolve("uno:socket,host="
170                    + stringHost + ",port=" + stringPort
171                    + ";urp;StarOffice.ServiceManager");
172    
173            // Create a service manager from the initial object
174            xmulticomponentfactory = (XMultiComponentFactory) UnoRuntime.queryInterface(
175                    XMultiComponentFactory.class, objectInitial);
176    
177            // Query for the XPropertySet interface.
178            XPropertySet xpropertysetMultiComponentFactory = (XPropertySet) UnoRuntime.queryInterface(
179                    XPropertySet.class, xmulticomponentfactory);
180    
181            // Get the default context from the office server.
182            Object objectDefaultContext = xpropertysetMultiComponentFactory.getPropertyValue("DefaultContext");
183    
184            // Query for the interface XComponentContext.
185            xcomponentcontext = (XComponentContext) UnoRuntime.queryInterface(
186                    XComponentContext.class, objectDefaultContext);
187    
188            /*
189             * A desktop environment contains tasks with one or more frames in
190             * which components can be loaded. Desktop is the environment for
191             * components which can instanciate within frames.
192             */
193            XComponentLoader xcomponentloader = (XComponentLoader) UnoRuntime.queryInterface(
194                    XComponentLoader.class,
195                    xmulticomponentfactory.createInstanceWithContext(
196                            "com.sun.star.frame.Desktop", xcomponentcontext));
197    
198            // Preparing properties for loading the document
199            PropertyValue[] propertyvalue = new PropertyValue[2];
200            // Setting the flag for hidding the open document
201            propertyvalue[0] = new PropertyValue();
202            propertyvalue[0].Name = "Hidden";
203            propertyvalue[0].Value = new Boolean(true);
204            // will open as a Writer doc not as a Writer/Web doc
205            propertyvalue[1] = new PropertyValue();
206            propertyvalue[1].Name = "FilterName";
207            propertyvalue[1].Value = "HTML (StarWriter)";
208    
209            // open the HTML doc for getting the title
210            
211            Object oHtmlDoc = xcomponentloader.loadComponentFromURL(
212                    htmlUrl, "_blank", 0, propertyvalue);
213    
214            // extract title
215            XDocumentInfoSupplier xDocumentInfoSupplier = (XDocumentInfoSupplier) UnoRuntime.queryInterface(
216                    XDocumentInfoSupplier.class, oHtmlDoc);
217    
218            XDocumentInfo xDocumentInfo = xDocumentInfoSupplier.getDocumentInfo();
219            
220            XPropertySet xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
221                    XPropertySet.class, xDocumentInfo);
222            
223            Object title = xPropertySet.getPropertyValue("Title");
224    
225            // extract language
226            // Note! The body element has to declare the language. 
227            // Declaring it on the root element is NOT enough!
228      
229            XMultiServiceFactory xMultiServiceFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(
230                    XMultiServiceFactory.class, oHtmlDoc);
231        
232            Object oCharStyle = xMultiServiceFactory.createInstance("com.sun.star.style.CharacterStyle");
233    
234            xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
235                    XPropertySet.class, oCharStyle);        
236            
237            Locale langWestern = (Locale) xPropertySet.getPropertyValue("CharLocale");
238            
239            Locale langCjk = (Locale) xPropertySet.getPropertyValue("CharLocaleAsian");
240    
241            Locale langCtl = (Locale) xPropertySet.getPropertyValue("CharLocaleComplex");
242            
243            if(log4j.isDebugEnabled()) {
244                log4j.debug("langWestern: " + langWestern.Language + "-" + langWestern.Country + "-" + langWestern.Variant);
245                log4j.debug("langCjk: " + langCjk.Language + "-" + langCjk.Country + "-" + langCjk.Variant);
246                log4j.debug("langCtl: " + langCtl.Language + "-" + langCtl.Country + "-" + langCtl.Variant);
247            }
248            
249            // Getting the method dispose() for closing the document
250            XComponent xComponent = (XComponent) UnoRuntime.queryInterface(
251                    XComponent.class, oHtmlDoc);
252    
253            xComponent.dispose();
254            
255            
256            // Loading the template
257            propertyvalue[0] = new PropertyValue();
258            propertyvalue[0].Name = "Hidden";
259            propertyvalue[0].Value = new Boolean(true);
260    
261            Object objectDocumentToStore = xcomponentloader.loadComponentFromURL(
262                    templateUrl, "_blank", 0, propertyvalue);
263    
264            // set root language
265    //        xMultiServiceFactory = (XMultiServiceFactory) UnoRuntime.queryInterface(
266    //                XMultiServiceFactory.class, objectDocumentToStore);
267    //    
268    //        oCharStyle = xMultiServiceFactory.createInstance("com.sun.star.style.CharacterStyle");
269    //
270    //        xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
271    //                XPropertySet.class, oCharStyle);        
272            
273            xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
274                    XPropertySet.class, objectDocumentToStore);        
275            
276            Locale metaLang = null;
277            Locale noneLang = new Locale("", "", "");
278            
279            if (!"".equals(langCtl.Language)) {
280                log4j.debug("Using CTL lang.");
281                xPropertySet.setPropertyValue("CharLocale", noneLang);
282    //            xPropertySet.setPropertyValue("CharLocale", noneLang);
283    //            xPropertySet.setPropertyValue("CharLocaleAsian", noneLang);
284    //            xPropertySet.setPropertyValue("CharLocaleComplex", langCtl);
285                metaLang = langCtl;
286            } else if (!"".equals(langCjk.Language)) {
287                log4j.debug("Using CJK lang.");
288                xPropertySet.setPropertyValue("CharLocale", noneLang);
289    //            xPropertySet.setPropertyValue("CharLocale", noneLang);
290    //            xPropertySet.setPropertyValue("CharLocaleAsian", langCjk);
291    //            xPropertySet.setPropertyValue("CharLocaleComplex", noneLang);
292                metaLang = langCjk;
293            } else {
294                log4j.debug("Using Western lang.");
295                xPropertySet.setPropertyValue("CharLocale", langWestern);
296    //            xPropertySet.setPropertyValue("CharLocaleAsian", noneLang);
297    //            xPropertySet.setPropertyValue("CharLocaleComplex", noneLang);
298                metaLang = langWestern;
299            }
300            
301            // set the title
302            xDocumentInfoSupplier = (XDocumentInfoSupplier) UnoRuntime.queryInterface(
303                    XDocumentInfoSupplier.class, objectDocumentToStore);
304            
305            xDocumentInfo = xDocumentInfoSupplier.getDocumentInfo();
306            
307            xPropertySet = (XPropertySet) UnoRuntime.queryInterface(
308                    XPropertySet.class, xDocumentInfo);
309            
310            xPropertySet.setPropertyValue("Title", title);
311            
312            // set meta lang
313            xPropertySet.setPropertyValue("Language", metaLang);
314            
315            // prepare for insertion
316            XTextDocument xTextDocument = (XTextDocument) UnoRuntime.queryInterface(
317                    XTextDocument.class, objectDocumentToStore);
318    
319            XText xText = xTextDocument.getText();
320            XTextCursor xTextCursor = xText.createTextCursor();
321            xTextCursor.gotoEnd(false);
322    
323            XDocumentInsertable xDocumentInsertable = (XDocumentInsertable) UnoRuntime.queryInterface(
324                    XDocumentInsertable.class, xTextCursor);
325    
326            // insert the HTML doc into the template
327            xDocumentInsertable.insertDocumentFromURL(htmlUrl, new PropertyValue[0]);
328    
329            // XXX should get rid of the empty paragraph left at the end of the document.
330    
331            // Getting an object that will offer a simple way to store a
332            // document to a URL.
333            XStorable xstorable = (XStorable) UnoRuntime.queryInterface(
334                    XStorable.class, objectDocumentToStore);
335    
336            // Preparing properties for converting the document
337            propertyvalue = new PropertyValue[2];
338            // Setting the flag for overwriting
339            propertyvalue[0] = new PropertyValue();
340            propertyvalue[0].Name = "Overwrite";
341            propertyvalue[0].Value = new Boolean(true);
342            // Setting the filter name
343            propertyvalue[1] = new PropertyValue();
344            propertyvalue[1].Name = "FilterName";
345            propertyvalue[1].Value = stringConvertType;
346    
347            // Storing and converting the document
348            xstorable.storeToURL(stringConvertedFile, propertyvalue);
349    
350            // Getting the method dispose() for closing the document
351            xComponent = (XComponent) UnoRuntime.queryInterface(
352                    XComponent.class, xstorable);
353    
354            // Closing the converted document
355            xComponent.dispose();
356        }
357    }