Converted DevModeInitializer.java to kotlin
This commit is contained in:
parent
c9351c9647
commit
51b17ac65e
@ -13,89 +13,51 @@
|
|||||||
* License for the specific language governing permissions and limitations under
|
* License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
package dorkbox.vaadin;
|
package dorkbox.vaadin
|
||||||
|
|
||||||
import static com.vaadin.flow.server.Constants.PACKAGE_JSON;
|
import com.vaadin.flow.component.WebComponentExporter
|
||||||
import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE;
|
import com.vaadin.flow.component.WebComponentExporterFactory
|
||||||
import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_FRONTEND_DIR;
|
import com.vaadin.flow.component.dependency.CssImport
|
||||||
import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_GENERATED_DIR;
|
import com.vaadin.flow.component.dependency.JavaScript
|
||||||
import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_FRONTEND_DIR;
|
import com.vaadin.flow.component.dependency.JsModule
|
||||||
import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_GENERATED_DIR;
|
import com.vaadin.flow.component.dependency.NpmPackage
|
||||||
import static com.vaadin.flow.server.frontend.FrontendUtils.WEBPACK_GENERATED;
|
import com.vaadin.flow.function.DeploymentConfiguration
|
||||||
|
import com.vaadin.flow.router.HasErrorParameter
|
||||||
import java.io.File;
|
import com.vaadin.flow.router.Route
|
||||||
import java.io.IOException;
|
import com.vaadin.flow.server.*
|
||||||
import java.io.InputStream;
|
import com.vaadin.flow.server.frontend.FrontendUtils
|
||||||
import java.io.Serializable;
|
import com.vaadin.flow.server.frontend.NodeTasks
|
||||||
import java.io.UncheckedIOException;
|
import com.vaadin.flow.server.frontend.scanner.ClassFinder.DefaultClassFinder
|
||||||
import java.lang.annotation.Annotation;
|
import com.vaadin.flow.server.startup.ClassLoaderAwareServletContainerInitializer
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import com.vaadin.flow.server.startup.ServletDeployer.StubServletConfig
|
||||||
import java.lang.reflect.Method;
|
import com.vaadin.flow.theme.NoTheme
|
||||||
import java.net.URL;
|
import com.vaadin.flow.theme.Theme
|
||||||
import java.net.URLDecoder;
|
import elemental.json.Json
|
||||||
import java.nio.charset.StandardCharsets;
|
import elemental.json.JsonObject
|
||||||
import java.nio.file.Files;
|
import org.apache.commons.io.FileUtils
|
||||||
import java.nio.file.Path;
|
import org.apache.commons.io.IOUtils
|
||||||
import java.nio.file.Paths;
|
import org.slf4j.Logger
|
||||||
import java.util.Collection;
|
import org.slf4j.LoggerFactory
|
||||||
import java.util.Collections;
|
import java.io.*
|
||||||
import java.util.Enumeration;
|
import java.lang.reflect.InvocationTargetException
|
||||||
import java.util.HashSet;
|
import java.net.URL
|
||||||
import java.util.List;
|
import java.net.URLDecoder
|
||||||
import java.util.Set;
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.nio.file.Files
|
||||||
import java.util.concurrent.CompletionException;
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.Executor;
|
import java.nio.file.Paths
|
||||||
import java.util.regex.Matcher;
|
import java.util.*
|
||||||
import java.util.regex.Pattern;
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.stream.Collectors;
|
import java.util.concurrent.CompletionException
|
||||||
import java.util.stream.Stream;
|
import java.util.concurrent.Executor
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.regex.Pattern
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.stream.Collectors
|
||||||
|
import java.util.stream.Stream
|
||||||
import javax.servlet.ServletContext;
|
import java.util.zip.ZipEntry
|
||||||
import javax.servlet.ServletContextEvent;
|
import java.util.zip.ZipOutputStream
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.*
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.annotation.HandlesTypes
|
||||||
import javax.servlet.ServletRegistration;
|
import javax.servlet.annotation.WebListener
|
||||||
import javax.servlet.annotation.HandlesTypes;
|
|
||||||
import javax.servlet.annotation.WebListener;
|
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.vaadin.flow.component.WebComponentExporter;
|
|
||||||
import com.vaadin.flow.component.WebComponentExporterFactory;
|
|
||||||
import com.vaadin.flow.component.dependency.CssImport;
|
|
||||||
import com.vaadin.flow.component.dependency.JavaScript;
|
|
||||||
import com.vaadin.flow.component.dependency.JsModule;
|
|
||||||
import com.vaadin.flow.component.dependency.NpmPackage;
|
|
||||||
import com.vaadin.flow.function.DeploymentConfiguration;
|
|
||||||
import com.vaadin.flow.router.HasErrorParameter;
|
|
||||||
import com.vaadin.flow.router.Route;
|
|
||||||
import com.vaadin.flow.server.Constants;
|
|
||||||
import com.vaadin.flow.server.DevModeHandler;
|
|
||||||
import com.vaadin.flow.server.ExecutionFailedException;
|
|
||||||
import com.vaadin.flow.server.InitParameters;
|
|
||||||
import com.vaadin.flow.server.UIInitListener;
|
|
||||||
import com.vaadin.flow.server.VaadinContext;
|
|
||||||
import com.vaadin.flow.server.VaadinServiceInitListener;
|
|
||||||
import com.vaadin.flow.server.VaadinServlet;
|
|
||||||
import com.vaadin.flow.server.VaadinServletContext;
|
|
||||||
import com.vaadin.flow.server.frontend.FallbackChunk;
|
|
||||||
import com.vaadin.flow.server.frontend.FrontendUtils;
|
|
||||||
import com.vaadin.flow.server.frontend.NodeTasks;
|
|
||||||
import com.vaadin.flow.server.frontend.NodeTasks.Builder;
|
|
||||||
import com.vaadin.flow.server.frontend.scanner.ClassFinder.DefaultClassFinder;
|
|
||||||
import com.vaadin.flow.server.startup.ClassLoaderAwareServletContainerInitializer;
|
|
||||||
import com.vaadin.flow.server.startup.ServletDeployer.StubServletConfig;
|
|
||||||
import com.vaadin.flow.theme.NoTheme;
|
|
||||||
import com.vaadin.flow.theme.Theme;
|
|
||||||
|
|
||||||
import elemental.json.Json;
|
|
||||||
import elemental.json.JsonObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS IS COPIED DIRECTLY FROM VAADIN 14.6.8 (flow 2.4.6)
|
* THIS IS COPIED DIRECTLY FROM VAADIN 14.6.8 (flow 2.4.6)
|
||||||
@ -112,122 +74,124 @@ import elemental.json.JsonObject;
|
|||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
@HandlesTypes({Route.class, UIInitListener.class,
|
@HandlesTypes(
|
||||||
VaadinServiceInitListener.class, WebComponentExporter.class,
|
Route::class,
|
||||||
WebComponentExporterFactory.class, NpmPackage.class,
|
UIInitListener::class,
|
||||||
NpmPackage.Container.class, JsModule.class, JsModule.Container.class,
|
VaadinServiceInitListener::class,
|
||||||
CssImport.class, CssImport.Container.class, JavaScript.class,
|
WebComponentExporter::class,
|
||||||
JavaScript.Container.class, Theme.class, NoTheme.class,
|
WebComponentExporterFactory::class,
|
||||||
HasErrorParameter.class })
|
NpmPackage::class,
|
||||||
|
NpmPackage.Container::class,
|
||||||
|
JsModule::class,
|
||||||
|
JsModule.Container::class,
|
||||||
|
CssImport::class,
|
||||||
|
CssImport.Container::class,
|
||||||
|
JavaScript::class,
|
||||||
|
JavaScript.Container::class,
|
||||||
|
Theme::class,
|
||||||
|
NoTheme::class,
|
||||||
|
HasErrorParameter::class
|
||||||
|
)
|
||||||
@WebListener
|
@WebListener
|
||||||
public class DevModeInitializer
|
class DevModeInitializer : ClassLoaderAwareServletContainerInitializer, Serializable, ServletContextListener {
|
||||||
implements ClassLoaderAwareServletContainerInitializer, Serializable,
|
internal class DevModeClassFinder(classes: Set<Class<*>?>?) : DefaultClassFinder(classes) {
|
||||||
ServletContextListener {
|
companion object {
|
||||||
|
private val APPLICABLE_CLASS_NAMES = Collections.unmodifiableSet(calculateApplicableClassNames())
|
||||||
|
|
||||||
static class DevModeClassFinder extends DefaultClassFinder {
|
private fun calculateApplicableClassNames(): Set<String> {
|
||||||
|
val handlesTypes: HandlesTypes = DevModeInitializer::class.java.getAnnotation(HandlesTypes::class.java)
|
||||||
private static final Set<String> APPLICABLE_CLASS_NAMES = Collections
|
val values: Array<Class<Any>> = handlesTypes.value.map { (it as Any).javaClass }.toTypedArray()
|
||||||
.unmodifiableSet(calculateApplicableClassNames());
|
return Stream.of<Class<*>>(*values).map { obj: Class<*> -> obj.name }
|
||||||
|
.collect(Collectors.toSet())
|
||||||
public DevModeClassFinder(Set<Class<?>> classes) {
|
}
|
||||||
super(classes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun getAnnotatedClasses(annotation: Class<out Annotation?>): Set<Class<*>> {
|
||||||
public Set<Class<?>> getAnnotatedClasses(
|
ensureImplementation(annotation)
|
||||||
Class<? extends Annotation> annotation) {
|
return super.getAnnotatedClasses(annotation)
|
||||||
ensureImplementation(annotation);
|
|
||||||
return super.getAnnotatedClasses(annotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun <T> getSubTypesOf(type: Class<T>): Set<Class<out T>> {
|
||||||
public <T> Set<Class<? extends T>> getSubTypesOf(Class<T> type) {
|
ensureImplementation(type)
|
||||||
ensureImplementation(type);
|
return super.getSubTypesOf(type)
|
||||||
return super.getSubTypesOf(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureImplementation(Class<?> clazz) {
|
private fun ensureImplementation(clazz: Class<*>) {
|
||||||
if (!APPLICABLE_CLASS_NAMES.contains(clazz.getName())) {
|
require(APPLICABLE_CLASS_NAMES.contains(clazz.name)) {
|
||||||
throw new IllegalArgumentException("Unexpected class name "
|
("Unexpected class name "
|
||||||
+ clazz + ". Implementation error: the class finder "
|
+ clazz + ". Implementation error: the class finder "
|
||||||
+ "instance is not aware of this class. "
|
+ "instance is not aware of this class. "
|
||||||
+ "Fix @HandlesTypes annotation value for "
|
+ "Fix @HandlesTypes annotation value for "
|
||||||
+ DevModeInitializer.class.getName());
|
+ DevModeInitializer::class.java.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> calculateApplicableClassNames() {
|
@Throws(ServletException::class)
|
||||||
HandlesTypes handlesTypes = DevModeInitializer.class
|
override fun process(classes: Set<Class<*>?>?, context: ServletContext) {
|
||||||
.getAnnotation(HandlesTypes.class);
|
val registrations: Collection<ServletRegistration> = context.servletRegistrations.values
|
||||||
return Stream.of(handlesTypes.value()).map(Class::getName)
|
var vaadinServletRegistration: ServletRegistration? = null
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
for (registration in registrations) {
|
||||||
|
try {
|
||||||
|
if (registration.className != null && isVaadinServletSubClass(registration.className)) {
|
||||||
|
vaadinServletRegistration = registration
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
throw ServletException(
|
||||||
|
String.format(
|
||||||
|
"Servlet class name (%s) can't be found!",
|
||||||
|
registration.className
|
||||||
|
),
|
||||||
|
e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern JAR_FILE_REGEX = Pattern
|
val config = if (vaadinServletRegistration != null) {
|
||||||
.compile(".*file:(.+\\.jar).*");
|
StubServletConfig.createDeploymentConfiguration(context, vaadinServletRegistration, VaadinServlet::class.java)
|
||||||
|
} else {
|
||||||
|
StubServletConfig.createDeploymentConfiguration(context, VaadinServlet::class.java)
|
||||||
|
}
|
||||||
|
initDevModeHandler(classes, context, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ClassNotFoundException::class)
|
||||||
|
private fun isVaadinServletSubClass(className: String): Boolean {
|
||||||
|
return VaadinServlet::class.java.isAssignableFrom(Class.forName(className))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contextInitialized(ctx: ServletContextEvent) {
|
||||||
|
// No need to do anything on init
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contextDestroyed(ctx: ServletContextEvent) {
|
||||||
|
val handler = DevModeHandler.getDevModeHandler()
|
||||||
|
if (handler != null && !handler.reuseDevServer()) {
|
||||||
|
handler.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val JAR_FILE_REGEX = Pattern.compile(".*file:(.+\\.jar).*")
|
||||||
|
|
||||||
// Path of jar files in a URL with zip protocol doesn't start with "zip:"
|
// Path of jar files in a URL with zip protocol doesn't start with "zip:"
|
||||||
// nor "file:". It contains only the path of the file.
|
// nor "file:". It contains only the path of the file.
|
||||||
// Weblogic uses zip protocol.
|
// Weblogic uses zip protocol.
|
||||||
private static final Pattern ZIP_PROTOCOL_JAR_FILE_REGEX = Pattern
|
private val ZIP_PROTOCOL_JAR_FILE_REGEX = Pattern.compile("(.+\\.jar).*")
|
||||||
.compile("(.+\\.jar).*");
|
private val VFS_FILE_REGEX = Pattern.compile("(vfs:/.+\\.jar).*")
|
||||||
|
private val VFS_DIRECTORY_REGEX = Pattern.compile("vfs:/.+")
|
||||||
private static final Pattern VFS_FILE_REGEX = Pattern
|
|
||||||
.compile("(vfs:/.+\\.jar).*");
|
|
||||||
|
|
||||||
private static final Pattern VFS_DIRECTORY_REGEX = Pattern
|
|
||||||
.compile("vfs:/.+");
|
|
||||||
|
|
||||||
// allow trailing slash
|
// allow trailing slash
|
||||||
private static final Pattern DIR_REGEX_FRONTEND_DEFAULT = Pattern.compile(
|
private val DIR_REGEX_FRONTEND_DEFAULT = Pattern.compile("^(?:file:0)?(.+)" + Constants.RESOURCES_FRONTEND_DEFAULT + "/?$")
|
||||||
"^(?:file:0)?(.+)" + Constants.RESOURCES_FRONTEND_DEFAULT + "/?$");
|
|
||||||
|
|
||||||
// allow trailing slash
|
// allow trailing slash
|
||||||
private static final Pattern DIR_REGEX_COMPATIBILITY_FRONTEND_DEFAULT = Pattern
|
private val DIR_REGEX_COMPATIBILITY_FRONTEND_DEFAULT = Pattern.compile(
|
||||||
.compile("^(?:file:)?(.+)"
|
"^(?:file:)?(.+)"
|
||||||
+ Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT
|
+ Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT
|
||||||
+ "/?$");
|
+ "/?$"
|
||||||
|
)
|
||||||
@Override
|
|
||||||
public void process(Set<Class<?>> classes, ServletContext context)
|
|
||||||
throws ServletException {
|
|
||||||
Collection<? extends ServletRegistration> registrations = context
|
|
||||||
.getServletRegistrations().values();
|
|
||||||
|
|
||||||
ServletRegistration vaadinServletRegistration = null;
|
|
||||||
for (ServletRegistration registration : registrations) {
|
|
||||||
try {
|
|
||||||
if (registration.getClassName() != null
|
|
||||||
&& isVaadinServletSubClass(
|
|
||||||
registration.getClassName())) {
|
|
||||||
vaadinServletRegistration = registration;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new ServletException(
|
|
||||||
String.format("Servlet class name (%s) can't be found!",
|
|
||||||
registration.getClassName()),
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeploymentConfiguration config;
|
|
||||||
if (vaadinServletRegistration != null) {
|
|
||||||
config = StubServletConfig.createDeploymentConfiguration(context,
|
|
||||||
vaadinServletRegistration, VaadinServlet.class);
|
|
||||||
} else {
|
|
||||||
config = StubServletConfig.createDeploymentConfiguration(context,
|
|
||||||
VaadinServlet.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
initDevModeHandler(classes, context, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isVaadinServletSubClass(String className)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
return VaadinServlet.class.isAssignableFrom(Class.forName(className));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the devmode server if not in production mode or compatibility
|
* Initialize the devmode server if not in production mode or compatibility
|
||||||
@ -243,153 +207,128 @@ public class DevModeInitializer
|
|||||||
* @throws ServletException
|
* @throws ServletException
|
||||||
* if dev mode can't be initialized
|
* if dev mode can't be initialized
|
||||||
*/
|
*/
|
||||||
public static void initDevModeHandler(Set<Class<?>> classes,
|
@Throws(ServletException::class)
|
||||||
ServletContext context, DeploymentConfiguration config)
|
fun initDevModeHandler(classes: Set<Class<*>?>?, context: ServletContext?, config: DeploymentConfiguration) {
|
||||||
throws ServletException {
|
System.err.println("CUSTOM INIT!")
|
||||||
if (config.isProductionMode()) {
|
if (config.isProductionMode) {
|
||||||
log().debug("Skipping DEV MODE because PRODUCTION MODE is set.");
|
log().debug("Skipping DEV MODE because PRODUCTION MODE is set.")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (config.isCompatibilityMode()) {
|
if (config.isCompatibilityMode) {
|
||||||
log().debug("Skipping DEV MODE because BOWER MODE is set.");
|
log().debug("Skipping DEV MODE because BOWER MODE is set.")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (!config.enableDevServer()) {
|
if (!config.enableDevServer()) {
|
||||||
log().debug(
|
log().debug("Skipping DEV MODE because dev server shouldn't be enabled.")
|
||||||
"Skipping DEV MODE because dev server shouldn't be enabled.");
|
return
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String baseDir = config.getStringProperty(FrontendUtils.PROJECT_BASEDIR,
|
|
||||||
null);
|
|
||||||
if (baseDir == null) {
|
|
||||||
baseDir = getBaseDirectoryFallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
String generatedDir = System.getProperty(PARAM_GENERATED_DIR,
|
val baseDir = config.getStringProperty(FrontendUtils.PROJECT_BASEDIR, null) ?: baseDirectoryFallback
|
||||||
DEFAULT_GENERATED_DIR);
|
val generatedDir = System.getProperty(FrontendUtils.PARAM_GENERATED_DIR, FrontendUtils.DEFAULT_GENERATED_DIR)
|
||||||
String frontendFolder = config.getStringProperty(PARAM_FRONTEND_DIR,
|
|
||||||
System.getProperty(PARAM_FRONTEND_DIR, DEFAULT_FRONTEND_DIR));
|
|
||||||
|
|
||||||
Builder builder = new Builder(new DevModeClassFinder(classes),
|
val frontendFolder = config.getStringProperty(FrontendUtils.PARAM_FRONTEND_DIR,
|
||||||
new File(baseDir), new File(generatedDir),
|
System.getProperty(FrontendUtils.PARAM_FRONTEND_DIR, FrontendUtils.DEFAULT_FRONTEND_DIR))
|
||||||
new File(frontendFolder));
|
|
||||||
|
|
||||||
log().info("Starting dev-mode updaters in {} folder.",
|
val builder = NodeTasks.Builder(DevModeClassFinder(classes), File(baseDir), File(generatedDir), File(frontendFolder))
|
||||||
builder.npmFolder);
|
|
||||||
|
|
||||||
|
log().info("Starting dev-mode updaters in {} folder.", builder.npmFolder)
|
||||||
if (!builder.generatedFolder.exists()) {
|
if (!builder.generatedFolder.exists()) {
|
||||||
try {
|
try {
|
||||||
FileUtils.forceMkdir(builder.generatedFolder);
|
FileUtils.forceMkdir(builder.generatedFolder)
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
throw new UncheckedIOException(
|
throw UncheckedIOException(
|
||||||
String.format("Failed to create directory '%s'",
|
String.format(
|
||||||
builder.generatedFolder),
|
"Failed to create directory '%s'",
|
||||||
e);
|
builder.generatedFolder
|
||||||
|
),
|
||||||
|
e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val generatedPackages = File(builder.generatedFolder, Constants.PACKAGE_JSON)
|
||||||
File generatedPackages = new File(builder.generatedFolder,
|
|
||||||
PACKAGE_JSON);
|
|
||||||
|
|
||||||
// If we are missing the generated webpack configuration then generate
|
// If we are missing the generated webpack configuration then generate
|
||||||
// webpack configurations
|
// webpack configurations
|
||||||
if (!new File(builder.npmFolder, WEBPACK_GENERATED).exists()) {
|
if (!File(builder.npmFolder, FrontendUtils.WEBPACK_GENERATED).exists()) {
|
||||||
builder.withWebpack(builder.npmFolder, FrontendUtils.WEBPACK_CONFIG,
|
builder.withWebpack(builder.npmFolder, FrontendUtils.WEBPACK_CONFIG, FrontendUtils.WEBPACK_GENERATED)
|
||||||
FrontendUtils.WEBPACK_GENERATED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are missing either the base or generated package json files
|
// If we are missing either the base or generated package json files
|
||||||
// generate those
|
// generate those
|
||||||
if (!new File(builder.npmFolder, PACKAGE_JSON).exists()
|
if (!File(builder.npmFolder, Constants.PACKAGE_JSON).exists() || !generatedPackages.exists()) {
|
||||||
|| !generatedPackages.exists()) {
|
builder.createMissingPackageJson(true)
|
||||||
builder.createMissingPackageJson(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<File> frontendLocations = getFrontendLocationsFromClassloader(
|
val frontendLocations = getFrontendLocationsFromClassloader(DevModeInitializer::class.java.classLoader)
|
||||||
DevModeInitializer.class.getClassLoader());
|
val useByteCodeScanner = config.getBooleanProperty(
|
||||||
|
InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE,
|
||||||
|
java.lang.Boolean.parseBoolean(
|
||||||
|
System.getProperty(
|
||||||
|
InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE,
|
||||||
|
java.lang.Boolean.FALSE.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
boolean useByteCodeScanner = config.getBooleanProperty(
|
val enablePnpm = config.isPnpmEnabled
|
||||||
SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE,
|
val useHomeNodeExec = config.getBooleanProperty(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, false)
|
||||||
Boolean.parseBoolean(System.getProperty(
|
val vaadinContext: VaadinContext = VaadinServletContext(context)
|
||||||
SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE,
|
val tokenFileData = Json.createObject()
|
||||||
Boolean.FALSE.toString())));
|
|
||||||
|
|
||||||
boolean enablePnpm = config.isPnpmEnabled();
|
|
||||||
|
|
||||||
boolean useHomeNodeExec = config.getBooleanProperty(
|
|
||||||
InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, false);
|
|
||||||
|
|
||||||
VaadinContext vaadinContext = new VaadinServletContext(context);
|
|
||||||
JsonObject tokenFileData = Json.createObject();
|
|
||||||
try {
|
try {
|
||||||
builder.enablePackagesUpdate(true)
|
builder.enablePackagesUpdate(true)
|
||||||
.useByteCodeScanner(useByteCodeScanner)
|
.useByteCodeScanner(useByteCodeScanner)
|
||||||
.copyResources(frontendLocations)
|
.copyResources(frontendLocations)
|
||||||
.copyLocalResources(new File(baseDir,
|
.copyLocalResources(File(baseDir, Constants.LOCAL_FRONTEND_RESOURCES_PATH))
|
||||||
Constants.LOCAL_FRONTEND_RESOURCES_PATH))
|
|
||||||
.enableImportsUpdate(true).runNpmInstall(true)
|
.enableImportsUpdate(true).runNpmInstall(true)
|
||||||
.populateTokenFileData(tokenFileData)
|
.populateTokenFileData(tokenFileData)
|
||||||
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
|
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
|
||||||
.withHomeNodeExecRequired(useHomeNodeExec).build()
|
.withHomeNodeExecRequired(useHomeNodeExec).build()
|
||||||
.execute();
|
.execute()
|
||||||
|
|
||||||
FallbackChunk chunk = FrontendUtils
|
val chunk = FrontendUtils.readFallbackChunk(tokenFileData)
|
||||||
.readFallbackChunk(tokenFileData);
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
vaadinContext.setAttribute(chunk);
|
vaadinContext.setAttribute(chunk)
|
||||||
}
|
}
|
||||||
} catch (ExecutionFailedException exception) {
|
} catch (exception: ExecutionFailedException) {
|
||||||
log().debug(
|
log().debug("Could not initialize dev mode handler. One of the node tasks failed", exception)
|
||||||
"Could not initialize dev mode handler. One of the node tasks failed",
|
throw ServletException(exception)
|
||||||
exception);
|
|
||||||
throw new ServletException(exception);
|
|
||||||
}
|
}
|
||||||
|
val tasks = builder.enablePackagesUpdate(true)
|
||||||
NodeTasks tasks = builder.enablePackagesUpdate(true)
|
|
||||||
.useByteCodeScanner(useByteCodeScanner)
|
.useByteCodeScanner(useByteCodeScanner)
|
||||||
.copyResources(frontendLocations)
|
.copyResources(frontendLocations)
|
||||||
.copyLocalResources(new File(baseDir,
|
.copyLocalResources(File(baseDir, Constants.LOCAL_FRONTEND_RESOURCES_PATH))
|
||||||
Constants.LOCAL_FRONTEND_RESOURCES_PATH))
|
|
||||||
.enableImportsUpdate(true).runNpmInstall(true)
|
.enableImportsUpdate(true).runNpmInstall(true)
|
||||||
.populateTokenFileData(tokenFileData)
|
.populateTokenFileData(tokenFileData)
|
||||||
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
|
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
|
||||||
.withHomeNodeExecRequired(useHomeNodeExec).build();
|
.withHomeNodeExecRequired(useHomeNodeExec).build()
|
||||||
|
|
||||||
// Check whether executor is provided by the caller (framework)
|
// Check whether executor is provided by the caller (framework)
|
||||||
Object service = config.getInitParameters().get(Executor.class);
|
val service = config.initParameters[Executor::class.java]
|
||||||
|
val runnable = Runnable {
|
||||||
|
runNodeTasks(
|
||||||
|
vaadinContext, tokenFileData,
|
||||||
|
tasks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Runnable runnable = () -> runNodeTasks(vaadinContext, tokenFileData,
|
val nodeTasksFuture =
|
||||||
tasks);
|
if (service is Executor) {
|
||||||
|
|
||||||
CompletableFuture<Void> nodeTasksFuture;
|
|
||||||
if (service instanceof Executor) {
|
|
||||||
// if there is an executor use it to run the task
|
// if there is an executor use it to run the task
|
||||||
nodeTasksFuture = CompletableFuture.runAsync(runnable,
|
CompletableFuture.runAsync(
|
||||||
(Executor) service);
|
runnable,
|
||||||
|
service as Executor?
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
nodeTasksFuture = CompletableFuture.runAsync(runnable);
|
CompletableFuture.runAsync(runnable)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DevModeHandler.start(config, builder.npmFolder, nodeTasksFuture);
|
DevModeHandler.start(config, builder.npmFolder, nodeTasksFuture)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Logger log() {
|
private fun log(): Logger {
|
||||||
return LoggerFactory.getLogger(DevModeInitializer.class);
|
return LoggerFactory.getLogger(DevModeInitializer::class.java)
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextInitialized(ServletContextEvent ctx) {
|
|
||||||
// No need to do anything on init
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextDestroyed(ServletContextEvent ctx) {
|
|
||||||
DevModeHandler handler = DevModeHandler.getDevModeHandler();
|
|
||||||
if (handler != null && !handler.reuseDevServer()) {
|
|
||||||
handler.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -397,22 +336,27 @@ public class DevModeInitializer
|
|||||||
* Maven or Gradle project. Check to avoid cluttering server directories
|
* Maven or Gradle project. Check to avoid cluttering server directories
|
||||||
* (see tickets #8249, #8403).
|
* (see tickets #8249, #8403).
|
||||||
*/
|
*/
|
||||||
private static String getBaseDirectoryFallback() {
|
private val baseDirectoryFallback: String
|
||||||
String baseDirCandidate = System.getProperty("user.dir", ".");
|
private get() {
|
||||||
Path path = Paths.get(baseDirCandidate);
|
val baseDirCandidate = System.getProperty("user.dir", ".")
|
||||||
if (path.toFile().isDirectory()
|
val path = Paths.get(baseDirCandidate)
|
||||||
|
return if (path.toFile().isDirectory
|
||||||
&& (path.resolve("pom.xml").toFile().exists()
|
&& (path.resolve("pom.xml").toFile().exists()
|
||||||
|| path.resolve("build.gradle").toFile().exists())) {
|
|| path.resolve("build.gradle").toFile().exists())
|
||||||
return path.toString();
|
) {
|
||||||
|
path.toString()
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(String.format(
|
throw IllegalStateException(
|
||||||
|
String.format(
|
||||||
"Failed to determine project directory for dev mode. "
|
"Failed to determine project directory for dev mode. "
|
||||||
+ "Directory '%s' does not look like a Maven or "
|
+ "Directory '%s' does not look like a Maven or "
|
||||||
+ "Gradle project. Ensure that you have run the "
|
+ "Gradle project. Ensure that you have run the "
|
||||||
+ "prepare-frontend Maven goal, which generates "
|
+ "prepare-frontend Maven goal, which generates "
|
||||||
+ "'flow-build-info.json', prior to deploying your "
|
+ "'flow-build-info.json', prior to deploying your "
|
||||||
+ "application",
|
+ "application",
|
||||||
path.toString()));
|
path.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,174 +365,162 @@ public class DevModeInitializer
|
|||||||
* META-INF/resources/frontend folder. We don't use URLClassLoader because
|
* META-INF/resources/frontend folder. We don't use URLClassLoader because
|
||||||
* will fail in Java 9+
|
* will fail in Java 9+
|
||||||
*/
|
*/
|
||||||
static Set<File> getFrontendLocationsFromClassloader(
|
@Throws(ServletException::class)
|
||||||
ClassLoader classLoader) throws ServletException {
|
fun getFrontendLocationsFromClassloader(classLoader: ClassLoader): Set<File> {
|
||||||
Set<File> frontendFiles = new HashSet<>();
|
val frontendFiles: MutableSet<File> = HashSet()
|
||||||
frontendFiles.addAll(getFrontendLocationsFromClassloader(classLoader,
|
frontendFiles.addAll(
|
||||||
Constants.RESOURCES_FRONTEND_DEFAULT));
|
getFrontendLocationsFromClassloader(
|
||||||
frontendFiles.addAll(getFrontendLocationsFromClassloader(classLoader,
|
classLoader,
|
||||||
Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT));
|
Constants.RESOURCES_FRONTEND_DEFAULT
|
||||||
return frontendFiles;
|
)
|
||||||
|
)
|
||||||
|
frontendFiles.addAll(
|
||||||
|
getFrontendLocationsFromClassloader(
|
||||||
|
classLoader,
|
||||||
|
Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return frontendFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void runNodeTasks(VaadinContext vaadinContext,
|
|
||||||
JsonObject tokenFileData, NodeTasks tasks) {
|
|
||||||
try {
|
|
||||||
tasks.execute();
|
|
||||||
|
|
||||||
FallbackChunk chunk = FrontendUtils
|
private fun runNodeTasks(vaadinContext: VaadinContext, tokenFileData: JsonObject, tasks: NodeTasks) {
|
||||||
.readFallbackChunk(tokenFileData);
|
try {
|
||||||
|
tasks.execute()
|
||||||
|
val chunk = FrontendUtils.readFallbackChunk(tokenFileData)
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
vaadinContext.setAttribute(chunk);
|
vaadinContext.setAttribute(chunk)
|
||||||
}
|
}
|
||||||
} catch (ExecutionFailedException exception) {
|
} catch (exception: ExecutionFailedException) {
|
||||||
log().debug(
|
log().debug("Could not initialize dev mode handler. One of the node tasks failed", exception)
|
||||||
"Could not initialize dev mode handler. One of the node tasks failed",
|
throw CompletionException(exception)
|
||||||
exception);
|
|
||||||
throw new CompletionException(exception);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<File> getFrontendLocationsFromClassloader(
|
@Throws(ServletException::class)
|
||||||
ClassLoader classLoader, String resourcesFolder)
|
private fun getFrontendLocationsFromClassloader(classLoader: ClassLoader, resourcesFolder: String): Set<File> {
|
||||||
throws ServletException {
|
val frontendFiles: MutableSet<File> = HashSet()
|
||||||
Set<File> frontendFiles = new HashSet<>();
|
|
||||||
try {
|
try {
|
||||||
Enumeration<URL> en = classLoader.getResources(resourcesFolder);
|
val en = classLoader.getResources(resourcesFolder) ?: return frontendFiles
|
||||||
if (en == null) {
|
val vfsJars: MutableSet<String> = HashSet()
|
||||||
return frontendFiles;
|
|
||||||
}
|
|
||||||
Set<String> vfsJars = new HashSet<>();
|
|
||||||
while (en.hasMoreElements()) {
|
while (en.hasMoreElements()) {
|
||||||
URL url = en.nextElement();
|
val url = en.nextElement()
|
||||||
String urlString = url.toString();
|
val urlString = url.toString()
|
||||||
|
val path = URLDecoder.decode(url.path, StandardCharsets.UTF_8.name())
|
||||||
|
|
||||||
|
val jarMatcher = JAR_FILE_REGEX.matcher(path)
|
||||||
|
val zipProtocolJarMatcher = ZIP_PROTOCOL_JAR_FILE_REGEX.matcher(path)
|
||||||
|
val dirMatcher = DIR_REGEX_FRONTEND_DEFAULT.matcher(path)
|
||||||
|
val dirCompatibilityMatcher = DIR_REGEX_COMPATIBILITY_FRONTEND_DEFAULT.matcher(path)
|
||||||
|
val jarVfsMatcher = VFS_FILE_REGEX.matcher(urlString)
|
||||||
|
val dirVfsMatcher = VFS_DIRECTORY_REGEX.matcher(urlString)
|
||||||
|
|
||||||
String path = URLDecoder.decode(url.getPath(),
|
|
||||||
StandardCharsets.UTF_8.name());
|
|
||||||
Matcher jarMatcher = JAR_FILE_REGEX.matcher(path);
|
|
||||||
Matcher zipProtocolJarMatcher = ZIP_PROTOCOL_JAR_FILE_REGEX
|
|
||||||
.matcher(path);
|
|
||||||
Matcher dirMatcher = DIR_REGEX_FRONTEND_DEFAULT.matcher(path);
|
|
||||||
Matcher dirCompatibilityMatcher = DIR_REGEX_COMPATIBILITY_FRONTEND_DEFAULT
|
|
||||||
.matcher(path);
|
|
||||||
Matcher jarVfsMatcher = VFS_FILE_REGEX.matcher(urlString);
|
|
||||||
Matcher dirVfsMatcher = VFS_DIRECTORY_REGEX.matcher(urlString);
|
|
||||||
if (jarVfsMatcher.find()) {
|
if (jarVfsMatcher.find()) {
|
||||||
String vfsJar = jarVfsMatcher.group(1);
|
val vfsJar = jarVfsMatcher.group(1)
|
||||||
if (vfsJars.add(vfsJar))
|
if (vfsJars.add(vfsJar)) frontendFiles.add(
|
||||||
frontendFiles.add(
|
getPhysicalFileOfJBossVfsJar(URL(vfsJar))
|
||||||
getPhysicalFileOfJBossVfsJar(new URL(vfsJar)));
|
)
|
||||||
} else if (dirVfsMatcher.find()) {
|
} else if (dirVfsMatcher.find()) {
|
||||||
URL vfsDirUrl = new URL(urlString.substring(0,
|
val vfsDirUrl = URL(
|
||||||
urlString.lastIndexOf(resourcesFolder)));
|
urlString.substring(0,urlString.lastIndexOf(resourcesFolder)
|
||||||
frontendFiles
|
)
|
||||||
.add(getPhysicalFileOfJBossVfsDirectory(vfsDirUrl));
|
)
|
||||||
|
frontendFiles.add(getPhysicalFileOfJBossVfsDirectory(vfsDirUrl))
|
||||||
} else if (jarMatcher.find()) {
|
} else if (jarMatcher.find()) {
|
||||||
frontendFiles.add(new File(jarMatcher.group(1)));
|
frontendFiles.add(File(jarMatcher.group(1)))
|
||||||
} else if ("zip".equalsIgnoreCase(url.getProtocol())
|
} else if ("zip".equals(url.protocol, ignoreCase = true) && zipProtocolJarMatcher.find()
|
||||||
&& zipProtocolJarMatcher.find()) {
|
) {
|
||||||
frontendFiles.add(new File(zipProtocolJarMatcher.group(1)));
|
frontendFiles.add(File(zipProtocolJarMatcher.group(1)))
|
||||||
} else if (dirMatcher.find()) {
|
} else if (dirMatcher.find()) {
|
||||||
frontendFiles.add(new File(dirMatcher.group(1)));
|
frontendFiles.add(File(dirMatcher.group(1)))
|
||||||
} else if (dirCompatibilityMatcher.find()) {
|
} else if (dirCompatibilityMatcher.find()) {
|
||||||
frontendFiles
|
frontendFiles.add(File(dirCompatibilityMatcher.group(1)))
|
||||||
.add(new File(dirCompatibilityMatcher.group(1)));
|
|
||||||
} else {
|
} else {
|
||||||
log().warn(
|
log().warn("Resource {} not visited because does not meet supported formats.", url.path)
|
||||||
"Resource {} not visited because does not meet supported formats.",
|
|
||||||
url.getPath());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
throw new UncheckedIOException(e);
|
throw UncheckedIOException(e)
|
||||||
|
}
|
||||||
|
return frontendFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
return frontendFiles;
|
@Throws(IOException::class, ServletException::class)
|
||||||
}
|
private fun getPhysicalFileOfJBossVfsDirectory(url: URL): File {
|
||||||
|
return try {
|
||||||
private static File getPhysicalFileOfJBossVfsDirectory(URL url)
|
val virtualFile = url.openConnection().content
|
||||||
throws IOException, ServletException {
|
val virtualFileClass: Class<*> = virtualFile.javaClass
|
||||||
try {
|
|
||||||
Object virtualFile = url.openConnection().getContent();
|
|
||||||
Class virtualFileClass = virtualFile.getClass();
|
|
||||||
|
|
||||||
// Reflection as we cannot afford a dependency to WildFly or JBoss
|
// Reflection as we cannot afford a dependency to WildFly or JBoss
|
||||||
Method getChildrenRecursivelyMethod = virtualFileClass
|
val getChildrenRecursivelyMethod = virtualFileClass.getMethod("getChildrenRecursively")
|
||||||
.getMethod("getChildrenRecursively");
|
val getPhysicalFileMethod = virtualFileClass.getMethod("getPhysicalFile")
|
||||||
Method getPhysicalFileMethod = virtualFileClass
|
|
||||||
.getMethod("getPhysicalFile");
|
|
||||||
|
|
||||||
// By calling getPhysicalFile, we make sure that the corresponding
|
// By calling getPhysicalFile, we make sure that the corresponding
|
||||||
// physical files/directories of the root directory and its children
|
// physical files/directories of the root directory and its children
|
||||||
// are created. Later, these physical files are scanned to collect
|
// are created. Later, these physical files are scanned to collect
|
||||||
// their resources.
|
// their resources.
|
||||||
List virtualFiles = (List) getChildrenRecursivelyMethod
|
val virtualFiles = getChildrenRecursivelyMethod.invoke(virtualFile) as List<*>
|
||||||
.invoke(virtualFile);
|
val rootDirectory = getPhysicalFileMethod.invoke(virtualFile) as File
|
||||||
File rootDirectory = (File) getPhysicalFileMethod
|
for (child in virtualFiles) {
|
||||||
.invoke(virtualFile);
|
|
||||||
for (Object child : virtualFiles) {
|
|
||||||
// side effect: create real-world files
|
// side effect: create real-world files
|
||||||
getPhysicalFileMethod.invoke(child);
|
getPhysicalFileMethod.invoke(child)
|
||||||
}
|
}
|
||||||
return rootDirectory;
|
rootDirectory
|
||||||
} catch (NoSuchMethodException | IllegalAccessException
|
} catch (exc: NoSuchMethodException) {
|
||||||
| InvocationTargetException exc) {
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
throw new ServletException("Failed to invoke JBoss VFS API.", exc);
|
} catch (exc: IllegalAccessException) {
|
||||||
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
|
} catch (exc: InvocationTargetException) {
|
||||||
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File getPhysicalFileOfJBossVfsJar(URL url)
|
@Throws(IOException::class, ServletException::class)
|
||||||
throws IOException, ServletException {
|
private fun getPhysicalFileOfJBossVfsJar(url: URL): File {
|
||||||
try {
|
return try {
|
||||||
Object jarVirtualFile = url.openConnection().getContent();
|
val jarVirtualFile = url.openConnection().content
|
||||||
|
|
||||||
// Creating a temporary jar file out of the vfs files
|
// Creating a temporary jar file out of the vfs files
|
||||||
String vfsJarPath = url.toString();
|
val vfsJarPath = url.toString()
|
||||||
String fileNamePrefix = vfsJarPath.substring(
|
val fileNamePrefix = vfsJarPath.substring(vfsJarPath.lastIndexOf('/') + 1, vfsJarPath.lastIndexOf(".jar"))
|
||||||
vfsJarPath.lastIndexOf('/') + 1,
|
val tempJar = Files.createTempFile(fileNamePrefix, ".jar")
|
||||||
vfsJarPath.lastIndexOf(".jar"));
|
generateJarFromJBossVfsFolder(jarVirtualFile, tempJar)
|
||||||
Path tempJar = Files.createTempFile(fileNamePrefix, ".jar");
|
|
||||||
|
|
||||||
generateJarFromJBossVfsFolder(jarVirtualFile, tempJar);
|
val tempJarFile = tempJar.toFile()
|
||||||
|
tempJarFile.deleteOnExit()
|
||||||
File tempJarFile = tempJar.toFile();
|
tempJarFile
|
||||||
tempJarFile.deleteOnExit();
|
} catch (exc: NoSuchMethodException) {
|
||||||
return tempJarFile;
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
} catch (NoSuchMethodException | IllegalAccessException
|
} catch (exc: IllegalAccessException) {
|
||||||
| InvocationTargetException exc) {
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
throw new ServletException("Failed to invoke JBoss VFS API.", exc);
|
} catch (exc: InvocationTargetException) {
|
||||||
|
throw ServletException("Failed to invoke JBoss VFS API.", exc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateJarFromJBossVfsFolder(Object jarVirtualFile,
|
@Throws(IOException::class, IllegalAccessException::class, InvocationTargetException::class, NoSuchMethodException::class)
|
||||||
Path tempJar) throws IOException, IllegalAccessException,
|
private fun generateJarFromJBossVfsFolder(jarVirtualFile: Any, tempJar: Path) {
|
||||||
InvocationTargetException, NoSuchMethodException {
|
|
||||||
// We should use reflection to use JBoss VFS API as we cannot afford a
|
// We should use reflection to use JBoss VFS API as we cannot afford a
|
||||||
// dependency to WildFly or JBoss
|
// dependency to WildFly or JBoss
|
||||||
Class virtualFileClass = jarVirtualFile.getClass();
|
val virtualFileClass: Class<*> = jarVirtualFile.javaClass
|
||||||
Method getChildrenRecursivelyMethod = virtualFileClass
|
val getChildrenRecursivelyMethod = virtualFileClass.getMethod("getChildrenRecursively")
|
||||||
.getMethod("getChildrenRecursively");
|
val openStreamMethod = virtualFileClass.getMethod("openStream")
|
||||||
Method openStreamMethod = virtualFileClass.getMethod("openStream");
|
val isFileMethod = virtualFileClass.getMethod("isFile")
|
||||||
Method isFileMethod = virtualFileClass.getMethod("isFile");
|
val getPathNameRelativeToMethod = virtualFileClass.getMethod("getPathNameRelativeTo", virtualFileClass)
|
||||||
Method getPathNameRelativeToMethod = virtualFileClass
|
val jarVirtualChildren = getChildrenRecursivelyMethod.invoke(jarVirtualFile) as List<*>
|
||||||
.getMethod("getPathNameRelativeTo", virtualFileClass);
|
ZipOutputStream(Files.newOutputStream(tempJar)).use { zipOutputStream ->
|
||||||
|
for (child in jarVirtualChildren) {
|
||||||
|
if (!(isFileMethod.invoke(child) as Boolean)) continue
|
||||||
|
|
||||||
List jarVirtualChildren = (List) getChildrenRecursivelyMethod
|
val relativePath = getPathNameRelativeToMethod.invoke(child, jarVirtualFile) as String
|
||||||
.invoke(jarVirtualFile);
|
|
||||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(
|
|
||||||
Files.newOutputStream(tempJar))) {
|
|
||||||
for (Object child : jarVirtualChildren) {
|
|
||||||
if (!(Boolean) isFileMethod.invoke(child))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
String relativePath = (String) getPathNameRelativeToMethod
|
val inputStream = openStreamMethod.invoke(child) as InputStream
|
||||||
.invoke(child, jarVirtualFile);
|
|
||||||
InputStream inputStream = (InputStream) openStreamMethod
|
val zipEntry = ZipEntry(relativePath)
|
||||||
.invoke(child);
|
zipOutputStream.putNextEntry(zipEntry)
|
||||||
ZipEntry zipEntry = new ZipEntry(relativePath);
|
IOUtils.copy(inputStream, zipOutputStream)
|
||||||
zipOutputStream.putNextEntry(zipEntry);
|
zipOutputStream.closeEntry()
|
||||||
IOUtils.copy(inputStream, zipOutputStream);
|
}
|
||||||
zipOutputStream.closeEntry();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user