first part of moving over cross-store classes/aspect; added aspectj compile support

This commit is contained in:
trisberg
2010-07-27 18:00:20 -04:00
parent be8817f443
commit fb2c81efdd
9 changed files with 332 additions and 39 deletions

View File

@@ -0,0 +1,32 @@
package org.springframework.persistence;
import java.lang.reflect.Field;
/**
* Listener interface for asynchronous storage operations.
* Can be annotated with OnlyOnFailure as an optimization
* if the listener is only interested in compensating transactions
* in the event of write failure.
*
* @author Rod Johnson
*
* @param <V> new value type
*/
public interface AsynchStoreCompletionListener<V> {
/**
* Constant indicating no store completion action
*/
class NONE implements AsynchStoreCompletionListener<Object> {
public void onCompletion(AsynchStoreCompletionListener.StoreResult result, Object newValue, Field foreignStore) {}
}
enum StoreResult {
SUCCESS,
FAILURE,
INDETERMINATE
};
void onCompletion(StoreResult result, V newValue, Field foreignStore);
}

View File

@@ -0,0 +1,34 @@
package org.springframework.persistence;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Persistence policies that can be attached to entities or relationship
* fields.
* @author rodjohnson
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface PersistencePolicy {
enum LATENCY_SENSITIVITY { NONE, MEDIUM, HIGH };
boolean largeObject() default false;
boolean queryable() default true;
boolean immutable() default false;
boolean transactional() default true;
boolean lossAcceptable() default false;
// TODO freshness, or should this be handled separately in a caching annotation
LATENCY_SENSITIVITY latencySensitivity() default LATENCY_SENSITIVITY.HIGH;
}

View File

@@ -0,0 +1,65 @@
package org.springframework.persistence;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation indicating that a field may be stored in a foreign store
* and specifying the necessary guarantees. Conceptual rather than
* implementation-specific.
* @see ForeignStoreKeyManager
*
* @author Rod Johnson
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RelatedEntity {
/**
*
* Optional information as to how to compute or locate the key value.
* Some strategies may take this into account.
*/
String keyExpression() default "";
/**
* Should we use the key of the present entity
* @return
*/
boolean sameKey() default false;
/**
* Policies for persistence
* @return
*/
PersistencePolicy policy() default @PersistencePolicy();
/**
* Name for the preferred data store. Merely a hint. May not be followed.
* @return
*/
String preferredStore() default "";
/**
* Is asynchronous store OK?
* @return
*/
boolean asynchStore() default false;
// TODO - indicates if an asynchronous write should begin
// only after commit of a transaction
boolean afterCommit() default false;
/**
* Completion listener class. Only used if asynchStore is true.
* Must have a no-arg constructor.
* @return
*/
@SuppressWarnings("unchecked")
Class<? extends AsynchStoreCompletionListener> storeCompletionListenerClass() default AsynchStoreCompletionListener.NONE.class;
String storeCompletionListenerBeanName() default "";
}

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);
}