Skip to content

Commit

Permalink
[BLEEDING] Flesh out aspects of ComponentRegistry.
Browse files Browse the repository at this point in the history
* Fixes data removal ignoring chat.logins and chat.text for a part.
* Move some components interfaces and ReflectionUtil to NCPCommons.
* Unregister components in reverse order.
* Add ComponentRegistryProvider for generic sub-registries (DataManager
for instance).
* Add IHoldSUbComponents for delayed sub-component registration
(convenient for iteration over parent-components with later registration
of sub components not missing out any registered parent components for
those). [Partly implemented: Using this during runtime does not yet
work, only used in onEnable.]
* Let CheckListener implement IHoldSubComponents and use this with
addCheck to register the queued checks after all the listeners.
* Register the core system components in a bunch before the
CheckListenerS, to allow sub-registries to work directly and to allow
getAPI().addComponent on the plugin class during construction of
CheckListeners.
  • Loading branch information
asofold committed Apr 15, 2013
1 parent 652342c commit de5f152
Show file tree
Hide file tree
Showing 13 changed files with 310 additions and 83 deletions.
@@ -1,27 +1,26 @@
package fr.neatmonster.nocheatplus.components;

/**
* A ComponentRegistry allows registering components, that then are delegated to where they belong.<br>
* A ComponentRegistry allows registering components, that then should be delegated to where they belong or just be ignored.<br>
* Notes:
* <li>Implementations should somehow specify what components can be registered.</li>
* <li>Implementations should somehow specify if/when they are unregistered automatically.</li>
* @author mc_dev
*
*/
public interface ComponentRegistry {
public interface ComponentRegistry<T>{

/**
* Convenience method to add components according to implemented interfaces,
* like Listener, INotifyReload, INeedConfig.<br>
* For the NoCheatPlus instance this must be done after the configuration has been initialized.
* @param obj
* Register a component.
* @param component
* @return If (newly) added. Adding an already present component should do nothing.
*/
public boolean addComponent(final Object obj);
public boolean addComponent(final T component);

/**
* Remove a registered component. <br>
* Does not unregister listeners currently.
* @param obj
* @param component
*/
public void removeComponent(final Object obj);
public void removeComponent(final T component);
}
@@ -0,0 +1,20 @@
package fr.neatmonster.nocheatplus.components;

import java.util.Collection;

/**
* An object allowing to get ComponentRegistry implementations of a specific type.
* This class is not specialized to maintain flexibility.
* @author mc_dev
*
*/
public interface ComponentRegistryProvider{

/**
* Get all available specialized ComponentFactory instances matching the given signature. This is not meant as a factory method but for more efficient registration for the case of the regestry being present.
* @param clazz
* @return Some collection, empty collection in case no matches are found.
*/
public <T> Collection<ComponentRegistry<T>> getComponentRegistries(Class<ComponentRegistry<T>> clazz);

}
@@ -0,0 +1,78 @@
package fr.neatmonster.nocheatplus.utilities;

import java.lang.reflect.Method;

public class ReflectionUtil {

/**
* Convenience method to check if members exist and fail if not.
* @param prefix
* @param specs
* @throws RuntimeException
*/
public static void checkMembers(String prefix, String[]... specs){
try {
for (String[] spec : specs){
Class<?> clazz = Class.forName(prefix + spec[0]);
for (int i = 1; i < spec.length; i++){
if (clazz.getField(spec[i]) == null) throw new NoSuchFieldException(prefix + spec[0] + " : " + spec[i]);
}
}
} catch (SecurityException e) {
// Let this one pass.
//throw new RuntimeException(e);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}

/**
* Dirty method. Does try.catch and return null for method invokation.
* @param obj
* @param methodName
* @param arg
* @return
*/
public static Object invokeGenericMethodOneArg(final Object obj, final String methodName, final Object arg){
// TODO: Isn't there a one-line-call for this ??
final Class<?> objClass = obj.getClass();
final Class<?> argClass = arg.getClass();
// Collect methods that might work.
Method methodFound = null;
boolean denyObject = false;
for (final Method method : objClass.getDeclaredMethods()){
if (method.getName().equals(methodName)){
final Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1 ){
// Prevent using Object as argument if there exists a method with a specialized argument.
if (parameterTypes[0] != Object.class && !parameterTypes[0].isAssignableFrom(argClass)){
denyObject = true;
}
// Override the found method if none found yet and assignment is possible, or if it has a specialized argument of an already found one.
if ((methodFound == null && parameterTypes[0].isAssignableFrom(argClass) || methodFound != null && methodFound.getParameterTypes()[0].isAssignableFrom(parameterTypes[0]))){
methodFound = method;
}
}
}
}
if (denyObject && methodFound.getParameterTypes()[0] == Object.class){
// TODO: Throw something !?
return null;
}
else if (methodFound != null && methodFound.getParameterTypes()[0].isAssignableFrom(argClass)){
try{
final Object res = methodFound.invoke(obj, arg);
return res;
}
catch (Throwable t){
// TODO: Throw something !?
return null;
}
}
else{
// TODO: Throw something !?
return null;
}
}

}

This file was deleted.

0 comments on commit de5f152

Please sign in to comment.