-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
patch(entrypoint-system): improved entrypoint system & beta update
* Improved entrypoint system * This is a beta release to prepare modules and extensions
- Loading branch information
Showing
7 changed files
with
198 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 70 additions & 26 deletions
96
src/main/kotlin/xyz/theprogramsrc/simplecoreapi/standalone/EntrypointLoader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,83 @@ | ||
package xyz.theprogramsrc.simplecoreapi.standalone | ||
|
||
import java.util.Properties | ||
import java.util.zip.ZipInputStream | ||
|
||
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR) | ||
@Retention(AnnotationRetention.RUNTIME) | ||
annotation class EntryPoint | ||
/** | ||
* Interface that will be used to load the entry point of the app. | ||
*/ | ||
interface EntryPoint { | ||
|
||
/** | ||
* Called when the app is loaded | ||
*/ | ||
fun onLoad() | ||
|
||
/** | ||
* Called when the app is enabled | ||
*/ | ||
fun onEnable() | ||
|
||
/** | ||
* Called when the app is disabled | ||
*/ | ||
fun onDisable() | ||
} | ||
|
||
/** | ||
* Class that manages the entry point of the app. It will be in charge of running the onLoad, onEnable and onDisable methods of the class importing [EntryPoint]. | ||
*/ | ||
class EntrypointLoader { | ||
companion object { | ||
private var entryPoint: EntryPoint? = null | ||
|
||
/** | ||
* Manually register the entrypoint. | ||
* Currently, this is used for testing purposes, but if you have issues with the entrypoint not being loaded, you can use this method to register it manually. | ||
* | ||
* @param clazz The entrypoint class. It must implement [EntryPoint] | ||
*/ | ||
fun registerEntrypoint(clazz: Class<out EntryPoint>) { | ||
entryPoint = clazz.getConstructor().newInstance() as EntryPoint | ||
} | ||
} | ||
private var enabled: Boolean = false | ||
|
||
init { | ||
// First get the resource 'module.properties' located at the root of the jar file | ||
val moduleProperties = EntrypointLoader::class.java.getResourceAsStream("/module.properties") | ||
if(moduleProperties != null) { | ||
// Now read the 'entrypoint' property | ||
val entrypoint = (Properties().let { | ||
it.load(moduleProperties) | ||
it.getProperty("entrypoint") | ||
} ?: "").replace("\"", "") | ||
|
||
assert(entrypoint.isNotBlank()) { "Entrypoint cannot be blank!" } | ||
|
||
// Now load the class | ||
val clazz = this::class.java.classLoader.loadClass(entrypoint) | ||
|
||
// Now check if the class itself is an entrypoint, if it is, initialize it, if not check for the first method that is an entrypoint | ||
if(clazz.isAnnotationPresent(EntryPoint::class.java)){ | ||
clazz.getConstructor().newInstance() | ||
} else { | ||
clazz.methods.forEach { method -> | ||
if(method.isAnnotationPresent(EntryPoint::class.java)){ | ||
method.invoke(null) | ||
return@forEach | ||
} | ||
if(entryPoint == null) { | ||
// First get the resource 'module.properties' located at the root of the jar file | ||
val moduleProperties = EntrypointLoader::class.java.getResourceAsStream("/module.properties") | ||
if(moduleProperties != null) { | ||
// Now read the 'entrypoint' property | ||
val entrypoint = (Properties().let { | ||
it.load(moduleProperties) | ||
it.getProperty("entrypoint") | ||
} ?: "").replace("\"", "") | ||
|
||
assert(entrypoint.isNotBlank()) { "Entrypoint cannot be blank!" } | ||
|
||
// Now load the class | ||
val clazz = this::class.java.classLoader.loadClass(entrypoint) | ||
|
||
// Now check if the class itself is an entrypoint, if it is, initialize it, if not check for the first method that is an entrypoint | ||
if(clazz.isAssignableFrom(EntryPoint::class.java)){ | ||
entryPoint = clazz.getConstructor().newInstance() as EntryPoint | ||
} | ||
} | ||
} | ||
|
||
entryPoint?.onLoad() | ||
} | ||
|
||
fun enable() { | ||
assert(!enabled) { "App already enabled! Please avoid calling this method more than once." } | ||
entryPoint?.onEnable() | ||
enabled = true | ||
} | ||
|
||
fun disable() { | ||
assert(enabled) { "App already disabled! Please avoid calling this method more than once." } | ||
entryPoint?.onDisable() | ||
enabled = false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
src/test/kotlin/xyz/theprogramsrc/simplecoreapi/global/modules/ModuleInteroperabilityTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package xyz.theprogramsrc.simplecoreapi.global.modules | ||
|
||
import org.apache.commons.io.FileUtils | ||
import org.junit.jupiter.api.AfterAll | ||
import xyz.theprogramsrc.simplecoreapi.global.SimpleCoreAPI | ||
import xyz.theprogramsrc.simplecoreapi.standalone.EntryPoint | ||
import xyz.theprogramsrc.simplecoreapi.standalone.EntrypointLoader | ||
import xyz.theprogramsrc.simplecoreapi.standalone.StandaloneLoader | ||
import java.io.File | ||
|
||
|
||
// This will test if modules are able to call methods from other modules. | ||
internal class ModuleInteroperabilityTest { | ||
|
||
//@Test | ||
fun `Test if module can call methods from other modules`() { | ||
// First we register the entrypoint | ||
EntrypointLoader.registerEntrypoint(MockApp::class.java) | ||
|
||
// Start the standalone loader. | ||
StandaloneLoader() | ||
} | ||
|
||
companion object { | ||
|
||
@AfterAll | ||
@JvmStatic | ||
fun tearDown() { | ||
arrayOf("SimpleCoreAPI/", "plugins/").map { File(it) }.filter{ it.exists() }.forEach { FileUtils.forceDelete(it) } | ||
} | ||
} | ||
} | ||
|
||
class MockApp: EntryPoint { | ||
|
||
override fun onLoad() { | ||
println("onLoad") | ||
SimpleCoreAPI.requireModule("TheProgramSrc/SimpleCore-TranslationsModule") // Require the TranslationsModule | ||
} | ||
|
||
override fun onEnable() { | ||
println("onEnable") | ||
} | ||
|
||
override fun onDisable() { | ||
println("onDisable") | ||
} | ||
} |