Package org.moyrax.javascript

Source Code of org.moyrax.javascript.Shell

package org.moyrax.javascript;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import net.sourceforge.htmlunit.corejs.javascript.Context;
import net.sourceforge.htmlunit.corejs.javascript.Function;
import net.sourceforge.htmlunit.corejs.javascript.JavaScriptException;
import net.sourceforge.htmlunit.corejs.javascript.NativeObject;
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.Validate;
import org.moyrax.javascript.annotation.GlobalFunction;
import org.moyrax.javascript.annotation.Script;
import org.moyrax.javascript.shell.Global;
import org.moyrax.resolver.ContextFileResolver;
import org.moyrax.resolver.ResourceResolver;
import org.moyrax.util.ScriptUtils;

/**
* This class provides additional functions to the Rhino shell.
*
* @author Matias Mirabelli <lumen.night@gmail.com>
* @since 0.50
*/
@Script(name = "Shell")
public class Shell extends Global {
  /** Default id for serialization. */
  private static final long serialVersionUID = 1L;


  /**
   * Default protocol name for searching resources.
   */
  private static final String DEFAULT_PROTOCOL = "context";

  /**
   * List of resolvers used to load resources on runtime.
   */
  private static Map<String, ResourceResolver> resolvers =
    new HashMap<String, ResourceResolver>();

  /**
   * Locates and retrieves resources from the context path..
   */
  private static ContextFileResolver contextResolver;

  /** Default constructor. */
  public Shell() {}

  /**
   * Includes a JavaScript resource from different locations.
   *
   * @param context Current execution context.
   * @param scope   Script global scope.
   * @param arguments  Arguments passed to this method from the script.
   * @param thisObj Reference to the current javascript object.
   */
  @GlobalFunction
  public static void include(final Context context, final Scriptable scope,
      final Object[] arguments, final Function thisObj) {

    final ArrayList<String> files = new ArrayList<String>();
    final ArrayList<InputStream> input = new ArrayList<InputStream>();

    for (int i = 0, j = arguments.length; i < j; i++) {
      final String resourceUri = (String)arguments[i];

      final Object result = findResolver(resourceUri)
      .resolve(resourceUri);

      if (result != null) {
        if (result.getClass().equals(File.class)) {
          files.add(((File)result).getAbsolutePath());
        } else if (InputStream.class.isInstance(result)) {
          input.add((InputStream)result);
        }
      } else {
        throw new JavaScriptException(arguments[i].toString() +
            " not found in the context path.", "", 0);
      }
    }

    if (files.size() > 0) {
      ScriptUtils.run(context, scope, files.toArray(new String[] {}));
    }

    if (input.size() > 0) {
      ScriptUtils.run(context, scope, input);
    }
  }

  /**
   * Includes HTML pages.
   *
   * @param context Current execution context.
   * @param scope   Script global scope.
   * @param arguments  Arguments passed to this method from the script.
   * @param thisObj Reference to the current javascript object.
   */
  @GlobalFunction
  public static void includePage(final Context context, final Scriptable scope,
      final Object[] arguments, final Function thisObj) {

    final HtmlPageContext pageContext = new HtmlPageContext(scope, context);

    for (int i = 0, j = arguments.length; i < j; i++) {
      String resourceUri;
      double logLevel = 0;

      if (arguments[i].getClass().equals(NativeObject.class)) {
        final NativeObject nativeObject = (NativeObject)arguments[i];

        Validate.isTrue(nativeObject.has("url", scope), "The url parameter " +
        "doesn't exists.");

        resourceUri = (String)nativeObject.get("url", scope);

        if (nativeObject.has("logLevel", scope)) {
          logLevel = (Double)nativeObject.get("logLevel", scope);
        }
      } else {
        resourceUri = (String)arguments[i];
      }

      pageContext.setLocation(resourceUri);
      pageContext.setLogLevel(logLevel);
      pageContext.open();
    }
  }

