Java HOWTO

From Enso Wiki

Jump to: navigation, search

Here's a quick example of a java extension that looks up keywords at apidoc.org. It makes use of apache's xmlrpc libs.


Server.java:

package net.tralfamadore.enso;

import java.net.URL;
import java.util.Map;
import java.io.IOException;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.webserver.WebServer;
import org.apache.xmlrpc.server.XmlRpcServer;
import org.apache.xmlrpc.server.PropertyHandlerMapping;

/**
 * Our XML RPC server.
 */
public class Server {
    private static final int port = 18080;
    public static String EXTENSION_ENDPOINT_URL = "http://127.0.0.1:" + port;

    public static void main(String[] args) throws Exception {
        WebServer webServer = new WebServer(port);

        XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();

        FlatHandlerMap phm = new FlatHandlerMap();
        phm.addHandler("Handler", Handler.class);
        xmlRpcServer.setHandlerMapping(phm);
        webServer.start();
        Enso.registerCommand(EXTENSION_ENDPOINT_URL,
                ApiLookup.COMMAND_NAME,
                ApiLookup.DESCRIPTION,
                ApiLookup.HELP,
                ApiLookup.POSTFIX);
    }
}

/**
 * The default handler names every call Class.method, but we need our (only) call
 * to be named callCommand, so we override some things and remove the class names.
 */
class FlatHandlerMap extends PropertyHandlerMapping {
    @SuppressWarnings(value = "unchecked")
    private void flattenHandlerNames() {
        for(Object k : handlerMap.keySet()) {
            Object v = handlerMap.get(k);
            k = k.toString().replaceFirst(".*\\.", "");
            handlerMap.put(k, v);
        }
    }
    @Override
    public void load(ClassLoader classLoader, String s) throws IOException, XmlRpcException {
        super.load(classLoader, s);
        flattenHandlerNames();
    }

    @Override
    public void load(ClassLoader classLoader, URL url) throws IOException, XmlRpcException {
        super.load(classLoader, url);
        flattenHandlerNames();
    }

    @Override
    public void load(ClassLoader classLoader, Map map) throws XmlRpcException {
        super.load(classLoader, map);
        flattenHandlerNames();
    }

    @Override
    public void addHandler(String s, Class aClass) throws XmlRpcException {
        super.addHandler(s, aClass);
        flattenHandlerNames();
    }
}

Handler.java:

package net.tralfamadore.enso;

/**
 * Default handler for XML RPC server.
 */
public class Handler {
    /**
     * This is the only command enso will call.  It is used to direct incoming requests.
     *
     * @param name The name of the command to execute.
     * @param postfix Data for the command, as a String.
     * @return Always 0 (a return value is required for the XMLRPC spec).
     */
    public int callCommand(String name, String postfix) {
        if(name.equals(ApiLookup.COMMAND_NAME)) {
            ApiLookup.launchMozilla(postfix);
        }
        return 0;
    }
}

Enso.java

package net.tralfamadore.enso;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import java.net.URL;
import java.net.MalformedURLException;

/**
 * A small class with some info and conveinience
 * methods for talking to our enso server.
 */
public class Enso {
    /** Where our enso server is running. */
    public static URL XMLRPC_ENDPOINT_URL;
    private static XmlRpcClient enso;

    static {
        try {
            XMLRPC_ENDPOINT_URL = new URL("http://127.0.0.1:11374");
            XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
            config.setServerURL(XMLRPC_ENDPOINT_URL);
            enso = new XmlRpcClient();
            enso.setConfig(config);
        } catch(MalformedURLException mue) {
            mue.printStackTrace();
        }
    }

    /** The 3 different enso postfix types (see enso docs) */
    public enum PostfixType {
        NONE,
        BOUNDED,
        ARBITRARY
    }

    /**
     * Registers the command with the enzo server.
     *
     * @param extentionURL Where our xml rpc server is running.
     * @param name The name of our command.
     * @param description The command description.
     * @param help More detailed help, displayed in web page.
     * @param type The postfix type this command uses @see{PostfixType}
     *
     * @throws XmlRpcException When an error occurs comminicating with the enso server.
     */
    public static void registerCommand(String  extentionURL,
                                       String name,
                                       String description,
                                       String help,
                                       PostfixType type)
            throws XmlRpcException
    {
        String[] args = { extentionURL, name, description, help, type.name().toLowerCase() };
        Boolean result = (Boolean) enso.execute("registerCommand", args);
        System.out.println(result);
    }

    /**
     * Interface to enso's getUnicodeSelection.
     *
     * @return The currently selected text, or empty string if there is none.
     */
    public static String getUnicodeSelection() {
        try {
            return (String)enso.execute("getUnicodeSelection", new Object[0]);
        } catch(XmlRpcException xre) {
            xre.printStackTrace();
            return "";
        }
    }
}

ApiLookup.java

package net.tralfamadore.enso;

/**
 * Looks up search terms on apidoc.org.
 */
public class ApiLookup {
    /** command name to use when regestering with enso */
    public static final String COMMAND_NAME = "api {search}";
    /** description to use when regestering with enso */
    public static final String DESCRIPTION = "search apidoc.org.";
    /** help message to use when regestering with enso */
    public static final String HELP = "Searches apidoc.org for the currently selected text or search argument";
    /** postfix type to use */
    public static final Enso.PostfixType POSTFIX = Enso.PostfixType.ARBITRARY;
    
    protected static final String site = "http://apidoc.org";

    /**
     * Performs the lookup.  Opens a browser to apidocs.org with a search on the given term.
     * 
     * @param search The term to search for.
     */
    public static void launchMozilla(String search) {
        if(search == null || search.isEmpty())
            search = Enso.getUnicodeSelection();
        if(search == null || search.isEmpty())
            search = site;
        else
            search = site + "/search?q=" + search;

        BrowserLauncher.launch(BrowserLauncher.Browser.MOZILLA, search);
    }
}

BrowserLauncher.java

package net.tralfamadore.enso;

import java.io.IOException;
import java.util.concurrent.Executor;

/**
 * Simple class which launches a browser.
 */

public class BrowserLauncher {
    private static Executor executor = new DefaultExecutor();

    /**
     * Enum interface the various browsers.
     */
    public static enum Browser {
        MOZILLA("\"C:/Program Files/Mozilla Firefox/firefox.exe\""),
        IE(null),
        SAFARI(null);

        private String path;

        Browser(String path) {
            this.path = path;
        }

        public String getPath() {
            return path;
        }
    }

    /**
     * Launches the specified browser with the given url.
     *
     * @param browser Browser to use.
     * @param url URL to go to
     */
    public static void launch(final Browser browser, final String url){
        Runnable r = new Runnable() {
            public void run() {
                try {
                    Process p = Runtime.getRuntime().exec(browser.getPath() + " " + url);
                    p.waitFor();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        executor.execute(r);
    }

    private static class DefaultExecutor implements Executor {
        public void execute(Runnable command) {
            new Thread(command).start();
        }
    }

--68.80.41.69 13:55, 19 January 2008 (PST)