Package ratpack.groovy.internal

Source Code of ratpack.groovy.internal.ClosureUtil$DelegatingClosureRunnable

/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ratpack.groovy.internal;

import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import ratpack.func.Action;
import ratpack.groovy.script.internal.LineNumber;
import ratpack.groovy.script.internal.ScriptPath;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.CodeSource;
import java.security.ProtectionDomain;

public abstract class ClosureUtil {

  private ClosureUtil() {
  }

  @SuppressWarnings("UnusedDeclaration") // used in GroovyChainDslFixture
  public static <D, R> R configureDelegateOnly(@DelegatesTo.Target D delegate, @DelegatesTo(strategy = Closure.DELEGATE_ONLY) Closure<R> configurer) {
    return configure(delegate, delegate, configurer, Closure.DELEGATE_ONLY);
  }

  public static <D, R> R configureDelegateFirst(@DelegatesTo.Target D delegate, @DelegatesTo(strategy = Closure.DELEGATE_FIRST) Closure<R> configurer) {
    return configure(delegate, delegate, configurer, Closure.DELEGATE_FIRST);
  }

  public static <D, A, R> R configureDelegateFirst(@DelegatesTo.Target D delegate, A argument, @DelegatesTo(strategy = Closure.DELEGATE_FIRST) Closure<R> configurer) {
    return configure(delegate, argument, configurer, Closure.DELEGATE_FIRST);
  }

  private static <R, D, A> R configure(D delegate, A argument, Closure<R> configurer, int resolveStrategy) {
    if (configurer == null) {
      return null;
    }
    @SuppressWarnings("unchecked")
    Closure<R> clone = (Closure<R>) configurer.clone();
    clone.setDelegate(delegate);
    clone.setResolveStrategy(resolveStrategy);
    if (clone.getMaximumNumberOfParameters() == 0) {
      return clone.call();
    } else {
      return clone.call(argument);
    }
  }

  // Type token is here for in the future when @DelegatesTo supports this kind of API
  public static <T> Action<T> delegatingAction(@SuppressWarnings("UnusedParameters") Class<T> type, final Closure<?> configurer) {
    return new Action<T>() {
      public void execute(T object) throws Exception {
        configureDelegateFirst(object, configurer);
      }
    };
  }

  @SuppressWarnings("unchecked")
  public static <T> Action<T> delegatingAction(final Closure<?> configurer) {
    return (Action<T>) delegatingAction(Object.class, configurer);
  }

  public static Action<Object> action(final Closure<?> closure) {
    final Closure<?> copy = closure.rehydrate(null, closure.getOwner(), closure.getThisObject());
    return new NoDelegateClosureAction(copy);
  }

  private static class NoDelegateClosureAction implements Action<Object> {

    private final Closure<?> copy;

    public NoDelegateClosureAction(Closure<?> copy) {
      this.copy = copy;
    }

    @Override
    public void execute(Object thing) throws Exception {
      copy.call(thing);
    }
  }

  private static class DelegatingClosureRunnable<D, A> implements Runnable {
    private final D delegate;
    private final A argument;
    private final Closure<?> closure;

    private DelegatingClosureRunnable(D delegate, A argument, Closure<?> closure) {
      this.delegate = delegate;
      this.argument = argument;
      this.closure = closure;
    }

    @Override
    public void run() {
      configureDelegateFirst(delegate, argument, closure);
    }
  }

  public static <D, A> Runnable delegateFirstRunnable(D delegate, A argument, Closure<?> closure) {
    return new DelegatingClosureRunnable<>(delegate, argument, closure);
  }

  public static <T> Closure<T> returning(final T thing) {
    return new PassThroughClosure<>(thing);
  }

  public static Closure<Void> noop() {
    return returning((Void) null);
  }

  private static class PassThroughClosure<T> extends Closure<T> {

    static final long serialVersionUID = 0;

    private final T thing;

    public PassThroughClosure(T thing) {
      super(null);
      this.thing = thing;
    }

    @SuppressWarnings("UnusedDeclaration")
    protected T doCall() {
      return thing;
    }

    @SuppressWarnings("UnusedDeclaration")
    protected T doCall(Object it) {
      return thing;
    }
  }

  public static Path findScript(Closure<?> closure) {
    Class<?> clazz = closure.getClass();
    ProtectionDomain protectionDomain = clazz.getProtectionDomain();
    CodeSource codeSource = protectionDomain.getCodeSource();
    URL location = codeSource.getLocation();
    URI uri;
    try {
      uri = location.toURI();
    } catch (URISyntaxException e) {
      return null;
    }

    Path path;
    if (uri.toString().equals("file:/groovy/script")) {
      path = findScriptByAnnotation(closure);
    } else {
      path = Paths.get(uri);
    }

    if (path != null && Files.exists(path)) {
      return path;
    } else {
      return null;
    }
  }

  private static Path findScriptByAnnotation(Closure<?> closure) {
    Class<?> rootClass = getRootClass(closure);
    ScriptPath annotation = rootClass.getAnnotation(ScriptPath.class);
    if (annotation == null) {
      return null;
    } else {
      String scriptPath = annotation.value();
      URI uri;
      try {
        uri = new URI(scriptPath);
      } catch (URISyntaxException e) {
        return null;
      }
      return Paths.get(uri);
    }
  }

  private static Class<?> getRootClass(Object object) {
    Class<?> rootClass = object.getClass();
    Class<?> enclosingClass = rootClass.getEnclosingClass();
    while (enclosingClass != null) {
      rootClass = enclosingClass;
      enclosingClass = rootClass.getEnclosingClass();
    }
    return rootClass;
  }

  public static SourceInfo getSourceInfo(Closure<?> closure) {
    Class<?> closureClass = closure.getClass();
    LineNumber lineNumber = closureClass.getAnnotation(LineNumber.class);
    if (lineNumber == null) {
      return null;
    }

    Class<?> rootClass = getRootClass(closure);
    ScriptPath scriptPath = rootClass.getAnnotation(ScriptPath.class);
    if (scriptPath == null) {
      return null;
    }

    return new SourceInfo(scriptPath.value(), lineNumber.value());
  }

  public static class SourceInfo {
    private final String uri;
    private final int lineNumber;

    public SourceInfo(String uri, int lineNumber) {
      this.uri = uri;
      this.lineNumber = lineNumber;
    }

    public String getUri() {
      return uri;
    }

    public int getLineNumber() {
      return lineNumber;
    }
  }
}
TOP

Related Classes of ratpack.groovy.internal.ClosureUtil$DelegatingClosureRunnable

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.