moving to datastore-graph project due to AspectJ compiler issue

This commit is contained in:
trisberg
2010-07-28 15:58:29 -04:00
parent 85e5387eb1
commit a14786143a
6 changed files with 399 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
#Mon Mar 29 14:00:24 PDT 2010
eclipse.preferences.version=1
org.aspectj.ajdt.core.compiler.BuildOptions.showweavemessages=false
org.aspectj.ajdt.core.compiler.lint.BrokeSerialVersionCompatibility=ignore
org.aspectj.ajdt.core.compiler.lint.CannotImplementLazyTJP=ignore
org.aspectj.ajdt.core.compiler.lint.InvalidAbsoluteTypeName=warning
org.aspectj.ajdt.core.compiler.lint.NeedSerialVersionUIDField=ignore
org.aspectj.ajdt.core.compiler.lint.NoInterfaceCtorJoinpoint=warning
org.aspectj.ajdt.core.compiler.lint.ShadowNotInStructure=ignore
org.aspectj.ajdt.core.compiler.lint.TypeNotExposedToWeaver=warning
org.aspectj.ajdt.core.compiler.lint.UnresolvableMember=warning
org.aspectj.ajdt.core.compiler.lint.WildcardTypeName=ignore
org.aspectj.ajdt.core.compiler.lint.adviceDidNotMatch=warning
org.aspectj.ajdt.core.compiler.lint.annotationAsTargetForDecpIgnored=warning
org.aspectj.ajdt.core.compiler.lint.calculatingSerialVersionUID=ignore
org.aspectj.ajdt.core.compiler.lint.cantFindType=error
org.aspectj.ajdt.core.compiler.lint.cantFindTypeAffectingJPMatch=warning
org.aspectj.ajdt.core.compiler.lint.cantMatchArrayTypeOnVarargs=ignore
org.aspectj.ajdt.core.compiler.lint.elementAlreadyAnnotated=warning
org.aspectj.ajdt.core.compiler.lint.enumAsTargetForDecpIgnored=warning
org.aspectj.ajdt.core.compiler.lint.invalidTargetForAnnotation=warning
org.aspectj.ajdt.core.compiler.lint.multipleAdviceStoppingLazyTjp=ignore
org.aspectj.ajdt.core.compiler.lint.noExplicitConstructorCall=warning
org.aspectj.ajdt.core.compiler.lint.noGuardForLazyTjp=ignore
org.aspectj.ajdt.core.compiler.lint.noJoinpointsForBridgeMethods=warning
org.aspectj.ajdt.core.compiler.lint.runtimeExceptionNotSoftened=warning
org.aspectj.ajdt.core.compiler.lint.swallowedExceptionInCatchBlock=ignore
org.aspectj.ajdt.core.compiler.lint.uncheckedAdviceConversion=warning
org.aspectj.ajdt.core.compiler.lint.uncheckedArgument=warning
org.aspectj.ajdt.core.compiler.lint.unmatchedTargetKind=warning
org.aspectj.ajdt.core.compiler.lint.unorderedAdviceAtShadow=ignore
org.aspectj.ajdt.core.compiler.list.UnmatchedSuperTypeInCall=warning
org.aspectj.ajdt.core.compiler.weaver.XHasMember=false
org.aspectj.ajdt.core.compiler.weaver.XNoInline=false
org.aspectj.ajdt.core.compiler.weaver.XNotReweavable=false
org.aspectj.ajdt.core.compiler.weaver.XSerializableAspects=false
org.aspectj.ajdt.core.compiler.weaver.timers=false
org.aspectj.ajdt.core.compiler.weaver.verbose=false
org.aspectj.ajdt.core.complier.lint.aspectExcludedByConfiguration=ignore
org.eclipse.ajdt.core.builder.incrementalCompilationOptimizations=true
org.eclipse.ajdt.core.compiler.nonStandardOptions=-Xset\:pipelineCompilation\=false -XhasMember
org.eclipse.ajdt.core.compiler.useProjectSettings=true

View File

@@ -0,0 +1,189 @@
package org.springframework.persistence.graph.neo4j;
import java.lang.reflect.Field;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.FieldSignature;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.util.GraphDatabaseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.persistence.graph.Direction;
import org.springframework.persistence.graph.GraphEntity;
import org.springframework.persistence.graph.Relationship;
import org.springframework.persistence.support.AbstractTypeAnnotatingMixinFields;
import org.springframework.persistence.support.EntityInstantiator;
/**
* Aspect to turn an object annotated with GraphEntity into a graph entity using Neo4J.
* Delegates all field access (except for fields assumed to be transient)
* to an underlying Neo4 graph node.
*
* @author Rod Johnson
*/
public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEntity,NodeBacked> {
//-------------------------------------------------------------------------
// Configure aspect for whole system.
// init() method can be invoked automatically if the aspect is a Spring
// bean, or called in user code.
//-------------------------------------------------------------------------
// Aspect shared Neo4J Graph Database Service
private GraphDatabaseService graphDatabaseService;
private EntityInstantiator<NodeBacked,Node> graphEntityInstantiator;
private GraphDatabaseUtil graphDatabaseUtil;
@Autowired
public void init(GraphDatabaseService gds, EntityInstantiator<NodeBacked, Node> gei) {
this.graphDatabaseService = gds;
this.graphEntityInstantiator = gei;
this.graphDatabaseUtil = new GraphDatabaseUtil(gds);
}
//-------------------------------------------------------------------------
// Advise user-defined constructors of NodeBacked objects to create a new
// Neo4J backing node
//-------------------------------------------------------------------------
pointcut arbitraryUserConstructorOfNodeBackedObject(NodeBacked entity) :
execution((@GraphEntity *).new(..)) &&
!execution((@GraphEntity *).new(Node)) &&
this(entity);
// Create a new node in the Graph if no Node was passed in a constructor
before(NodeBacked entity) : arbitraryUserConstructorOfNodeBackedObject(entity) {
entity.setUnderlyingNode(graphDatabaseService.createNode());
log.info("User-defined constructor called on class " + entity.getClass() + "; created Node [" + entity.getUnderlyingNode() +"]; " +
"Updating metamodel");
// TODO pull naming out into a strategy interface
Node subReference = Neo4jHelper.findSubreferenceNode(entity.getClass(), graphDatabaseService);
entity.getUnderlyingNode().createRelationshipTo(subReference, Neo4jHelper.INSTANCE_OF_RELATIONSHIP_TYPE);
graphDatabaseUtil.incrementAndGetCounter(subReference, Neo4jHelper.SUBREFERENCE_NODE_COUNTER_KEY);
}
// Introduced field
private Node NodeBacked.underlyingNode;
public void NodeBacked.setUnderlyingNode(Node n) {
this.underlyingNode = n;
}
public Node NodeBacked.getUnderlyingNode() {
return underlyingNode;
}
//-------------------------------------------------------------------------
// Equals and hashCode for Neo4j entities.
// Final to prevent overriding.
//-------------------------------------------------------------------------
// TODO could use template method for further checks if needed
public final boolean NodeBacked.equals(Object obj) {
if (obj instanceof NodeBacked) {
return this.getUnderlyingNode().equals(((NodeBacked) obj).getUnderlyingNode());
}
return false;
}
public final int NodeBacked.hashCode() {
return getUnderlyingNode().hashCode();
}
Object around(NodeBacked entity) : entityFieldGet(entity) {
Field f = ((FieldSignature) thisJoinPoint.getSignature()).getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
String propName = getNeo4jPropertyName(thisJoinPoint.getSignature());
log.info("GET " + f + " <- Neo4J simple node property [" + propName + "]");
return entity.getUnderlyingNode().getProperty(propName, null);
}
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
Relationship r = f.getAnnotation(Relationship.class);
if (r == null) {
throw new IllegalStateException("Must have @Relationship on " + f);
}
Node me = entity.getUnderlyingNode();
if (me == null) {
throw new IllegalStateException("Entity must have a backing Node");
}
RelationshipType type = DynamicRelationshipType.withName(r.type());
org.neo4j.graphdb.Relationship singleRelationship = me.getSingleRelationship(type, r.direction().toNeo4jDir());
// TODO is this correct
if (singleRelationship == null) {
log.info("GET " + f + ": " + f.getType().getName() + ": not set yet so returning field value");
return proceed(entity);
}
Node targetNode = singleRelationship.getOtherNode(me);
log.info("GET " + f + ": " + f.getType().getName() + ": setting from relationship " + singleRelationship);
return graphEntityInstantiator.createEntityFromState(targetNode, (Class<NodeBacked>) f.getType());
}
// Must be transient
log.info("Ignored GET " + f + ": " + f.getType().getName() + " not primitive or GraphEntity");
return proceed(entity);
}
Object around(NodeBacked entity, Object newVal) : entityFieldSet(entity, newVal) {
Field f = ((FieldSignature) thisJoinPoint.getSignature()).getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
String propName = getNeo4jPropertyName(thisJoinPoint.getSignature());
entity.getUnderlyingNode().setProperty(propName, newVal);
log.info("SET " + f + " -> Neo4J simple node property [" + propName + "] with value=[" + newVal + "]");
return null;
}
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
Relationship r = f.getAnnotation(Relationship.class);
if (r == null) {
throw new IllegalStateException("Must have @Relationship on " + f);
}
graphEntityFieldSet(entity, r, (NodeBacked) newVal);
log.info("SET " + f + " -> Neo4J relationship with value=[" + newVal + "]");
return null;
}
else {
log.info("Ignored SET " + f + ": " + f.getType().getName() + " not primitive or GraphEntity");
return proceed(entity, newVal);
}
}
private void graphEntityFieldSet(NodeBacked entity, Relationship r, NodeBacked newVal) {
Node me = entity.getUnderlyingNode();
RelationshipType type = DynamicRelationshipType.withName(r.type());
Node targetNode = newVal.getUnderlyingNode();
if (r.direction() == Direction.OUTGOING) {
me.createRelationshipTo(targetNode, type);
}
else {
targetNode.createRelationshipTo(me, type);
}
}
private boolean isNeo4jRelationshipField(Field f) {
//return f.getType().isAnnotationPresent(GraphEntity.class);
return NodeBacked.class.isAssignableFrom(f.getType());
}
private String getNeo4jPropertyName(Signature sig) {
return sig.toShortString();
}
}

