001/*
002 * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     bstefanescu
016 */
017package org.nuxeo.shell.equinox;
018
019import java.io.IOException;
020import java.io.InputStreamReader;
021import java.io.PrintWriter;
022import java.io.Reader;
023import java.net.Socket;
024import java.util.ArrayList;
025
026import org.nuxeo.shell.ShellException;
027import org.nuxeo.shell.cmds.Interactive;
028import org.nuxeo.shell.utils.StringUtils;
029
030/**
031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
032 */
033public class Connector {
034
035    protected String[] commands;
036
037    protected Socket socket;
038
039    protected Reader in;
040
041    protected PrintWriter out;
042
043    public static Connector newConnector(String address) {
044        int p = address.indexOf(':');
045        if (p == -1) {
046            throw new ShellException("Illegal address '" + address + "'. Must be in format 'host:port'");
047        }
048        return new Connector(address.substring(0, p), Integer.parseInt(address.substring(p + 1)));
049    }
050
051    public Connector(String host, int port) {
052        try {
053            socket = new Socket(host, port);
054            socket.setReuseAddress(true);
055            in = new InputStreamReader(socket.getInputStream());
056            out = new PrintWriter(socket.getOutputStream());
057            initConnection();
058        } catch (Exception e) {
059            throw new ShellException("Failed to connect to " + host + ':' + port);
060        }
061    }
062
063    protected void initConnection() throws IOException {
064        readAll();
065        String r = send("help");
066        String[] lines = StringUtils.split(r, '\n', true);
067        ArrayList<String> cmds = new ArrayList<String>();
068        for (String line : lines) {
069            if (line.length() == 0 || line.startsWith("---")) {
070                continue;
071            }
072            int i = line.indexOf(' ');
073            cmds.add(line.substring(0, i));
074        }
075        commands = cmds.toArray(new String[cmds.size()]);
076    }
077
078    public String[] getBundles() {
079        String r = send("ss");
080        String[] lines = StringUtils.split(r, '\n', true);
081        ArrayList<String> bundles = new ArrayList<String>();
082        for (String line : lines) {
083            if (line.length() == 0 || line.startsWith("id")) {
084                continue;
085            }
086            String[] ar = line.split("\\s");
087            String b = ar[ar.length - 1];
088            int i = b.indexOf('_');
089            if (i > -1) {
090                b = b.substring(0, i);
091            }
092            bundles.add(b);
093        }
094        return bundles.toArray(new String[bundles.size()]);
095    }
096
097    public String[] getCommands() {
098        return commands;
099    }
100
101    public Reader getIn() {
102        return in;
103    }
104
105    public PrintWriter getOut() {
106        return out;
107    }
108
109    public void println(String text) {
110        out.println(text);
111        out.flush();
112    }
113
114    public void println() {
115        out.println();
116        out.flush();
117    }
118
119    public String sendCurrentCommand() {
120        return send(Interactive.getCurrentCmdLine());
121    }
122
123    public String send(String command) {
124        try {
125            println(command);
126            return readAll();
127        } catch (IOException e) {
128            throw new ShellException("Failed to read response", e);
129        }
130    }
131
132    /**
133     * Get the response and remove the ending "osgi>" if present - also trim the string before returning. (CRLF is not
134     * included at the end)
135     *
136     * @return
137     * @throws IOException
138     */
139    public String readAll() throws IOException {
140        StringBuilder result = new StringBuilder();
141        char[] cbuf = new char[4096];
142        int r = in.read(cbuf);
143        while (r > 0) {
144            result.append(new String(cbuf, 0, r));
145            if (result.lastIndexOf("osgi> ") == result.length() - "osgi> ".length()) {
146                break;
147            }
148            r = in.read(cbuf);
149        }
150        String str = result.toString().trim();
151        if (str.endsWith("osgi>")) {
152            str = str.substring(0, str.length() - "osgi>".length());
153            str = str.trim();
154        }
155        return str;
156    }
157
158    public void disconnect() {
159        try {
160            socket.close();
161        } catch (Exception e) {
162            throw new ShellException("Failed to disconnect", e);
163        }
164    }
165
166    public Socket getSocket() {
167        return socket;
168    }
169
170}