org.gradle.play.internal.run.DefaultVersionedPlayRunAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2014 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 org.gradle.play.internal.run;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.internal.Cast;
import org.gradle.internal.UncheckedException;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.reflect.DirectInstantiator;
import org.gradle.internal.reflect.JavaMethod;
import org.gradle.scala.internal.reflect.ScalaMethod;
import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.JarFile;
public abstract class DefaultVersionedPlayRunAdapter implements VersionedPlayRunAdapter, Serializable {
private static final String PLAY_EXCEPTION_CLASSNAME = "play.api.PlayException";
private static final Logger LOGGER = Logging.getLogger(DefaultVersionedPlayRunAdapter.class);
private final AtomicReference currentClassloader = new AtomicReference();
private final Queue> loadersToClose = new ConcurrentLinkedQueue>();
protected abstract Class> getBuildLinkClass(ClassLoader classLoader) throws ClassNotFoundException;
protected abstract Class> getDocHandlerFactoryClass(ClassLoader classLoader) throws ClassNotFoundException;
protected abstract Class> getBuildDocHandlerClass(ClassLoader docsClassLoader) throws ClassNotFoundException;
protected abstract ClassLoader createAssetsClassLoader(File assetsJar, Iterable assetsDirs, ClassLoader classLoader);
@Override
public Object getBuildLink(final ClassLoader classLoader, final Reloader reloader, final File projectPath, final File applicationJar, final Iterable changingClasspath, final File assetsJar, final Iterable assetsDirs) throws ClassNotFoundException {
final ClassLoader assetsClassLoader = createAssetsClassLoader(assetsJar, assetsDirs, classLoader);
final Class extends Throwable> playExceptionClass = Cast.uncheckedCast(classLoader.loadClass(PLAY_EXCEPTION_CLASSNAME));
return Proxy.newProxyInstance(classLoader, new Class>[]{getBuildLinkClass(classLoader)}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("projectPath")) {
return projectPath;
} else if (method.getName().equals("reload")) {
Reloader.Result result = reloader.requireUpToDate();
// We can't close replaced loaders immediately, because their classes may be used during shutdown,
// after the return of the reload() call that caused the loader to be swapped out.
// We have no way of knowing when the loader is actually done with, so we use the request after the request
// that triggered the reload as the trigger point to close the replaced loader.
closeOldLoaders();
if (result.changed) {
ClassPath classpath = DefaultClassPath.of(applicationJar).plus(DefaultClassPath.of(changingClasspath));
URLClassLoader currentClassLoader = new URLClassLoader(classpath.getAsURLArray(), assetsClassLoader);
storeClassLoader(currentClassLoader);
return currentClassLoader;
} else {
Throwable failure = result.failure;
if (failure == null) {
return null;
} else {
try {
return DirectInstantiator.instantiate(playExceptionClass, "Gradle Build Failure", failure.getMessage(), failure);
} catch (Exception e) {
LOGGER.warn("Could not translate " + failure + " to " + PLAY_EXCEPTION_CLASSNAME, e);
return failure;
}
}
}
} else if (method.getName().equals("settings")) {
return new HashMap();
}
//TODO: all methods
return null;
}
});
}
private void storeClassLoader(ClassLoader classLoader) {
final ClassLoader previous = currentClassloader.getAndSet(classLoader);
if (previous != null && previous instanceof Closeable) {
loadersToClose.add(new SoftReference(Cast.cast(Closeable.class, previous)));
}
}
private void closeOldLoaders() throws IOException {
SoftReference ref = loadersToClose.poll();
while (ref != null) {
Closeable closeable = ref.get();
if (closeable != null) {
closeable.close();
}
ref.clear();
ref = loadersToClose.poll();
}
}
@Override
public Object getBuildDocHandler(ClassLoader docsClassLoader, Iterable classpath) throws NoSuchMethodException, ClassNotFoundException, IOException, IllegalAccessException {
Class> docHandlerFactoryClass = getDocHandlerFactoryClass(docsClassLoader);
Method docHandlerFactoryMethod = docHandlerFactoryClass.getMethod("fromJar", JarFile.class, String.class);
JarFile documentationJar = findDocumentationJar(classpath);
try {
return docHandlerFactoryMethod.invoke(null, documentationJar, "play/docs/content");
} catch (InvocationTargetException e) {
throw UncheckedException.unwrapAndRethrow(e);
}
}
private JarFile findDocumentationJar(Iterable classpath) throws IOException {
File docJarFile = null;
for (File file : classpath) {
if (file.getName().startsWith("play-docs")) {
docJarFile = file;
break;
}
}
return new JarFile(docJarFile);
}
@Override
public InetSocketAddress runDevHttpServer(ClassLoader classLoader, ClassLoader docsClassLoader, Object buildLink, Object buildDocHandler, int httpPort) throws ClassNotFoundException {
ScalaMethod runMethod = ScalaReflectionUtil.scalaMethod(classLoader, "play.core.server.NettyServer", "mainDevHttpMode", getBuildLinkClass(classLoader), getBuildDocHandlerClass(docsClassLoader), int.class);
Object reloadableServer = runMethod.invoke(buildLink, buildDocHandler, httpPort);
return JavaMethod.of(reloadableServer, InetSocketAddress.class, "mainAddress").invoke(reloadableServer);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy