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

com.disney.groovity.Groovity Maven / Gradle / Ivy

There is a newer version: 2.1.0-beta.1
Show newest version
/*******************************************************************************
 * © 2018 Disney | ABC Television Group
 *
 * Licensed under the Apache License, Version 2.0 (the "Apache License")
 * with the following modification; you may not use this file except in
 * compliance with the Apache License and the following modification to it:
 * Section 6. Trademarks. is deleted and replaced with:
 *
 * 6. Trademarks. This License does not grant permission to use the trade
 *     names, trademarks, service marks, or product names of the Licensor
 *     and its affiliates, except as required to comply with Section 4(c) of
 *     the License and to reproduce the content of the NOTICE file.
 *
 * You may obtain a copy of the Apache License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Apache License with the above modification is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the Apache License for the specific
 * language governing permissions and limitations under the Apache License.
 *******************************************************************************/
package com.disney.groovity;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import groovy.transform.Trait;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.ErrorCollector;
import org.codehaus.groovy.control.Janitor;
import org.codehaus.groovy.control.Phases;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.codehaus.groovy.tools.GroovyClass;
import org.codehaus.groovy.tools.Utilities;

import com.disney.groovity.cache.Caches;
import com.disney.groovity.compile.CompilerConfigurationDecorator;
import com.disney.groovity.compile.GroovityASTTransformation;
import com.disney.groovity.compile.GroovityClassLoader;
import com.disney.groovity.compile.GroovityCompilerEvent;
import com.disney.groovity.compile.GroovityCompilerEvent.Change;
import com.disney.groovity.compile.GroovitySourceTransformer;
import com.disney.groovity.compile.StatsASTTransformation;
import com.disney.groovity.compile.GroovitySourceTransformer.TransformedSource;
import com.disney.groovity.compile.SkipStatistics;
import com.disney.groovity.conf.Configurator;
import com.disney.groovity.conf.MultiConfigurator;
import com.disney.groovity.doc.Arg;
import com.disney.groovity.doc.Attr;
import com.disney.groovity.doc.ClassDescriptor;
import com.disney.groovity.doc.Function;
import com.disney.groovity.doc.Tag;
import com.disney.groovity.doc.ClassDescriptor.TypedName;
import com.disney.groovity.source.GroovitySource;
import com.disney.groovity.source.GroovitySourceListener;
import com.disney.groovity.source.GroovitySourceLocator;
import com.disney.groovity.stats.GroovityStatistics;
import com.disney.groovity.util.AsyncChannel;
import com.disney.groovity.util.ClosureWritable;
import com.disney.groovity.util.InterruptFactory;
import com.disney.groovity.util.ScriptHelper;
import com.disney.groovity.util.TypeLabel;


/**
 * Groovity is the runtime engine for compiling, loading, running and visiting scripts.  A Groovity is acquired using 
 * a GroovityBuilder which is used to define initialization parameters - Groovity itself only exposes runtime capabilities.
 * 

* Groovity handles compilation of sources from the configured source locators, the reading and writing of JAR files if so configured, * the configuration, binding, argument resolution, loading and running of scripts, as well as visitation and notification of script * changes for external frameworks *

* Groovity is safe for multithreaded access, however it enforces single-threaded compilation, so calls to compile or compileAll * should be prepared to handle an exception if concurrent compilation is attempted. * * @author Alex Vigdor * */ public class Groovity implements GroovityConstants{ private static final Logger log = Logger.getLogger(Groovity.class.getName()); private static final String GROOVITY_SCRIPT_BINDING_PREFIX = INTERNAL_BINDING_PREFIX.concat("Groovity$script:"); private static final String GROOVITY_BINDING_DECORATED =INTERNAL_BINDING_PREFIX.concat("Groovity$bndDcr"); private static final List internalMethodNames = Arrays.asList(RUN,LOAD,TAG,STREAM,"methodMissing","propertyMissing","$static_propertyMissing","$static_methodMissing"); private static final Pattern sourcePattern = Pattern.compile("(?i)(/.*)\\".concat(GROOVITY_SOURCE_EXTENSION)); private static final Pattern traitPattern = Pattern.compile("\\btrait\\b"); private static final Script PLACEHOLDER_SCRIPT = new Script() { public Object run() { return null; } }; private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private final ConcurrentHashMap> scripts = new ConcurrentHashMap>(); private final ConcurrentHashMap scriptDates = new ConcurrentHashMap(); private final ConcurrentHashMap compileEvents = new ConcurrentHashMap(); private final ConcurrentHashMap> embeddedScripts = new ConcurrentHashMap>(); private File jarDirectory = null; private ClassLoader parentLoader; private List observers = new ArrayList(); private GroovitySourceLocator[] sourceLocators; private EnumSet sourcePhases; private EnumSet jarPhases; private String scriptBaseClass; private Taggables tagLib; private HttpClient httpClient; private AtomicBoolean inCompile = new AtomicBoolean(); private int asyncThreads = Runtime.getRuntime().availableProcessors()*16; private ExecutorService asyncExecutor; private ScheduledExecutorService configExecutor; private ScheduledExecutorService cacheRefreshExecutor; private ScheduledExecutorService cacheTimeExecutor; private InterruptFactory interruptFactory; private boolean caseSensitive = true; private BindingDecorator bindingDecorator; private ArgsLookup argsLookup = null; private GroovitySourceListener groovitySourceListener = new GroovitySourceListener() { public void sourcesChanged(GroovitySource... sources) { if(sourcePhases!=null && sourcePhases.contains(GroovityPhase.RUNTIME)){ try{ compile(false,true,sources); } catch(Error e){ log.log(Level.SEVERE,"Automatic compilation threw error",e); } } } }; private Configurator configurator; @SuppressWarnings("rawtypes") private ConcurrentHashMap traits = new ConcurrentHashMap<>(); @SuppressWarnings("rawtypes") private ConcurrentHashMap inherentTraits = new ConcurrentHashMap<>(); private List compilerConfigurationDecorators; private AtomicBoolean started = new AtomicBoolean(false); //encourage use of the builder protected Groovity(){ } protected Script createScript(final String scriptName) throws InstantiationException, IllegalAccessException{ final Class