RuntimeException: cannot create native pipe

Help with installation and general system troubleshooting questions concerning the office suite LibreOffice.
Post Reply
arunkumar7h
Posts: 3
Joined: Mon Feb 11, 2019 11:13 am

RuntimeException: cannot create native pipe

Post by arunkumar7h »

Hi All,

I'm using LibreOffice 5.2 and I'm facing a strange error :

Here's my code :

Code: Select all

import com.sun.star.beans.PropertyValue;
import com.sun.star.bridge.UnoUrlResolver;
import com.sun.star.bridge.XUnoUrlResolver;
import com.sun.star.comp.helper.Bootstrap;
import com.sun.star.comp.helper.BootstrapException;
import com.sun.star.connection.NoConnectException;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.CloseVetoException;
import com.sun.star.util.XCloseable;
import org.slf4j.Logger;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.*;
import static com.sun.star.comp.helper.Bootstrap.createInitialComponentContext;
import static com.sun.star.lib.util.NativeLibraryLoader.getResource;
import static com.sun.star.uno.UnoRuntime.queryInterface;
import static java.lang.String.format;
import static java.util.Arrays.stream;
import static java.util.regex.Pattern.compile;
import static java.util.stream.Collectors.joining;
import static org.slf4j.LoggerFactory.getLogger;

class OpenOfficeConnectionUnoImpl implements OpenOfficeConnection {

    private static final Logger LOGGER = getLogger(OpenOfficeConnectionUnoImpl.class);

    private static final String OFFICE_FILE_NAME = "soffice";
    private static final String PIPE_NAME_MASK = NCProperties.getInstance().getProperty("pipe.name.mask", "uno_%s");
    private static final String TMP_FOLDER_MASK = NCProperties.getInstance().getProperty("temp.folder.mask", "/tmp/openoffice_uno_%s");
    private static final Pattern ID_PATTERN = compile("^[a-zA-Z0-9_-]+$");
    private static final int CONNECTION_INTERVAL = 200;

    private final String id;
    private final long connectionTimeout;

    private XComponentContext context;
    private XDesktop desktop;

