How to mask system modules at runtime? - java-9

I want to create a module layer configuration at runtime, that consists of a subset of system modules provided by a default JRE. Basically the same as what you can achieve with jlink -- but at runtime.
The following snippets show the outline of my current non-working solution. The calling block looks like:
ClassLoader loader = createCustomClassLoader("java.base", "java.logging");
assertNotNull(loader.loadClass("java.util.logging.Logger"));
assertThrows(Exception.class, () -> loader.loadClass("javax.script.ScriptEngine"));
The ClassLoader factory is:
private ClassLoader createTestClassLoader(String... rootNames) {
ModuleFinder before = ModuleFinder.of();
List<Configuration> parents = List.of(ModuleLayer.boot().configuration());
ModuleFinder after = ModuleFinder.of();
Configuration configuration = Configuration.resolve(before, parents, after, Arrays.asList(rootNames));
ClassLoader parentLoader = ClassLoader.getSystemClassLoader();
ModuleLayer configuredLayer = ModuleLayer.boot().defineModulesWithOneLoader(configuration, parentLoader);
ClassLoader classLoader = configuredLayer.findLoader(rootNames[rootNames.length-1]);
assertNotNull(classLoader); // classLoader is null (***)
classLoader.setDefaultAssertionStatus(true); // -ea
return classLoader;
}
Is this masking of system modules possible at runtime? If yes, how?

Related

Configure streamCaching in camel.Main

We have an XML configuration with Camel routes that includes this bean to configure spooling to disk for large messages:
<streamCaching id="diskSpoolConfig" bufferSize="16384" spoolEnabled="true" spoolThreshold="10000000"/>
I'd like to configure Camel so streamCaching uses disk-spooling automatically, without having to specify this in the XML config. The Camel instance is started from a JAR with
Main main = new Main();
main.setApplicationContextUri("file:routes.xml");
main.run();
I found doc about application.properties and set
camel.main.streamCachingSpoolEnabled=true
but I'm unclear where this file needs to reside in the JAR so it gets read. I also tried with
Main main = new Main();
main.addMainListener(new MainListenerSupport() {
public void beforeConfigure(BaseMainSupport main) {
CamelContext context = main.getCamelContext();
context.setStreamCaching(true);
context.getStreamCachingStrategy().setSpoolEnabled(true);
context.getStreamCachingStrategy().setSpoolThreshold(10 * 1024 * 1024);
}
});
main.setApplicationContextUri("file:routes.xml");
main.run();
That was also ineffectual. Maybe it gets applied too late? Because for example when I set context.getShutdownStrategy().setTimeout(5); in beforeConfigure(), it has an effect.
How can I start a Camel instance with disk-spooling enabled?
It is possible to create a context from multiple config files. This allows having presets inside the jar, but loading routes from outside:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:preset.xml",
"file:routes.xml"
);
Main main = new Main();
main.setApplicationContext(context);
main.run();

Project-wide properties to Java

I'm writing some multi-module Android app (actually in Kotlin) and I'd like to have some project-wide flags. I was thinking about setting those flags in Gradle and accessing them from my code. But I couldn't find how to do that. Is it possible?
You could generate a property file in Gradle which is added to your runtime classpath. Please adapt the following groovy/java to kotlin/android
ext {
someProperty = 'xxx'
}
dependencies {
compile files("$buildDir/generated/resources")
}
task generateResources {
// configure task inputs/outputs for up-to-date checking/caching
inputs.property("someProperty", someProperty)
outputs.dir "$buildDir/generated/resources"
doLast {
file("$buildDir/generated/resources/myprops.properties").text = "someProperty=$someProperty"
}
}
// important: wire the task into the DAG
compileJava.dependsOn generateResources
Then in your java code
InputStream in = MyClass.getClassLoader().getResourceAsStream("myprops.properties");
Properties props = new Properties()
props.load(in)
String someProperty = props getProperty("someProperty"); // xxx

Injecting Spring Beans to Groovy Script

I've seen many examples about Groovy objects as Spring beans but not vice versa. I'm using Groovy in a Java EE application like this:
GroovyCodeSource groovyCodeSource = new GroovyCodeSource(urlResource);
Class groovyClass = loader.parseClass(groovyCodeSource, false);
return (GroovyObject) groovyClass.newInstance();
In this way, classes written in Groovy with #Configurable annotation are being injected with Spring beans. It's OK for now.
How can I get the same by using GroovyScriptEngine? I don't want to define a class and I want it to work like a plain script. Is Spring/Groovy capable of that?
I've seen a post about this but I'm not sure whether it answers my question or not:
HERE
Do you mean that you'd like to add properties to the script, and inject those? Would you provide getter and setter? This does not make much sense to me. What makes sense, is adding the mainContext to the bindings of the script, or adding selected beans to the bindings.
These beans - or the context - would then be accessible directly in the script, as if it was injected.
def ctx = grailsApplication.mainContext
def binding = new Binding([:])
Map variables = [
'aService',
'anotherService'
].inject([config:grailsApplication.config, mainContext:ctx]) { m, beanName ->
def bean = ctx.getBean(beanName)
m[beanName] = bean
m
}
binding.variables << variables
def compiler = new CompilerConfiguration()
compiler.setScriptBaseClass(baseScriptClassName)
def shell = new GroovyShell(new GroovyClassLoader(), binding, compiler)
script=shell.parse(scriptStr)
script.binding=binding
script.init()
script.run()