View File

@@ -0,0 +1,61 @@
package org.springframework.persistence.support;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ClassUtils;
/**
* Try for a constructor taking state: failing that, try a no-arg
* constructor and then setUnderlyingNode().
*
* @author Rod Johnson
*/
public abstract class AbstractConstructorEntityInstantiator<BACKING_INTERFACE, STATE> implements EntityInstantiator<BACKING_INTERFACE, STATE> {
private final Log log = LogFactory.getLog(getClass());
final public <T extends BACKING_INTERFACE> T createEntityFromState(STATE n, Class<T> c) {
try {
return fromStateInternal(n, c);
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
final private <T extends BACKING_INTERFACE> T fromStateInternal(STATE n, Class<T> c) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
// TODO this is fragile
Class<? extends STATE> stateInterface = (Class<? extends STATE>) n.getClass().getInterfaces()[0];
Constructor<T> nodeConstructor = ClassUtils.getConstructorIfAvailable(c, stateInterface);
if (nodeConstructor != null) {
// TODO is this the correct way to instantiate or does Spring have a preferred way?
log.info("Using " + c + " constructor taking " + stateInterface);
return nodeConstructor.newInstance(n);
}
Constructor<T> noArgConstructor = ClassUtils.getConstructorIfAvailable(c);
if (noArgConstructor != null) {
log.info("Using " + c + " no-arg constructor");
T t = noArgConstructor.newInstance();
setState(t, n);
return t;
}
throw new IllegalArgumentException(getClass().getSimpleName() + ": entity " + c + " must have either a constructor taking [" + stateInterface +
"] or a no-arg constructor and state set method");
}
/**
* Subclasses must implement to set state
* @param entity
* @param s
*/
protected abstract void setState(BACKING_INTERFACE entity, STATE s);
}

View File

@@ -0,0 +1,54 @@
package org.springframework.persistence.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.persistence.RelatedEntity;
/**
* Abstract superaspect to advise field read and write
* and introduce a mixin interface.
*
* @param <N> type of introduced interface
*
* @author Rod Johnson
*/
privileged abstract public aspect AbstractMixinFields<N> {
protected final Log log = LogFactory.getLog(getClass());
//-------------------------------------------------------------------------
// ITDs to add behavior and state to classes
//-------------------------------------------------------------------------
// Enable Spring DI for all mixed-in objects
declare @type: N+: @Configurable;
//-------------------------------------------------------------------------
// Advice for field get/set to delegate to backing Node.
//-------------------------------------------------------------------------
protected pointcut entityFieldGet(N entity) :
get(* N+.*) &&
this(entity) &&
!(get(@RelatedEntity * *)
|| get(* N.*)
|| getsNotToAdvise());
/**
* Never matches. Subclasses can override to exempt certain field reads from advice
*/
protected pointcut getsNotToAdvise();
protected pointcut entityFieldSet(N entity, Object newVal) :
set(* N+.*) &&
this(entity) &&
args(newVal) &&
!(set(@RelatedEntity * *) ||
set(* N.*) ||
setsNotToAdvise());
/**
* Never matches. Subclasses can override to exempt certain field writes from advice
*/
protected pointcut setsNotToAdvise();
}

View File

@@ -0,0 +1,21 @@
package org.springframework.persistence.support;
import java.lang.annotation.Annotation;
/**
* Abstract superaspect for aspects that advice
* field access with a mixin for all types annotated with
* a given annotation.
*
* @param <ET> annotation on entity
* @param <N> type of introduced interface
*
* @author Rod Johnson
*/
privileged abstract public aspect AbstractTypeAnnotatingMixinFields<ET extends Annotation, N>
extends AbstractMixinFields<N> {
// ITD to introduce N state to Annotated objects
declare parents : (@ET *) implements N;
}

View File

@@ -0,0 +1,32 @@
package org.springframework.persistence.support;
/**
* Interface to be implemented by classes that can instantiate and
* configure entities.
* The framework must do this when creating objects resulting from finders,
* even when there may be no no-arg constructor supplied by the user.
*
* @author Rod Johnson
*/
public interface EntityInstantiator<BACKING_INTERFACE,STATE> {
/*
* The best solution if available is to add a constructor that takes Node
* to each GraphEntity. This means generating an aspect beside every
* class as Roo presently does.
*
* An alternative that does not require Roo
* is a user-authored constructor taking Node and calling setUnderlyingNode()
* but this is less elegant and pollutes the domain object.
*
* If the user supplies a no-arg constructor, instantiation can occur by invoking it
* prior to calling setUnderlyingNode().
*
* If the user does NOT supply a no-arg constructor, we must rely on Sun-specific
* code to instantiate entities without invoking a constructor.
*/
<T extends BACKING_INTERFACE> T createEntityFromState(STATE s, Class<T> c);
}