/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jooby.run;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URI;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import org.jboss.modules.DependencySpec;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;
import org.jboss.modules.ModuleLoader;
import org.jboss.modules.ModuleSpec;
import org.jboss.modules.ResourceLoaderSpec;
import org.jboss.modules.ResourceLoaders;
public class AppModuleLoader extends ModuleLoader {
private Map<ModuleIdentifier, ModuleSpec> modules;
public AppModuleLoader(final Map<ModuleIdentifier, ModuleSpec> modules) {
this.modules = modules;
}
@Override
protected ModuleSpec findModule(final ModuleIdentifier moduleId) throws ModuleLoadException {
ModuleSpec spec = modules.get(moduleId);
return spec == null ? super.findModule(moduleId) : spec;
}
public void unload(final Module module) {
super.unloadModuleLocal(module);
}
/**
* Build a flat jboss module, with some minor exceptions (like j2v8).
*
* @param name module name.
* @param cp Classpath.
* @return A new app module loader.
* @throws Exception If something goes wrong.
*/
public static AppModuleLoader build(final String name, final File... cp) throws Exception {
Map<ModuleIdentifier, ModuleSpec> modules = newModule(name, 0, "", cp);
return new AppModuleLoader(modules);
}
private static Map<ModuleIdentifier, ModuleSpec> newModule(final String name,
final int level, final String prefix, final File... cp) throws Exception {
Map<ModuleIdentifier, ModuleSpec> modules = new HashMap<>();
String mId = name.replace(".jar", "");
ModuleSpec.Builder builder = ModuleSpec.build(ModuleIdentifier.fromString(mId));
if (level == 0) {
String classurl = AppModuleLoader.class
.getResource("/" + Main.JOOBY_REF.replace(".", "/") + ".class")
.toString();
String jartoken = ".jar!";
File jar = new File(URI
.create(classurl.substring(0, classurl.indexOf(jartoken) + jartoken.length() - 1)
.replace("jar:", "")));
Main.debug("loading hack: %s?%s", jar, jar.exists());
builder.addResourceRoot(ResourceLoaderSpec
.createResourceLoaderSpec(ResourceLoaders
.createJarResourceLoader("jooby-run", new JarFile(jar))));
}
int l = (prefix.length() + mId.length() + level);
Main.debug("%1$" + l + "s", prefix + mId);
for (File file : cp) {
if (file.getName().endsWith(".pom")) {
// skip pom(s)
continue;
}
if (!file.exists()) {
// skip missing file/dir
continue;
}
String fname = "└── " + file.getAbsolutePath();
if (file.getName().startsWith("j2v8") && !name.equals(file.getName())) {
ModuleSpec dependency = newModule(file.getName(), level + 2, "└── ", file)
.values()
.iterator()
.next();
builder.addDependency(
DependencySpec.createModuleDependencySpec(dependency.getModuleIdentifier()));
modules.put(dependency.getModuleIdentifier(), dependency);
} else {
Main.debug("%1$" + (fname.length() + level + 2) + "s", fname);
if (file.getName().endsWith(".jar")) {
builder.addResourceRoot(ResourceLoaderSpec
.createResourceLoaderSpec(ResourceLoaders
.createJarResourceLoader(file.getName(), new JarFile(file))));
} else {
builder.addResourceRoot(ResourceLoaderSpec
.createResourceLoaderSpec(ResourceLoaders
.createFileResourceLoader(file.getName(), file)));
}
}
}
Set<String> sysPaths = sysPaths();
Main.trace("system packages:");
sysPaths.forEach(p -> Main.trace(" %s", p));
builder.addDependency(DependencySpec.createSystemDependencySpec(sysPaths));
builder.addDependency(DependencySpec.createLocalDependencySpec());
ModuleSpec module = builder.create();
modules.put(module.getModuleIdentifier(), builder.create());
return modules;
}
@SuppressWarnings({"rawtypes", "unchecked" })
private static Set<String> jdkPaths() throws Exception {
Class jdkPath = AppModuleLoader.class.getClassLoader().loadClass("org.jboss.modules.JDKPaths");
Field field = jdkPath.getDeclaredField("JDK");
field.setAccessible(true);
return (Set<String>) field.get(null);
}
private static Set<String> sysPaths() throws Exception {
Set<String> pkgs = new LinkedHashSet<>();
pkgs.addAll(jdkPaths());
pkgs.addAll(pkgs(new InputStreamReader(Main.class.getResourceAsStream("pkgs"))));
/**
* Hack to let users to configure system packages, javax.transaction cause issues with
* hibernate.
*/
pkgs.addAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.includes").toFile()));
pkgs.removeAll(pkgs(Paths.get("src", "etc", "jboss-modules", "pkgs.excludes").toFile()));
return pkgs;
}
private static Set<String> pkgs(final File file) throws IOException {
if (file.exists()) {
return pkgs(new FileReader(file));
}
return new LinkedHashSet<>();
}
private static Set<String> pkgs(final Reader reader) throws IOException {
try (BufferedReader in = new BufferedReader(reader)) {
Set<String> pkgs = new LinkedHashSet<>();
String line = in.readLine();
while (line != null) {
pkgs.add(line.trim());
line = in.readLine();
}
return pkgs;
}
}
public static void main(final String[] args) throws MalformedURLException {
URI jaruri = URI.create(
"jar:file:/Users/edgar/.m2/repository/org/jooby/jooby-run/1.0.4-SNAPSHOT/jooby-run-1.0.4-SNAPSHOT.jar!/org/jooby/internal/run__/JoobyRef.class");
System.out.println(jaruri.toURL().toExternalForm());
}
}