All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.java.html.boot.BrowserBuilder Maven / Gradle / Ivy

The newest version!
/**
 * HTML via Java(tm) Language Bindings
 * Copyright (C) 2013 Jaroslav Tulach 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details. apidesign.org
 * designates this particular file as subject to the
 * "Classpath" exception as provided by apidesign.org
 * in the License file that accompanied this code.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. Look for COPYING file in the top folder.
 * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
 */
package net.java.html.boot;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.java.html.js.JavaScriptBody;
import org.apidesign.html.boot.impl.FnUtils;
import org.apidesign.html.boot.spi.Fn;
import org.apidesign.html.boot.impl.FindResources;

/** Use this builder to launch your Java/HTML based application. Typical
 * usage in a main method of your application looks like this: 
 * 
 * 
 * public static void main(String... args) {
 *     BrowserBuilder.{@link #newBrowser}.
 *          {@link #loadClass(java.lang.Class) loadClass(YourMain.class)}.
 *          {@link #loadPage(java.lang.String) loadPage("index.html")}.
 *          {@link #invoke(java.lang.String, java.lang.String[]) invoke("initialized", args)}.
 *          {@link #showAndWait()};
 *     System.exit(0);
 * }
 * 
* The above will load YourMain class via * a special classloader, it will locate an index.html (relative * to YourMain class) and show it in a browser window. When the * initialization is over, a public static method initialized * in YourMain will be called with provided string parameters. *

* This module provides only API for building browsers. To use it properly one * also needs an implementation on the classpath of one's application. For example * use:

 * <dependency>
 *   <groupId>org.apidesign.html</groupId>
 *   <artifactId>boot-fx</artifactId>
 *   <scope>runtime</scope>
 * </dependency>
 * 
* * @author Jaroslav Tulach */ public final class BrowserBuilder { private static final Logger LOG = Logger.getLogger(BrowserBuilder.class.getName()); private String resource; private Class clazz; private Class[] browserClass; private Runnable onLoad; private String methodName; private String[] methodArgs; private final Object[] context; private BrowserBuilder(Object[] context) { this.context = context; } /** Entry method to obtain a new browser builder. Follow by calling * its instance methods like {@link #loadClass(java.lang.Class)} and * {@link #loadPage(java.lang.String)}. * * @param context any instances that should be available to the builder - * implemenation dependant * @return new browser builder */ public static BrowserBuilder newBrowser(Object... context) { return new BrowserBuilder(context); } /** The class to load when the browser is initialized. This class * is loaded by a special classloader (that supports {@link JavaScriptBody} * and co.). * * @param mainClass the class to load and resolve when the browser is ready * @return this builder */ public BrowserBuilder loadClass(Class mainClass) { this.clazz = mainClass; return this; } /** Page to load into the browser. If the page represents * a {@link URL} known to the Java system, the URL is passed to the browser. * If system property browser.rootdir is specified, then a * file page relative to this directory is used as the URL. * If no such file exists, the system seeks for the * resource via {@link Class#getResource(java.lang.String)} * method (relative to the {@link #loadClass(java.lang.Class) specified class}). * If such resource is not found, a file relative to the location JAR * that contains the {@link #loadClass(java.lang.Class) main class} is * searched for. * * @param page the location (relative, absolute, or URL) of a page to load * @return this browser */ public BrowserBuilder loadPage(String page) { this.resource = page; return this; } /** Specifies callback method to notify the application that the browser is ready. * There should be a public static method in the class specified * by {@link #loadClass(java.lang.Class)} which takes an array of {@link String} * argument. The method is called on the browser dispatch thread one * the browser finishes loading of the {@link #loadPage(java.lang.String) HTML page}. * * @param methodName name of a method to seek for * @param args parameters to pass to the method * @return this builder */ public BrowserBuilder invoke(String methodName, String... args) { this.methodName = methodName; this.methodArgs = args; return this; } /** Shows the browser, loads specified page in and executes the * {@link #invoke(java.lang.String, java.lang.String[]) initialization method}. * The method returns when the browser is closed. * * @throws NullPointerException if some of essential parameters (like {@link #loadPage(java.lang.String) page} or * {@link #loadClass(java.lang.Class) class} have not been specified */ public void showAndWait() { if (resource == null) { throw new NullPointerException("Need to specify resource via loadPage method"); } URL url = null; MalformedURLException mal = null; try { String baseURL = System.getProperty("browser.rootdir"); if (baseURL != null) { url = new File(baseURL, resource).toURI().toURL(); } else { url = new URL(resource); } } catch (MalformedURLException ex) { mal = ex; } if (url == null) { url = clazz.getResource(resource); } if (url == null) { URL jar = clazz.getProtectionDomain().getCodeSource().getLocation(); try { url = new URL(jar, resource); } catch (MalformedURLException ex) { ex.initCause(mal); mal = ex; } } if (url == null) { IllegalStateException ise = new IllegalStateException("Can't find resouce: " + resource + " relative to " + clazz); if (mal != null) { ise.initCause(mal); } throw ise; } Fn.Presenter dfnr = null; for (Object o : context) { if (o instanceof Fn.Presenter) { dfnr = (Fn.Presenter)o; break; } } if (dfnr == null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class)) { dfnr = o; break; } if (dfnr == null) { throw new IllegalStateException("Can't find any Fn.Presenter"); } final ClassLoader loader; if (FnUtils.isJavaScriptCapable(clazz.getClassLoader())) { loader = clazz.getClassLoader(); } else { FImpl impl = new FImpl(clazz.getClassLoader()); loader = FnUtils.newLoader(impl, dfnr, clazz.getClassLoader().getParent()); } final Fn.Presenter currentP = dfnr; class OnPageLoad implements Runnable { @Override public void run() { try { Thread.currentThread().setContextClassLoader(loader); Class newClazz = Class.forName(clazz.getName(), true, loader); if (browserClass != null) { browserClass[0] = newClazz; } if (onLoad != null) { onLoad.run(); } INIT: if (methodName != null) { Throwable firstError = null; if (methodArgs.length == 0) { try { Method m = newClazz.getMethod(methodName); FnUtils.currentPresenter(currentP); m.invoke(null); break INIT; } catch (Throwable ex) { firstError = ex; } finally { FnUtils.currentPresenter(null); } } try { Method m = newClazz.getMethod(methodName, String[].class); FnUtils.currentPresenter(currentP); m.invoke(m, (Object) methodArgs); } catch (Throwable ex) { if (firstError != null) { LOG.log(Level.SEVERE, "Can't call " + methodName, firstError); } LOG.log(Level.SEVERE, "Can't call " + methodName + " with args " + Arrays.toString(methodArgs), ex); } finally { FnUtils.currentPresenter(null); } } } catch (ClassNotFoundException ex) { LOG.log(Level.SEVERE, "Can't load " + clazz.getName(), ex); } } } dfnr.displayPage(url, new OnPageLoad()); return; } private static final class FImpl implements FindResources { final ClassLoader l; public FImpl(ClassLoader l) { this.l = l; } @Override public void findResources(String path, Collection results, boolean oneIsEnough) { if (oneIsEnough) { URL u = l.getResource(path); if (u != null) { results.add(u); } } else { try { Enumeration en = l.getResources(path); while (en.hasMoreElements()) { results.add(en.nextElement()); } } catch (IOException ex) { // no results } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy