Search in sources :

Example 1 with ScriptHelper

use of com.disney.groovity.util.ScriptHelper in project groovity by disney.

the class Ws method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, Closure body) throws Exception {
    Object url = resolve(attributes, URL);
    if (url == null) {
        throw new RuntimeException("ws() requires 'url' attribute");
    }
    ScriptHelper context = getScriptHelper(body);
    Map variables = context.getBinding().getVariables();
    URI uri;
    URIBuilder builder;
    ArrayList<Header> headers;
    Function handlerFunction;
    Optional<UserPass> userPass;
    Optional<HttpSignatureSigner> signer;
    final AtomicReference openMessage = new AtomicReference<>();
    try {
        builder = new URIBuilder(url.toString());
        bind(context, Uri.CURRENT_URI_BUILDER, builder);
        headers = new ArrayList<Header>();
        bind(context, com.disney.groovity.tags.Header.CURRENT_LIST_FOR_HEADERS, headers);
        Credentials.acceptCredentials(variables);
        Signature.acceptSigner(variables);
        Object oldOut = get(context, OUT);
        StringWriter sw = new StringWriter();
        Object rval = null;
        bind(context, OUT, sw);
        try {
            rval = body.call();
            if (rval instanceof Writable) {
                ((Writable) rval).writeTo(sw);
            }
        } finally {
            bind(context, OUT, oldOut);
            userPass = Credentials.resolveCredentials(variables);
            signer = Signature.resolveSigner(variables);
        }
        String val = sw.toString().trim();
        if (val.length() > 0) {
            openMessage.set(val);
        } else if (rval != null) {
            openMessage.set(rval);
        }
        uri = builder.build();
        handlerFunction = (Function) get(body, Handler.HANDLER_BINDING);
    } catch (URISyntaxException e1) {
        throw new RuntimeException("Invalid URI " + url, e1);
    } finally {
        unbind(context, Uri.CURRENT_URI_BUILDER);
        unbind(context, com.disney.groovity.tags.Header.CURRENT_LIST_FOR_HEADERS);
        unbind(context, Handler.HANDLER_BINDING);
    }
    final Closure closer = resolve(attributes, CLOSE, Closure.class);
    final Closure errorHandler = resolve(attributes, ERROR, Closure.class);
    final Class messageFormat = resolve(attributes, MESSAGE, Class.class);
    final Integer timeout = resolve(attributes, TIMEOUT, Integer.class);
    final AtomicReference<WebSocket> socket = new AtomicReference<>();
    ClientEndpointConfig.Builder configBuilder = ClientEndpointConfig.Builder.create();
    Session session;
    try {
        session = getContainer().connectToServer(new Endpoint() {

            @Override
            public void onOpen(Session session, EndpointConfig config) {
                try {
                    openCount.incrementAndGet();
                    if (timeout != null) {
                        session.setMaxIdleTimeout(timeout * 1000);
                    }
                    WebSocket ws = new WebSocket(session);
                    socket.set(ws);
                    ws.setName(uri.toString());
                    if (handlerFunction != null) {
                        ws.setMessageHandler(arg -> {
                            synchronized (handlerFunction) {
                                handlerFunction.apply(arg);
                            }
                        }, messageFormat);
                    }
                    if (openMessage.get() != null) {
                        ws.call(openMessage.get());
                    }
                } catch (Exception e) {
                    log.log(Level.SEVERE, "Error opening web socket session " + uri, e);
                }
            }

            @Override
            public void onClose(Session session, CloseReason reason) {
                try {
                    closeCount.incrementAndGet();
                    openSessions.remove(session);
                    if (closer != null) {
                        if (closer.getMaximumNumberOfParameters() > 0) {
                            closer.call(reason);
                        } else {
                            closer.call();
                        }
                    }
                } catch (Exception e) {
                    log.log(Level.SEVERE, "Error closing web socket session " + uri, e);
                }
            }

            @Override
            public void onError(Session session, Throwable th) {
                try {
                    errorCount.incrementAndGet();
                    if (errorHandler == null) {
                        throw th;
                    }
                    errorHandler.call(th);
                } catch (Throwable e) {
                    Level logLevel = Level.WARNING;
                    if (th != e) {
                        log.log(logLevel, "Error handling error for web socket session " + uri, e);
                    } else if (th instanceof IOException) {
                        logLevel = Level.FINE;
                    }
                    log.log(logLevel, "WebSocket client error: " + uri, th);
                }
            }
        }, configBuilder.configurator(new ClientEndpointConfig.Configurator() {

            public void beforeRequest(Map<String, List<String>> reqHeaders) {
                // copy programmatic headers
                for (Header header : headers) {
                    List<String> hl = reqHeaders.get(header.getName());
                    if (hl == null) {
                        hl = new ArrayList<>();
                        reqHeaders.put(header.getName(), hl);
                    }
                    hl.add(header.getValue());
                }
                Map<String, Map<String, String>> allChallenges = null;
                if (userPass.isPresent() || signer.isPresent()) {
                    allChallenges = getChallenges(uri, reqHeaders);
                }
                if (userPass.isPresent()) {
                    UserPass user = userPass.get();
                    if (allChallenges != null) {
                        List<String> auths = reqHeaders.get(AUTHORIZATION_HEADER);
                        if (auths == null) {
                            auths = new ArrayList<>();
                            reqHeaders.put(AUTHORIZATION_HEADER, auths);
                        }
                        if (allChallenges.containsKey("basic")) {
                            StringBuilder authBuilder = new StringBuilder(user.getUser());
                            authBuilder.append(":");
                            char[] pass = user.getPass();
                            for (char c : pass) {
                                authBuilder.append(c);
                            }
                            try {
                                auths.add("Basic " + printBase64Binary(authBuilder.toString().getBytes("UTF-8")));
                            } catch (UnsupportedEncodingException e) {
                                log.severe(e.getMessage());
                            }
                        }
                        if (allChallenges.containsKey("digest")) {
                            final String digestUri = uri.getPath() + ((uri.getRawQuery() != null) ? "?" + uri.getRawQuery() : "");
                            Map<String, String> digestChallenge = allChallenges.get("digest");
                            if (log.isLoggable(Level.FINE)) {
                                log.fine("Generating digest auth for " + digestChallenge.toString());
                            }
                            DigestAuthorization digestAuth = new DigestAuthorization();
                            digestAuth.setUsername(user.getUser());
                            digestAuth.setQop("auth");
                            digestAuth.setCnonce(String.valueOf(ThreadLocalRandom.current().nextLong(10000000, 999999999999l)));
                            digestAuth.setNonceCount("000001");
                            digestAuth.setUri(digestUri);
                            for (Entry<String, String> entry : digestChallenge.entrySet()) {
                                String k = entry.getKey();
                                String v = entry.getValue();
                                if ("nonce".equalsIgnoreCase(k)) {
                                    digestAuth.setNonce(v);
                                } else if ("realm".equalsIgnoreCase(k)) {
                                    digestAuth.setRealm(v);
                                } else if ("opaque".equalsIgnoreCase(k)) {
                                    digestAuth.setOpaque(v);
                                }
                            }
                            String signingString;
                            try {
                                signingString = digestAuth.generateSigningString(user.getUser(), new String(user.getPass()), new AuthorizationRequest() {

                                    @Override
                                    public String getURI() {
                                        return digestUri;
                                    }

                                    @Override
                                    public String getMethod() {
                                        return "GET";
                                    }

                                    @Override
                                    public List<String> getHeaders(String name) {
                                        return reqHeaders.get(name);
                                    }
                                });
                                MessageDigest md5 = MessageDigest.getInstance("MD5");
                                digestAuth.setDigest(md5.digest(signingString.toString().getBytes()));
                                if (log.isLoggable(Level.FINE)) {
                                    log.fine("Generated digest auth " + digestAuth.toString());
                                }
                                auths.add(digestAuth.toString());
                            } catch (NoSuchAlgorithmException e) {
                                log.severe("Missing MD5 " + e.getMessage());
                            }
                        }
                    }
                }
                if (signer.isPresent()) {
                    if (allChallenges.containsKey("signature")) {
                        HttpSignatureSigner sig = signer.get();
                        HttpGet signReq = createRequest(uri, reqHeaders);
                        List<Header> beforeHeaders = Arrays.asList(signReq.getAllHeaders());
                        try {
                            sig.process(signReq, null);
                        } catch (HttpException | IOException e) {
                            log.log(Level.SEVERE, "Error processing http signature", e);
                        }
                        Header[] afterHeaders = signReq.getAllHeaders();
                        for (Header h : afterHeaders) {
                            if (!beforeHeaders.contains(h)) {
                                List<String> hl = reqHeaders.get(h.getName());
                                if (hl == null) {
                                    hl = new ArrayList<>();
                                    reqHeaders.put(h.getName(), hl);
                                }
                                hl.add(h.getValue());
                                if (log.isLoggable(Level.FINE)) {
                                    log.fine("Copied HTTP signature header " + h);
                                }
                            }
                        }
                    }
                }
            }
        }).build(), uri);
    } catch (Exception e) {
        errorCount.incrementAndGet();
        throw e;
    }
    openSessions.add(session);
    String var = resolve(attributes, VAR, String.class);
    if (var != null) {
        context.getBinding().setVariable(var, socket.get());
    }
    return socket.get();
}
Also used : AuthorizationRequest(com.disney.http.auth.AuthorizationRequest) Writable(groovy.lang.Writable) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Endpoint(javax.websocket.Endpoint) CloseReason(javax.websocket.CloseReason) MessageDigest(java.security.MessageDigest) UnsupportedEncodingException(java.io.UnsupportedEncodingException) URIBuilder(org.apache.http.client.utils.URIBuilder) Header(org.apache.http.Header) Level(java.util.logging.Level) ScriptHelper(com.disney.groovity.util.ScriptHelper) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) LinkedHashMap(java.util.LinkedHashMap) Closure(groovy.lang.Closure) HttpGet(org.apache.http.client.methods.HttpGet) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) Function(java.util.function.Function) StringWriter(java.io.StringWriter) HttpSignatureSigner(com.disney.http.auth.client.signer.HttpSignatureSigner) HttpException(org.apache.http.HttpException) ClientEndpointConfig(javax.websocket.ClientEndpointConfig) DigestAuthorization(com.disney.http.auth.DigestAuthorization) UserPass(com.disney.groovity.tags.Credentials.UserPass) AtomicReference(java.util.concurrent.atomic.AtomicReference) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) HttpException(org.apache.http.HttpException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) WebSocket(com.disney.groovity.util.WebSocket) ClientEndpointConfig(javax.websocket.ClientEndpointConfig) EndpointConfig(javax.websocket.EndpointConfig) Session(javax.websocket.Session)

Example 2 with ScriptHelper

use of com.disney.groovity.util.ScriptHelper in project groovity by disney.

the class Log method tag.

@SuppressWarnings("rawtypes")
@Override
public Object tag(Map attributes, Closure body) throws Exception {
    ScriptHelper helper = getScriptHelper(body);
    GroovityClassLoader classLoader = helper.getClassLoader();
    Logger logger = classLoader.getLogger();
    Throwable thrown = resolve(attributes, "thrown", Throwable.class);
    doLog(attributes, logger, Level.FINE, "debug", thrown);
    doLog(attributes, logger, Level.INFO, "info", thrown);
    doLog(attributes, logger, Level.WARNING, "warn", thrown);
    doLog(attributes, logger, Level.SEVERE, "error", thrown);
    return null;
}
Also used : GroovityClassLoader(com.disney.groovity.compile.GroovityClassLoader) ScriptHelper(com.disney.groovity.util.ScriptHelper) Logger(java.util.logging.Logger)

Example 3 with ScriptHelper

use of com.disney.groovity.util.ScriptHelper in project groovity by disney.

the class Each method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
public Object tag(Map attributes, Closure body) {
    Object in = resolve(attributes, "in");
    if (in == null) {
        // for null let's be graceful and act like a zero-length iteration, saves coding null checks
        return null;
    }
    Object max = resolve(attributes, "max");
    int imax = -1;
    if (max != null) {
        if (max instanceof Number) {
            imax = ((Number) max).intValue();
        } else {
            imax = Integer.parseInt(max.toString());
        }
    }
    Object pos = resolve(attributes, "pos");
    if (in instanceof Map) {
        in = ((Map) in).entrySet();
    }
    if (in instanceof Enumeration) {
        in = Collections.list((Enumeration) in);
    }
    if (in.getClass().isArray()) {
        in = Arrays.asList((Object[]) in);
    }
    if (!(in instanceof Iterable)) {
        throw new RuntimeException("Each tag requires an iterable 'in' attribute, not " + in + " of type " + in.getClass().getName());
    }
    Object var = attributes.get(VAR);
    String varName = var == null ? null : var.toString();
    String posName = pos == null ? null : pos.toString();
    Object oldVar = null;
    Object oldPos = null;
    ScriptHelper context = getScriptHelper(body);
    if (varName != null) {
        oldVar = get(context, varName);
    }
    if (posName != null) {
        oldPos = get(context, posName);
    }
    int count = 0;
    for (Object it : ((Iterable) in)) {
        if (count == imax) {
            break;
        }
        if (varName != null) {
            bind(context, varName, it);
        }
        if (posName != null) {
            bind(context, posName, count);
        }
        body.call(it);
        count++;
    }
    if (oldVar != null) {
        bind(context, varName, oldVar);
    } else if (varName != null) {
        unbind(context, varName);
    }
    if (oldPos != null) {
        bind(context, posName, oldPos);
    } else if (posName != null) {
        unbind(context, posName);
    }
    return null;
}
Also used : Enumeration(java.util.Enumeration) ScriptHelper(com.disney.groovity.util.ScriptHelper) Map(java.util.Map)

Example 4 with ScriptHelper

use of com.disney.groovity.util.ScriptHelper in project groovity by disney.

the class Async method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, final Closure body) throws Exception {
    final Integer timeoutSeconds = resolve(attributes, TIMEOUT, Integer.class);
    final ScriptHelper scriptHelper = getScriptHelper(body);
    final Binding binding = scriptHelper.getBinding();
    final Map variables = binding.getVariables();
    final AwaitContext asyncContext = AwaitContext.get(variables);
    DeadlockFreeExecutor createdThreadPool = null;
    // make a copy of current binding for async
    final Map asyncVariables = asyncCopy(variables);
    if (asyncContext == null || !asyncVariables.containsKey(Async.EXECUTOR_BINDING)) {
        Integer numThreads = resolve(attributes, POOL, Integer.class);
        if (numThreads != null) {
            createdThreadPool = new DeadlockFreeExecutor(interruptFactory, numThreads);
            asyncVariables.put(EXECUTOR_BINDING, createdThreadPool);
        }
    }
    final DeadlockFreeExecutor asyncPool = createdThreadPool != null ? createdThreadPool : ((asyncContext != null) ? getExecutor(asyncVariables) : sharedThreadPool);
    final boolean shutdownPool = createdThreadPool != null;
    final CharArrayWriter out = new CharArrayWriter();
    asyncVariables.put(OUT, out);
    if (asyncContext != null) {
        // signal a boundary for sequencing async output
        asyncContext.signalAsync(variables, out);
    }
    final Execution parentStack = asyncContext != null ? asyncContext.getWaitingExecution() : null;
    String scriptPath = scriptHelper.getClassLoader().getScriptName();
    final long timeoutTime = timeoutSeconds == null ? -1 : System.currentTimeMillis() + (timeoutSeconds * 1000);
    final Callable<Object> bodyRunner = new Callable<Object>() {

        @Override
        public Object call() throws Exception {
            Binding asyncBinding = new Binding(asyncVariables);
            Binding oldThreadBinding = ScriptHelper.THREAD_BINDING.get();
            ScriptHelper.THREAD_BINDING.set(asyncBinding);
            final Execution restoreStack = parentStack != null ? GroovityStatistics.registerStack(parentStack) : null;
            try {
                Closure asyncBody;
                if (body.getThisObject() instanceof Class) {
                    // if the parent script is not available it is a special case (static) and we may share the context
                    asyncBody = body;
                    asyncBody.setDelegate(asyncBinding);
                    asyncBody.setResolveStrategy(Closure.DELEGATE_FIRST);
                } else {
                    Script asyncInstance = scriptHelper.load(scriptPath);
                    asyncBody = body.rehydrate(asyncInstance, asyncInstance, asyncInstance);
                }
                if (timeoutTime > 0) {
                    // use an interrupt to enforce the timeout
                    long startTime = System.currentTimeMillis();
                    if (startTime > timeoutTime) {
                        throw new InterruptedException();
                    }
                    final ScheduledFuture<?> interrupt = interruptFactory.scheduleInterrupt(timeoutTime - startTime);
                    try {
                        return asyncBody.call();
                    } finally {
                        interrupt.cancel(true);
                    }
                }
                return asyncBody.call();
            } catch (Throwable e) {
                if (asyncContext == null) {
                    // with no known waiters this exception could get lost, let's log it
                    log.log(Level.SEVERE, "Error in async", e);
                }
                throw e;
            } finally {
                if (oldThreadBinding == null) {
                    ScriptHelper.THREAD_BINDING.remove();
                } else {
                    ScriptHelper.THREAD_BINDING.set(oldThreadBinding);
                }
                if (parentStack != null) {
                    GroovityStatistics.registerStack(restoreStack);
                }
                if (shutdownPool) {
                    sharedThreadPool.submit(new Runnable() {

                        @Override
                        public void run() {
                            asyncPool.shutdown();
                            try {
                                if (!asyncPool.awaitTermination(60, TimeUnit.SECONDS)) {
                                    asyncPool.shutdownNow();
                                    asyncPool.awaitTermination(60, TimeUnit.SECONDS);
                                }
                            } catch (InterruptedException e) {
                                asyncPool.shutdownNow();
                            }
                        }
                    });
                }
            }
        }
    };
    Future<Object> future = asyncPool.submit(bodyRunner);
    if (asyncContext != null) {
        asyncContext.add(future);
    }
    String var = resolve(attributes, VAR, String.class);
    if (var != null && var.length() > 0) {
        variables.put(var, future);
    }
    return future;
}
Also used : Binding(groovy.lang.Binding) Script(groovy.lang.Script) Closure(groovy.lang.Closure) CharArrayWriter(java.io.CharArrayWriter) Callable(java.util.concurrent.Callable) Execution(com.disney.groovity.stats.GroovityStatistics.Execution) ScriptHelper(com.disney.groovity.util.ScriptHelper) HashMap(java.util.HashMap) Map(java.util.Map) AwaitContext(com.disney.groovity.tags.Await.AwaitContext) DeadlockFreeExecutor(com.disney.groovity.util.DeadlockFreeExecutor)

Example 5 with ScriptHelper

use of com.disney.groovity.util.ScriptHelper in project groovity by disney.

the class Groovity method run.

/**
 * This is the primary method of interest - execute an individual groovity script by path using a given binding.
 * If the script returns a Writable (streaming template or GString) and a Writer is bound to "out", the value will be streamed to out,
 * otherwise the return value is passed through to the caller.
 *
 * @param scriptName the path of the script to execute, e.g. /myFolder/myScript
 * @param binding the groovy binding to use as global variable scope
 * @return the return value of the script, if any
 * @throws InstantiationException
 * @throws IllegalAccessException
 * @throws ClassNotFoundException
 * @throws IOException
 */
public Object run(final String scriptName, final Binding binding) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
    Script script = load(scriptName, binding);
    if (script != null) {
        Object rval = script.run();
        ScriptHelper scriptHelper = ((GroovityClassLoader) script.getClass().getClassLoader()).getScriptHelper();
        if (!scriptHelper.processReturn(script, rval)) {
            return rval;
        }
    }
    return null;
}
Also used : Script(groovy.lang.Script) GroovityClassLoader(com.disney.groovity.compile.GroovityClassLoader) ScriptHelper(com.disney.groovity.util.ScriptHelper)

Aggregations

ScriptHelper (com.disney.groovity.util.ScriptHelper)8 Map (java.util.Map)6 Binding (groovy.lang.Binding)4 CharArrayWriter (java.io.CharArrayWriter)4 Closure (groovy.lang.Closure)3 GroovityClassLoader (com.disney.groovity.compile.GroovityClassLoader)2 AwaitContext (com.disney.groovity.tags.Await.AwaitContext)2 UserPass (com.disney.groovity.tags.Credentials.UserPass)2 DeadlockFreeExecutor (com.disney.groovity.util.DeadlockFreeExecutor)2 HttpSignatureSigner (com.disney.http.auth.client.signer.HttpSignatureSigner)2 Script (groovy.lang.Script)2 Writable (groovy.lang.Writable)2 IOException (java.io.IOException)2 StringWriter (java.io.StringWriter)2 URI (java.net.URI)2 URISyntaxException (java.net.URISyntaxException)2 Callable (java.util.concurrent.Callable)2 ExecutionException (java.util.concurrent.ExecutionException)2 Function (java.util.function.Function)2 Header (org.apache.http.Header)2