Source: ptolemy/actor/lib/jjs/capeCodeHost.js

// JavaScript functions for a Ptolemy II (Nashorn) accessor host.
// Copyright (c) 2016-2018 The Regents of the University of California.
// All rights reserved.
//
// Permission is hereby granted, without written agreement and without
// license or royalty fees, to use, copy, modify, and distribute this
// software and its documentation for any purpose, provided that the above
// copyright notice and the following two paragraphs appear in all copies
// of this software.
//
// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
// ENHANCEMENTS, OR MODIFICATIONS.
//

/** JavaScript functions for the CapeCode host, which is based on
 *  Ptolemy II and Java's Nashorn JavaScript engine.
 *
 *  This host supports version 1 accessors.
 *
 *  To implement this host, JavaScript.java does the following:
 *
 *  1) Load the nashornHost.js file,
 *  which realizes functions that are independent of Ptolemy II.
 *  2) load this file (capeCodeHost.js) which overrides some of those
 *  function definitions.
 *  3) Load localFunctions.js, which evaluates the accessor in the
 *  context that includes the overrides.
 *
 *  @module capeCodeHost
 *  @author Edward A. Lee, Contributor: Christopher Brooks
 *  @version $$Id$$
 *  @since Ptolemy II 11.0
 */

// Stop extra messages from jslint.  Note that there should be no
// space between the / and the * and global.
/*globals Java, actor, console, debug, getAccessorCode, load */
/*jshint globalstrict: true */
/*jslint nomen: true */
"use strict";

////////////////////////////////////////////////////////////////////////////
//// Java dependencies.

// Java classes that define some static functions to call from JS.
var FileUtilities = Java.type('ptolemy.util.FileUtilities');

// If you are going to override functions from commonHost, then work
// in localFunctions.js, not in this file.

//////// NOTE: The following function overrides nashornHost.js.

/** Pop up a dialog with the specified message.
 *  NOTE: This function is not required by the accessor specification, so accessors
 *  should not rely on it being present.
 *  @param message The message
 */
function alert(message) {
    var MessageHandler = Java.type('ptolemy.util.MessageHandler');
    MessageHandler.message(message);
}

//////// NOTE: The following function overrides nashornHost.js.

/** Report an error. This implementation delegates to the host actor to
 *  report the error. In this implementation, the host actor has an error output
 *  port. If that port is connected to something, then the error message is sent
 *  to that port. Otherwise, the error is reported via a dialog or on stderr (the
 *  latter if running headless).
 *  This function should be used only for non-fatal errors, where it is OK to
 *  continue executing. For fatal errors, throw an exception.
 *  @param message The message for the exception.
 */
function error(message) {
    // Print a stack trace to the console.
    /*
    console.error(message);
    console.error('------------------------- error stack trace:');
    var e = new Error('dummy');
    var stack = e.stack.replace(/^[^\(]+?[\n$]/gm, '')
            .replace(/^\s+at\s+/gm, '')
            .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@')
            .split('\n');
    console.error(stack);
    console.error('-------------------------');
    */

    actor.error(message);
}

/////////// NOTE: The following function is deprecated, but provided for compatibility.

/** Perform a blocking HTTP request.
 *  @param url The url for the request, method, properties, body, timeout) {
 *  @param method the request method for the url connection.
 *  @param properties An array of properties for the connection.
 *  @param body If non-empty, the body to be written to the output
 *  stream of the connection.
 *  @param timeout If specified, the connect and read timeout in milliseconds.
 *
 *  @deprecated: Use the http module instead, which provides non-blocking requests.
 */
function httpRequest(url, method, properties, body, timeout) {
    var theURL = new(Java.type('java.net.URL'))(url),
        protocol = theURL.getProtocol().toLowerCase(),
        connection,
        key,
        writer;

    if (debug) {
        console.log("httpRequest(" + (function (obj) {
            var result = [],
                p;
            for (p in obj) {
                if (obj.hasOwnProperty(p)) {
                    result.push(JSON.stringify(obj[p]));
                }
            }
            return result;
        })(arguments) + ")");
    }
    if (actor.isRestricted &&
        !(protocol.equals("http") ||
            protocol.equals("https"))) {
        throw "Actor is restricted. Only HTTP(S) requests will be honored by httpRequest().";
    }
    connection = theURL.openConnection();

    for (key in properties) {
        if (properties.hasOwnProperty(key)) {
            connection.setRequestProperty(key, properties[key]);
        }
    }

    connection.setRequestMethod(method);

    // If a timeout has been specified, set it.
    if (timeout && timeout >= 0) {
        connection.setConnectTimeout(timeout);
        connection.setReadTimeout(timeout);
    }

    // Send body if applicable.
    if (body && !body.equals('')) {
        connection.setDoOutput(true);
        writer = new(Java.type('java.io.OutputStreamWriter'))(connection
            .getOutputStream());
        writer.write(body);
        writer.flush();
        writer.close();
    }

    // Wait for response.
    return FileUtilities.readFromInputStream(
        connection.getInputStream()
    );
}

/////////// NOTE: The following function is deprecated, but provided for compatibility.

/** Synchronously read a URL.
 *  @param url The url.
 *  @param timeout The timeout in milliseconds
 *
 *  @deprecated: Use the http module, which provides non-blocking functions.
 */
function readURL(url, timeout) {
    if (!timeout) {
        timeout = 3000;
    }
    if (debug) {
        console.log("readURL('" + url + "')");
    }
    
    return httpRequest(url, "GET", null, "", timeout);
}