  /**
   * Reads resources from different locations.
   *
   * @param context Current execution context.
   * @param scope   Script global scope.
   * @param arguments  Arguments passed to this method from the script.
   * @param thisObj Reference to the current javascript object.
   */
  @GlobalFunction
  public static Object readResource(final Context context, final Scriptable scope,
      final Object[] arguments, final Function thisObj) {

    final ArrayList<InputStream> input = new ArrayList<InputStream>();

    for (int i = 0, j = arguments.length; i < j; i++) {
      final String resourceUri = (String)arguments[i];

      final Object result = findResolver(resourceUri)
        .resolve(resourceUri);

      if (result != null) {
        try {
          if (result.getClass().equals(File.class)) {
            input.add(new FileInputStream((File)result));
          } else if (InputStream.class.isInstance(result)) {
            input.add((InputStream)result);
          }
        } catch(IOException ex) {}
      } else {
        throw new JavaScriptException(arguments[i].toString() +
            " not found in the context path.", "", 0);
      }
    }

    if (input.size() > 0) {
      ByteArrayOutputStream out = new ByteArrayOutputStream();

      for (InputStream resource : input) {
        try {
          IOUtils.copy(resource, out);
        } catch(IOException ex) {
          // Not handled.
        }
      }

      return out.toString();
    }

    return "";
  }

  /**
   * Sets the context path for this shell.
   *
   * @param contextPath List of directory included in the context path. It
   *    cannot be null.
   */
  public static void setContextPath(final File[] contextPath) {
    setContextPath(contextPath, null);
  }

  /**
   * Sets the context path for this shell.
   *
   * @param contextPath List of directory included in the context path. It
   *    cannot be null.
   * @param excludes  List of directories excluded from the context path. It
   *    can be null.
   */
  public static void setContextPath(final File[] contextPath,
      final File[] excludes) {

    Validate.notNull(contextPath, "contextPath cannot be null.");

    /* Creates the default resolver. */
    if (contextResolver == null) {
      contextResolver = new ContextFileResolver();

      setResolver(DEFAULT_PROTOCOL, contextResolver);
    }

    contextResolver.setContextPath(contextPath, excludes);
  }

  /**
   * Adds a new resolver for the specified protocol. The protocol represents the
   * starting part of an URI string. For example, a valid location for a
   * <code>lib</code> protocol coukd be:<br/><br/>
   *
   * lib:/some/path/to/lib.js<br/><br/>
   *
   * When the application tries to load a resource specifying the protocol, the
   * execution will be delegated to the registered resolver.
   *
   * @param protocol Protocol name. It cannot be null.
   * @param resolver {@link ResourceResolver} which handles the protocol. If it
   *    is null, the resolver will be removed.
   *
   * @throws IllegalStateException If the protocol already has a resolver
   *    attached to it.
   */
  public static void setResolver(final String protocol,
      final ResourceResolver resolver) {

    Validate.notNull(protocol, "The protocol parameter cannot be null.");

    if (resolver == null && resolvers.containsKey(protocol)) {
      resolvers.remove(protocol);

      return;
    }

    resolvers.put(protocol, resolver);
  }

  /**
   * Determines which resolver should handle the specified location.
   *
   * @param uri  Location that a resolver must handle. It cannot be null.
   *
   * @throws IllegalArgumentException If the protocol of the URI cannot be
   *    handled by any resolver.
   */
  private static ResourceResolver findResolver(final String uri) {
    Validate.notNull(uri, "The uri parameter cannot be null.");

    /* Is there a protocol? */
    if (uri.indexOf(":") == -1) {
      if (contextResolver == null) {
        /* Oops, I have nothing. */
        throw new IllegalArgumentException("The context path is not "
            + "initialized.");
      }

      return contextResolver;
    }

    final String protocol = uri.substring(0, uri.indexOf(":"));

    /* Doh, this protocol cannot has a defined resolver. Tries to find
       a handler. */
    if (!resolvers.containsKey(protocol)) {
      Collection<ResourceResolver> resolverList = resolvers.values();

      for (ResourceResolver resolver : resolverList) {
        int result = resolver.canHandle(uri);

        if (result == ResourceResolver.HANDLE_EXCLUSIVE ||
            result == ResourceResolver.HANDLE_SHARED) {
          return resolver;
        }
      }

      /* Indeed, I can't handle it. */
      throw new IllegalArgumentException("The protocol '" + protocol + "' "
          + "cannot be handled.");
    }

    return resolvers.get(protocol);
  }
}
TOP

Related Classes of org.moyrax.javascript.Shell

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.