mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#882 - ENH: Support document store only use (ie. Use @DocStore without @Entity and persist, fetch only against ElasticSearch with no SQL DB)
This commit is contained in:
@@ -39,13 +39,13 @@ public final class DocStoreQueueEntry {
|
||||
}
|
||||
}
|
||||
|
||||
final Action type;
|
||||
private final Action type;
|
||||
|
||||
final String queueId;
|
||||
private final String queueId;
|
||||
|
||||
final String path;
|
||||
private final String path;
|
||||
|
||||
final Object beanId;
|
||||
private final Object beanId;
|
||||
|
||||
/**
|
||||
* Construct for an INDEX or DELETE action.
|
||||
|
||||
@@ -132,6 +132,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private DocStoreConfig docStoreConfig = new DocStoreConfig();
|
||||
|
||||
/**
|
||||
* Set to true when the EbeanServer only uses Document store.
|
||||
*/
|
||||
private boolean docStoreOnly;
|
||||
|
||||
/**
|
||||
* This is used to populate @WhoCreated, @WhoModified and
|
||||
* support other audit features (who executed a query etc).
|
||||
@@ -1210,6 +1215,20 @@ public class ServerConfig {
|
||||
this.namingConvention = namingConvention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this EbeanServer is a Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public boolean isDocStoreOnly() {
|
||||
return docStoreOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this EbeanServer is Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public void setDocStoreOnly(boolean docStoreOnly) {
|
||||
this.docStoreOnly = docStoreOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the ElasticSearch integration.
|
||||
*/
|
||||
@@ -2405,6 +2424,7 @@ public class ServerConfig {
|
||||
dbTypeConfig.setGeometrySRID(srid);
|
||||
}
|
||||
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
|
||||
@@ -73,6 +73,11 @@ public interface BeanType<T> {
|
||||
*/
|
||||
boolean isValidExpression(String property);
|
||||
|
||||
/**
|
||||
* Return true if the type is document store only.
|
||||
*/
|
||||
boolean isDocStoreOnly();
|
||||
|
||||
/**
|
||||
* Return the base table this bean type maps to.
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.avaje.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreTransaction;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
@@ -79,6 +80,11 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocStoreTransaction getDocStoreTransaction() {
|
||||
return transaction.getDocStoreTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocStoreMode getDocStoreMode() {
|
||||
return transaction.getDocStoreMode();
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.avaje.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreTransaction;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
@@ -265,4 +266,9 @@ public interface SpiTransaction extends Transaction {
|
||||
* Send the change set to be prepared and then logged.
|
||||
*/
|
||||
void sendChangeLog(ChangeSet changeSet);
|
||||
|
||||
/**
|
||||
* Return a document store transaction.
|
||||
*/
|
||||
DocStoreTransaction getDocStoreTransaction();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.avaje.ebean.config.PropertyMap;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.UnderscoreNamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.dbmigration.DbOffline;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -94,9 +95,14 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
BootupClasses bootupClasses = getBootupClasses(serverConfig);
|
||||
|
||||
setDataSource(serverConfig);
|
||||
// check the autoCommit and Transaction Isolation
|
||||
boolean online = checkDataSource(serverConfig);
|
||||
boolean online = true;
|
||||
if (serverConfig.isDocStoreOnly()) {
|
||||
serverConfig.setDatabasePlatform(new H2Platform());
|
||||
} else {
|
||||
setDataSource(serverConfig);
|
||||
// check the autoCommit and Transaction Isolation
|
||||
online = checkDataSource(serverConfig);
|
||||
}
|
||||
|
||||
// determine database platform (Oracle etc)
|
||||
setDatabasePlatform(serverConfig);
|
||||
|
||||
@@ -284,7 +284,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
*/
|
||||
public void executePlugins(boolean online) {
|
||||
|
||||
ddlGenerator.execute(online);
|
||||
if (!serverConfig.isDocStoreOnly()) {
|
||||
ddlGenerator.execute(online);
|
||||
}
|
||||
for (Plugin plugin : serverPlugins) {
|
||||
plugin.online(online);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.avaje.ebeaninternal.server.readaudit.DefaultReadAuditPrepare;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.DocStoreTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExplicitTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
@@ -342,11 +343,12 @@ public class InternalConfiguration {
|
||||
if (serverConfig.isExplicitTransactionBeginMode()) {
|
||||
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
if (serverConfig.isDocStoreOnly()) {
|
||||
return new DocStoreTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* Prepare the query and calculate the query plan key.
|
||||
*/
|
||||
public void prepareQuery() {
|
||||
|
||||
if (beanDescriptor.isDocStoreOnly()) {
|
||||
query.setUseDocStore(true);
|
||||
}
|
||||
adapterPreQuery();
|
||||
this.secondaryQueries = query.convertJoins();
|
||||
this.queryPlanKey = query.prepare(this);
|
||||
|
||||
@@ -138,6 +138,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private long version;
|
||||
|
||||
private long now;
|
||||
|
||||
/**
|
||||
* Flag set when request is added to JDBC batch registered as a "getter callback" to automatically flush batch.
|
||||
*/
|
||||
@@ -1096,4 +1098,41 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
// delete handled by the BeanController so return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist to the document store now (via buffer, not post commit).
|
||||
*/
|
||||
public void docStorePersist() {
|
||||
idValue = beanDescriptor.getId(entityBean);
|
||||
switch (type) {
|
||||
case UPDATE:
|
||||
dirtyProperties = intercept.getDirtyProperties();
|
||||
break;
|
||||
}
|
||||
// processing now so set IGNORE (unlike DB + DocStore processing with post-commit)
|
||||
docStoreMode = DocStoreMode.IGNORE;
|
||||
try {
|
||||
docStoreUpdate(transaction.getDocStoreTransaction().obtain());
|
||||
postExecute();
|
||||
if (type == Type.UPDATE
|
||||
&& beanDescriptor.isDocStoreEmbeddedInvalidation()
|
||||
&& transaction.isPersistCascade()) {
|
||||
// queue embedded/nested updates for later processing
|
||||
beanDescriptor.docStoreUpdateEmbedded(this, transaction.getDocStoreTransaction().queue());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Error persisting doc store bean", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a common 'now' value across both when created and when updated etc.
|
||||
*/
|
||||
public long now() {
|
||||
if (now == 0) {
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
return now;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.core.bootup;
|
||||
|
||||
import com.avaje.ebean.annotation.DocStore;
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.IdGenerator;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
@@ -463,18 +464,14 @@ public class BootupClasses implements ClassFilter {
|
||||
}
|
||||
|
||||
private boolean isEntity(Class<?> cls) {
|
||||
|
||||
Annotation ann = cls.getAnnotation(Entity.class);
|
||||
if (ann != null) {
|
||||
return true;
|
||||
}
|
||||
ann = cls.getAnnotation(Table.class);
|
||||
return ann != null;
|
||||
return has(cls, Entity.class) || has(cls, Table.class) || has(cls, DocStore.class);
|
||||
}
|
||||
|
||||
private boolean isEmbeddable(Class<?> cls) {
|
||||
return has(cls, Embeddable.class);
|
||||
}
|
||||
|
||||
Annotation ann = cls.getAnnotation(Embeddable.class);
|
||||
return ann != null;
|
||||
private boolean has(Class<?> cls, Class<? extends Annotation> ann) {
|
||||
return cls.getAnnotation(ann) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -139,7 +138,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
|
||||
public enum EntityType {
|
||||
ORM, EMBEDDED, VIEW, SQL
|
||||
ORM, EMBEDDED, VIEW, SQL, DOC
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,7 +396,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
private final BeanDescriptorJsonHelp<T> jsonHelp;
|
||||
private DocStoreBeanAdapter<T> docStoreAdapter;
|
||||
private DocumentMapping docMapping;
|
||||
|
||||
private boolean docStoreEmbeddedInvalidation;
|
||||
|
||||
private final String defaultSelectClause;
|
||||
|
||||
@@ -602,6 +601,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a "Doc Store only" entity bean.
|
||||
*/
|
||||
public boolean isDocStoreOnly() {
|
||||
return EntityType.DOC == entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this domain object.
|
||||
*/
|
||||
@@ -712,6 +718,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform last initialisation for the descriptor.
|
||||
*/
|
||||
public void initLast() {
|
||||
docStoreEmbeddedInvalidation = docStoreAdapter.hasEmbeddedInvalidation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the document mapping.
|
||||
*/
|
||||
@@ -927,6 +940,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return docStoreAdapter.isMapped();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean type has embedded doc store invalidation.
|
||||
*/
|
||||
public boolean isDocStoreEmbeddedInvalidation() {
|
||||
return docStoreEmbeddedInvalidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the queueId used to uniquely identify this type when queuing an index updateAdd.
|
||||
*/
|
||||
|
||||
@@ -558,10 +558,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
// create BeanManager for each non-embedded entity bean
|
||||
for (BeanDescriptor<?> d : descMap.values()) {
|
||||
d.initLast();
|
||||
if (!d.isEmbedded()) {
|
||||
BeanManager<?> m = beanManagerFactory.create(d);
|
||||
beanManagerMap.put(d.getFullName(), m);
|
||||
|
||||
checkForValidEmbeddedId(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +333,10 @@ public class DeployBeanDescriptor<T> {
|
||||
return EntityType.ORM.equals(et);
|
||||
}
|
||||
|
||||
public boolean isDocStoreOnly() {
|
||||
return EntityType.DOC.equals(entityType);
|
||||
}
|
||||
|
||||
public EntityType getEntityType() {
|
||||
if (entityType == null) {
|
||||
entityType = EntityType.ORM;
|
||||
|
||||
@@ -95,12 +95,12 @@ public class DeployTableJoin {
|
||||
/**
|
||||
* Add a JoinColumn set.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, Set<JoinColumn> jcSet, BeanTable beanTable) {
|
||||
for (JoinColumn jc: jcSet) {
|
||||
addJoinColumn(order, jc, beanTable);
|
||||
public void addJoinColumn(boolean order, Set<JoinColumn> joinColumns, BeanTable beanTable) {
|
||||
for (JoinColumn joinColumn : joinColumns) {
|
||||
addJoinColumn(order, joinColumn, beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
|
||||
+10
-11
@@ -1,14 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
|
||||
import com.avaje.ebean.annotation.HistoryExclude;
|
||||
import com.avaje.ebean.annotation.PrivateOwned;
|
||||
import com.avaje.ebean.annotation.Where;
|
||||
@@ -25,17 +16,25 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
*/
|
||||
public class AnnotationAssocManys extends AnnotationParser {
|
||||
class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the DeployInfo.
|
||||
*/
|
||||
public AnnotationAssocManys(DeployBeanInfo<?> info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) {
|
||||
AnnotationAssocManys(DeployBeanInfo<?> info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) {
|
||||
super(info, javaxValidationAnnotations);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,9 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
|
||||
private void readEmbedded(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
if (descriptor.isDocStoreOnly() && prop.getDocStoreDoc() == null) {
|
||||
prop.setDocStoreEmbedded("");
|
||||
}
|
||||
prop.setEmbedded();
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
* Looks first at the field and then at the getter method.
|
||||
* </p>
|
||||
@@ -55,7 +55,7 @@ public abstract class AnnotationBase {
|
||||
* If a <code>repeatable</code> annotation class is specified and the annotation is platform
|
||||
* specific(see {@link #getPlatformMatchingAnnotation(Set, Class)}), then the platform specific
|
||||
* annotation is returned. Otherwise the first annotation is retured. Note that you must no longer
|
||||
* handle "java 1.6 repeatable containers" like {@link JoinColumn} / {@link JoinColumns} yourself.
|
||||
* handle "java 1.6 repeatable containers" like {@link JoinColumn} / {@link JoinColumns} yourself.
|
||||
* </p>
|
||||
* <p>
|
||||
*/
|
||||
@@ -94,8 +94,7 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
@@ -170,10 +169,10 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first annotation of a type for this platform. (if annotation is platform specific, otherwise first
|
||||
* Finds the first annotation of a type for this platform. (if annotation is platform specific, otherwise first
|
||||
* found annotation is returned)
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType,
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType,
|
||||
Class<? extends DatabasePlatform> databasePlatform) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
@@ -205,7 +204,7 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all {@link Annotation}s of {@code annotationType} on the supplied {@link AnnotatedElement}.
|
||||
* <p>
|
||||
@@ -232,7 +231,7 @@ public abstract class AnnotationBase {
|
||||
|
||||
Annotation[] anns = annotatedElement.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
ret.add((A) ann);
|
||||
} else {
|
||||
@@ -263,18 +262,18 @@ public abstract class AnnotationBase {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final ConcurrentMap<Annotation, Method> valueMethods = new ConcurrentHashMap<Annotation, Method>();
|
||||
private static final Method nullMethod = getNullMethod();
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the <code>value()</code> method for a possible containerAnnotation.
|
||||
* Method is retuned only, if its signature is <code>array of containingType</code>.
|
||||
* Method is retuned only, if its signature is <code>array of containingType</code>.
|
||||
*/
|
||||
private static <A extends Annotation> Method getRepeatableValueMethod(
|
||||
Annotation containerAnnotation, Class<A> containingType) {
|
||||
|
||||
|
||||
Method method = valueMethods.get(containerAnnotation);
|
||||
if (method == null) {
|
||||
try {
|
||||
@@ -295,11 +294,11 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds a suitable annotation from <code>Set<T> anns</code> for this platform.
|
||||
* To distinguish between platforms, annotation type <code>T</code> must define
|
||||
* a method withthis signature:
|
||||
* To distinguish between platforms, annotation type <code>T</code> must define
|
||||
* a method withthis signature:
|
||||
* <p>
|
||||
* <code>Class<? extends DatabasePlatform>[] platforms() default {};</code>
|
||||
* </p>
|
||||
@@ -345,4 +344,4 @@ public abstract class AnnotationBase {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +108,17 @@ public class AnnotationClass extends AnnotationParser {
|
||||
|
||||
private void read(Class<?> cls) {
|
||||
|
||||
// maybe doc store only so check for this before @Entity
|
||||
DocStore docStore = AnnotationBase.findAnnotation(cls,DocStore.class);
|
||||
if (docStore != null) {
|
||||
descriptor.readDocStore(docStore);
|
||||
descriptor.setEntityType(EntityType.DOC);
|
||||
descriptor.setName(cls.getSimpleName());
|
||||
}
|
||||
|
||||
Entity entity = AnnotationBase.findAnnotation(cls,Entity.class);
|
||||
if (entity != null) {
|
||||
descriptor.setEntityType(EntityType.ORM);
|
||||
if (entity.name().equals("")) {
|
||||
descriptor.setName(cls.getSimpleName());
|
||||
} else {
|
||||
@@ -170,11 +179,6 @@ public class AnnotationClass extends AnnotationParser {
|
||||
descriptor.setDbComment(comment.value());
|
||||
}
|
||||
|
||||
DocStore docStore = AnnotationBase.findAnnotation(cls,DocStore.class);
|
||||
if (docStore != null) {
|
||||
descriptor.readDocStore(docStore);
|
||||
}
|
||||
|
||||
UpdateMode updateMode = AnnotationBase.findAnnotation(cls,UpdateMode.class);
|
||||
if (updateMode != null) {
|
||||
descriptor.setUpdateChangesOnly(updateMode.updateChangesOnly());
|
||||
|
||||
@@ -96,6 +96,13 @@ public class AnnotationFields extends AnnotationParser {
|
||||
DocEmbedded docEmbedded = get(prop, DocEmbedded.class);
|
||||
if (docEmbedded != null) {
|
||||
prop.setDocStoreEmbedded(docEmbedded.doc());
|
||||
if (descriptor.isDocStoreOnly()) {
|
||||
if (get(prop, ManyToOne.class) == null) {
|
||||
prop.setEmbedded();
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
|
||||
+4
-3
@@ -16,18 +16,19 @@ public class DmlBeanPersisterFactory implements BeanPersisterFactory {
|
||||
this.metaFactory = new MetaFactory(dbPlatform);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a DmlBeanPersister for the given bean type.
|
||||
*/
|
||||
public BeanPersister create(BeanDescriptor<?> desc) {
|
||||
|
||||
if (desc.isDocStoreOnly()) {
|
||||
return new DocStoreBeanPersister(GeneratedProperties.of(desc));
|
||||
}
|
||||
|
||||
UpdateMeta updMeta = metaFactory.createUpdate(desc);
|
||||
DeleteMeta delMeta = metaFactory.createDelete(desc);
|
||||
InsertMeta insMeta = metaFactory.createInsert(desc);
|
||||
|
||||
return new DmlBeanPersister(updMeta, insMeta, delMeta);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dml;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.persist.BeanPersister;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Document store based BeanPersister.
|
||||
*/
|
||||
class DocStoreBeanPersister implements BeanPersister {
|
||||
|
||||
private final GeneratedProperties generatedProperties;
|
||||
|
||||
DocStoreBeanPersister(GeneratedProperties generatedProperties) {
|
||||
this.generatedProperties = generatedProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(PersistRequestBean<?> request) throws PersistenceException {
|
||||
//request.setIdValueForDocStore();
|
||||
generatedProperties.preInsert(request.getEntityBean(), request.now());
|
||||
request.docStorePersist();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(PersistRequestBean<?> request) throws PersistenceException {
|
||||
generatedProperties.preUpdate(request.getEntityBean(), request.now());
|
||||
request.docStorePersist();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(PersistRequestBean<?> request) throws PersistenceException {
|
||||
request.docStorePersist();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dml;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes the generated property (like WhenCreated, WhoCreated etc) for doc store persisting.
|
||||
*/
|
||||
class GeneratedProperties {
|
||||
|
||||
/**
|
||||
* Create the GeneratedProperties for the given bean type.
|
||||
*/
|
||||
static GeneratedProperties of(BeanDescriptor<?> desc) {
|
||||
return new GeneratedPropertyCollector(desc).generatedProperties();
|
||||
}
|
||||
|
||||
private final SetValue[] onInsert;
|
||||
private final SetValue[] onUpdate;
|
||||
|
||||
GeneratedProperties(List<BeanProperty> inserts, List<BeanProperty> updates) {
|
||||
this.onInsert = adapt(inserts);
|
||||
this.onUpdate = adapt(updates);
|
||||
}
|
||||
|
||||
private SetValue[] adapt(List<BeanProperty> inserts) {
|
||||
SetValue[] setters = new SetValue[inserts.size()];
|
||||
for (int i = 0; i < inserts.size(); i++) {
|
||||
setters[i] = new SetValue(inserts.get(i));
|
||||
}
|
||||
return setters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the generated on insert values.
|
||||
*/
|
||||
public void preInsert(EntityBean bean, long now) {
|
||||
for (SetValue setter : onInsert) {
|
||||
setter.preInsert(bean, now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the generated on update values.
|
||||
*/
|
||||
public void preUpdate(EntityBean bean, long now) {
|
||||
for (SetValue setter : onUpdate) {
|
||||
setter.preUpdate(bean, now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SetValue {
|
||||
|
||||
private final BeanProperty property;
|
||||
private final GeneratedProperty generatedProperty;
|
||||
|
||||
SetValue(BeanProperty property) {
|
||||
this.property = property;
|
||||
this.generatedProperty = property.getGeneratedProperty();
|
||||
}
|
||||
|
||||
public void preInsert(EntityBean bean, long now) {
|
||||
Object value = generatedProperty.getInsertValue(property, bean, now);
|
||||
property.setValue(bean, value);
|
||||
}
|
||||
|
||||
public void preUpdate(EntityBean bean, long now) {
|
||||
Object value = generatedProperty.getUpdateValue(property, bean, now);
|
||||
property.setValue(bean, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dml;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Collects the generated properties for inserts and updates for a given bean type.
|
||||
*/
|
||||
class GeneratedPropertyCollector {
|
||||
|
||||
private final List<BeanProperty> preInsert = new ArrayList<>();
|
||||
private final List<BeanProperty> preUpdate = new ArrayList<>();
|
||||
|
||||
GeneratedPropertyCollector(BeanDescriptor<?> desc) {
|
||||
for (BeanProperty beanProperty : desc.propertiesBaseScalar()) {
|
||||
add(beanProperty);
|
||||
}
|
||||
}
|
||||
|
||||
GeneratedProperties generatedProperties() {
|
||||
return new GeneratedProperties(preInsert, preUpdate);
|
||||
}
|
||||
|
||||
void add(BeanProperty prop) {
|
||||
GeneratedProperty gen = prop.getGeneratedProperty();
|
||||
if (gen != null) {
|
||||
if (gen.includeInInsert()) {
|
||||
preInsert.add(prop);
|
||||
}
|
||||
if (gen.includeInUpdate()) {
|
||||
preUpdate.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Document store only transaction.
|
||||
*/
|
||||
public class DocStoreOnlyTransaction extends JdbcTransaction {
|
||||
|
||||
/**
|
||||
* Create a new DocStore only Transaction.
|
||||
*/
|
||||
public DocStoreOnlyTransaction(String id, boolean explicit, TransactionManager manager) {
|
||||
super(id, explicit, null, manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
protected void deactivate() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getInternalConnection() {
|
||||
throw new RuntimeException("not supported on DocStoreTransaction");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
throw new RuntimeException("not supported on DocStoreTransaction");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performRollback() throws SQLException {
|
||||
// do nothing (could perhaps throw not supported exception)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommit() throws SQLException {
|
||||
if (docStoreTxn != null) {
|
||||
manager.docStoreUpdateProcessor.commit(docStoreTxn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* Transaction manager used for doc store only EbeanServer instance.
|
||||
* <p>
|
||||
* There is no underlying JDBC DataSource etc
|
||||
*/
|
||||
public class DocStoreTransactionManager extends TransactionManager {
|
||||
|
||||
private final String prefix = "";
|
||||
|
||||
/**
|
||||
* Create the TransactionManager
|
||||
*/
|
||||
public DocStoreTransactionManager(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr) {
|
||||
super(localL2Caching, config, clusterManager, backgroundExecutor, docStoreUpdateProcessor, descMgr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiTransaction createTransaction(boolean explicit, int isolationLevel) {
|
||||
long id = transactionCounter.incrementAndGet();
|
||||
return createTransaction(explicit, null, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiTransaction createQueryTransaction() {
|
||||
return new DocStoreOnlyTransaction("", false, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) {
|
||||
return new DocStoreOnlyTransaction(prefix + id, explicit, this);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Str;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeanservice.docstore.api.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -164,6 +165,8 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
*/
|
||||
protected final boolean skipCacheAfterWrite;
|
||||
|
||||
protected DocStoreTransaction docStoreTxn;
|
||||
|
||||
/**
|
||||
* Create a new JdbcTransaction.
|
||||
*/
|
||||
@@ -1079,6 +1082,15 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
getEvent().add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocStoreTransaction getDocStoreTransaction() {
|
||||
if (docStoreTxn == null) {
|
||||
queryOnly = false;
|
||||
docStoreTxn = manager.createDocStoreTransaction(docStoreBatchSize);
|
||||
}
|
||||
return docStoreTxn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putUserObject(String name, Object value) {
|
||||
if (userObjects == null) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreTransaction;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import org.avaje.datasource.DataSourcePool;
|
||||
@@ -144,6 +145,10 @@ public class TransactionManager {
|
||||
return docStoreActive;
|
||||
}
|
||||
|
||||
public DocStoreTransaction createDocStoreTransaction(int docStoreBatchSize) {
|
||||
return docStoreUpdateProcessor.createTransaction(docStoreBatchSize);
|
||||
}
|
||||
|
||||
public boolean isSkipCacheAfterWrite() {
|
||||
return skipCacheAfterWrite;
|
||||
}
|
||||
@@ -433,4 +438,5 @@ public class TransactionManager {
|
||||
beanDescriptorManager.processViewInvalidation(viewInvalidation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.avaje.ebeanservice.docstore.api;
|
||||
|
||||
/**
|
||||
* A document store transaction.
|
||||
* <p>
|
||||
* This might just be a buffer to batch persist requests to the document store and may not
|
||||
* support transactional semantics (like rollback).
|
||||
*/
|
||||
public interface DocStoreTransaction {
|
||||
|
||||
/**
|
||||
* Obtain a context to persist to (like a buffer).
|
||||
*/
|
||||
DocStoreUpdateContext obtain();
|
||||
|
||||
/**
|
||||
* Add changes that should be queued to the DocStoreUpdates.
|
||||
* <p>
|
||||
* This mostly means nested/embedded updates that need to be processed after the source
|
||||
* persist event has propagated.
|
||||
* </p>
|
||||
*/
|
||||
DocStoreUpdates queue();
|
||||
|
||||
/**
|
||||
* Flush all changes to the document store.
|
||||
*/
|
||||
void flush();
|
||||
}
|
||||
@@ -31,4 +31,15 @@ public interface DocStoreUpdateProcessor {
|
||||
*/
|
||||
void process(DocStoreUpdates docStoreUpdates, int bulkBatchSize);
|
||||
|
||||
/**
|
||||
* Create a document store transaction hinting at the batch size.
|
||||
* <p>
|
||||
* The batch size can be set via {@link com.avaje.ebean.Transaction#setDocStoreBatchSize(int)}
|
||||
*/
|
||||
DocStoreTransaction createTransaction(int batchSize);
|
||||
|
||||
/**
|
||||
* Perform commit/flush of the changes made via the document store transaction.
|
||||
*/
|
||||
void commit(DocStoreTransaction docStoreTransaction);
|
||||
}
|
||||
|
||||
+6
-3
@@ -174,9 +174,12 @@ public abstract class DocStoreBeanBaseAdapter<T> implements DocStoreBeanAdapter<
|
||||
String path = pathProp.getPath();
|
||||
if (path != null) {
|
||||
BeanDescriptor<?> targetDesc = desc.getBeanDescriptor(path);
|
||||
String idName = targetDesc.getIdProperty().getName();
|
||||
String fullPath = path + "." + idName;
|
||||
targetDesc.docStoreAdapter().registerInvalidationPath(desc.getDocStoreQueueId(), fullPath, pathProp.getProperties());
|
||||
BeanProperty idProperty = targetDesc.getIdProperty();
|
||||
if (idProperty != null) {
|
||||
// embedded beans don't have id property
|
||||
String fullPath = path + "." + idProperty.getName();
|
||||
targetDesc.docStoreAdapter().registerInvalidationPath(desc.getDocStoreQueueId(), fullPath, pathProp.getProperties());
|
||||
}
|
||||
}
|
||||
}
|
||||
registerPaths = true;
|
||||
|
||||
+12
-1
@@ -2,6 +2,7 @@ package com.avaje.ebeanservice.docstore.none;
|
||||
|
||||
import com.avaje.ebean.plugin.BeanType;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreQueryUpdate;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreTransaction;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
|
||||
@@ -10,7 +11,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* DocStoreUpdateProcessor that barfs if it is used.
|
||||
*/
|
||||
public class NoneDocStoreUpdateProcessor implements DocStoreUpdateProcessor {
|
||||
class NoneDocStoreUpdateProcessor implements DocStoreUpdateProcessor {
|
||||
|
||||
@Override
|
||||
public <T> DocStoreQueryUpdate<T> createQueryUpdate(BeanType<T> beanType, int bulkBatchSize) throws IOException {
|
||||
@@ -21,4 +22,14 @@ public class NoneDocStoreUpdateProcessor implements DocStoreUpdateProcessor {
|
||||
public void process(DocStoreUpdates docStoreUpdates, int bulkBatchSize) {
|
||||
throw NoneDocStore.implementationNotInClassPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocStoreTransaction createTransaction(int batchSize) {
|
||||
throw NoneDocStore.implementationNotInClassPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(DocStoreTransaction docStoreTransaction) {
|
||||
throw NoneDocStore.implementationNotInClassPath();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user