    OpenOfficeConnectionUnoImpl(String id, long connectionTimeout) {
        checkNotNull(id, "OpenOffice connection id is null");
        checkArgument(ID_PATTERN.matcher(id).find(), "OpenOffice connection id is not valid");
        checkArgument(connectionTimeout > CONNECTION_INTERVAL,
                "OpenOffice connection timeout must be more than " + CONNECTION_INTERVAL);

        this.id = id;
        this.connectionTimeout = connectionTimeout;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void startConnection() throws Exception {
        if (isAvailable()) return;
        startOfficeInTerminal(id);
        context = getXContext(id, connectionTimeout);
        desktop = getXDesktop(context);
    }

    @Override
    public boolean isStarted() {
        return context != null && desktop != null;
    }

    @Override
    public boolean isAvailable() {
        if (!isStarted()) {
            return false;
        }

        try {
            return context.getServiceManager() != null;
        } catch (Exception e) {
            LOGGER.debug(format("OpenOffice connection '%s' is broken", id), e);
            return false;
        }
    }

    @Override
    public void convertFile(String inputFilePath, String outputFilePath) throws Exception {
        checkState(isAvailable(), "OpenOffice connection is not available");
        XComponent document = getXDocument(desktop, inputFilePath);
        performConvertFile(document, outputFilePath);
    }

    @Override
    public void closeConnection() {
        if (!isAvailable()) {
            killOfficeInTerminal(id);
            return;
        }

        try {
            desktop.terminate();
        } catch (Exception ignore) {
            LOGGER.trace("Close OpenOffice desktop error", ignore);
        }
        closeUnoObject(context);

        killOfficeInTerminal(id);
    }

    /**
     * Create OpenOffice process in terminal with named pipe
     */
    private void startOfficeInTerminal(String id) {
        File fOffice = getResource(Bootstrap.class.getClassLoader(), OFFICE_FILE_NAME);

        String defaultSofficeParams = "--headless --nologo --nodefault --norestore --nocrashreport --nolockcheck";
        String sofficeParams = NCProperties.getInstance().getProperty("soffice.common.params", defaultSofficeParams);
        List<String> sOfficeArgs = Arrays.asList(sofficeParams.trim().split(" "));

        String defaultUnshareParams = "sudo unshare -n";
        String unshareParams = NCProperties.getInstance().getProperty("unshare.common.params", defaultUnshareParams);
        List<String> unshareArgs = Arrays.asList(unshareParams.trim().split(" "));

        List<String> cmdArrayList = new ArrayList<>();
        cmdArrayList.addAll(unshareArgs);
        cmdArrayList.add(fOffice.getPath());
        cmdArrayList.addAll(sOfficeArgs);
        cmdArrayList.add("--accept=pipe,name=" + format(PIPE_NAME_MASK, id) + ";urp");
        cmdArrayList.add("-env:UserInstallation=file://" + format(TMP_FOLDER_MASK, id) + "/");

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Start OpenOffice process: '{}'", cmdArrayList.stream().collect(joining(" ")));
        }

        ProcessBuilder processBuilder = new ProcessBuilder(cmdArrayList.toArray(new String[0]));
        processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
        processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        try {
            processBuilder.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private XComponentContext getXContext(String id, long connectionTimeout) throws Exception {
        XComponentContext xLocalContext = createInitialComponentContext(null);
        XUnoUrlResolver xUrlResolver = UnoUrlResolver.create(xLocalContext);
        String connectStr = "uno:pipe,name=" + format(PIPE_NAME_MASK, id) + ";urp;StarOffice.ComponentContext";
        LOGGER.debug("Connect to OpenOffice process: '{}'", id);
        LOGGER.debug("Connect String : '{}'", connectStr);
        return getXComponentContext(xUrlResolver, connectStr, connectionTimeout);
    }

    private XComponentContext getXComponentContext(XUnoUrlResolver urlResolver, String connectStr, long timeout)
            throws Exception {
        long intervalCount = timeout / CONNECTION_INTERVAL;
        for (int i = 0; ; ++i) {
            LOGGER.trace(" i Count ------------------- : '{}'", i);
            LOGGER.trace(" Interval Count ------------------- : '{}'", intervalCount);
            try {
                Object context = urlResolver.resolve(connectStr);
                XComponentContext xContext = queryInterface(XComponentContext.class, context);
                if (xContext == null) {
                    throw new BootstrapException("No OpenOffice component context");
                } else {
                    return xContext;
                }
            } catch (NoConnectException e) {
                // wait CONNECTION_INTERVAL ms, then try to connect again
                // but do not wait longer then intervalCount times.
                if (i == intervalCount) {
                    throw e;
                }
                Thread.sleep(CONNECTION_INTERVAL);
            }
        }
    }

    private XDesktop getXDesktop(XComponentContext context) throws Exception {
        XMultiComponentFactory componentFactory = context.getServiceManager();
        Object desktopService = componentFactory.createInstanceWithContext("com.sun.star.frame.Desktop", context);
        return queryInterface(XDesktop.class, desktopService);
    }

    private XComponent getXDocument(XDesktop xDesktop, String path) throws Exception {
        XComponentLoader xComponentLoader = queryInterface(XComponentLoader.class, xDesktop);
        return xComponentLoader.loadComponentFromURL("file:///" + pathToUri(path), "_blank", 0, new PropertyValue[0]);
    }

    private void performConvertFile(XComponent document, String path) throws Exception {
        XStorable xStorable = queryInterface(XStorable.class, document);

        PropertyValue[] conversionProperties = new PropertyValue[1];
        conversionProperties[0] = new PropertyValue();
        conversionProperties[0].Name = "FilterName";
        conversionProperties[0].Value = "writer_pdf_Export";

        xStorable.storeToURL("file:///" + pathToUri(path), conversionProperties);

        closeUnoObject(xStorable);
    }

    private String pathToUri(String path) {
        return path.replace("\\", "/").replace("//", "/");
    }

    /**
     * find and kill in terminal OpenOffice process with appropriate pipe name
     */
    private void killOfficeInTerminal(String id) {
        String[] killCmd = {
                "/bin/sh", "-c",
                "ps -ef | grep -E " +
                        "'" + OFFICE_FILE_NAME + "(.+)--accept=pipe,name=" + format(PIPE_NAME_MASK, id) + ";urp' " +
                        "| awk {'print $2'} | xargs kill -9"
        };

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Kill OpenOffice process: '{}'", stream(killCmd).collect(joining(" ")));
        }

        try {
            Runtime.getRuntime().exec(killCmd);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void closeUnoObject(Object obj) {
        try {
            XCloseable xCloseable = queryInterface(XCloseable.class, obj);
            if (xCloseable != null) {
                try {
                    xCloseable.close(false);
                } catch (CloseVetoException e) {
                    throw new RuntimeException(e);
                }
            } else {
                XComponent xComp = queryInterface(XComponent.class, obj);
                if (xComp != null) {
                    xComp.dispose();
                }
            }
        } catch (Exception ignore) {
            LOGGER.trace("Close UNO object error", ignore);
        }
    }

    @Override
    public String toString() {
        return "OpenOfficeConnectionUnoImpl{" +
                "id='" + id + '\'' +
                '}';
    }
}

Exception :

Caused by: com.sun.star.connection.NoConnectException: java.io.IOException
at com.sun.star.lib.connections.pipe.pipeConnector.connect(pipeConnector.java:113)
at com.sun.star.comp.connections.Connector.connect(Connector.java:118)
at com.sun.star.comp.urlresolver.UrlResolver$_UrlResolver.resolve(UrlResolver.java:106)
at com.netcracker.solutions.gtdc.sfa.dg.converters.OpenOfficeConnectionUnoImpl.getXComponentContext(OpenOfficeConnectionUnoImpl.java:167)
at com.netcracker.solutions.gtdc.sfa.dg.converters.OpenOfficeConnectionUnoImpl.getXContext(OpenOfficeConnectionUnoImpl.java:159)
at com.netcracker.solutions.gtdc.sfa.dg.converters.OpenOfficeConnectionUnoImpl.startConnection(OpenOfficeConnectionUnoImpl.java:72)
at com.netcracker.solutions.gtdc.sfa.dg.converters.OpenOfficeConnectionFactory.makeObject(OpenOfficeConnectionFactory.java:49)
at com.netcracker.solutions.gtdc.sfa.dg.converters.OpenOfficeConnectionFactory.makeObject(OpenOfficeConnectionFactory.java:20)

Could anyone please help me or suggest with this ?

Thank you.

Using Oracle Linux 7.4
OpenOffice 5.2 on Windows 10
Post Reply