-
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.
- Loading branch information
Showing
20 changed files
with
695 additions
and
113 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
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
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
59 changes: 59 additions & 0 deletions
59
src/main/java/rip/hippo/lwjeb/configuration/config/impl/ListenerFactoryConfiguration.java
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,59 @@ | ||
package rip.hippo.lwjeb.configuration.config.impl; | ||
|
||
import rip.hippo.lwjeb.configuration.config.Configuration; | ||
import rip.hippo.lwjeb.configuration.invocation.ListenerFactory; | ||
import rip.hippo.lwjeb.configuration.invocation.impl.DirectListenerFactory; | ||
|
||
|
||
/** | ||
* @author Hippo | ||
* @version 1.0.0, 3/18/21 | ||
* @since 5.2.0 | ||
* | ||
* The listener factory configuration allows you to configure how your listeners are created. | ||
*/ | ||
public final class ListenerFactoryConfiguration implements Configuration<ListenerFactoryConfiguration> { | ||
|
||
/** | ||
* The listener factory. | ||
*/ | ||
private ListenerFactory listenerFactory; | ||
|
||
/** | ||
* Static constructor wrapper to create the default config. | ||
* | ||
* @return The default config. | ||
*/ | ||
public static ListenerFactoryConfiguration getDefault() { | ||
return new ListenerFactoryConfiguration().provideDefault(); | ||
} | ||
|
||
/** | ||
* Sets the default config values. | ||
* | ||
* @return The default config. | ||
*/ | ||
@Override | ||
public ListenerFactoryConfiguration provideDefault() { | ||
this.setListenerFactory(new DirectListenerFactory()); | ||
return this; | ||
} | ||
|
||
/** | ||
* Gets the listener factory. | ||
* | ||
* @return The listener factory. | ||
*/ | ||
public ListenerFactory getListenerFactory() { | ||
return listenerFactory; | ||
} | ||
|
||
/** | ||
* Sets the listener factory. | ||
* | ||
* @param listenerFactory The new listener factory. | ||
*/ | ||
public void setListenerFactory(ListenerFactory listenerFactory) { | ||
this.listenerFactory = listenerFactory; | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/rip/hippo/lwjeb/configuration/invocation/ListenerFactory.java
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,29 @@ | ||
package rip.hippo.lwjeb.configuration.invocation; | ||
|
||
import rip.hippo.lwjeb.configuration.config.impl.BusConfiguration; | ||
import rip.hippo.lwjeb.configuration.config.impl.ExceptionHandlingConfiguration; | ||
import rip.hippo.lwjeb.listener.Listener; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* @author Hippo | ||
* @version 1.0.0, 3/17/21 | ||
* @since 5.2.0 | ||
* | ||
* A Listener factory is a functional interface on which job is to create {@link Listener}s. | ||
*/ | ||
@FunctionalInterface | ||
public interface ListenerFactory { | ||
|
||
/** | ||
* Creates a listener. | ||
* | ||
* @param parent The parent method. | ||
* @param method The method to invoke. | ||
* @param topic The event topic. | ||
* @param config The bus configuration. | ||
* @return The listener. | ||
*/ | ||
Listener create(Class<?> parent, Method method, Class<?> topic, BusConfiguration config); | ||
} |
59 changes: 59 additions & 0 deletions
59
src/main/java/rip/hippo/lwjeb/configuration/invocation/impl/DirectListenerFactory.java
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,59 @@ | ||
package rip.hippo.lwjeb.configuration.invocation.impl; | ||
|
||
import rip.hippo.lwjeb.configuration.config.impl.BusConfiguration; | ||
import rip.hippo.lwjeb.configuration.config.impl.ExceptionHandlingConfiguration; | ||
import rip.hippo.lwjeb.configuration.invocation.ListenerFactory; | ||
import rip.hippo.lwjeb.listener.Listener; | ||
import rip.hippo.lwjeb.listener.classfile.ListenerClassFile; | ||
|
||
import java.io.IOException; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Parameter; | ||
|
||
/** | ||
* @author Hippo | ||
* @version 1.0.0, 3/17/21 | ||
* @since 5.2.0 | ||
* | ||
* A direct listener factory will dynamically create a listener proxy class to invoke its message handlers directly. | ||
*/ | ||
public final class DirectListenerFactory implements ListenerFactory { | ||
|
||
/** | ||
* Dynamically generates a listener to invoke {@code method}. | ||
* | ||
* @param parent The parent. | ||
* @param method The method. | ||
* @param topic The topic. | ||
* @param config The bus configuration. | ||
* @return The dynamic listener. | ||
*/ | ||
@Override | ||
public Listener create(Class<?> parent, Method method, Class<?> topic, BusConfiguration config) { | ||
String name = "lwjeb/generated/" + parent.getName().replace('.', '/') + "/" + getUniqueMethodName(method); | ||
ListenerClassFile listenerClassFile = new ListenerClassFile(parent, topic, method, name); | ||
|
||
try { | ||
Class<?> compiledClass = config.getListenerClassLoader().createClass(name.replace('/', '.'), listenerClassFile.toByteArray()); | ||
|
||
return (Listener)compiledClass.getConstructor() | ||
.newInstance(); | ||
} catch (ReflectiveOperationException | IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
/** | ||
* Gets a unique method name from a method instance. | ||
* | ||
* @param method The method. | ||
* @return The unique name. | ||
*/ | ||
static String getUniqueMethodName(Method method) { | ||
StringBuilder parameters = new StringBuilder(); | ||
for (Parameter parameter : method.getParameters()) { | ||
parameters.append(parameter.getType().getName().replace('.', '_')); | ||
} | ||
return method.getName() + parameters.toString(); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
.../java/rip/hippo/lwjeb/configuration/invocation/impl/LambdaMetaFactoryListenerFactory.java
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,43 @@ | ||
package rip.hippo.lwjeb.configuration.invocation.impl; | ||
|
||
import rip.hippo.lwjeb.configuration.config.impl.BusConfiguration; | ||
import rip.hippo.lwjeb.configuration.invocation.ListenerFactory; | ||
import rip.hippo.lwjeb.listener.Listener; | ||
|
||
import java.lang.invoke.*; | ||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* @author Hippo | ||
* @version 1.0.0, 3/18/21 | ||
* @since 5.2.0 | ||
* | ||
* This uses {@link LambdaMetafactory} to create a {@link CallSite} to invoke the method. | ||
*/ | ||
public final class LambdaMetaFactoryListenerFactory implements ListenerFactory { | ||
|
||
/** | ||
* Creates a listener that is invoked with {@link LambdaMetafactory}. | ||
* | ||
* @param parent The parent. | ||
* @param method The method. | ||
* @param topic The topic. | ||
* @param config The bus configuration. | ||
* @return The listener. | ||
*/ | ||
@Override | ||
public Listener create(Class<?> parent, Method method, Class<?> topic, BusConfiguration config) { | ||
try { | ||
MethodHandles.Lookup lookup = MethodHandles.lookup(); | ||
MethodType invokedType = MethodType.methodType(Listener.class); | ||
MethodHandle implMethod = lookup.unreflect(method); | ||
MethodType instantiatedMethodType = implMethod.type(); | ||
MethodType samMethodType = instantiatedMethodType.changeParameterType(0, Object.class).changeParameterType(1, Object.class); | ||
|
||
CallSite callSite = LambdaMetafactory.metafactory(lookup, "invoke", invokedType, samMethodType, implMethod, instantiatedMethodType); | ||
return (Listener) callSite.getTarget().invoke(); | ||
} catch (Throwable t) { | ||
throw new RuntimeException(t); | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/java/rip/hippo/lwjeb/configuration/invocation/impl/MethodHandleListenerFactory.java
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 rip.hippo.lwjeb.configuration.invocation.impl; | ||
|
||
import rip.hippo.lwjeb.configuration.config.impl.BusConfiguration; | ||
import rip.hippo.lwjeb.configuration.invocation.ListenerFactory; | ||
import rip.hippo.lwjeb.listener.Listener; | ||
|
||
import java.lang.invoke.LambdaMetafactory; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodType; | ||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* @author Hippo | ||
* @version 1.0.0, 3/18/21 | ||
* @since 5.2.0 | ||
* | ||
* A method handle listener factory creates listeners that are invoked via {@link MethodHandle}s. | ||
*/ | ||
public final class MethodHandleListenerFactory implements ListenerFactory { | ||
|
||
/** | ||
* Creates a listener that is invoked with {@link MethodHandle}. | ||
* | ||
* @param parent The parent. | ||
* @param method The method. | ||
* @param topic The topic. | ||
* @param config The bus configuration. | ||
* @return The listener. | ||
*/ | ||
@Override | ||
public Listener create(Class<?> parent, Method method, Class<?> topic, BusConfiguration config) { | ||
try { | ||
MethodType methodType = MethodType.methodType(void.class, topic); | ||
MethodHandle methodHandle = MethodHandles.lookup().findVirtual(parent, method.getName(), methodType); | ||
|
||
return (parentObject, topicObject) -> { | ||
try { | ||
methodHandle.invoke(parentObject, topicObject); | ||
} catch (Throwable t) { | ||
throw new RuntimeException(t); | ||
} | ||
}; | ||
} catch (Throwable e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
Oops, something went wrong.