Skip to content

Commit

Permalink
plugin loader done
Browse files Browse the repository at this point in the history
  • Loading branch information
0xMartin committed Aug 11, 2024
1 parent ded1d49 commit 843fcc4
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 95 deletions.
62 changes: 20 additions & 42 deletions examples/plugin-example/plugin/build.gradle
Original file line number Diff line number Diff line change
@@ -1,69 +1,47 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Gradle plugin project to get you started.
* For more details on writing Custom Plugins, please refer to https://docs.gradle.org/8.7/userguide/custom_plugins.html in the Gradle documentation.
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.7/userguide/building_java_projects.html in the Gradle documentation.
*/

plugins {
// Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
id 'java-gradle-plugin'
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()

// Local libs
// Local NATT libs
flatDir {
dirs 'libs'
}
}

dependencies {
// Use JUnit Jupiter for testing.
testImplementation libs.junit.jupiter

// NATT SPI
implementation name: 'natt-spi-1.0.0'

testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

gradlePlugin {
// Define the plugin
plugins {
greeting {
id = 'natt.plugin'
implementationClass = 'natt.plugin.PluginMain'
}
}
}

// Add a source set for the functional test suite
sourceSets {
functionalTest {
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations.functionalTestImplementation.extendsFrom(configurations.testImplementation)
configurations.functionalTestRuntimeOnly.extendsFrom(configurations.testRuntimeOnly)

// Add a task to run the functional tests
tasks.register('functionalTest', Test) {
testClassesDirs = sourceSets.functionalTest.output.classesDirs
classpath = sourceSets.functionalTest.runtimeClasspath
useJUnitPlatform()
application {
// Define the main class for the application.
mainClass = 'natt.plugin.PluginMain'
}

gradlePlugin.testSourceSets.add(sourceSets.functionalTest)

tasks.named('check') {
// Run the functional tests as part of `check`
dependsOn(tasks.functionalTest)
}

tasks.named('test') {
// Use JUnit Jupiter for unit tests.
useJUnitPlatform()
}
jar {
manifest {
attributes(
'Main-Class': 'natt.plugin.PluginMain',
'Implementation-Version': version
)
}
}
4 changes: 2 additions & 2 deletions natt/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ java {

application {
// Define the main class for the application.
mainClass = 'utb.fai.NetworkAppTestingTool'
mainClass = 'utb.fai.natt.NetworkAppTestingTool'
}

jar {
manifest {
attributes(
'Main-Class': 'utb.fai.NetworkAppTestingTool',
'Main-Class': 'utb.fai.natt.NetworkAppTestingTool',
'Implementation-Version': version
)
}
Expand Down
3 changes: 0 additions & 3 deletions natt/src/main/java/utb/fai/natt/NetworkAppTestingTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ public static void main(String[] args) {
// inicializace nastroje
NATTCore core = new NATTCore(args);

// nacte vsechny pluginy
core.loadPlugins();

// nacte soubor s konfiguraci testu
core.loadConfigFile();

Expand Down
35 changes: 17 additions & 18 deletions natt/src/main/java/utb/fai/natt/core/NATTCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public NATTCore(String[] args) throws InternalErrorException {
this.localHostIO = new LocalHostIO(configPath);
this.networkIO = new NetworkIO(configPath);
this.pluginLoader = new PluginLoader(NATTContext.instance());
this.pluginLoader.loadPlugins();

/************************************************************************************************************************* */

Expand Down Expand Up @@ -140,30 +141,29 @@ public NATTCore(String[] args) throws InternalErrorException {

// zobrazi vsechny nactene pluginy
if (cmd.hasOption("p")) {
this.pluginLoader.loadPlugins();
int i = 1;
logger.info("Loaded plugins:");
System.out.println("Loaded plugins:");
for (INATTPlugin plugin : this.pluginLoader.getPlugins()) {
logger.info(String.format("%d: %s", i++, plugin.getName()));
System.out.println(String.format("%d: %s", i++, plugin.getName()));
}
System.exit(0);
}

// zobrazi seznam vsech registrovanych keywordu (jejich nazvu)
if (cmd.hasOption("k")) {
logger.info("Registered keywords:");
for (Map.Entry<String, java.lang.Class<?>> entry : NATTContext.instance().getKeywordSet().entrySet()) {
try {
java.lang.Class<?> keywordClass = entry.getValue();
java.lang.reflect.Constructor<?> constructor = keywordClass.getDeclaredConstructor();
NATTKeyword keywordInstance = (NATTKeyword) constructor.newInstance();
if (keywordInstance != null) {
logger.info(keywordInstance.getKeywordName());
System.out.println(keywordInstance.getKeywordName());
}
} catch (Exception e) {
logger.warning("Failed to create keyword instance for keyword " + entry.getKey() + ".");
System.out.println("Failed to create keyword instance for keyword " + entry.getKey() + ".");
}
}
System.exit(0);
}

// ve json formatu vypisi dokumentaci vsech registrovanych keyword
Expand All @@ -187,7 +187,7 @@ public NATTCore(String[] args) throws InternalErrorException {
ObjectMapper objectMapper = new ObjectMapper();
try {
String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(documentationList);
logger.info(json);
System.out.println(json);
} catch (JsonProcessingException e) {
logger.error("Failed to convert keyword documentation to JSON.");
}
Expand Down Expand Up @@ -216,10 +216,20 @@ public NATTCore(String[] args) throws InternalErrorException {
logger.info("Working directory path: " + currentDirectory);
}

/**
* Vrati cestu ke konfiguraci
*
* @return Cesta ke konfiguraci
*/
public String getConfigPath() {
return configPath;
}

/**
* Nastavi cestu ke konfiguraci
*
* @param configPath cesta ke konfiguraci
*/
public void setConfigPath(String configPath) {
this.configPath = configPath;
}
Expand All @@ -235,17 +245,6 @@ public static void termiteAllModules() {
NATTContext.instance().getModules().clear();
}

/**
* Nacte vsechny moduly, ktere jsou definovany v konfiguraci
*/
public void loadPlugins() {
if (this.pluginLoader != null) {
this.pluginLoader.loadPlugins();
} else {
logger.error("Plugin loader is not initialized.");
}
}

/**
* Nacte obsah konfiguracniho souboru, ktery bude obsahovat popis testovani.
*
Expand Down
62 changes: 32 additions & 30 deletions natt/src/main/java/utb/fai/natt/core/PluginLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

import java.util.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
* Trida pro nacteni a inicializaci pluginu.
Expand Down Expand Up @@ -64,33 +65,35 @@ public void loadPlugin(File file) throws Exception {
URL[] urls = { file.toURI().toURL() };
try (URLClassLoader classLoader = new URLClassLoader(urls, PluginLoader.class.getClassLoader())) {

// nacte manifest
Properties properties = new Properties();
try (FileInputStream fis = new FileInputStream(new File(file.getParent(), "plugin.properties"))) {
properties.load(fis);
}

// nacte hlavni tridu s pluginem
String mainClassName = properties.getProperty("Main-Class");
if (mainClassName == null) {
throw new IOException("No Main-Class defined in plugin.properties for " + file.getName());
}

// kontrola, zda je trida implementuje INATTPlugin
Class<?> pluginClass = classLoader.loadClass(mainClassName);
if (!INATTPlugin.class.isAssignableFrom(pluginClass)) {
throw new ClassCastException("Class " + mainClassName + " does not implement INATTPlugin");
}

// inicializace a registrace pluginu
INATTPlugin plugin = (INATTPlugin) pluginClass.getDeclaredConstructor().newInstance();
if (plugin != null) {
plugin.initialize(this.context);
this.plugins.add(plugin);
logger.info("Successfully loaded and initialized plugin ["
+ plugin.getName() + "] from file: " + file.getName());
} else {
logger.error("Failed to initialize plugin from file: " + file.getName());
// Nacte manifest z JAR souboru
try (JarFile jarFile = new JarFile(file)) {
Manifest manifest = jarFile.getManifest();
if (manifest == null) {
throw new IOException("Manifest file not found in " + file.getName());
}

Attributes attributes = manifest.getMainAttributes();
String mainClassName = attributes.getValue("Main-Class");
if (mainClassName == null) {
throw new IOException("No Main-Class defined in manifest for " + file.getName());
}

// kontrola, zda je trida implementuje INATTPlugin
Class<?> pluginClass = classLoader.loadClass(mainClassName);
if (!INATTPlugin.class.isAssignableFrom(pluginClass)) {
throw new ClassCastException("Class " + mainClassName + " does not implement INATTPlugin");
}

// inicializace a registrace pluginu
INATTPlugin plugin = (INATTPlugin) pluginClass.getDeclaredConstructor().newInstance();
if (plugin != null) {
plugin.initialize(this.context);
this.plugins.add(plugin);
logger.info("Successfully loaded and initialized plugin ["
+ plugin.getName() + "] from file: " + file.getName());
} else {
logger.error("Failed to initialize plugin from file: " + file.getName());
}
}
}
}
Expand All @@ -103,5 +106,4 @@ public void loadPlugin(File file) throws Exception {
public List<INATTPlugin> getPlugins() {
return plugins;
}

}

0 comments on commit 843fcc4

Please sign in to comment.