aboutsummaryrefslogtreecommitdiffstats
path: root/infrastructure/com.etherpad.openofficeservice
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure/com.etherpad.openofficeservice')
-rw-r--r--infrastructure/com.etherpad.openofficeservice/importexport.scala287
1 files changed, 287 insertions, 0 deletions
diff --git a/infrastructure/com.etherpad.openofficeservice/importexport.scala b/infrastructure/com.etherpad.openofficeservice/importexport.scala
new file mode 100644
index 0000000..606cff9
--- /dev/null
+++ b/infrastructure/com.etherpad.openofficeservice/importexport.scala
@@ -0,0 +1,287 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.etherpad.openofficeservice;
+
+import net.appjet.common.sars.{SarsServer,SarsMessageHandler};
+
+import java.io.{DataInputStream,DataOutputStream};
+import java.io.{File,FileOutputStream,ByteArrayInputStream,ByteArrayOutputStream};
+
+/* Libraries needed for OO.org Conversion */
+import com.sun.star.bridge.{XBridge,XBridgeFactory};
+import com.sun.star.beans.{PropertyValue,XPropertySet};
+import com.sun.star.connection.{NoConnectException,XConnection,XConnector};
+import com.sun.star.container.XNamed;
+import com.sun.star.document.{XExporter,XFilter};
+import com.sun.star.frame.{XComponentLoader,XStorable};
+import com.sun.star.lang.{XComponent,XMultiComponentFactory};
+import com.sun.star.uno.{UnoRuntime,XComponentContext};
+
+class OOSException(m: String) extends RuntimeException(m);
+class UnsupportedFormatException(format: String) extends OOSException("Unsupported format: "+format);
+object TemporaryFailure extends OOSException("Temporary failure");
+
+object OpenOfficeServerUtility {
+ def checkServerAvailability(host: String, port: Int): Boolean = {
+ // Assume the server is running; this is the responsibility of the user
+ return true;
+ }
+ def runOpenOfficeServer(path: String, host: String, port: Int, timeout: Int, wait: Boolean) {
+ // nothing
+ }
+}
+
+class OpenOfficeFileConverter {
+ var host: String = "localhost";
+ var port: Int = 8100;
+
+ def setOpenOfficeServerDetails(host: String, port: Int) {
+ this.host = host;
+ this.port = port;
+ }
+
+ def convertFile(src: File, dst: File, converter: String, extension: String): Boolean = {
+ try {
+ val fromFile: String = "file:///" + src.getAbsolutePath();
+ val toFile: String = "file:///" + dst.getAbsolutePath();
+
+ val cnx: String = "socket,host="+this.host+",port="+this.port+"";
+ val xRemoteContext: XComponentContext = com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
+ val x: Object = xRemoteContext.getServiceManager().createInstanceWithContext("com.sun.star.connection.Connector", xRemoteContext);
+ val xConnector: XConnector = UnoRuntime.queryInterface(classOf[XConnector], x).asInstanceOf[XConnector];
+ val connection: XConnection = xConnector.connect(cnx);
+
+ if(connection == null) {
+ throw new OOSException("Connection failure");
+ }
+ val x2: Object = xRemoteContext.getServiceManager().createInstanceWithContext("com.sun.star.bridge.BridgeFactory", xRemoteContext);
+ val xBridgeFactory: XBridgeFactory = UnoRuntime.queryInterface(classOf[XBridgeFactory], x2).asInstanceOf[XBridgeFactory];
+ val xBridge: XBridge = xBridgeFactory.createBridge("", "urp", connection, null);
+ val x3: Object = xBridge.getInstance("StarOffice.ServiceManager");
+ if (x3 == null) {
+ throw new OOSException("Failed to get bridge");
+ }
+
+ val xMultiComponentFactory: XMultiComponentFactory = UnoRuntime.queryInterface(classOf[XMultiComponentFactory], x3).asInstanceOf[XMultiComponentFactory];
+ val xProperySet: XPropertySet = UnoRuntime.queryInterface(classOf[XPropertySet], xMultiComponentFactory).asInstanceOf[XPropertySet];
+ val oDefaultContext: Object = xProperySet.getPropertyValue("DefaultContext");
+ val xComponentContext: XComponentContext = UnoRuntime.queryInterface(classOf[XComponentContext], oDefaultContext).asInstanceOf[XComponentContext];
+
+ val desktopObj: Object = xMultiComponentFactory.createInstanceWithContext("com.sun.star.frame.Desktop", xComponentContext);
+ val xcomponentloader: XComponentLoader = UnoRuntime.queryInterface(classOf[XComponentLoader], desktopObj).asInstanceOf[XComponentLoader];
+
+ if(xcomponentloader == null) {
+ throw new OOSException("XComponent Loader could not be loaded");
+ }
+
+ val loadProps: Array[PropertyValue] = new Array[PropertyValue](2);
+ loadProps(0) = new PropertyValue();
+ loadProps(0).Name = "Hidden";
+ loadProps(0).Value = boolean2Boolean(false);
+
+ loadProps(1) = new PropertyValue();
+ loadProps(1).Name = "UpdateDocMode";
+ loadProps(1).Value = "1";
+
+ val component: XComponent = xcomponentloader.loadComponentFromURL(fromFile,"_blank", 0, loadProps);
+
+ if (component == null) {
+ throw new OOSException("Failed to load document");
+ }
+
+ val convProps: Array[PropertyValue] = new Array[PropertyValue](2);
+ convProps(0) = new PropertyValue();
+ convProps(0).Name = "FilterName";
+ convProps(0).Value = converter;
+
+ val xstorable: XStorable = UnoRuntime.queryInterface(classOf[XStorable],component).asInstanceOf[XStorable];
+ if (xstorable == null) {
+ throw new OOSException("Storable could not be loaded");
+ }
+ xstorable.storeToURL(toFile, convProps);
+ component.dispose();
+ return true;
+ }
+ catch {
+ case e => {
+ e.printStackTrace();
+ throw new OOSException("Unknown exception occurred: "+e.getMessage());
+ }
+ }
+ }
+}
+
+object OpenOfficeService {
+ val formats = Map(
+ "pdf" -> "writer_pdf_Export",
+ "doc" -> "MS Word 97",
+ "html" -> "HTML (StarWriter)",
+ "odt" -> "writer8",
+ //"html" -> "XHTML Writer File",
+ "txt" -> "Text"
+ );
+
+ def createTempFile(bytes: Array[byte], suffix: String) = {
+ var f = File.createTempFile("ooconvert-", if (suffix == null) { null } else if (suffix == "") { "" } else { "."+suffix });
+ if (bytes != null) {
+ val fos = new FileOutputStream(f);
+ fos.write(bytes);
+ }
+ f;
+ }
+
+ var soffice = "soffice";
+ def setExecutable(exec: String) {
+ soffice = exec;
+ }
+
+ var openOfficeServerHost: String = "localhost";
+ var openOfficeServerPort: Int = 8100;
+
+ def setOpenOfficeServer(host: String, port: Int) {
+ openOfficeServerHost = host;
+ openOfficeServerPort = port;
+ }
+
+ def convertFile(from: String, to: String, bytes: Array[byte]): Array[byte] = {
+ if (from == to) {
+ return bytes;
+ }
+
+ val tempFile = createTempFile(bytes, from);
+ val outFile = createTempFile(null, to);
+
+ /*
+ Just hardcoding server and port here.
+ If you intend to use an Openoffice.org instance on a network machine,
+ do it at your risk.
+
+ Just, remember to setOpenOfficeServer from etherpad/importexport/importexport.js,
+ Also, remember that OO.org is reading and writing files over file:/// URI. So, make sure that
+ you can access the files from network machine. Hint, NFS. Not Need for Speed game, you idiot,
+ Network File System.
+
+ */
+
+ if (! OpenOfficeServerUtility.checkServerAvailability(openOfficeServerHost, openOfficeServerPort)) {
+ try {
+ OpenOfficeServerUtility.runOpenOfficeServer(soffice, openOfficeServerHost, openOfficeServerPort, 20000, true);
+ } catch {
+ case e: java.io.IOException => {
+ e.printStackTrace();
+ throw TemporaryFailure;
+ }
+ }
+ }
+ var converter = new OpenOfficeFileConverter();
+ converter.setOpenOfficeServerDetails(openOfficeServerHost, openOfficeServerPort);
+ var status = false;
+ try {
+ status = converter.convertFile(tempFile, outFile, formats(to), to);
+ } catch {
+ case e => {
+ e.printStackTrace();
+ throw new OOSException("Unknown exception occurred: "+e.getMessage());
+ }
+ }
+ if (status == false) {
+ throw new UnsupportedFormatException(from);
+ }
+ net.appjet.common.util.BetterFile.getFileBytes(outFile);
+ }
+
+ def main(args: Array[String]) {
+ if (args.length > 0) {
+ soffice = args(0);
+ if (soffice.length == 0) {
+ exit(1);
+ }
+ }
+
+ // Query format:
+ // from: String, to: String, count: Int, bytes: Array[byte]
+ // Response format:
+ // status: Int, <data>
+ // status 0 (success) - <data>: count: Int, bytes: Array[byte]
+ // status 1 (temporary failure) - <data>: <none>
+ // status 2 (permanent failure) - <data>: type: Int
+ // type - 0: unknown failure.
+ // - 1: unsupported format
+ val handler = new SarsMessageHandler {
+ override def handle(b: Array[byte]): Option[Array[byte]] = {
+ val is = new DataInputStream(new ByteArrayInputStream(b));
+ val from = is.readUTF;
+ val to = is.readUTF;
+ val len = is.readInt;
+ val bytes = new Array[byte](len);
+ is.readFully(bytes);
+ var status = 0;
+ var permfailuretype = 0;
+
+ println("Converting "+from+" -> "+to+" ("+len+" bytes)");
+
+ val output = try {
+ convertFile(from, to, bytes);
+ } catch {
+ case TemporaryFailure => {
+ status = 1;
+ null;
+ }
+ case e: UnsupportedFormatException => {
+ status = 2;
+ permfailuretype = 1;
+ null;
+ }
+ case e => {
+ status = 2;
+ permfailuretype = 0;
+ e.printStackTrace();
+ null;
+ }
+ }
+
+ val retBytes = new ByteArrayOutputStream();
+ val ret = new DataOutputStream(retBytes);
+ if (status != 0) {
+ ret.writeInt(status); // error
+ status match {
+ case 2 => {
+ ret.writeInt(permfailuretype);
+ }
+ case _ => { }
+ }
+ } else {
+ ret.writeInt(0); // success
+ ret.writeInt(output.length);
+ ret.write(output, 0, output.length);
+ }
+ Some(retBytes.toByteArray());
+ }
+ }
+
+ val server = new SarsServer("ooffice-password", handler, None, 8101);
+ server.start();
+ println("Server running...");
+ server.join();
+ println("Server quitting...");
+ }
+}
+
+
+
+
+