This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push:
new 885335b1b cleanup, including some deprecation
885335b1b is described below
commit 885335b1bdde795c2bf5cc3bd9a17e9e6a2e4062
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sat May 30 17:06:54 2026 -0400
cleanup, including some deprecation
---
.../java/org/apache/cayenne/ObjectContext.java | 7 +-
.../org/apache/cayenne/access/DataContext.java | 64 +-
.../cayenne/access/DataContextDeleteAction.java | 50 +-
.../cayenne/access/DataContextMergeHandler.java | 12 +-
.../cayenne/access/DataContextQueryAction.java | 16 +-
.../cayenne/access/DataContextSnapshotBuilder.java | 7 +-
.../java/org/apache/cayenne/access/DataDomain.java | 1517 ++++++++++----------
.../access/DataDomainLegacyQueryAction.java | 2 -
.../java/org/apache/cayenne/access/DataNode.java | 14 +-
.../org/apache/cayenne/access/QueryEngine.java | 12 +-
.../main/java/org/apache/cayenne/query/Query.java | 6 +-
11 files changed, 846 insertions(+), 861 deletions(-)
diff --git a/cayenne/src/main/java/org/apache/cayenne/ObjectContext.java
b/cayenne/src/main/java/org/apache/cayenne/ObjectContext.java
index 4166b06f1..cc9d45c6d 100644
--- a/cayenne/src/main/java/org/apache/cayenne/ObjectContext.java
+++ b/cayenne/src/main/java/org/apache/cayenne/ObjectContext.java
@@ -171,9 +171,12 @@ public interface ObjectContext extends DataChannel,
Serializable {
void rollbackChangesLocally();
/**
- * Executes a selecting query, returning a list of persistent objects or
- * data rows.
+ * Executes a selecting query, returning a list of persistent objects or
data rows.
*/
+ // TODO: this will need to be deprecated at some point. The reason we
can't do that yet is that
+ // EJBQLQuery, SQLTemplate, RefreshQuery, RelationshipQuery,
ObjectIdQuery do not implement "Select".
+ // Those queries should eventually either go away (EJBQLQuery,
ObjectIdQuery, SQLTemplate) or made implement Select
+ // (RelationshipQuery, RefreshQuery)
List performQuery(Query query);
/**
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
index f52368a28..8cf567906 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataContext.java
@@ -19,18 +19,6 @@
package org.apache.cayenne.access;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.DataRow;
@@ -55,7 +43,14 @@ import org.apache.cayenne.graph.GraphEvent;
import org.apache.cayenne.graph.GraphManager;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.*;
+import org.apache.cayenne.query.IteratedQueryDecorator;
+import org.apache.cayenne.query.MappedExec;
+import org.apache.cayenne.query.MappedSelect;
+import org.apache.cayenne.query.ObjectIdQuery;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.query.RefreshQuery;
+import org.apache.cayenne.query.Select;
import org.apache.cayenne.reflect.ClassDescriptor;
import org.apache.cayenne.reflect.PropertyDescriptor;
import org.apache.cayenne.runtime.CayenneRuntime;
@@ -65,6 +60,18 @@ import org.apache.cayenne.util.GenericResponse;
import org.apache.cayenne.util.ObjectContextGraphAction;
import org.apache.cayenne.util.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
/**
* The most common implementation of {@link ObjectContext}. DataContext is an
* isolated container of an object graph, in a sense that any uncommitted
@@ -78,16 +85,18 @@ public class DataContext implements ObjectContext {
*
* @since 3.0
*/
- protected static final ThreadLocal<ObjectContext> threadObjectContext =
new ThreadLocal<ObjectContext>();
+ @Deprecated(since = "5.0", forRemoval = true)
+ protected static final ThreadLocal<ObjectContext> threadObjectContext =
new ThreadLocal<>();
/**
* Returns the ObjectContext bound to the current thread.
*
* @since 3.0
* @return the ObjectContext associated with caller thread.
- * @throws IllegalStateException
- * if there is no ObjectContext bound to the current thread.
+ * @throws IllegalStateException if there is no ObjectContext bound to the
current thread.
+ * @deprecated if you are using thread context, you can create your own
ThreadLocal
*/
+ @Deprecated(since = "5.0", forRemoval = true)
public static ObjectContext getThreadObjectContext() throws
IllegalStateException {
ObjectContext context = threadObjectContext.get();
if (context == null) {
@@ -104,7 +113,9 @@ public class DataContext implements ObjectContext {
* unbind currently bound ObjectContext.
*
* @since 3.0
+ * @deprecated if you are using thread context, you can create your own
ThreadLocal
*/
+ @Deprecated(since = "5.0", forRemoval = true)
public static void bindThreadObjectContext(ObjectContext context) {
threadObjectContext.set(context);
}
@@ -133,11 +144,6 @@ public class DataContext implements ObjectContext {
protected transient QueryCache queryCache;
protected transient EntityResolver entityResolver;
- /**
- * @deprecated since 4.0 used in a method that itself should be deprecated,
- * so this is a temp code
- */
- @Deprecated
protected transient TransactionFactory transactionFactory;
protected transient DataContextMergeHandler mergeHandler;
@@ -313,7 +319,7 @@ public class DataContext implements ObjectContext {
List<?> response = channel.onQuery(this, new
DataDomainQuery()).firstList();
- if (response != null && response.size() > 0 && response.get(0)
instanceof DataDomain dataDomain) {
+ if (response != null && !response.isEmpty() && response.getFirst()
instanceof DataDomain dataDomain) {
return dataDomain;
}
@@ -563,7 +569,7 @@ public class DataContext implements ObjectContext {
if (object.getPersistenceState() == PersistenceState.HOLLOW) {
ObjectId oid = object.getObjectId();
List<?> objects = performQuery(new ObjectIdQuery(oid, false,
ObjectIdQuery.CACHE));
- if (objects.size() == 0) {
+ if (objects.isEmpty()) {
throw new FaultFailureException(
"Error resolving fault, no matching row exists in the
database for ObjectId: " + oid);
} else if (objects.size() > 1) {
@@ -630,7 +636,7 @@ public class DataContext implements ObjectContext {
ClassDescriptor descriptor =
getEntityResolver().getClassDescriptor(entity.getName());
List<T> list = objectsFromDataRows(descriptor,
Collections.singletonList(dataRow));
- return list.get(0);
+ return list.getFirst();
}
/**
@@ -645,7 +651,7 @@ public class DataContext implements ObjectContext {
ClassDescriptor descriptor =
getEntityResolver().getClassDescriptor(entityName);
List<?> list = objectsFromDataRows(descriptor,
Collections.singletonList(dataRow));
- return (Persistent) list.get(0);
+ return (Persistent) list.getFirst();
}
/**
@@ -900,13 +906,13 @@ public class DataContext implements ObjectContext {
public <T> T selectOne(Select<T> query) {
List<T> objects = select(query);
- if (objects.size() == 0) {
+ if (objects.isEmpty()) {
return null;
} else if (objects.size() > 1) {
throw new CayenneRuntimeException("Expected zero or one object,
instead query matched: %d", objects.size());
}
- return objects.get(0);
+ return objects.getFirst();
}
/**
@@ -916,7 +922,7 @@ public class DataContext implements ObjectContext {
public <T> T selectFirst(Select<T> query) {
List<T> objects = select(query);
- return (objects == null || objects.isEmpty()) ? null : objects.get(0);
+ return (objects == null || objects.isEmpty()) ? null :
objects.getFirst();
}
/**
@@ -925,7 +931,7 @@ public class DataContext implements ObjectContext {
@Override
public <T> void iterate(Select<T> query, ResultIteratorCallback<T>
callback) {
- try (ResultIterator<T> it = iterator(query);) {
+ try (ResultIterator<T> it = iterator(query)) {
for (T t : it) {
callback.next(t);
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.java
index 9eb4784da..b14126f37 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextDeleteAction.java
@@ -19,11 +19,6 @@
package org.apache.cayenne.access;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.DeleteDenyException;
import org.apache.cayenne.ObjectContext;
@@ -40,14 +35,19 @@ import org.apache.cayenne.reflect.PropertyVisitor;
import org.apache.cayenne.reflect.ToManyProperty;
import org.apache.cayenne.reflect.ToOneProperty;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
/**
* A CayenneContext helper that processes object deletion.
- *
+ *
* @since 1.2
*/
class DataContextDeleteAction {
- private ObjectContext context;
+ private final ObjectContext context;
DataContextDeleteAction(ObjectContext context) {
this.context = context;
@@ -73,19 +73,19 @@ class DataContextDeleteAction {
if (object.getObjectContext() != context) {
throw new CayenneRuntimeException(
- "Attempt to delete object regsitered in a different
ObjectContext. Object: %s, context: %s"
- , object, context);
+ "Attempt to delete object registered in a different
ObjectContext. Object: %s, context: %s",
+ object,
+ context);
}
// must resolve HOLLOW objects before delete... needed
// to process relationships and optimistic locking...
context.prepareForAccess(object, null, false);
-
+
if (oldState == PersistenceState.NEW) {
deleteNew(object);
- }
- else {
+ } else {
deletePersistent(object);
}
@@ -95,7 +95,7 @@ class DataContextDeleteAction {
private void deleteNew(Persistent object) throws DeleteDenyException {
object.setPersistenceState(PersistenceState.TRANSIENT);
processDeleteRules(object, PersistenceState.NEW);
-
+
// if an object was NEW, we must throw it out
context.getGraphManager().unregisterNode(object.getObjectId());
}
@@ -104,7 +104,7 @@ class DataContextDeleteAction {
context.getEntityResolver().getCallbackRegistry().performCallbacks(
LifecycleEvent.PRE_REMOVE,
object);
-
+
int oldState = object.getPersistenceState();
object.setPersistenceState(PersistenceState.DELETED);
processDeleteRules(object, oldState);
@@ -114,18 +114,16 @@ class DataContextDeleteAction {
@SuppressWarnings("unchecked")
private Collection<Persistent> toCollection(Object object) {
- if (object == null) {
- return Collections.emptyList();
- }
+ return switch (object) {
+ case null -> Collections.emptyList();
+
+
+ // create copies of collections to avoid iterator exceptions
+ case Collection ignored -> new
ArrayList<>((Collection<Persistent>) object);
+ case Map ignored -> new ArrayList<>(((Map<?, Persistent>)
object).values());
+ default -> Collections.singleton((Persistent) object);
+ };
- // create copies of collections to avoid iterator exceptions
- if (object instanceof Collection) {
- return new ArrayList<>((Collection<Persistent>) object);
- } else if (object instanceof Map) {
- return new ArrayList<>(((Map<?, Persistent>) object).values());
- } else {
- return Collections.singleton((Persistent)object);
- }
}
private void processDeleteRules(final Persistent object, int oldState)
@@ -149,7 +147,7 @@ class DataContextDeleteAction {
final Collection<Persistent> relatedObjects =
toCollection(property.readProperty(object));
// no related object, bail out
- if (relatedObjects.size() == 0) {
+ if (relatedObjects.isEmpty()) {
continue;
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
index 8bed8e676..40a02fbef 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextMergeHandler.java
@@ -47,7 +47,7 @@ import org.apache.cayenne.reflect.ToOneProperty;
class DataContextMergeHandler implements GraphChangeHandler,
DataChannelListener {
private boolean active;
- private DataContext context;
+ private final DataContext context;
DataContextMergeHandler(DataContext context) {
this.active = true;
@@ -136,10 +136,6 @@ class DataContextMergeHandler implements
GraphChangeHandler, DataChannelListener
public void graphRolledback(GraphEvent event) {
// TODO: andrus, 3/26/2006 - enable this once all ObjectStore diffs
implement
// working undo operation
-
- // if(shouldProcessEvent(e)) {
- // event.getDiff().undo(this);
- // }
}
// *** GraphChangeHandler methods
@@ -177,16 +173,16 @@ class DataContextMergeHandler implements
GraphChangeHandler, DataChannelListener
@Override
public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
- arcChanged(nodeId, targetNodeId, arcId);
+ arcChanged(nodeId, arcId);
}
@Override
public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
- arcChanged(nodeId, targetNodeId, arcId);
+ arcChanged(nodeId, arcId);
}
// works the same for add and remove as long as we don't get too smart per
TODO below.
- private void arcChanged(Object nodeId, Object targetNodeId, Object arcId) {
+ private void arcChanged(Object nodeId, Object arcId) {
final Persistent source = (Persistent)
context.getGraphManager().getNode(nodeId);
if (source != null && source.getPersistenceState() !=
PersistenceState.HOLLOW) {
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextQueryAction.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextQueryAction.java
index 2aa45cc1d..4222daa9f 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextQueryAction.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextQueryAction.java
@@ -19,12 +19,6 @@
package org.apache.cayenne.access;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.Persistent;
@@ -36,6 +30,12 @@ import org.apache.cayenne.query.RefreshQuery;
import org.apache.cayenne.util.ListResponse;
import org.apache.cayenne.util.ObjectContextQueryAction;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
/**
* A DataContext-specific version of
* {@link org.apache.cayenne.util.ObjectContextQueryAction}.
@@ -140,7 +140,7 @@ class DataContextQueryAction extends
ObjectContextQueryAction {
if(rsMapping.size() > 1) {
mixedResults = true;
} else if(rsMapping.size() == 1) {
- mixedResults = !(rsMapping.get(0) instanceof
EntityResultSegment)
+ mixedResults = !(rsMapping.getFirst() instanceof
EntityResultSegment)
|| !metadata.isSingleResultSetMapping();
}
}
@@ -172,7 +172,7 @@ class DataContextQueryAction extends
ObjectContextQueryAction {
}
// 2. invalidate object collection
- Collection objects = refreshQuery.getObjects();
+ Collection<?> objects = refreshQuery.getObjects();
if (objects != null && !objects.isEmpty()) {
synchronized (context.getObjectStore()) {
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextSnapshotBuilder.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextSnapshotBuilder.java
index 4eb72dd1f..5183488fe 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/DataContextSnapshotBuilder.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/DataContextSnapshotBuilder.java
@@ -121,7 +121,7 @@ class DataContextSnapshotBuilder implements PropertyVisitor
{
+ ". Object may have been deleted externally.",
object.getObjectId());
}
- DbRelationship dbRel = rel.getDbRelationships().get(0);
+ DbRelationship dbRel = rel.getDbRelationships().getFirst();
for (DbJoin join : dbRel.getJoins()) {
String key = join.getSourceName();
snapshot.put(key, storedSnapshot.get(key));
@@ -134,13 +134,12 @@ class DataContextSnapshotBuilder implements
PropertyVisitor {
Persistent target = (Persistent) targetObject;
Map<String, Object> idParts = target.getObjectId().getIdSnapshot();
- // this may happen in uncommitted objects - see the warning in
- // the JavaDoc of this method.
+ // this may happen in uncommitted objects - see the warning in the
JavaDoc of this method.
if (idParts.isEmpty()) {
return true;
}
- DbRelationship dbRel = rel.getDbRelationships().get(0);
+ DbRelationship dbRel = rel.getDbRelationships().getFirst();
Map<String, Object> fk =
dbRel.srcFkSnapshotWithTargetSnapshot(idParts);
snapshot.putAll(fk);
return true;
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
index 9b2811bf5..440d626c9 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
@@ -64,777 +64,766 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public class DataDomain implements QueryEngine, DataChannel {
- public static final String SHARED_CACHE_ENABLED_PROPERTY =
"cayenne.DataDomain.sharedCache";
- public static final boolean SHARED_CACHE_ENABLED_DEFAULT = true;
+ public static final String SHARED_CACHE_ENABLED_PROPERTY =
"cayenne.DataDomain.sharedCache";
+ public static final boolean SHARED_CACHE_ENABLED_DEFAULT = true;
- public static final String VALIDATING_OBJECTS_ON_COMMIT_PROPERTY =
"cayenne.DataDomain.validatingObjectsOnCommit";
- public static final boolean VALIDATING_OBJECTS_ON_COMMIT_DEFAULT = true;
+ public static final String VALIDATING_OBJECTS_ON_COMMIT_PROPERTY =
"cayenne.DataDomain.validatingObjectsOnCommit";
+ public static final boolean VALIDATING_OBJECTS_ON_COMMIT_DEFAULT = true;
- /**
- * @since 3.1
- */
- @Inject
- protected JdbcEventLogger jdbcEventLogger;
+ /**
+ * @since 3.1
+ */
+ @Inject
+ protected JdbcEventLogger jdbcEventLogger;
- /**
- * @since 4.0
- */
- @Inject
- protected TransactionManager transactionManager;
+ /**
+ * @since 4.0
+ */
+ @Inject
+ protected TransactionManager transactionManager;
- /**
+ /**
* @since 4.0
*/
protected DataRowStoreFactory dataRowStoreFactory;
/**
- * @since 3.1
- */
- protected int maxIdQualifierSize;
-
- /**
- * @since 4.1
- */
- protected List<DataChannelQueryFilter> queryFilters;
-
- /**
- * @since 4.1
- */
- protected List<DataChannelSyncFilter> syncFilters;
-
- /**
- * @since 4.2
- */
- @Inject
- protected DataDomainFlushActionFactory flushActionFactory;
-
- /**
- * @since 4.2
- */
- @Inject
- protected AdhocObjectFactory objectFactory;
-
- protected Map<String, DataNode> nodes;
- protected Map<String, DataNode> nodesByDataMapName;
- protected DataNode defaultNode;
- protected Map<String, String> properties;
-
- protected EntityResolver entityResolver;
- protected DataRowStore sharedSnapshotCache;
- protected String name;
- protected QueryCache queryCache;
-
- // these are initialized from properties...
- protected boolean sharedCacheEnabled;
- protected boolean validatingObjectsOnCommit;
-
- /**
- * @since 1.2
- */
- protected EventManager eventManager;
-
- /**
- * @since 1.2
- */
- protected EntitySorter entitySorter;
-
- protected boolean stopped;
-
- /**
- * Creates a DataDomain and assigns it a name.
- */
- public DataDomain(String name) {
- init(name);
- resetProperties();
- }
-
- /**
- * Creates new DataDomain.
- *
- * @param name
- * DataDomain name. Domain can be located using its name in
the
- * Configuration object.
- * @param properties
- * A Map containing domain configuration properties.
- * @deprecated since 4.0 unused
- */
- @Deprecated
- public DataDomain(String name, Map<String, String> properties) {
- init(name);
- initWithProperties(properties);
- }
-
- private void init(String name) {
-
- this.queryFilters = new CopyOnWriteArrayList<>();
- this.syncFilters = new CopyOnWriteArrayList<>();
- this.nodesByDataMapName = new ConcurrentHashMap<>();
- this.nodes = new ConcurrentHashMap<>();
-
- // properties are read-only, so no need for concurrent map, or
any
- // specific map
- // for that matter
- this.properties = Collections.emptyMap();
-
- setName(name);
- }
-
- /**
- * Checks that Domain is not stopped. Throws DomainStoppedException
- * otherwise.
- *
- * @since 3.0
- */
- protected void checkStopped() throws DomainStoppedException {
- if (stopped) {
- throw new DomainStoppedException("Domain " + name
- + " was shutdown and can no longer be
used to access the database");
- }
- }
-
- /**
- * @since 3.1
- */
- public EntitySorter getEntitySorter() {
- return entitySorter;
- }
-
- /**
- * @since 3.1
- */
- public void setEntitySorter(EntitySorter entitySorter) {
- this.entitySorter = entitySorter;
- }
-
- /**
- * @since 1.1
- */
- protected void resetProperties() {
- properties = Collections.emptyMap();
-
- sharedCacheEnabled = SHARED_CACHE_ENABLED_DEFAULT;
- validatingObjectsOnCommit =
VALIDATING_OBJECTS_ON_COMMIT_DEFAULT;
- }
-
- /**
- * Reinitializes domain state with a new set of properties.
- *
- * @since 1.1
- * @deprecated since 4.0 properties are processed by the DI provider.
- */
- @Deprecated
- public void initWithProperties(Map<String, String> properties) {
-
- // clone properties to ensure that it is read-only internally
- properties = properties != null ? new HashMap<>(properties) :
Collections.<String, String>emptyMap();
-
- String sharedCacheEnabled =
properties.get(SHARED_CACHE_ENABLED_PROPERTY);
- String validatingObjectsOnCommit =
properties.get(VALIDATING_OBJECTS_ON_COMMIT_PROPERTY);
-
- // init ivars from properties
- this.sharedCacheEnabled = (sharedCacheEnabled != null) ?
"true".equalsIgnoreCase(sharedCacheEnabled)
- : SHARED_CACHE_ENABLED_DEFAULT;
- this.validatingObjectsOnCommit = (validatingObjectsOnCommit !=
null) ? "true"
- .equalsIgnoreCase(validatingObjectsOnCommit) :
VALIDATING_OBJECTS_ON_COMMIT_DEFAULT;
-
- this.properties = properties;
- }
-
- /**
- * Returns EventManager used by this DataDomain.
- *
- * @since 1.2
- */
- public EventManager getEventManager() {
- return eventManager;
- }
-
- /**
- * Sets EventManager used by this DataDomain.
- *
- * @since 1.2
- */
- public void setEventManager(EventManager eventManager) {
- this.eventManager = eventManager;
-
- if (sharedSnapshotCache != null) {
- sharedSnapshotCache.setEventManager(eventManager);
- }
- }
-
- /**
- * Returns "name" property value.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets "name" property to a new value.
- */
- public synchronized void setName(String name) {
- this.name = name;
- if (sharedSnapshotCache != null) {
- this.sharedSnapshotCache.setName(name);
- }
- }
-
- /**
- * Returns <code>true</code> if DataContexts produced by this
DataDomain are
- * using shared DataRowStore. Returns <code>false</code> if each
DataContext
- * would work with its own DataRowStore. Note that this setting can be
- * overwritten per DataContext.
- */
- public boolean isSharedCacheEnabled() {
- return sharedCacheEnabled;
- }
-
- public void setSharedCacheEnabled(boolean sharedCacheEnabled) {
- this.sharedCacheEnabled = sharedCacheEnabled;
- }
-
- /**
- * Returns whether child DataContexts default behavior is to perform
object
- * validation before commit is executed.
- *
- * @since 1.1
- */
- public boolean isValidatingObjectsOnCommit() {
- return validatingObjectsOnCommit;
- }
-
- /**
- * Sets the property defining whether child DataContexts should perform
- * object validation before commit is executed.
- *
- * @since 1.1
- */
- public void setValidatingObjectsOnCommit(boolean flag) {
- this.validatingObjectsOnCommit = flag;
- }
-
- /**
- * @since 1.1
- * @return a Map of properties for this DataDomain.
- */
- public Map<String, String> getProperties() {
- return properties;
- }
-
- /**
- * Returns snapshots cache for this DataDomain, lazily initializing it
on
- * the first call if 'sharedCacheEnabled' flag is true.
- */
- public DataRowStore getSharedSnapshotCache() {
- if (sharedSnapshotCache == null && sharedCacheEnabled) {
- this.sharedSnapshotCache = nonNullSharedSnapshotCache();
- }
-
- return sharedSnapshotCache;
- }
-
- /**
- * Returns a guaranteed non-null shared snapshot cache regardless of the
- * 'sharedCacheEnabled' flag setting.
- */
- synchronized DataRowStore nonNullSharedSnapshotCache() {
- if (sharedSnapshotCache == null) {
- this.sharedSnapshotCache =
dataRowStoreFactory.createDataRowStore(name);
- }
-
- return sharedSnapshotCache;
- }
-
- /**
- * Shuts down the previous cache instance, sets cache to the new
- * DataSowStore instance and updates two properties of the new
DataSowStore:
- * name and eventManager.
- */
- public synchronized void setSharedSnapshotCache(DataRowStore
snapshotCache) {
- if (this.sharedSnapshotCache != snapshotCache) {
- if (this.sharedSnapshotCache != null) {
- this.sharedSnapshotCache.shutdown();
- }
- this.sharedSnapshotCache = snapshotCache;
-
- if (snapshotCache != null) {
-
snapshotCache.setEventManager(getEventManager());
- snapshotCache.setName(getName());
- }
- }
- }
-
- public void addDataMap(DataMap dataMap) {
- getEntityResolver().addDataMap(dataMap);
- refreshEntitySorter();
- }
-
- /**
- * @since 3.1
- */
- public DataMap getDataMap(String mapName) {
- return getEntityResolver().getDataMap(mapName);
- }
-
- /**
- * Removes named DataMap from this DataDomain and any underlying
DataNodes
- * that include it.
- *
- * @since 3.1
- */
- public void removeDataMap(String mapName) {
- DataMap map = getDataMap(mapName);
- if (map == null) {
- return;
- }
-
- // remove from data nodes
- for (DataNode node : nodes.values()) {
- node.removeDataMap(mapName);
- }
-
- nodesByDataMapName.remove(mapName);
-
- // remove from EntityResolver
- getEntityResolver().removeDataMap(map);
-
- refreshEntitySorter();
- }
-
- /**
- * Removes a DataNode from DataDomain. Any maps previously associated
with
- * this node within domain will still be kept around, however they
wan't be
- * mapped to any node.
- */
- public void removeDataNode(String nodeName) {
- DataNode removed = nodes.remove(nodeName);
- if (removed != null) {
- removed.setEntityResolver(null);
- nodesByDataMapName.values().removeIf(dataNode ->
dataNode == removed);
- }
- }
-
- /**
- * Returns a collection of registered DataMaps.
- */
- public Collection<DataMap> getDataMaps() {
- return getEntityResolver().getDataMaps();
- }
-
- /**
- * Returns an unmodifiable collection of DataNodes associated with this
- * domain.
- */
- public Collection<DataNode> getDataNodes() {
- return Collections.unmodifiableCollection(nodes.values());
- }
-
- /**
- * Adds new DataNode.
- */
- public void addNode(DataNode node) {
-
- // add node to name->node map
- nodes.put(node.getName(), node);
- node.setEntityResolver(getEntityResolver());
-
- // add node to "ent name->node" map
- for (DataMap map : node.getDataMaps()) {
- addDataMap(map);
- nodesByDataMapName.put(map.getName(), node);
- }
- }
-
- /**
- * Returns registered DataNode whose name matches <code>name</code>
- * parameter.
- *
- * @since 3.1
- */
- public DataNode getDataNode(String nodeName) {
- return nodes.get(nodeName);
- }
-
- /**
- * Returns a DataNode that should handle queries for all entities in a
- * DataMap.
- *
- * @since 1.1
- */
- public DataNode lookupDataNode(DataMap map) {
-
- DataNode node = nodesByDataMapName.get(map.getName());
- if (node == null) {
-
- // see if one of the node states has changed, and the
map is now
- // linked...
- for (DataNode n : getDataNodes()) {
- for (DataMap m : n.getDataMaps()) {
- if (m == map) {
-
nodesByDataMapName.put(map.getName(), n);
- node = n;
- break;
- }
- }
-
- if (node != null) {
- break;
- }
- }
-
- if (node == null) {
-
- if (defaultNode != null) {
- nodesByDataMapName.put(map.getName(),
defaultNode);
- node = defaultNode;
- } else {
- throw new CayenneRuntimeException("No
DataNode configured for DataMap '%s'"
- + " and no default
DataNode set", map.getName());
- }
- }
- }
-
- return node;
- }
-
- /**
- * Sets EntityResolver. If not set explicitly, DataDomain creates a
default
- * EntityResolver internally on demand.
- *
- * @since 1.1
- */
- public void setEntityResolver(EntityResolver entityResolver) {
- this.entityResolver = entityResolver;
- }
-
- // creates default entity resolver if there is none set yet
- private synchronized void createEntityResolver() {
- if (entityResolver == null) {
- // entity resolver will be self-indexing as we add all
our maps
- // to it as they are added to the DataDomain
- entityResolver = new EntityResolver();
- }
- }
-
- /**
- * Shutdowns all owned data nodes and marks this domain as stopped.
- */
- @BeforeScopeEnd
- public void shutdown() {
- if (!stopped) {
- stopped = true;
-
- if (sharedSnapshotCache != null) {
- sharedSnapshotCache.shutdown();
- }
- }
- }
-
- /**
- * Routes queries to appropriate DataNodes for execution.
- */
- public void performQueries(final Collection<? extends Query> queries,
final OperationObserver callback) {
- transactionManager.performInTransaction(() -> {
- new DataDomainLegacyQueryAction(DataDomain.this, new
QueryChain(queries), callback).execute();
- return null;
- });
- }
-
- // ****** DataChannel methods:
-
- /**
- * Runs query returning generic QueryResponse.
- *
- * @since 1.2
- */
- @Override
- public QueryResponse onQuery(final ObjectContext originatingContext,
final Query query) {
- checkStopped();
-
- return new
DataDomainQueryFilterChain().onQuery(originatingContext, query);
- }
-
- QueryResponse onQueryNoFilters(final ObjectContext originatingContext,
final Query query) {
- // transaction note:
- // we don't wrap this code in transaction to reduce transaction
scope to
- // just the DB operation for better performance ... query
action will
- // start a transaction itself when and if needed
- return new DataDomainQueryAction(originatingContext,
DataDomain.this, query).execute();
- }
-
- /**
- * Returns an EntityResolver that stores mapping information for this
- * domain.
- */
- @Override
- public EntityResolver getEntityResolver() {
- if (entityResolver == null) {
- createEntityResolver();
- }
-
- return entityResolver;
- }
-
- /**
- * Only handles commit-type synchronization, ignoring any other type.
- *
- * @since 1.2
- */
- @Override
- public GraphDiff onSync(final ObjectContext originatingContext, final
GraphDiff changes, int syncType) {
-
- checkStopped();
-
- return new
DataDomainSyncFilterChain().onSync(originatingContext, changes, syncType);
- }
-
- GraphDiff onSyncNoFilters(final ObjectContext originatingContext, final
GraphDiff changes, int syncType) {
-
- GraphDiff result;
- switch (syncType) {
- case DataChannel.ROLLBACK_CASCADE_SYNC:
- result = onSyncRollback(originatingContext);
- break;
- // "cascade" and "no_cascade" are the same from the DataDomain
perspective
- case DataChannel.FLUSH_NOCASCADE_SYNC:
- case DataChannel.FLUSH_CASCADE_SYNC:
- result = onSyncFlush(originatingContext, changes);
- break;
- default:
- throw new CayenneRuntimeException("Invalid
synchronization type: %d", syncType);
- }
-
- return result;
- }
-
- GraphDiff onSyncRollback(ObjectContext originatingContext) {
- // if there is a transaction in progress, roll it back
-
- Transaction transaction =
BaseTransaction.getThreadTransaction();
- if (transaction != null) {
- transaction.setRollbackOnly();
- }
-
- return new CompoundDiff();
- }
-
- GraphDiff onSyncFlush(ObjectContext originatingContext, GraphDiff
childChanges) {
-
- if (!(originatingContext instanceof DataContext)) {
- throw new CayenneRuntimeException("No support for
committing ObjectContexts that are not DataContexts yet. "
- + "Unsupported context:
%s", originatingContext);
- }
-
- DataDomainFlushAction action =
flushActionFactory.createFlushAction(this);
- return action.flush((DataContext) originatingContext,
childChanges);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append("name",
name).toString();
- }
-
- /**
- * Returns shared {@link QueryCache} used by this DataDomain.
- *
- * @since 3.0
- */
- public QueryCache getQueryCache() {
- return queryCache;
- }
-
- public void setQueryCache(QueryCache queryCache) {
- this.queryCache = queryCache;
- }
-
- /**
- * @since 4.0
- */
- public DataRowStoreFactory getDataRowStoreFactory() {
- return dataRowStoreFactory;
- }
-
- /**
- * @since 4.0
- */
- public void setDataRowStoreFactory(DataRowStoreFactory
dataRowStoreFactory) {
- this.dataRowStoreFactory = dataRowStoreFactory;
- }
-
- /**
- * @since 3.1
- */
- JdbcEventLogger getJdbcEventLogger() {
- return jdbcEventLogger;
- }
-
- void refreshEntitySorter() {
- if (entitySorter != null) {
- entitySorter.setEntityResolver(getEntityResolver());
- }
- }
-
- /**
- * Returns an unmodifiable list of query filters registered with this
DataDomain.
- * <p>
- * Filter ordering note: filters are applied in reverse order of their
- * occurrence in the filter list. I.e. the last filter in the list
called
- * first in the chain.
- *
- * @since 4.1
- */
- public List<DataChannelQueryFilter> getQueryFilters() {
- return Collections.unmodifiableList(queryFilters);
- }
-
- /**
- * Returns an unmodifiable list of sync filters registered with this
DataDomain.
- * <p>
- * Filter ordering note: filters are applied in reverse order of their
- * occurrence in the filter list. I.e. the last filter in the list
called
- * first in the chain.
- *
- * @since 4.1
- */
- public List<DataChannelSyncFilter> getSyncFilters() {
- return Collections.unmodifiableList(syncFilters);
- }
-
- /**
- * Adds a new query filter.
- * Also registers passed filter as an event listener, if any of its
methods have event annotations.
- *
- * @since 4.1
- */
- public void addQueryFilter(DataChannelQueryFilter filter) {
- // skip double listener registration, if filter already in sync
filters list
- if(!syncFilters.contains(filter)) {
- addListener(filter);
- }
- queryFilters.add(filter);
- }
-
- /**
- * Adds a new sync filter.
- * Also registers passed filter as an event listener, if any of its
methods have event annotations.
- *
- * @since 4.1
- */
- public void addSyncFilter(DataChannelSyncFilter filter) {
- // skip double listener registration, if filter already in
query filters list
- if(!queryFilters.contains(filter)) {
- addListener(filter);
- }
- syncFilters.add(filter);
- }
-
- /**
- * Removes a query filter from the filter chain.
- *
- * @since 4.1
- */
- public void removeQueryFilter(DataChannelQueryFilter filter) {
- queryFilters.remove(filter);
- }
-
- /**
- * Removes a sync filter from the filter chain.
- *
- * @since 4.1
- */
- public void removeSyncFilter(DataChannelSyncFilter filter) {
- syncFilters.remove(filter);
- }
-
- /**
- * Adds a listener, mapping its methods to events based on annotations.
This
- * is a shortcut for
- * 'getEntityResolver().getCallbackRegistry().addListener(listener)'.
- *
- * @since 4.0
- */
- public void addListener(Object listener) {
- getEntityResolver().getCallbackRegistry().addListener(listener);
- }
-
- final class DataDomainQueryFilterChain implements
DataChannelQueryFilterChain {
-
- private int idx;
-
- DataDomainQueryFilterChain() {
- idx = queryFilters.size();
- }
-
- @Override
- public QueryResponse onQuery(ObjectContext originatingContext,
Query query) {
- return --idx >= 0
- ?
queryFilters.get(idx).onQuery(originatingContext, query, this)
- : onQueryNoFilters(originatingContext,
query);
- }
- }
-
- final class DataDomainSyncFilterChain implements
DataChannelSyncFilterChain {
-
- private int idx;
-
- DataDomainSyncFilterChain() {
- idx = syncFilters.size();
- }
-
- @Override
- public GraphDiff onSync(ObjectContext originatingContext, final
GraphDiff changes, int syncType) {
- return --idx >= 0
- ?
syncFilters.get(idx).onSync(originatingContext, changes, syncType, this)
- : onSyncNoFilters(originatingContext,
changes, syncType);
- }
- }
-
- /**
- * An optional DataNode that is used for DataMaps that are not linked
to a
- * DataNode explicitly.
- *
- * @since 3.1
- */
- public DataNode getDefaultNode() {
- return defaultNode;
- }
-
- /**
- * @since 3.1
- */
- public void setDefaultNode(DataNode defaultNode) {
- this.defaultNode = defaultNode;
- }
-
- /**
- * Returns a maximum number of object IDs to match in a single query for
- * queries that select objects based on collection of ObjectIds. This
- * affects queries generated by Cayenne when processing paginated
queries
- * and DISJOINT_BY_ID prefetches and is intended to address database
- * limitations on the size of SQL statements as well as to cap memory
use in
- * Cayenne when generating such queries. The default is 10000. It can be
- * changed either by calling {@link #setMaxIdQualifierSize(int)} or
changing
- * the value for property
- * {@link Constants#MAX_ID_QUALIFIER_SIZE_PROPERTY}.
- *
- * @since 3.1
- */
- public int getMaxIdQualifierSize() {
- return maxIdQualifierSize;
- }
-
- /**
- * @since 3.1
- */
- public void setMaxIdQualifierSize(int maxIdQualifierSize) {
- this.maxIdQualifierSize = maxIdQualifierSize;
- }
-
- TransactionManager getTransactionManager() {
- return transactionManager;
- }
-
- AdhocObjectFactory getObjectFactory() {
- return objectFactory;
- }
+ * @since 3.1
+ */
+ protected int maxIdQualifierSize;
+
+ /**
+ * @since 4.1
+ */
+ protected List<DataChannelQueryFilter> queryFilters;
+
+ /**
+ * @since 4.1
+ */
+ protected List<DataChannelSyncFilter> syncFilters;
+
+ /**
+ * @since 4.2
+ */
+ @Inject
+ protected DataDomainFlushActionFactory flushActionFactory;
+
+ /**
+ * @since 4.2
+ */
+ @Inject
+ protected AdhocObjectFactory objectFactory;
+
+ protected Map<String, DataNode> nodes;
+ protected Map<String, DataNode> nodesByDataMapName;
+ protected DataNode defaultNode;
+ protected Map<String, String> properties;
+
+ protected EntityResolver entityResolver;
+ protected DataRowStore sharedSnapshotCache;
+ protected String name;
+ protected QueryCache queryCache;
+
+ // these are initialized from properties...
+ protected boolean sharedCacheEnabled;
+ protected boolean validatingObjectsOnCommit;
+
+ /**
+ * @since 1.2
+ */
+ protected EventManager eventManager;
+
+ /**
+ * @since 1.2
+ */
+ protected EntitySorter entitySorter;
+
+ protected boolean stopped;
+
+ /**
+ * Creates a DataDomain and assigns it a name.
+ */
+ public DataDomain(String name) {
+ init(name);
+ resetProperties();
+ }
+
+ /**
+ * Creates new DataDomain.
+ *
+ * @param name DataDomain name. Domain can be located using its name
in the
+ * Configuration object.
+ * @param properties A Map containing domain configuration properties.
+ * @deprecated since 4.0 unused
+ */
+ @Deprecated
+ public DataDomain(String name, Map<String, String> properties) {
+ init(name);
+ initWithProperties(properties);
+ }
+
+ private void init(String name) {
+
+ this.queryFilters = new CopyOnWriteArrayList<>();
+ this.syncFilters = new CopyOnWriteArrayList<>();
+ this.nodesByDataMapName = new ConcurrentHashMap<>();
+ this.nodes = new ConcurrentHashMap<>();
+
+ // properties are read-only, so no need for concurrent map, or any
+ // specific map
+ // for that matter
+ this.properties = Collections.emptyMap();
+
+ setName(name);
+ }
+
+ /**
+ * Checks that Domain is not stopped. Throws DomainStoppedException
+ * otherwise.
+ *
+ * @since 3.0
+ */
+ protected void checkStopped() throws DomainStoppedException {
+ if (stopped) {
+ throw new DomainStoppedException("Domain " + name
+ + " was shutdown and can no longer be used to access the
database");
+ }
+ }
+
+ /**
+ * @since 3.1
+ */
+ public EntitySorter getEntitySorter() {
+ return entitySorter;
+ }
+
+ /**
+ * @since 3.1
+ */
+ public void setEntitySorter(EntitySorter entitySorter) {
+ this.entitySorter = entitySorter;
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected void resetProperties() {
+ properties = Collections.emptyMap();
+
+ sharedCacheEnabled = SHARED_CACHE_ENABLED_DEFAULT;
+ validatingObjectsOnCommit = VALIDATING_OBJECTS_ON_COMMIT_DEFAULT;
+ }
+
+ /**
+ * Reinitializes domain state with a new set of properties.
+ *
+ * @since 1.1
+ * @deprecated since 4.0 properties are processed by the DI provider.
+ */
+ @Deprecated
+ public void initWithProperties(Map<String, String> properties) {
+
+ // clone properties to ensure that it is read-only internally
+ properties = properties != null ? new HashMap<>(properties) :
Collections.emptyMap();
+
+ String sharedCacheEnabled =
properties.get(SHARED_CACHE_ENABLED_PROPERTY);
+ String validatingObjectsOnCommit =
properties.get(VALIDATING_OBJECTS_ON_COMMIT_PROPERTY);
+
+ // init ivars from properties
+ this.sharedCacheEnabled = (sharedCacheEnabled != null) ?
"true".equalsIgnoreCase(sharedCacheEnabled)
+ : SHARED_CACHE_ENABLED_DEFAULT;
+ this.validatingObjectsOnCommit = (validatingObjectsOnCommit != null) ?
"true"
+ .equalsIgnoreCase(validatingObjectsOnCommit) :
VALIDATING_OBJECTS_ON_COMMIT_DEFAULT;
+
+ this.properties = properties;
+ }
+
+ /**
+ * Returns EventManager used by this DataDomain.
+ *
+ * @since 1.2
+ */
+ public EventManager getEventManager() {
+ return eventManager;
+ }
+
+ /**
+ * Sets EventManager used by this DataDomain.
+ *
+ * @since 1.2
+ */
+ public void setEventManager(EventManager eventManager) {
+ this.eventManager = eventManager;
+
+ if (sharedSnapshotCache != null) {
+ sharedSnapshotCache.setEventManager(eventManager);
+ }
+ }
+
+ /**
+ * Returns "name" property value.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets "name" property to a new value.
+ */
+ public synchronized void setName(String name) {
+ this.name = name;
+ if (sharedSnapshotCache != null) {
+ this.sharedSnapshotCache.setName(name);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if DataContexts produced by this DataDomain
are
+ * using shared DataRowStore. Returns <code>false</code> if each
DataContext
+ * would work with its own DataRowStore. Note that this setting can be
+ * overwritten per DataContext.
+ */
+ public boolean isSharedCacheEnabled() {
+ return sharedCacheEnabled;
+ }
+
+ public void setSharedCacheEnabled(boolean sharedCacheEnabled) {
+ this.sharedCacheEnabled = sharedCacheEnabled;
+ }
+
+ /**
+ * Returns whether child DataContexts default behavior is to perform object
+ * validation before commit is executed.
+ *
+ * @since 1.1
+ */
+ public boolean isValidatingObjectsOnCommit() {
+ return validatingObjectsOnCommit;
+ }
+
+ /**
+ * Sets the property defining whether child DataContexts should perform
+ * object validation before commit is executed.
+ *
+ * @since 1.1
+ */
+ public void setValidatingObjectsOnCommit(boolean flag) {
+ this.validatingObjectsOnCommit = flag;
+ }
+
+ /**
+ * @return a Map of properties for this DataDomain.
+ * @since 1.1
+ */
+ public Map<String, String> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Returns snapshots cache for this DataDomain, lazily initializing it on
+ * the first call if 'sharedCacheEnabled' flag is true.
+ */
+ public DataRowStore getSharedSnapshotCache() {
+ if (sharedSnapshotCache == null && sharedCacheEnabled) {
+ this.sharedSnapshotCache = nonNullSharedSnapshotCache();
+ }
+
+ return sharedSnapshotCache;
+ }
+
+ /**
+ * Returns a guaranteed non-null shared snapshot cache regardless of the
+ * 'sharedCacheEnabled' flag setting.
+ */
+ synchronized DataRowStore nonNullSharedSnapshotCache() {
+ if (sharedSnapshotCache == null) {
+ this.sharedSnapshotCache =
dataRowStoreFactory.createDataRowStore(name);
+ }
+
+ return sharedSnapshotCache;
+ }
+
+ /**
+ * Shuts down the previous cache instance, sets cache to the new
+ * DataSowStore instance and updates two properties of the new
DataSowStore:
+ * name and eventManager.
+ */
+ public synchronized void setSharedSnapshotCache(DataRowStore
snapshotCache) {
+ if (this.sharedSnapshotCache != snapshotCache) {
+ if (this.sharedSnapshotCache != null) {
+ this.sharedSnapshotCache.shutdown();
+ }
+ this.sharedSnapshotCache = snapshotCache;
+
+ if (snapshotCache != null) {
+ snapshotCache.setEventManager(getEventManager());
+ snapshotCache.setName(getName());
+ }
+ }
+ }
+
+ public void addDataMap(DataMap dataMap) {
+ getEntityResolver().addDataMap(dataMap);
+ refreshEntitySorter();
+ }
+
+ /**
+ * @since 3.1
+ */
+ public DataMap getDataMap(String mapName) {
+ return getEntityResolver().getDataMap(mapName);
+ }
+
+ /**
+ * Removes named DataMap from this DataDomain and any underlying DataNodes
+ * that include it.
+ *
+ * @since 3.1
+ */
+ public void removeDataMap(String mapName) {
+ DataMap map = getDataMap(mapName);
+ if (map == null) {
+ return;
+ }
+
+ // remove from data nodes
+ for (DataNode node : nodes.values()) {
+ node.removeDataMap(mapName);
+ }
+
+ nodesByDataMapName.remove(mapName);
+
+ // remove from EntityResolver
+ getEntityResolver().removeDataMap(map);
+
+ refreshEntitySorter();
+ }
+
+ /**
+ * Removes a DataNode from DataDomain. Any maps previously associated with
+ * this node within domain will still be kept around, however they wan't be
+ * mapped to any node.
+ */
+ public void removeDataNode(String nodeName) {
+ DataNode removed = nodes.remove(nodeName);
+ if (removed != null) {
+ removed.setEntityResolver(null);
+ nodesByDataMapName.values().removeIf(dataNode -> dataNode ==
removed);
+ }
+ }
+
+ /**
+ * Returns a collection of registered DataMaps.
+ */
+ public Collection<DataMap> getDataMaps() {
+ return getEntityResolver().getDataMaps();
+ }
+
+ /**
+ * Returns an unmodifiable collection of DataNodes associated with this
+ * domain.
+ */
+ public Collection<DataNode> getDataNodes() {
+ return Collections.unmodifiableCollection(nodes.values());
+ }
+
+ /**
+ * Adds new DataNode.
+ */
+ public void addNode(DataNode node) {
+
+ // add node to name->node map
+ nodes.put(node.getName(), node);
+ node.setEntityResolver(getEntityResolver());
+
+ // add node to "ent name->node" map
+ for (DataMap map : node.getDataMaps()) {
+ addDataMap(map);
+ nodesByDataMapName.put(map.getName(), node);
+ }
+ }
+
+ /**
+ * Returns registered DataNode whose name matches <code>name</code>
+ * parameter.
+ *
+ * @since 3.1
+ */
+ public DataNode getDataNode(String nodeName) {
+ return nodes.get(nodeName);
+ }
+
+ /**
+ * Returns a DataNode that should handle queries for all entities in a
+ * DataMap.
+ *
+ * @since 1.1
+ */
+ public DataNode lookupDataNode(DataMap map) {
+
+ DataNode node = nodesByDataMapName.get(map.getName());
+ if (node == null) {
+
+ // see if one of the node states has changed, and the map is now
+ // linked...
+ for (DataNode n : getDataNodes()) {
+ for (DataMap m : n.getDataMaps()) {
+ if (m == map) {
+ nodesByDataMapName.put(map.getName(), n);
+ node = n;
+ break;
+ }
+ }
+
+ if (node != null) {
+ break;
+ }
+ }
+
+ if (node == null) {
+
+ if (defaultNode != null) {
+ nodesByDataMapName.put(map.getName(), defaultNode);
+ node = defaultNode;
+ } else {
+ throw new CayenneRuntimeException("No DataNode configured
for DataMap '%s'"
+ + " and no default DataNode set", map.getName());
+ }
+ }
+ }
+
+ return node;
+ }
+
+ /**
+ * Sets EntityResolver. If not set explicitly, DataDomain creates a default
+ * EntityResolver internally on demand.
+ *
+ * @since 1.1
+ */
+ public void setEntityResolver(EntityResolver entityResolver) {
+ this.entityResolver = entityResolver;
+ }
+
+ // creates default entity resolver if there is none set yet
+ private synchronized void createEntityResolver() {
+ if (entityResolver == null) {
+ // entity resolver will be self-indexing as we add all our maps
+ // to it as they are added to the DataDomain
+ entityResolver = new EntityResolver();
+ }
+ }
+
+ /**
+ * Shutdowns all owned data nodes and marks this domain as stopped.
+ */
+ @BeforeScopeEnd
+ public void shutdown() {
+ if (!stopped) {
+ stopped = true;
+
+ if (sharedSnapshotCache != null) {
+ sharedSnapshotCache.shutdown();
+ }
+ }
+ }
+
+ /**
+ * Routes queries to appropriate DataNodes for execution.
+ */
+ @Override
+ public void performQueries(Collection<? extends Query> queries,
OperationObserver callback) {
+ transactionManager.performInTransaction(() -> {
+ new DataDomainLegacyQueryAction(DataDomain.this, new
QueryChain(queries), callback).execute();
+ return null;
+ });
+ }
+
+ // ****** DataChannel methods:
+
+ /**
+ * Runs query returning generic QueryResponse.
+ *
+ * @since 1.2
+ */
+ @Override
+ public QueryResponse onQuery(ObjectContext originatingContext, Query
query) {
+ checkStopped();
+ return new DataDomainQueryFilterChain().onQuery(originatingContext,
query);
+ }
+
+ QueryResponse onQueryNoFilters(ObjectContext originatingContext, Query
query) {
+ // transaction note:
+ // we don't wrap this code in transaction to reduce transaction scope
to
+ // just the DB operation for better performance ... query action will
+ // start a transaction itself when and if needed
+ return new DataDomainQueryAction(originatingContext, DataDomain.this,
query).execute();
+ }
+
+ /**
+ * Returns an EntityResolver that stores mapping information for this
domain.
+ */
+ @Override
+ public EntityResolver getEntityResolver() {
+ if (entityResolver == null) {
+ createEntityResolver();
+ }
+
+ return entityResolver;
+ }
+
+ /**
+ * Only handles commit-type synchronization, ignoring any other type.
+ *
+ * @since 1.2
+ */
+ @Override
+ public GraphDiff onSync(ObjectContext originatingContext, GraphDiff
changes, int syncType) {
+
+ checkStopped();
+
+ return new DataDomainSyncFilterChain().onSync(originatingContext,
changes, syncType);
+ }
+
+ GraphDiff onSyncNoFilters(ObjectContext originatingContext, GraphDiff
changes, int syncType) {
+
+ return switch (syncType) {
+ case DataChannel.ROLLBACK_CASCADE_SYNC -> onSyncRollback();
+ // "cascade" and "no_cascade" are the same from the DataDomain
perspective
+ case DataChannel.FLUSH_NOCASCADE_SYNC,
DataChannel.FLUSH_CASCADE_SYNC ->
+ onSyncFlush(originatingContext, changes);
+ default -> throw new CayenneRuntimeException("Invalid
synchronization type: %d", syncType);
+ };
+ }
+
+ GraphDiff onSyncRollback() {
+ // if there is a transaction in progress, roll it back
+
+ Transaction transaction = BaseTransaction.getThreadTransaction();
+ if (transaction != null) {
+ transaction.setRollbackOnly();
+ }
+
+ return new CompoundDiff();
+ }
+
+ GraphDiff onSyncFlush(ObjectContext originatingContext, GraphDiff
childChanges) {
+
+ if (!(originatingContext instanceof DataContext)) {
+ throw new CayenneRuntimeException("No support for committing
ObjectContexts that are not DataContexts yet. "
+ + "Unsupported context: %s", originatingContext);
+ }
+
+ DataDomainFlushAction action =
flushActionFactory.createFlushAction(this);
+ return action.flush((DataContext) originatingContext, childChanges);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("name", name).toString();
+ }
+
+ /**
+ * Returns shared {@link QueryCache} used by this DataDomain.
+ *
+ * @since 3.0
+ */
+ public QueryCache getQueryCache() {
+ return queryCache;
+ }
+
+ public void setQueryCache(QueryCache queryCache) {
+ this.queryCache = queryCache;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public DataRowStoreFactory getDataRowStoreFactory() {
+ return dataRowStoreFactory;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setDataRowStoreFactory(DataRowStoreFactory
dataRowStoreFactory) {
+ this.dataRowStoreFactory = dataRowStoreFactory;
+ }
+
+ /**
+ * @since 3.1
+ */
+ JdbcEventLogger getJdbcEventLogger() {
+ return jdbcEventLogger;
+ }
+
+ void refreshEntitySorter() {
+ if (entitySorter != null) {
+ entitySorter.setEntityResolver(getEntityResolver());
+ }
+ }
+
+ /**
+ * Returns an unmodifiable list of query filters registered with this
DataDomain.
+ * <p>
+ * Filter ordering note: filters are applied in reverse order of their
+ * occurrence in the filter list. I.e. the last filter in the list called
+ * first in the chain.
+ *
+ * @since 4.1
+ */
+ public List<DataChannelQueryFilter> getQueryFilters() {
+ return Collections.unmodifiableList(queryFilters);
+ }
+
+ /**
+ * Returns an unmodifiable list of sync filters registered with this
DataDomain.
+ * <p>
+ * Filter ordering note: filters are applied in reverse order of their
+ * occurrence in the filter list. I.e. the last filter in the list called
+ * first in the chain.
+ *
+ * @since 4.1
+ */
+ public List<DataChannelSyncFilter> getSyncFilters() {
+ return Collections.unmodifiableList(syncFilters);
+ }
+
+ /**
+ * Adds a new query filter.
+ * Also registers passed filter as an event listener, if any of its
methods have event annotations.
+ *
+ * @since 4.1
+ */
+ public void addQueryFilter(DataChannelQueryFilter filter) {
+ // skip double listener registration, if filter already in sync
filters list
+ if (!syncFilters.contains(filter)) {
+ addListener(filter);
+ }
+ queryFilters.add(filter);
+ }
+
+ /**
+ * Adds a new sync filter.
+ * Also registers passed filter as an event listener, if any of its
methods have event annotations.
+ *
+ * @since 4.1
+ */
+ public void addSyncFilter(DataChannelSyncFilter filter) {
+ // skip double listener registration, if filter already in query
filters list
+ if (!queryFilters.contains(filter)) {
+ addListener(filter);
+ }
+ syncFilters.add(filter);
+ }
+
+ /**
+ * Removes a query filter from the filter chain.
+ *
+ * @since 4.1
+ */
+ public void removeQueryFilter(DataChannelQueryFilter filter) {
+ queryFilters.remove(filter);
+ }
+
+ /**
+ * Removes a sync filter from the filter chain.
+ *
+ * @since 4.1
+ */
+ public void removeSyncFilter(DataChannelSyncFilter filter) {
+ syncFilters.remove(filter);
+ }
+
+ /**
+ * Adds a listener, mapping its methods to events based on annotations.
This
+ * is a shortcut for
+ * 'getEntityResolver().getCallbackRegistry().addListener(listener)'.
+ *
+ * @since 4.0
+ */
+ public void addListener(Object listener) {
+ getEntityResolver().getCallbackRegistry().addListener(listener);
+ }
+
+ final class DataDomainQueryFilterChain implements
DataChannelQueryFilterChain {
+
+ private int idx;
+
+ DataDomainQueryFilterChain() {
+ idx = queryFilters.size();
+ }
+
+ @Override
+ public QueryResponse onQuery(ObjectContext originatingContext, Query
query) {
+ return --idx >= 0
+ ? queryFilters.get(idx).onQuery(originatingContext, query,
this)
+ : onQueryNoFilters(originatingContext, query);
+ }
+ }
+
+ final class DataDomainSyncFilterChain implements
DataChannelSyncFilterChain {
+
+ private int idx;
+
+ DataDomainSyncFilterChain() {
+ idx = syncFilters.size();
+ }
+
+ @Override
+ public GraphDiff onSync(ObjectContext originatingContext, GraphDiff
changes, int syncType) {
+ return --idx >= 0
+ ? syncFilters.get(idx).onSync(originatingContext, changes,
syncType, this)
+ : onSyncNoFilters(originatingContext, changes, syncType);
+ }
+ }
+
+ /**
+ * An optional DataNode that is used for DataMaps that are not linked to a
+ * DataNode explicitly.
+ *
+ * @since 3.1
+ */
+ public DataNode getDefaultNode() {
+ return defaultNode;
+ }
+
+ /**
+ * @since 3.1
+ */
+ public void setDefaultNode(DataNode defaultNode) {
+ this.defaultNode = defaultNode;
+ }
+
+ /**
+ * Returns a maximum number of object IDs to match in a single query for
+ * queries that select objects based on collection of ObjectIds. This
+ * affects queries generated by Cayenne when processing paginated queries
+ * and DISJOINT_BY_ID prefetches and is intended to address database
+ * limitations on the size of SQL statements as well as to cap memory use
in
+ * Cayenne when generating such queries. The default is 10000. It can be
+ * changed either by calling {@link #setMaxIdQualifierSize(int)} or
changing
+ * the value for property
+ * {@link Constants#MAX_ID_QUALIFIER_SIZE_PROPERTY}.
+ *
+ * @since 3.1
+ */
+ public int getMaxIdQualifierSize() {
+ return maxIdQualifierSize;
+ }
+
+ /**
+ * @since 3.1
+ */
+ public void setMaxIdQualifierSize(int maxIdQualifierSize) {
+ this.maxIdQualifierSize = maxIdQualifierSize;
+ }
+
+ TransactionManager getTransactionManager() {
+ return transactionManager;
+ }
+
+ AdhocObjectFactory getObjectFactory() {
+ return objectFactory;
+ }
}
diff --git
a/cayenne/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java
index 31145ef96..acefda9e7 100644
---
a/cayenne/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java
+++
b/cayenne/src/main/java/org/apache/cayenne/access/DataDomainLegacyQueryAction.java
@@ -41,8 +41,6 @@ import java.util.Map;
*/
class DataDomainLegacyQueryAction implements QueryRouter, OperationObserver {
- static final boolean DONE = true;
-
DataDomain domain;
OperationObserver callback;
Query query;
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java
b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java
index 1cfade84d..fbffa6f23 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataNode.java
@@ -49,7 +49,6 @@ import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -216,7 +215,9 @@ public class DataNode implements QueryEngine {
* Returns a DataNode that should handle queries for all DataMap
components.
*
* @since 1.1
+ * @deprecated unused and unneeded
*/
+ @Deprecated(since = "5.0", forRemoval = true)
public DataNode lookupDataNode(DataMap dataMap) {
// we don't know any better than to return ourselves...
return this;
@@ -246,7 +247,7 @@ public class DataNode implements QueryEngine {
// upper limit.
getAdapter().getExtendedTypes();
- Connection connection = null;
+ Connection connection;
try {
connection = this.getDataSource().getConnection();
@@ -324,7 +325,7 @@ public class DataNode implements QueryEngine {
* @since 4.0
*/
public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata
queryMetadata) {
- return rowReader(descriptor, queryMetadata,
Collections.<ObjAttribute, ColumnDescriptor> emptyMap());
+ return rowReader(descriptor, queryMetadata,
Collections.emptyMap());
}
/**
@@ -461,7 +462,7 @@ public class DataNode implements QueryEngine {
* @since 3.0
*/
@Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ public boolean isWrapperFor(Class<?> iface) {
return iface.isAssignableFrom(dataSource.getClass());
}
@@ -481,9 +482,8 @@ public class DataNode implements QueryEngine {
* @since 3.1
*/
@Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException
{
- // don't throw SQLFeatureNotSupported - this will break JDK 1.5
- // runtime
+ public Logger getParentLogger() {
+ // don't throw SQLFeatureNotSupported - this will break JDK 1.5
runtime
throw new UnsupportedOperationException();
}
}
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/QueryEngine.java
b/cayenne/src/main/java/org/apache/cayenne/access/QueryEngine.java
index 4b73fb208..dbc9deaab 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/QueryEngine.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/QueryEngine.java
@@ -19,11 +19,11 @@
package org.apache.cayenne.access;
-import java.util.Collection;
-
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.query.Query;
+import java.util.Collection;
+
/**
* Defines methods used to run Cayenne queries.
*/
@@ -32,12 +32,10 @@ public interface QueryEngine {
/**
* Executes a list of queries wrapping them in its own transaction.
Results of
* execution are passed to {@link OperationObserver}object via its
callback methods.
- *
- * @since 1.1 The signature has changed from List to Collection.
+ *
+ * @since 1.1
*/
- void performQueries(
- Collection<? extends Query> queries,
- OperationObserver resultConsumer);
+ void performQueries(Collection<? extends Query> queries, OperationObserver
resultConsumer);
/**
* Returns a resolver for this query engine that is capable of resolving
between
diff --git a/cayenne/src/main/java/org/apache/cayenne/query/Query.java
b/cayenne/src/main/java/org/apache/cayenne/query/Query.java
index dd6c52ec0..5a60aa21f 100644
--- a/cayenne/src/main/java/org/apache/cayenne/query/Query.java
+++ b/cayenne/src/main/java/org/apache/cayenne/query/Query.java
@@ -19,12 +19,10 @@
package org.apache.cayenne.query;
-import java.io.Serializable;
-
import org.apache.cayenne.access.QueryEngine;
-import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.QueryDescriptor;
+
+import java.io.Serializable;
/**
* Defines minimal API of a query descriptor that is executable via Cayenne.