Spring DSL in Grails - resources.groovy - bean configuration in a different file?

This question already exists in a way, but the existing question is missing some important links.
I'm trying to move the configuration of beans for my tests into separate files that end in *TestsSpringBeans.groovy
I've attempted to do this after reading "Loading Bean Definitions from the File System" (search for it) in the Groovy documentation.
Here are the relevant code segments:
import grails.util.*
beans = {
...
switch(Environment.current) {
case Environment.TEST:
loadBeans("classpath:*TestsSpringBeans.groovy")
break
}
}
resources.groovy - Loading the *TestSpringBeans files from the File System.
somePlace(jobdb.Company) {
name = "SomeCompany"
addr1 = "addr1"
addr2 = "addr2"
city = "city"
email = "somedude#h0tmail.com"
fax = "555-555-5555"
phone = "444-444-4444"
state = "PA"
zip = "19608"
version: 0
created = new Date()
updated = new Date()
website = "http://www.yahoo.com"
deleted = false
}
CompanyServiceTestsSpringBeans.groovy - Defining a bean for the Integration Test
// Retrieve configured bean from
Company someplace = ApplicationHolder.getApplication().getMainContext().getBean('somePlace')
CompanyServiceTests.groovy - Obtain the bean somePlace within the Integration Test...
Upon calling getBean('somePlace') within the test an error is displayed which reads that No bean named 'somePlace' is defined
The CompanyServiceTests.groovy file is stored with my integration tests, should I be storing this file somewhere else in the project directory structure?
Since your tests run in a way that using the classpath as a reference point is less important, you might try to load the beans { ... } file by referencing via project directory specific path. (e.g. $baseDir/test/resources/MyCustomBeans.groovy) or load the beans explicitly in your tests via #BeforeClass if you are using JUnit4 annotations:
def bb = new BeanBuilder()
def resource = new FileSystemResource('src/test/resources/testContext.groovy')
bb.loadBeans(resource)
appCtx = bb.createApplicationContext()
...

How to discovering types exported by OSGi bundle without installing/activating?

Basically i want to discover if a jar implements any number of interfaces wihtout activating or starting the bundle. Is it possible to read the meta data from the meta-inf from an API just like the container does but without activating a bundle ?
I want to use OSGi to support plugins of which numerous interfaces will be published and i would like to know which interfaces are implemented by a bundle when the user uploads without activating the bundle etc.
I do not think it is possible to discover what services a bundle is going to provide, because this can happen from inside the Java code, without any meta-data about it. Of course, if you use Declarative Services, there is a meta-data file. Also, the bundle needs to import (or provide) the service interface, which may give you a hint (but not more).
You can inspect what Java packages a bundles imports and exports without activating it.
If you are willing to install (not resolve, not activate) it, you can query it. The Felix or Equinox shells can list those packages after all.
Here is the relevant source from Felix' shell. It uses the PackageAdmin service:
public void execute(String s, PrintStream out, PrintStream err)
{
// Get package admin service.
ServiceReference ref = m_context.getServiceReference(
org.osgi.service.packageadmin.PackageAdmin.class.getName());
PackageAdmin pa = (ref == null) ? null :
(PackageAdmin) m_context.getService(ref);
// ...
Bundle bundle = m_context.getBundle( bundleId );
ExportedPackage[] exports = pa.getExportedPackages(bundle);
// ...
}
you may try something like below. Find the ".class" files in the exported packages using bundle.findResource(...) method.
BundleContext context = bundle.getBundleContext();
ServiceReference ref = context.getServiceReference(PackageAdmin.class.getName());
PackageAdmin packageAdmin = (PackageAdmin)context.getService(ref);
List<Class> agentClasses = new ArrayList<Class>();
ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(bundle);
for(ExportedPackage ePackage : exportedPackages){
String packageName = ePackage.getName();
String packagePath = "/"+packageName.replace('.', '/');
//find all the class files in current exported package
Enumeration clazzes = bundle.findEntries(packagePath, "*.class", false);
while(clazzes.hasMoreElements()){
URL url = (URL)clazzes.nextElement();
String path = url.getPath();
int index = path.lastIndexOf("/");
int endIndex = path.length()-6;//Strip ".class" substring
String className = path.substring(index+1, endIndex);
String fullClassName=packageName+"."+className;
try {
Class clazz = bundle.loadClass(fullClassName);
//check whether the class is annotated with Agent tag.
if(clazz.isAnnotationPresent(Agent.class))
agentClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

Resources