Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Nullable;

Expand All @@ -43,10 +46,48 @@ public static <T> T createModel(Class<T> apiInterface, NodeModel delegateNode, M
new SimpleProxy(delegateNode, bindingConfiguration));
}

private static class MethodCacheKey
{
Method method;
Class<?> delegateClass;

public MethodCacheKey(Method method, Class<?> delegateClass)
{
this.method = method;
this.delegateClass = delegateClass;
}

@Override
public int hashCode()
{
return Objects.hash(delegateClass, method);
}

@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof MethodCacheKey))
{
return false;
}
MethodCacheKey other = (MethodCacheKey) obj;
return Objects.equals(delegateClass, other.delegateClass) && Objects.equals(method, other.method);
}
}

private static class SimpleProxy implements InvocationHandler
{
private NodeModel delegate;
private ModelBindingConfiguration bindingConfiguration;
private static Map<MethodCacheKey, Object> methodCache = new HashMap<>();

public SimpleProxy(NodeModel delegate, ModelBindingConfiguration bindingConfiguration)
{
Expand Down Expand Up @@ -207,12 +248,26 @@ else if (returnClass.equals(Object.class))
@Nullable
private Method findMatchingMethod(Method method)
{
MethodCacheKey cacheKey = new MethodCacheKey(method, delegate.getClass());
Object cachedMethod = methodCache.get(cacheKey);
if (cachedMethod instanceof Method)
{
return (Method) cachedMethod;
}
else if (cachedMethod instanceof String)
{
return null;
}

try
{
return delegate.getClass().getMethod(method.getName(), method.getParameterTypes());
cachedMethod = delegate.getClass().getMethod(method.getName(), method.getParameterTypes());
methodCache.put(cacheKey, cachedMethod);
return (Method) cachedMethod;
}
catch (NoSuchMethodException e)
{
methodCache.put(cacheKey, "no such method");
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
*/
package org.raml.yagi.framework.model;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;

public class PackageModelBinding implements ModelBinding
{
private static final ClassNodeModelFactory NULL_WRAPPER = new ClassNodeModelFactory(null);
private String packageName;
private Map<Class<?>, ClassNodeModelFactory> cache = new HashMap<>();

public PackageModelBinding(String packageName)
{
Expand All @@ -30,15 +35,24 @@ public PackageModelBinding(String packageName)
@Override
public NodeModelFactory binding(Class<?> clazz)
{
final String simpleName = clazz.getSimpleName();
ClassNodeModelFactory factory = cache.get(clazz);
if (factory != null)
{
return (factory == NULL_WRAPPER) ? null : factory;
}

try
{
final String simpleName = clazz.getSimpleName();
final Class<?> aClass = Class.forName(packageName + "." + simpleName);
return new ClassNodeModelFactory((Class<? extends NodeModel>) aClass);
factory = new ClassNodeModelFactory((Class<? extends NodeModel>) aClass);
cache.put(clazz, factory);
return factory;
}
catch (ClassNotFoundException e)
{
// No binding available
cache.put(clazz, NULL_WRAPPER);
return null;
}
}
Expand Down
57 changes: 48 additions & 9 deletions yagi/src/main/java/org/raml/yagi/framework/nodes/BaseNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
*/
package org.raml.yagi.framework.nodes;

import org.raml.yagi.framework.util.NodeSelector;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.raml.yagi.framework.util.NodeSelector;

public abstract class BaseNode implements Node
{
Expand All @@ -34,6 +37,8 @@ public abstract class BaseNode implements Node

private List<NodeAnnotation> annotations = new ArrayList<>();

private Map<Class<?>, List<?>> descendantsCache = new HashMap<>();

public BaseNode()
{
}
Expand Down Expand Up @@ -79,12 +84,14 @@ public void addChild(Node node)
{
node.setParent(this);
children.add(node);
clearCache();
}

@Override
public void removeChild(Node node)
{
children.remove(node);
clearCache();
}

@Override
Expand All @@ -102,21 +109,46 @@ public Node getContextNode()
return contextNode;
}

@SuppressWarnings("unchecked")
@Nonnull
@Override
public <T extends Node> List<T> findDescendantsWith(Class<T> nodeType)
{
if (children.isEmpty())
{
return Collections.emptyList();
}

List<?> descendants = descendantsCache.get(nodeType);
if (descendants != null)
{
return (List<T>) descendants;
}
final List<T> result = new ArrayList<>();
final List<Node> children = getChildren();
for (Node child : children)
collectDescendantsWithType(this, nodeType, result);
descendantsCache.put(nodeType, result);
return result;
}

private void clearCache()
{
descendantsCache.clear();
if (parent != null)
{
((BaseNode) parent).clearCache();
}
}

private static <T extends Node> void collectDescendantsWithType(Node node, Class<T> nodeType, List<T> descendants)
{
for (Node child : node.getChildren())
{
if (nodeType.isAssignableFrom(child.getClass()))
{
result.add(nodeType.cast(child));
descendants.add(nodeType.cast(child));
}
result.addAll(child.findDescendantsWith(nodeType));
collectDescendantsWithType(child, nodeType, descendants);
}
return result;
}

@Nullable
Expand Down Expand Up @@ -145,6 +177,7 @@ public void replaceWith(Node newNode)
{
newNode.addChild(child);
}
clearCache();
}
}

Expand All @@ -165,6 +198,7 @@ public void replaceTree(Node newSubTree)
}
getParent().setChild(idx, newSubTree);
}
clearCache();
}
}

Expand All @@ -176,20 +210,23 @@ public void removeChildren()
child.setParent(null);
}
children.clear();
clearCache();
}

@Override
public void setChild(int idx, Node newNode)
{
children.set(idx, newNode);
newNode.setParent(this);
clearCache();
}

@Override
public void addChild(int idx, Node newNode)
{
children.add(idx, newNode);
newNode.setParent(this);
clearCache();
}

@Override
Expand All @@ -200,12 +237,14 @@ public void setParent(Node parent)
this.parent.removeChild(this);
}
this.parent = parent;
clearCache();
}

@Override
public void setSource(Node source)
{
this.source = source;
clearCache();
}

@Override
Expand Down