You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2022/06/30 15:08:09 UTC
[cayenne] 07/09: CAY-2737 Cayenne 4.3: cleanup deprecated code - delete LegacyDataDomainFlushAction
This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 4e1bd02c6c0a4ca42321b4d1f5688cf460829f92
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Thu Jun 30 18:00:18 2022 +0300
CAY-2737 Cayenne 4.3: cleanup deprecated code
- delete LegacyDataDomainFlushAction
---
.../cayenne/access/DataDomainDBDiffBuilder.java | 252 --------------
.../cayenne/access/DataDomainDeleteBucket.java | 128 --------
.../cayenne/access/DataDomainFlattenedBucket.java | 208 ------------
.../cayenne/access/DataDomainFlushObserver.java | 162 ---------
.../access/DataDomainIndirectDiffBuilder.java | 178 ----------
.../cayenne/access/DataDomainInsertBucket.java | 237 --------------
.../cayenne/access/DataDomainSyncBucket.java | 278 ----------------
.../cayenne/access/DataDomainUpdateBucket.java | 157 ---------
.../access/DataNodeSyncQualifierDescriptor.java | 162 ---------
.../java/org/apache/cayenne/access/DbArcId.java | 96 ------
.../cayenne/access/DbEntityClassDescriptor.java | 111 -------
.../org/apache/cayenne/access/FlattenedArcKey.java | 362 ---------------------
.../access/LegacyDataDomainFlushAction.java | 271 ---------------
.../access/LegacyDataDomainFlushActionFactory.java | 45 ---
14 files changed, 2647 deletions(-)
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java
deleted file mode 100644
index 013a201f8..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.DataDomainSyncBucket.PropagatedValueFactory;
-import org.apache.cayenne.exp.parser.ASTDbPath;
-import org.apache.cayenne.graph.ArcId;
-import org.apache.cayenne.graph.GraphChangeHandler;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Processes object diffs, generating DB diffs. Can be used for both UPDATE and
- * INSERT.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainDBDiffBuilder implements GraphChangeHandler {
-
- private ObjEntity objEntity;
- private DbEntity dbEntity;
-
- // diff snapshot expressed in terms of object properties.
- private Map<Object, Object> currentPropertyDiff;
- private Map<Object, Object> currentArcDiff;
- private Object currentId;
-
- /**
- * Resets the builder to process a new combination of objEntity/dbEntity.
- */
- void reset(DbEntityClassDescriptor descriptor) {
- this.objEntity = descriptor.getEntity();
- this.dbEntity = descriptor.getDbEntity();
- }
-
- /**
- * Resets the builder to process a new object for the previously set
- * combination of objEntity/dbEntity.
- */
- private void reset() {
- currentPropertyDiff = null;
- currentArcDiff = null;
- currentId = null;
- }
-
- /**
- * Processes GraphDiffs of a single object, converting them to DB diff.
- */
- Map<String, Object> buildDBDiff(GraphDiff singleObjectDiff) {
-
- reset();
- singleObjectDiff.apply(this);
-
- if (currentPropertyDiff == null && currentArcDiff == null && currentId == null) {
- return null;
- }
-
- Map<String, Object> dbDiff = new HashMap<>();
-
- appendSimpleProperties(dbDiff);
- appendForeignKeys(dbDiff);
- appendPrimaryKeys(dbDiff);
-
- return dbDiff.isEmpty() ? null : dbDiff;
- }
-
- private void appendSimpleProperties(Map<String, Object> dbDiff) {
- // populate changed columns
- if (currentPropertyDiff != null) {
- for (final Map.Entry<Object, Object> entry : currentPropertyDiff.entrySet()) {
- ObjAttribute attribute = objEntity.getAttribute(entry.getKey().toString());
-
- // In case of a flattened attribute, ensure that it belongs to this bucket...
- DbAttribute dbAttribute = attribute.getDbAttribute();
- if (dbAttribute.getEntity() == dbEntity) {
- dbDiff.put(dbAttribute.getName(), entry.getValue());
- }
- }
- }
- }
-
- private void appendForeignKeys(Map<String, Object> dbDiff) {
- // populate changed FKs
- if (currentArcDiff != null) {
- for (Entry<Object, Object> entry : currentArcDiff.entrySet()) {
-
- DbRelationship dbRelation;
-
- String arcIdString = entry.getKey().toString();
- ObjRelationship relation = objEntity.getRelationship(arcIdString);
- if (relation == null) {
- dbRelation = dbEntity.getRelationship(arcIdString.substring(ASTDbPath.DB_PREFIX.length()));
- } else {
- dbRelation = relation.getDbRelationships().get(relation.getDbRelationships().size() - 1);
- }
-
- // In case of a vertical inheritance, ensure that it belongs to this bucket...
- if (dbRelation.getSourceEntity() == dbEntity) {
- ObjectId targetId = (ObjectId) entry.getValue();
- for (DbJoin join : dbRelation.getJoins()) {
- Object value = (targetId != null)
- ? new PropagatedValueFactory(targetId, join.getTargetName())
- : null;
-
- dbDiff.put(join.getSourceName(), value);
- }
- }
- }
- }
- }
-
- private void appendPrimaryKeys(Map<String, Object> dbDiff) {
-
- // populate changed PKs; note that we might end up overriding some
- // values taken
- // from the object (e.g. zero PK's).
- if (currentId != null) {
- dbDiff.putAll(((ObjectId) currentId).getIdSnapshot());
- }
- }
-
- // ==================================================
- // GraphChangeHandler methods.
- // ==================================================
-
- @Override
- public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
- // note - no checking for phantom mod... assuming there is no phantom
- // diffs
-
- if (currentPropertyDiff == null) {
- currentPropertyDiff = new HashMap<>();
- }
-
- currentPropertyDiff.put(property, newValue);
- }
-
- @Override
- public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
- String arcIdString = arcId.toString();
- ObjRelationship relationship = objEntity.getRelationship(arcIdString);
-
- if (relationship == null) {
- // phantom FK
- if (arcIdString.startsWith(ASTDbPath.DB_PREFIX)) {
- String relName = arcIdString.substring(ASTDbPath.DB_PREFIX.length());
- DbRelationship dbRelationship = dbEntity.getRelationship(relName);
- if (!dbRelationship.isSourceIndependentFromTargetChange()) {
- doArcCreated(targetNodeId, arcId);
- }
- } else {
- throw new IllegalArgumentException("Bad arcId: " + arcId);
- }
-
- } else {
- if (!relationship.isToMany() && relationship.isToPK()) {
- doArcCreated(targetNodeId, arcId);
- }
- }
- }
-
- private void doArcCreated(Object targetNodeId, ArcId arcId) {
- if (currentArcDiff == null) {
- currentArcDiff = new HashMap<>();
- }
- currentArcDiff.put(arcId, targetNodeId);
- }
-
- @Override
- public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
-
- String arcIdString = arcId.toString();
- ObjRelationship relationship = objEntity.getRelationship(arcIdString);
-
- if (relationship == null) {
- // phantom FK
- if (arcIdString.startsWith(ASTDbPath.DB_PREFIX)) {
-
- DbRelationship dbRelationship = dbEntity.getRelationship(arcIdString.substring(ASTDbPath.DB_PREFIX
- .length()));
- if (!dbRelationship.isSourceIndependentFromTargetChange()) {
- doArcDeleted(targetNodeId, arcId);
- }
- } else {
- throw new IllegalArgumentException("Bad arcId: " + arcId);
- }
-
- } else if (!relationship.isSourceIndependentFromTargetChange()) {
- doArcDeleted(targetNodeId, arcId);
- }
- }
-
- private void doArcDeleted(Object targetNodeId, ArcId arcId) {
- if (currentArcDiff == null) {
- currentArcDiff = new HashMap<>();
- currentArcDiff.put(arcId, null);
- } else {
- // skip deletion record if a substitute arc was created prior to
- // deleting the old arc...
- Object existingTargetId = currentArcDiff.get(arcId);
- if (existingTargetId == null || targetNodeId.equals(existingTargetId)) {
- currentArcDiff.put(arcId, null);
- }
- }
- }
-
- @Override
- public void nodeCreated(Object nodeId) {
- // need to append PK columns
- this.currentId = nodeId;
- }
-
- @Override
- public void nodeRemoved(Object nodeId) {
- // noop
- }
-
- @Override
- public void nodeIdChanged(Object nodeId, Object newId) {
- // noop
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java
deleted file mode 100644
index 755c01b59..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.query.DeleteBatchQuery;
-import org.apache.cayenne.query.Query;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainDeleteBucket extends DataDomainSyncBucket {
-
- DataDomainDeleteBucket(LegacyDataDomainFlushAction parent) {
- super(parent);
- }
-
- @Override
- void postprocess() {
-
- if (!objectsByDescriptor.isEmpty()) {
-
- Collection<ObjectId> deletedIds = parent.getResultDeletedIds();
-
- for (List<Persistent> objects : objectsByDescriptor.values()) {
- for (Persistent object : objects) {
- deletedIds.add(object.getObjectId());
- }
- }
- }
- }
-
- @Override
- void appendQueriesInternal(Collection<Query> queries) {
-
- DataNodeSyncQualifierDescriptor qualifierBuilder = new DataNodeSyncQualifierDescriptor();
-
- EntitySorter sorter = parent.getDomain().getEntitySorter();
- sorter.sortDbEntities(dbEntities, true);
-
- for (DbEntity dbEntity : dbEntities) {
- Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity
- .get(dbEntity);
- Map<Object, Query> batches = new LinkedHashMap<>();
-
- for (DbEntityClassDescriptor descriptor : descriptors) {
-
- qualifierBuilder.reset(descriptor);
-
- boolean isRootDbEntity = descriptor.isMaster();
-
- // remove object set for dependent entity, so that it does not show up
- // on post processing
- List<Persistent> objects = objectsByDescriptor.get(descriptor
- .getClassDescriptor());
- if (objects.isEmpty()) {
- continue;
- }
-
- checkReadOnly(descriptor.getEntity());
-
- if (isRootDbEntity) {
- sorter.sortObjectsForEntity(descriptor.getEntity(), objects, true);
- }
-
- for (Persistent o : objects) {
- ObjectDiff diff = parent.objectDiff(o.getObjectId());
-
- Map<String, Object> qualifierSnapshot = qualifierBuilder
- .createQualifierSnapshot(diff);
-
- // organize batches by the nulls in qualifier
- Set<String> nullQualifierNames = new HashSet<String>();
- for (Map.Entry<String, ?> entry : qualifierSnapshot.entrySet()) {
- if (entry.getValue() == null) {
- nullQualifierNames.add(entry.getKey());
- }
- }
-
- Object batchKey = Arrays.asList(nullQualifierNames);
-
- DeleteBatchQuery batch = (DeleteBatchQuery) batches.get(batchKey);
- if (batch == null) {
- batch = new DeleteBatchQuery(dbEntity, qualifierBuilder
- .getAttributes(), nullQualifierNames, 27);
- batch.setUsingOptimisticLocking(qualifierBuilder
- .isUsingOptimisticLocking());
- batches.put(batchKey, batch);
- }
-
- batch.add(qualifierSnapshot);
- }
- }
-
- queries.addAll(batches.values());
- }
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
deleted file mode 100644
index 488affd0c..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.query.BatchQueryRow;
-import org.apache.cayenne.query.DeleteBatchQuery;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A sync bucket that holds flattened queries.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainFlattenedBucket {
-
- final LegacyDataDomainFlushAction parent;
- final Map<DbEntity, List<FlattenedArcKey>> insertArcKeys;
- final Map<DbEntity, DeleteBatchQuery> flattenedDeleteQueries;
-
- DataDomainFlattenedBucket(LegacyDataDomainFlushAction parent) {
- this.parent = parent;
- this.insertArcKeys = new HashMap<>();
- this.flattenedDeleteQueries = new HashMap<>();
- }
-
- boolean isEmpty() {
- return insertArcKeys.isEmpty() && flattenedDeleteQueries.isEmpty();
- }
-
- void addInsertArcKey(DbEntity flattenedEntity, FlattenedArcKey flattenedArcKey) {
- List<FlattenedArcKey> arcKeys = insertArcKeys.get(flattenedEntity);
-
- if (arcKeys == null) {
- arcKeys = new ArrayList<>();
- insertArcKeys.put(flattenedEntity, arcKeys);
- }
-
- arcKeys.add(flattenedArcKey);
- }
-
- void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo) {
-
- DeleteBatchQuery relationDeleteQuery = flattenedDeleteQueries.get(flattenedEntity);
- if (relationDeleteQuery == null) {
- Collection<DbAttribute> pk = flattenedEntity.getPrimaryKeys();
- List<DbAttribute> pkList = pk instanceof List ? (List<DbAttribute>) pk : new ArrayList<>(pk);
- relationDeleteQuery = new DeleteBatchQuery(flattenedEntity, pkList, Collections.<String> emptySet(), 50);
- relationDeleteQuery.setUsingOptimisticLocking(false);
- flattenedDeleteQueries.put(flattenedEntity, relationDeleteQuery);
- }
-
- DataNode node = parent.getDomain().lookupDataNode(flattenedEntity.getDataMap());
- List<Map<String, Object>> flattenedSnapshots = flattenedDeleteInfo.buildJoinSnapshotsForDelete(node);
- if (!flattenedSnapshots.isEmpty()) {
- for (Map<String, Object> flattenedSnapshot : flattenedSnapshots) {
- relationDeleteQuery.add(flattenedSnapshot);
- }
- }
- }
-
- /**
- * responsible for adding the flattened Insert Queries. Its possible an insert query for the same DbEntity/ObjectId
- * already has been added from the insert bucket queries if that Object also has an attribute. So we want to merge
- * the data for each insert into a single insert.
- */
- void appendInserts(Collection<Query> queries) {
-
- // TODO: see "O(N) lookups" TODO's below. The first is relatively benign, as N is the number of DbEntities in the
- // preceeding DataDomainInsertBucket processing. The second nested one is potentially much worse, as it may
- // result in a linear scan of thousands of objects. E.g. it will affect cases with vertical inheritance with
- // relationships in subclasses...
-
- // The fix to the above is to merge this code into DataDomainInsertBucket, so that we can combine regular and
- // flattened snapshots at the point of InsertBatchQuery creation.
-
- for (Map.Entry<DbEntity, List<FlattenedArcKey>> entry : insertArcKeys.entrySet()) {
- DbEntity dbEntity = entry.getKey();
- List<FlattenedArcKey> flattenedArcKeys = entry.getValue();
-
- DataNode node = parent.getDomain().lookupDataNode(dbEntity.getDataMap());
-
- // TODO: O(N) lookup
- InsertBatchQuery existingQuery = findInsertBatchQuery(queries, dbEntity);
- InsertBatchQuery newQuery = new InsertBatchQuery(dbEntity, 50);
-
- // merge the snapshots of the FAKs by ObjectId for all ToOne relationships in case we have multiple Arcs per Object
- Map<ObjectId, Map<String, Object>> toOneSnapshots = new HashMap<>();
-
- // gather the list of the ToMany snapshots (these will actually be their own insert rows)
- List<Map<String, Object>> toManySnapshots = new ArrayList<>();
-
- for (FlattenedArcKey flattenedArcKey : flattenedArcKeys) {
- Map<String, Object> joinSnapshot = flattenedArcKey.buildJoinSnapshotForInsert(node);
-
- if (flattenedArcKey.relationship.isToMany()) {
- toManySnapshots.add(joinSnapshot);
- } else {
- ObjectId objectId = flattenedArcKey.id1.getSourceId();
-
- Map<String, Object> snapshot = toOneSnapshots.get(objectId);
-
- if (snapshot == null) {
- toOneSnapshots.put(objectId, joinSnapshot);
- } else {
- // merge joinSnapshot data with existing snapshot
- for (Map.Entry<String, Object> dbValue : joinSnapshot.entrySet()) {
- snapshot.put(dbValue.getKey(), dbValue.getValue());
- }
- }
- }
- }
-
- // apply the merged ToOne snapshots information and possibly merge it with an existing BatchQueryRow
- for (Map.Entry<ObjectId, Map<String, Object>> flattenedSnapshot : toOneSnapshots.entrySet()) {
- ObjectId objectId = flattenedSnapshot.getKey();
- Map<String, Object> snapshot = flattenedSnapshot.getValue();
-
- if (existingQuery != null) {
-
- // TODO: O(N) lookup
- BatchQueryRow existingRow = findRowForObjectId(existingQuery.getRows(), objectId);
- // todo: do we need to worry about flattenedArcKey.id2 ?
-
- if (existingRow != null) {
- List<DbAttribute> existingQueryDbAttributes = existingQuery.getDbAttributes();
-
- for(int i=0; i < existingQueryDbAttributes.size(); i++) {
- Object value = existingRow.getValue(i);
- if (value != null) {
- snapshot.put(existingQueryDbAttributes.get(i).getName(), value);
- }
- }
- }
- }
-
- newQuery.add(snapshot, objectId);
- }
-
- // apply the ToMany snapshots as new BatchQueryRows
- for(Map<String, Object> toManySnapshot : toManySnapshots) {
- newQuery.add(toManySnapshot);
- }
-
- if (existingQuery != null) {
- queries.remove(existingQuery);
- }
-
- queries.add(newQuery);
- }
- }
-
- void appendDeletes(Collection<Query> queries) {
- if (!flattenedDeleteQueries.isEmpty()) {
- queries.addAll(flattenedDeleteQueries.values());
- }
- }
-
- private InsertBatchQuery findInsertBatchQuery(Collection<Query> queries, DbEntity dbEntity) {
- for(Query query : queries) {
- if (query instanceof InsertBatchQuery) {
- InsertBatchQuery insertBatchQuery = (InsertBatchQuery)query;
- if (insertBatchQuery.getDbEntity().equals(dbEntity)) {
- return insertBatchQuery;
- }
- }
- }
- return null;
- }
-
- private BatchQueryRow findRowForObjectId(List<BatchQueryRow> rows, ObjectId objectId) {
- for (BatchQueryRow row : rows) {
- if (row.getObjectId().equals(objectId)) {
- return row;
- }
- }
- return null;
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java
deleted file mode 100644
index e99a546bf..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.List;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.ResultIterator;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.query.BatchQuery;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.util.Util;
-
-/**
- * Used as an observer for DataContext commit operations.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainFlushObserver implements OperationObserver {
-
- /**
- * @since 3.1
- */
- private JdbcEventLogger logger;
-
- DataDomainFlushObserver(JdbcEventLogger logger) {
- this.logger = logger;
- }
-
- @Override
- public void nextQueryException(Query query, Exception ex) {
- throw new CayenneRuntimeException("Raising from query exception.", Util.unwindException(ex));
- }
-
- @Override
- public void nextGlobalException(Exception ex) {
- throw new CayenneRuntimeException("Raising from underlyingQueryEngine exception.", Util.unwindException(ex));
- }
-
- /**
- * Processes generated keys.
- *
- * @since 1.2
- */
- @Override
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public void nextGeneratedRows(Query query, ResultIterator<?> keysIterator, List<ObjectId> idsToUpdate) {
-
- // read and close the iterator before doing anything else
- List<DataRow> keys;
- try {
- keys = (List<DataRow>) keysIterator.allRows();
- } finally {
- keysIterator.close();
- }
-
- if (!(query instanceof InsertBatchQuery)) {
- throw new CayenneRuntimeException("Generated keys only supported for InsertBatchQuery, instead got %s", query);
- }
-
- if (keys.size() != idsToUpdate.size()) {
- throw new CayenneRuntimeException("Mismatching number of generated PKs: expected %d, instead got %d", idsToUpdate.size(), keys.size());
- }
-
- for (int i = 0; i < keys.size(); i++) {
- DataRow key = keys.get(i);
-
- // empty key?
- if (key.size() == 0) {
- throw new CayenneRuntimeException("Empty key generated.");
- }
-
- ObjectId idToUpdate = idsToUpdate.get(i);
- if (idToUpdate == null || !idToUpdate.isTemporary()) {
- // why would this happen?
- return;
- }
-
- BatchQuery batch = (BatchQuery) query;
- for (DbAttribute attribute : batch.getDbEntity().getGeneratedAttributes()) {
-
- // batch can have generated attributes that are not PKs, e.g.
- // columns with
- // DB DEFAULT values. Ignore those.
- if (attribute.isPrimaryKey()) {
-
- Object value = key.get(attribute.getName());
-
- // As of now (01/2005) many tested drivers don't provide decent
- // descriptors of
- // identity result sets, so a data row may contain garbage labels.
- if (value == null) {
- value = key.values().iterator().next();
- }
-
- // Log the generated PK
- logger.logGeneratedKey(attribute, value);
-
- // I guess we should override any existing value,
- // as generated key is the latest thing that exists in the DB.
- idToUpdate.getReplacementIdMap().put(attribute.getName(), value);
- break;
- }
- }
- }
- }
-
- public void setJdbcEventLogger(JdbcEventLogger logger) {
- this.logger = logger;
- }
-
- public JdbcEventLogger getJdbcEventLogger() {
- return this.logger;
- }
-
- @Override
- public void nextBatchCount(Query query, int[] resultCount) {
- }
-
- @Override
- public void nextCount(Query query, int resultCount) {
- }
-
- @Override
- public void nextRows(Query query, List<?> dataRows) {
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public void nextRows(Query q, ResultIterator it) {
- throw new UnsupportedOperationException(
- "'nextDataRows(Query,ResultIterator)' is unsupported (and unexpected) on commit.");
- }
-
- @Override
- public boolean isIteratedResult() {
- return false;
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java
deleted file mode 100644
index ae1574e54..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.graph.ArcId;
-import org.apache.cayenne.graph.GraphChangeHandler;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-/**
- * A processor of ObjectStore indirect changes, such as flattened relationships
- * and to-many relationships.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class DataDomainIndirectDiffBuilder implements GraphChangeHandler {
-
- private final LegacyDataDomainFlushAction parent;
- private final EntityResolver resolver;
- private final Collection<ObjectId> indirectModifications;
- private final Collection<FlattenedArcKey> flattenedInserts;
- private final Collection<FlattenedArcKey> flattenedDeletes;
-
- DataDomainIndirectDiffBuilder(LegacyDataDomainFlushAction parent) {
- this.parent = parent;
- this.indirectModifications = parent.getResultIndirectlyModifiedIds();
- this.resolver = parent.getDomain().getEntityResolver();
- this.flattenedInserts = new HashSet<>();
- this.flattenedDeletes = new HashSet<>();
- }
-
- void processIndirectChanges(GraphDiff allChanges) {
- // extract flattened and indirect changes and remove duplicate changes...
- allChanges.apply(this);
-
- if (!flattenedInserts.isEmpty()) {
- for (final FlattenedArcKey key : flattenedInserts) {
- DbEntity entity = key.getJoinEntity();
- parent.addFlattenedInsert(entity, key);
- }
- }
-
- if (!flattenedDeletes.isEmpty()) {
- for (final FlattenedArcKey key : flattenedDeletes) {
- DbEntity entity = key.getJoinEntity();
- parent.addFlattenedDelete(entity, key);
- }
- }
- }
-
- @Override
- public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
- ObjEntity entity = resolver.getObjEntity(((ObjectId) nodeId).getEntityName());
- ObjRelationship relationship = entity.getRelationship(arcId.toString());
-
- if (relationship.isSourceIndependentFromTargetChange()) {
-
- ObjectId nodeObjectId = (ObjectId) nodeId;
- if (!nodeObjectId.isTemporary()) {
- indirectModifications.add(nodeObjectId);
- }
-
- if (relationship.isFlattened()) {
- if (relationship.isReadOnly()) {
- throw new CayenneRuntimeException("Cannot set the read-only flattened relationship '%s' in ObjEntity '%s'."
- , relationship.getName(), relationship.getSourceEntity().getName());
- }
-
- // build path without last segment
- StringBuilder path = new StringBuilder();
- for(int i=0; i<relationship.getDbRelationships().size() - 1; i++) {
- if(path.length() > 0) {
- path.append('.');
- }
- path.append(relationship.getDbRelationships().get(i).getName());
- }
-
- if(!parent.getContext().getObjectStore().hasFlattenedPath(nodeObjectId, path.toString())) {
- // Register this combination (so we can remove it later if an insert occurs before commit)
- FlattenedArcKey key = new FlattenedArcKey(nodeObjectId, (ObjectId) targetNodeId, relationship);
-
- // If this combination has already been deleted, simply undelete it.
- if (!flattenedDeletes.remove(key)) {
- flattenedInserts.add(key);
- }
- }
- }
- }
- }
-
- @Override
- public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
-
- ObjEntity entity = resolver.getObjEntity(((ObjectId) nodeId).getEntityName());
- ObjRelationship relationship = entity.getRelationship(arcId.toString());
-
- if (relationship.isSourceIndependentFromTargetChange()) {
- // do not record temporary id mods...
- ObjectId nodeObjectId = (ObjectId) nodeId;
- if (!nodeObjectId.isTemporary()) {
- indirectModifications.add(nodeObjectId);
- }
-
- if (relationship.isFlattened()) {
- if (relationship.isReadOnly()) {
- throw new CayenneRuntimeException("Cannot unset the read-only flattened relationship %s"
- , relationship.getName());
- }
-
- // build path without last segment
- StringBuilder path = new StringBuilder();
- for(int i=0; i<relationship.getDbRelationships().size() - 1; i++) {
- if(path.length() > 0) {
- path.append('.');
- }
- path.append(relationship.getDbRelationships().get(i).getName());
- }
-
- if(!parent.getContext().getObjectStore().hasFlattenedPath(nodeObjectId, path.toString())) {
- // Register this combination (so we can remove it later if an insert occurs before commit)
- FlattenedArcKey key = new FlattenedArcKey(nodeObjectId, (ObjectId) targetNodeId, relationship);
-
- // If this combination has already been inserted, simply "uninsert" it also do not delete it twice
- if (!flattenedInserts.remove(key)) {
- flattenedDeletes.add(key);
- }
- }
- }
- }
- }
-
- @Override
- public void nodeIdChanged(Object nodeId, Object newId) {
- // noop
- }
-
- @Override
- public void nodeCreated(Object nodeId) {
- // noop
- }
-
- @Override
- public void nodeRemoved(Object nodeId) {
- // noop
- }
-
- @Override
- public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
- // noop
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java
deleted file mode 100644
index d3b59278f..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.dba.PkGenerator;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainInsertBucket extends DataDomainSyncBucket {
-
- List<FlattenedInsert> flattenedInserts;
-
- DataDomainInsertBucket(LegacyDataDomainFlushAction parent) {
- super(parent);
- }
-
- @Override
- void appendQueriesInternal(Collection<Query> queries) {
-
- DataDomainDBDiffBuilder diffBuilder = new DataDomainDBDiffBuilder();
-
- EntitySorter sorter = parent.getDomain().getEntitySorter();
- sorter.sortDbEntities(dbEntities, false);
-
- for (DbEntity dbEntity : dbEntities) {
-
- Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
-
- InsertBatchQuery batch = new InsertBatchQuery(dbEntity, 27);
- for (DbEntityClassDescriptor descriptor : descriptors) {
-
- diffBuilder.reset(descriptor);
-
- List<Persistent> objects = objectsByDescriptor.get(descriptor.getClassDescriptor());
- if (objects.isEmpty()) {
- continue;
- }
-
- checkReadOnly(descriptor.getEntity());
- createPermIds(descriptor, objects);
- sorter.sortObjectsForEntity(descriptor.getEntity(), objects, false);
-
- for (Persistent o : objects) {
- Map<String, Object> snapshot = diffBuilder.buildDBDiff(parent.objectDiff(o.getObjectId()));
-
- // we need to insert even if there is no changes to default
- // values so creating an empty changes map
- if (snapshot == null) {
- snapshot = new HashMap<>();
- }
-
- batch.add(snapshot, o.getObjectId());
- if(!descriptor.isMaster()) {
- trackFlattenedInsert(descriptor, o);
- }
- }
- }
-
- queries.add(batch);
- }
- }
-
- void createPermIds(DbEntityClassDescriptor descriptor, Collection<Persistent> objects) {
-
- if (objects.isEmpty()) {
- return;
- }
-
- ObjEntity objEntity = descriptor.getEntity();
- DbEntity entity = descriptor.getDbEntity();
-
- DataNode node = parent.getDomain().lookupDataNode(entity.getDataMap());
- boolean supportsGeneratedKeys = node.getAdapter().supportsGeneratedKeys();
-
- PkGenerator pkGenerator = node.getAdapter().getPkGenerator();
-
- for (Persistent object : objects) {
- ObjectId id = object.getObjectId();
- if (id == null || !id.isTemporary()) {
- continue;
- }
-
- // modify replacement id directly...
- Map<String, Object> idMap = id.getReplacementIdMap();
-
- boolean autoPkDone = false;
-
- for (DbAttribute dbAttr : entity.getPrimaryKeys()) {
- String dbAttrName = dbAttr.getName();
-
- if (idMap.containsKey(dbAttrName)) {
- continue;
- }
-
- // handle meaningful PK
- ObjAttribute objAttr = objEntity.getAttributeForDbAttribute(dbAttr);
- if (objAttr != null) {
-
- Object value = descriptor.getClassDescriptor().getProperty(objAttr.getName())
- .readPropertyDirectly(object);
-
- if (value != null) {
- Class<?> javaClass = objAttr.getJavaClass();
- if (javaClass.isPrimitive() && value instanceof Number && ((Number) value).intValue() == 0) {
- // primitive 0 has to be treated as NULL, or
- // otherwise we can't generate PK for POJO's
- } else {
- idMap.put(dbAttrName, value);
- continue;
- }
- }
- }
-
- // skip db-generated
- if (supportsGeneratedKeys && dbAttr.isGenerated()) {
- continue;
- }
-
- // skip propagated
- if (isPropagated(dbAttr)) {
- continue;
- }
-
- // only a single key can be generated from DB... if this is done
- // already in this loop, we must bail out.
- if (autoPkDone) {
- throw new CayenneRuntimeException("Primary Key autogeneration only works for a single attribute.");
- }
-
- // finally, use database generation mechanism
- try {
- Object pkValue = pkGenerator.generatePk(node, dbAttr);
- idMap.put(dbAttrName, pkValue);
- autoPkDone = true;
- } catch (Exception ex) {
- throw new CayenneRuntimeException("Error generating PK: %s", ex, ex.getMessage());
- }
- }
- }
- }
-
- // TODO, andrus 4/12/2006 - move to DbAttribute in 2.0+
- boolean isPropagated(DbAttribute attribute) {
-
- for (DbRelationship dbRel : attribute.getEntity().getRelationships()) {
- if (!dbRel.isToMasterPK()) {
- continue;
- }
-
- for (DbJoin join : dbRel.getJoins()) {
- if (attribute.getName().equals(join.getSourceName())) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- void trackFlattenedInsert(DbEntityClassDescriptor descriptor, Persistent object) {
- if(flattenedInserts == null) {
- flattenedInserts = new LinkedList<>();
- }
-
- StringBuilder sb = new StringBuilder();
- for(DbRelationship rel : descriptor.getPathFromMaster()) {
- if(sb.length() > 0) {
- sb.append('.');
- }
- sb.append(rel.getName());
- }
-
- flattenedInserts.add(new FlattenedInsert(sb.toString(), object));
- }
-
- @Override
- void postprocess() {
- super.postprocess();
- if(flattenedInserts != null) {
- for(FlattenedInsert insert : flattenedInserts) {
- insert.register(parent.getContext().getObjectStore());
- }
- }
- }
-
- private static class FlattenedInsert {
- private final String path;
- private final Persistent object;
-
- private FlattenedInsert(String path, Persistent object) {
- this.path = path;
- this.object = object;
- }
-
- private void register(ObjectStore objectStore) {
- objectStore.markFlattenedPath(object.getObjectId(), path, ObjectId.of("tmp"));
- }
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java
deleted file mode 100644
index 23dc5c295..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.graph.CompoundDiff;
-import org.apache.cayenne.graph.NodeIdChangeOperation;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.reflect.ArcProperty;
-import org.apache.cayenne.reflect.AttributeProperty;
-import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.PropertyException;
-import org.apache.cayenne.reflect.ToManyMapProperty;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-/**
- * A superclass of batch query wrappers.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-abstract class DataDomainSyncBucket {
-
- final Map<ClassDescriptor, List<Persistent>> objectsByDescriptor;
- final LegacyDataDomainFlushAction parent;
-
- List<DbEntity> dbEntities;
- Map<DbEntity, Collection<DbEntityClassDescriptor>> descriptorsByDbEntity;
-
- DataDomainSyncBucket(LegacyDataDomainFlushAction parent) {
- this.objectsByDescriptor = new HashMap<>();
- this.parent = parent;
- }
-
- boolean isEmpty() {
- return objectsByDescriptor.isEmpty();
- }
-
- abstract void appendQueriesInternal(Collection<Query> queries);
-
- /**
- * Appends all queries originated in the bucket to provided collection.
- */
- void appendQueries(Collection<Query> queries) {
-
- if (!objectsByDescriptor.isEmpty()) {
- groupObjEntitiesBySpannedDbEntities();
- appendQueriesInternal(queries);
- }
- }
-
- void checkReadOnly(ObjEntity entity) throws CayenneRuntimeException {
-
- if (entity == null) {
- throw new NullPointerException("Entity must not be null.");
- }
-
- if (entity.isReadOnly()) {
- throw new CayenneRuntimeException("Attempt to modify object(s) mapped to a read-only entity: '%s'. " +
- "Can't commit changes.", entity.getName());
- }
- }
-
- private void groupObjEntitiesBySpannedDbEntities() {
-
- dbEntities = new ArrayList<>(objectsByDescriptor.size());
- descriptorsByDbEntity = new HashMap<>(objectsByDescriptor.size() * 2);
-
- for (ClassDescriptor descriptor : objectsByDescriptor.keySet()) {
- addSpannedDbEntities(descriptor);
- }
- }
-
- void addSpannedDbEntities(ClassDescriptor descriptor) {
- // root DbEntity
- addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor));
-
- // secondary DbEntities...
- // Note that this logic won't allow flattened attributes to span multiple databases...
- for (ObjAttribute objAttribute : descriptor.getEntity().getAttributes()) {
- if (objAttribute.isFlattened()) {
- addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor, objAttribute));
- }
- }
- }
-
- void addDescriptor(ClassDescriptor descriptor, DbEntityClassDescriptor dbEntityDescriptor) {
- DbEntity dbEntity = dbEntityDescriptor.getDbEntity();
- Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
-
- if (descriptors == null) {
- descriptors = new ArrayList<>(1);
- dbEntities.add(dbEntity);
- descriptorsByDbEntity.put(dbEntity, descriptors);
- }
-
- if (!containsClassDescriptor(descriptors, descriptor)) {
- descriptors.add(dbEntityDescriptor);
- }
- }
-
- private boolean containsClassDescriptor(
- Collection<DbEntityClassDescriptor> descriptors,
- ClassDescriptor classDescriptor) {
- for (DbEntityClassDescriptor descriptor : descriptors) {
- if (classDescriptor.equals(descriptor.getClassDescriptor())) {
- return true;
- }
- }
- return false;
- }
-
- void addDirtyObject(Persistent object, ClassDescriptor descriptor) {
- objectsByDescriptor.computeIfAbsent(descriptor, k -> new ArrayList<>()).add(object);
- }
-
- void postprocess() {
-
- if (!objectsByDescriptor.isEmpty()) {
-
- CompoundDiff result = parent.getResultDiff();
- Map<ObjectId, DataRow> modifiedSnapshots = parent
- .getResultModifiedSnapshots();
- Collection<ObjectId> deletedIds = parent.getResultDeletedIds();
-
- for (Map.Entry<ClassDescriptor, List<Persistent>> entry : objectsByDescriptor.entrySet()) {
-
- ClassDescriptor descriptor = entry.getKey();
-
- for (Persistent object : entry.getValue()) {
- ObjectId id = object.getObjectId();
-
- ObjectId finalId;
-
- // record id change and update attributes for generated ids
- if (id.isReplacementIdAttached()) {
-
- Map<String, Object> replacement = id.getReplacementIdMap();
- for (AttributeProperty property : descriptor.getIdProperties()) {
-
- Object value = replacement.get(property
- .getAttribute()
- .getDbAttributeName());
-
- // TODO: andrus, 11/28/2006: this operation may be redundant
- // if the id wasn't generated. We may need to optimize it...
- if (value != null) {
- property.writePropertyDirectly(object, null, value);
- }
- }
-
- ObjectId replacementId = id.createReplacementId();
-
- result.add(new NodeIdChangeOperation(id, replacementId));
-
- // classify replaced permanent ids as "deleted", as
- // DataRowCache has no notion of replaced id...
- if (!id.isTemporary()) {
- deletedIds.add(id);
- }
-
- finalId = replacementId;
- } else if (id.isTemporary()) {
- throw new CayenneRuntimeException("Temporary ID hasn't been replaced on commit: %s", object);
- } else {
- finalId = id;
- }
-
- // do not take the snapshot until generated columns are processed (see code above)
- DataRow dataRow = parent.getContext().currentSnapshot(object);
-
- if (object instanceof DataObject) {
- DataObject dataObject = (DataObject) object;
- dataRow.setReplacesVersion(dataObject.getSnapshotVersion());
- dataObject.setSnapshotVersion(dataRow.getVersion());
- }
-
- modifiedSnapshots.put(finalId, dataRow);
-
- // update Map reverse relationships
- for (ArcProperty arc : descriptor.getMapArcProperties()) {
- ToManyMapProperty reverseArc = (ToManyMapProperty) arc.getComplimentaryReverseArc();
-
- // must resolve faults... hopefully for to-one this will not cause extra fetches...
- Object source = arc.readProperty(object);
- if (source != null && !reverseArc.isFault(source)) {
- remapTarget(reverseArc, source, object);
- }
- }
- }
- }
- }
- }
-
- private void remapTarget(
- ToManyMapProperty property,
- Object source,
- Object target) throws PropertyException {
-
- Map<Object, Object> map = (Map<Object, Object>) property.readProperty(source);
- Object newKey = property.getMapKey(target);
- Object currentValue = map.get(newKey);
-
- if (currentValue == target) {
- // nothing to do
- return;
- }
- // else - do not check for conflicts here (i.e. another object mapped for the same
- // key), as we have no control of the order in which this method is called, so
- // another object may be remapped later by the caller
-
- // must do a slow map scan to ensure the object is not mapped under a different key...
- Iterator<Map.Entry<Object, Object>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<Object, Object> e = it.next();
- if (e.getValue() == target) {
- it.remove();
- break;
- }
- }
-
- map.put(newKey, target);
- }
-
- // a factory for extracting PKs generated on commit.
- final static class PropagatedValueFactory implements Supplier {
-
- ObjectId masterID;
- String masterKey;
-
- PropagatedValueFactory(ObjectId masterID, String masterKey) {
- this.masterID = masterID;
- this.masterKey = masterKey;
- }
-
- public Object get() {
- Object value = masterID.getIdSnapshot().get(masterKey);
- if (value == null) {
- throw new CayenneRuntimeException("Can't extract a master key. "
- + "Missing key (%s), master ID (%s)", masterKey, masterID);
- }
-
- return value;
- }
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java
deleted file mode 100644
index 55d426ca6..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.map.Attribute;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.UpdateBatchQuery;
-import org.apache.cayenne.reflect.ClassDescriptor;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainUpdateBucket extends DataDomainSyncBucket {
-
- DataDomainUpdateBucket(LegacyDataDomainFlushAction parent) {
- super(parent);
- }
-
- @Override
- void addSpannedDbEntities(ClassDescriptor descriptor) {
- super.addSpannedDbEntities(descriptor);
- // for update we need to add entities for flattened toOne relationships
- for(ObjRelationship objRelationship : descriptor.getEntity().getRelationships()) {
- if(objRelationship.isFlattened() && !objRelationship.isToMany()) {
- addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor, objRelationship));
- }
- }
- }
-
- @Override
- void appendQueriesInternal(Collection<Query> queries) {
-
- DataDomainDBDiffBuilder diffBuilder = new DataDomainDBDiffBuilder();
- DataNodeSyncQualifierDescriptor qualifierBuilder = new DataNodeSyncQualifierDescriptor();
-
- for (DbEntity dbEntity : dbEntities) {
-
- Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
- Map<Object, Query> batches = new LinkedHashMap<>();
-
- for (DbEntityClassDescriptor descriptor : descriptors) {
- ObjEntity entity = descriptor.getEntity();
-
- diffBuilder.reset(descriptor);
- qualifierBuilder.reset(descriptor);
- boolean isRootDbEntity = entity.getDbEntity() == dbEntity;
-
- for (Persistent o : objectsByDescriptor.get(descriptor.getClassDescriptor())) {
- ObjectDiff diff = parent.objectDiff(o.getObjectId());
-
- Map<String, Object> snapshot = diffBuilder.buildDBDiff(diff);
-
- // check whether MODIFIED object has real db-level modifications
- if (snapshot == null) {
- continue;
- }
-
- // after we filtered out "fake" modifications, check if an
- // attempt is made to modify a read only entity
- checkReadOnly(entity);
-
- Map<String, Object> qualifierSnapshot = qualifierBuilder.createQualifierSnapshot(diff);
-
- // organize batches by the updated columns + nulls in qualifier
- Set<String> snapshotSet = snapshot.keySet();
- Set<String> nullQualifierNames = new HashSet<>();
- for (Map.Entry<String, Object> entry : qualifierSnapshot.entrySet()) {
- if (entry.getValue() == null) {
- nullQualifierNames.add(entry.getKey());
- }
- }
-
- List<Set<String>> batchKey = Arrays.asList(snapshotSet, nullQualifierNames);
-
- UpdateBatchQuery batch = (UpdateBatchQuery) batches.get(batchKey);
- if (batch == null) {
- batch = new UpdateBatchQuery(
- dbEntity,
- qualifierBuilder.getAttributes(),
- updatedAttributes(dbEntity, snapshot),
- nullQualifierNames,
- 10);
-
- batch.setUsingOptimisticLocking(qualifierBuilder.isUsingOptimisticLocking());
- batches.put(batchKey, batch);
- }
-
- batch.add(qualifierSnapshot, snapshot, o.getObjectId());
-
- // update replacement id with meaningful PK changes
- if (isRootDbEntity) {
- Map<String, Object> replacementId = o
- .getObjectId()
- .getReplacementIdMap();
-
- for (DbAttribute pk : dbEntity.getPrimaryKeys()) {
- String name = pk.getName();
- if (snapshot.containsKey(name)
- && !replacementId.containsKey(name)) {
- replacementId.put(name, snapshot.get(name));
- }
- }
- }
- }
- }
-
- queries.addAll(batches.values());
- }
- }
-
- /**
- * Creates a list of DbAttributes that are updated in a snapshot
- */
- private List<DbAttribute> updatedAttributes(DbEntity entity, Map<String, Object> updatedSnapshot) {
- List<DbAttribute> attributes = new ArrayList<>(updatedSnapshot.size());
- Map<String, ? extends Attribute> entityAttributes = entity.getAttributeMap();
-
- for (String name : updatedSnapshot.keySet()) {
- attributes.add((DbAttribute)entityAttributes.get(name));
- }
-
- return attributes;
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java
deleted file mode 100644
index 49c225b03..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-/**
- * Builds update qualifier snapshots, including optimistic locking.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataNodeSyncQualifierDescriptor {
-
- private List<DbAttribute> attributes;
- private List<Function<ObjectDiff, Object>> valueTransformers;
- private boolean usingOptimisticLocking;
-
- public boolean isUsingOptimisticLocking() {
- return usingOptimisticLocking;
- }
-
- List<DbAttribute> getAttributes() {
- return attributes;
- }
-
- Map<String, Object> createQualifierSnapshot(ObjectDiff diff) {
- int len = attributes.size();
-
- Map<String, Object> map = new HashMap<>(len * 2);
- for (int i = 0; i < len; i++) {
- DbAttribute attribute = attributes.get(i);
- if (!map.containsKey(attribute.getName())) {
- Object value = valueTransformers.get(i).apply(diff);
- map.put(attribute.getName(), value);
- }
- }
-
- return map;
- }
-
- void reset(DbEntityClassDescriptor descriptor) {
-
- attributes = new ArrayList<>(3);
- valueTransformers = new ArrayList<>(3);
- usingOptimisticLocking = descriptor.getEntity().getLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC;
-
- // master PK columns
- if (descriptor.isMaster()) {
- for (final DbAttribute attribute : descriptor.getDbEntity().getPrimaryKeys()) {
- attributes.add(attribute);
- valueTransformers.add(input -> {
- ObjectId id = (ObjectId) input.getNodeId();
- return id.getIdSnapshot().get(attribute.getName());
- });
- }
- } else {
-
- // TODO: andrus 12/23/2007 - only one step relationship is supported...
- if (descriptor.getPathFromMaster().size() != 1) {
- throw new CayenneRuntimeException(
- "Only single step dependent relationships are currently supported. Actual path length: %d"
- , descriptor.getPathFromMaster().size());
- }
-
- DbRelationship masterDependentDbRel = descriptor.getPathFromMaster().get(0);
-
- if (masterDependentDbRel != null) {
- for (final DbJoin dbAttrPair : masterDependentDbRel.getJoins()) {
- DbAttribute dbAttribute = dbAttrPair.getTarget();
- if (!attributes.contains(dbAttribute)) {
-
- attributes.add(dbAttribute);
- valueTransformers.add(input -> {
- ObjectId id = (ObjectId) input.getNodeId();
- return id.getIdSnapshot().get(dbAttrPair.getTargetName());
- });
- }
- }
- }
- }
-
- if (descriptor.isMaster() && usingOptimisticLocking) {
-
- for (final ObjAttribute attribute : descriptor.getEntity().getAttributes()) {
-
- if (attribute.isUsedForLocking() && !attribute.isFlattened()) {
- // only care about first step in a flattened attribute
- DbAttribute dbAttribute = (DbAttribute) attribute.getDbPathIterator().next();
-
- // only use qualifier if dbEntities match
- if (dbAttribute.getEntity().equals(descriptor.getDbEntity()) && !attributes.contains(dbAttribute)) {
- attributes.add(dbAttribute);
- valueTransformers.add(input -> input.getSnapshotValue(attribute.getName()));
- }
- }
- }
-
- for (final ObjRelationship relationship : descriptor.getEntity().getRelationships()) {
-
- if (relationship.isUsedForLocking()) {
- // only care about the first DbRelationship
- DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
-
- for (final DbJoin dbAttrPair : dbRelationship.getJoins()) {
- DbAttribute dbAttribute = dbAttrPair.getSource();
-
- // relationship transformers override attribute transformers for meaningful FK's...
- // why meaningful FKs can go out of sync is another story (CAY-595)
- int index = attributes.indexOf(dbAttribute);
- if (index >= 0 && !dbAttribute.isForeignKey()) {
- continue;
- }
-
- Function<ObjectDiff, Object> transformer = input -> {
- ObjectId targetId = input.getArcSnapshotValue(relationship.getName());
- return targetId != null ? targetId.getIdSnapshot().get(dbAttrPair.getTargetName()) : null;
- };
-
- if (index < 0) {
- attributes.add(dbAttribute);
- valueTransformers.add(transformer);
- } else {
- valueTransformers.set(index, transformer);
- }
- }
- }
- }
- }
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java
deleted file mode 100644
index a18626f8d..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.util.EqualsBuilder;
-import org.apache.cayenne.util.HashCodeBuilder;
-
-/**
- * An id similar to ObjectId that identifies a DbEntity snapshot for implicit
- * DbEntities of flattened attributes or relationships. Provides 'equals' and
- * 'hashCode' implementations adequate for use as a map key.
- *
- * @since 4.0
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class DbArcId {
-
- private int hashCode;
-
- private ObjectId sourceId;
- private DbRelationship incomingArc;
-
- private DbEntity entity;
-
- DbArcId(ObjectId sourceId, DbRelationship incomingArc) {
- this.sourceId = sourceId;
- this.incomingArc = incomingArc;
- }
-
- DbEntity getEntity() {
- if (entity == null) {
- entity = (DbEntity) incomingArc.getTargetEntity();
- }
-
- return entity;
- }
-
- ObjectId getSourceId() {
- return sourceId;
- }
-
- DbRelationship getIncominArc() {
- return incomingArc;
- }
-
- @Override
- public int hashCode() {
-
- if (this.hashCode == 0) {
- HashCodeBuilder builder = new HashCodeBuilder(3, 5);
- builder.append(sourceId);
- builder.append(incomingArc.getName());
- this.hashCode = builder.toHashCode();
- }
-
- return hashCode;
- }
-
- @Override
- public boolean equals(Object object) {
-
- if (this == object) {
- return true;
- }
-
- if (!(object instanceof DbArcId)) {
- return false;
- }
-
- DbArcId id = (DbArcId) object;
-
- return new EqualsBuilder().append(sourceId, id.sourceId)
- .append(incomingArc.getName(), id.incomingArc.getName())
- .isEquals();
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java
deleted file mode 100644
index 496a968bf..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.reflect.ClassDescriptor;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A descriptor of a primary or secondary DbEntity for a given persistent class during
- * commit.
- *
- * @since 3.0
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DbEntityClassDescriptor {
-
- private ClassDescriptor classDescriptor;
- private List<DbRelationship> pathFromMaster;
- private DbEntity dbEntity;
-
- DbEntityClassDescriptor(ClassDescriptor classDescriptor) {
- this.classDescriptor = classDescriptor;
- this.dbEntity = classDescriptor.getEntity().getDbEntity();
- }
-
- DbEntityClassDescriptor(ClassDescriptor classDescriptor, ObjAttribute masterAttribute) {
- this.classDescriptor = classDescriptor;
-
- Iterator<?> it = masterAttribute.getDbPathIterator();
-
- if (masterAttribute.isFlattened()) {
-
- while (it.hasNext()) {
- Object object = it.next();
- if (object instanceof DbRelationship) {
-
- if (pathFromMaster == null) {
- pathFromMaster = new ArrayList<>(1);
- }
-
- pathFromMaster.add((DbRelationship) object);
- }
- else if (object instanceof DbAttribute) {
- this.dbEntity = ((DbAttribute) object).getEntity();
- }
- }
- }
-
- if (dbEntity == null) {
- dbEntity = classDescriptor.getEntity().getDbEntity();
- }
- }
-
- DbEntityClassDescriptor(ClassDescriptor classDescriptor, ObjRelationship masterRelationship) {
- if(masterRelationship.getDbRelationships().size() > 2) {
- throw new CayenneRuntimeException("Only two step flattened relationships are supported, " + masterRelationship.getDbRelationshipPath());
- }
- this.classDescriptor = classDescriptor;
- DbRelationship pathRelationship = masterRelationship.getDbRelationships().get(0);
- pathFromMaster = new ArrayList<>(1);
- pathFromMaster.add(pathRelationship);
- dbEntity = pathRelationship.getTargetEntity();
- }
-
- boolean isMaster() {
- return pathFromMaster == null;
- }
-
- ClassDescriptor getClassDescriptor() {
- return classDescriptor;
- }
-
- List<DbRelationship> getPathFromMaster() {
- return pathFromMaster;
- }
-
- DbEntity getDbEntity() {
- return dbEntity;
- }
-
- ObjEntity getEntity() {
- return classDescriptor.getEntity();
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java b/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java
deleted file mode 100644
index 64e410c1d..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.DataDomainSyncBucket.PropagatedValueFactory;
-import org.apache.cayenne.access.util.DefaultOperationObserver;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.QuotingStrategy;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.util.HashCodeBuilder;
-import org.apache.cayenne.util.Util;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A holder of flattened relationship modification data.
- *
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class FlattenedArcKey {
-
- ObjRelationship relationship;
-
- DbArcId id1;
- DbArcId id2;
-
- FlattenedArcKey(ObjectId sourceId, ObjectId destinationId, ObjRelationship relationship) {
-
- this.relationship = relationship;
-
- List<DbRelationship> dbRelationships = relationship.getDbRelationships();
- if (dbRelationships.size() != 2) {
- throw new CayenneRuntimeException(
- "Only single-step flattened relationships are supported in this operation, whereas the relationship '%s' has %s",
- relationship, dbRelationships.size());
- }
-
- DbRelationship r1 = dbRelationships.get(0);
- DbRelationship r2 = dbRelationships.get(1).getReverseRelationship();
-
- if (r2 == null) {
- throw new IllegalStateException("No reverse relationship for DbRelationship " + dbRelationships.get(1));
- }
-
- id1 = new DbArcId(sourceId, r1);
- id2 = new DbArcId(destinationId, r2);
- }
-
- /**
- * Returns a join DbEntity for the single-step flattened relationship.
- */
- DbEntity getJoinEntity() {
- return id1.getEntity();
- }
-
- /**
- * Returns a snapshot for join record for the single-step flattened
- * relationship, generating value for the primary key column if it is not
- * propagated via the relationships.
- */
- Map<String, Object> buildJoinSnapshotForInsert(DataNode node) {
- Map<String, Object> snapshot = lazyJoinSnapshot();
-
- boolean autoPkDone = false;
- DbEntity joinEntity = getJoinEntity();
-
- for (DbAttribute dbAttr : joinEntity.getPrimaryKeys()) {
- String dbAttrName = dbAttr.getName();
- if (snapshot.containsKey(dbAttrName)) {
- continue;
- }
-
- DbAdapter adapter = node.getAdapter();
-
- // skip db-generated... looks like we don't care about the actual PK
- // value here, so no need to retrieve db-generated pk back to Java.
- if (adapter.supportsGeneratedKeys() && dbAttr.isGenerated()) {
- continue;
- }
-
- if (autoPkDone) {
- throw new CayenneRuntimeException("Primary Key autogeneration only works for a single attribute.");
- }
-
- // finally, use database generation mechanism
- try {
- Object pkValue = adapter.getPkGenerator().generatePk(node, dbAttr);
- snapshot.put(dbAttrName, pkValue);
- autoPkDone = true;
- } catch (Exception ex) {
- throw new CayenneRuntimeException("Error generating PK: %s", ex, ex.getMessage());
- }
- }
-
- return snapshot;
- }
-
- /**
- * Returns pk snapshots for join records for the single-step flattened
- * relationship. Multiple joins between the same pair of objects are
- * theoretically possible, so the return value is a list.
- */
- List buildJoinSnapshotsForDelete(DataNode node) {
- Map<String, Object> snapshot = eagerJoinSnapshot();
-
- DbEntity joinEntity = getJoinEntity();
-
- boolean fetchKey = false;
- for (DbAttribute dbAttr : joinEntity.getPrimaryKeys()) {
- String dbAttrName = dbAttr.getName();
- if (!snapshot.containsKey(dbAttrName)) {
- fetchKey = true;
- break;
- }
- }
-
- if (!fetchKey) {
- return Collections.singletonList(snapshot);
- }
-
- // ok, the key is not included in snapshot, must do the fetch...
- // TODO: this should be optimized in the future, but now
- // DeleteBatchQuery
- // expects a PK snapshot, so we must provide it.
-
- QuotingStrategy quoter = node.getAdapter().getQuotingStrategy();
-
- StringBuilder sql = new StringBuilder("SELECT ");
- Collection<DbAttribute> pk = joinEntity.getPrimaryKeys();
- final List<DbAttribute> pkList = pk instanceof List ? (List<DbAttribute>) pk : new ArrayList<>(pk);
-
- for (int i = 0; i < pkList.size(); i++) {
-
- if (i > 0) {
- sql.append(", ");
- }
-
- DbAttribute attribute = pkList.get(i);
-
- sql.append("#result('");
- sql.append(quoter.quotedName(attribute));
-
- // since the name of the column can potentially be quoted and
- // use reserved keywords as name, let's specify generated column
- // name parameters to ensure the query doesn't explode
- sql.append("' '").append(TypesMapping.getJavaBySqlType(attribute));
- sql.append("' '").append("pk").append(i);
- sql.append("')");
- }
-
- sql.append(" FROM ").append(quoter.quotedFullyQualifiedName(joinEntity)).append(" WHERE ");
- int i = snapshot.size();
- for (Object key : snapshot.keySet()) {
- sql.append(quoter.quotedIdentifier(joinEntity, String.valueOf(key))).append(" #bindEqual($").append(key)
- .append(")");
-
- if (--i > 0) {
- sql.append(" AND ");
- }
- }
-
- SQLTemplate query = new SQLTemplate(joinEntity.getDataMap(), sql.toString(), true);
- query.setParams(snapshot);
-
- final List[] result = new List[1];
-
- node.performQueries(Collections.singleton((Query) query), new DefaultOperationObserver() {
-
- @Override
- public void nextRows(Query query, List<?> dataRows) {
-
- if (!dataRows.isEmpty()) {
- // decode results...
-
- List<DataRow> fixedRows = new ArrayList<>(dataRows.size());
- for (Object o : dataRows) {
- DataRow row = (DataRow) o;
-
- DataRow fixedRow = new DataRow(2);
-
- for (int i = 0; i < pkList.size(); i++) {
- DbAttribute attribute = pkList.get(i);
- fixedRow.put(attribute.getName(), row.get("pk" + i));
- }
-
- fixedRows.add(fixedRow);
- }
-
- dataRows = fixedRows;
- }
-
- result[0] = dataRows;
- }
-
- @Override
- public void nextQueryException(Query query, Exception ex) {
- throw new CayenneRuntimeException("Raising from query exception.", Util.unwindException(ex));
- }
-
- @Override
- public void nextGlobalException(Exception ex) {
- throw new CayenneRuntimeException("Raising from underlyingQueryEngine exception.", Util
- .unwindException(ex));
- }
- });
-
- return result[0];
- }
-
- @Override
- public int hashCode() {
- // order ids in array for hashcode consistency purposes. The actual
- // order direction is not important, as long as it
- // is consistent across invocations
-
- int compare = id1.getSourceId().getEntityName().compareTo(id2.getSourceId().getEntityName());
-
- if (compare == 0) {
- compare = id1.getIncominArc().getName().compareTo(id2.getIncominArc().getName());
-
- if (compare == 0) {
- // since ordering is mostly important for detecting equivalent
- // FlattenedArc keys coming from 2 opposite directions, the name
- // of ObjRelationship can be a good criteria
-
- ObjRelationship or2 = relationship.getReverseRelationship();
- compare = or2 != null ? relationship.getName().compareTo(or2.getName()) : 1;
-
- // TODO: if(compare == 0) ??
- }
- }
-
- DbArcId[] ordered;
- if (compare < 0) {
- ordered = new DbArcId[] { id1, id2 };
- } else {
- ordered = new DbArcId[] { id2, id1 };
- }
-
- return new HashCodeBuilder().append(ordered).toHashCode();
- }
-
- /**
- * Defines equal based on whether the relationship is bidirectional.
- */
- @Override
- public boolean equals(Object object) {
-
- if (this == object) {
- return true;
- }
-
- if (!(object instanceof FlattenedArcKey)) {
- return false;
- }
-
- FlattenedArcKey key = (FlattenedArcKey) object;
-
- // ignore id order in comparison
- if (id1.equals(key.id1)) {
- return id2.equals(key.id2);
- } else if (id1.equals(key.id2)) {
- return id2.equals(key.id1);
- }
-
- return false;
- }
-
- private Map<String, Object> eagerJoinSnapshot() {
-
- List<DbRelationship> relList = relationship.getDbRelationships();
- if (relList.size() != 2) {
- throw new CayenneRuntimeException(
- "Only single-step flattened relationships are supported in this operation: %s", relationship);
- }
-
- DbRelationship firstDbRel = relList.get(0);
- DbRelationship secondDbRel = relList.get(1);
-
- // here ordering of ids is determined by 'relationship', so use id1, id2
- // instead of orderedIds
- Map<String, ?> sourceId = id1.getSourceId().getIdSnapshot();
- Map<String, ?> destinationId = id2.getSourceId().getIdSnapshot();
-
- Map<String, Object> snapshot = new HashMap<>(sourceId.size() + destinationId.size(), 1);
- for (DbJoin join : firstDbRel.getJoins()) {
- snapshot.put(join.getTargetName(), sourceId.get(join.getSourceName()));
- }
-
- for (DbJoin join : secondDbRel.getJoins()) {
- snapshot.put(join.getSourceName(), destinationId.get(join.getTargetName()));
- }
-
- return snapshot;
- }
-
- private Map<String, Object> lazyJoinSnapshot() {
-
- List<DbRelationship> relList = relationship.getDbRelationships();
- if (relList.size() != 2) {
- throw new CayenneRuntimeException(
- "Only single-step flattened relationships are supported in this operation: %s", relationship);
- }
-
- DbRelationship firstDbRel = relList.get(0);
- DbRelationship secondDbRel = relList.get(1);
-
- List<DbJoin> fromSourceJoins = firstDbRel.getJoins();
- List<DbJoin> toTargetJoins = secondDbRel.getJoins();
-
- Map<String, Object> snapshot = new HashMap<>(fromSourceJoins.size() + toTargetJoins.size(), 1);
-
- // here ordering of ids is determined by 'relationship', so use id1, id2
- // instead of orderedIds
-
- for (DbJoin join : fromSourceJoins) {
- Object value = new PropagatedValueFactory(id1.getSourceId(), join.getSourceName());
- snapshot.put(join.getTargetName(), value);
- }
-
- for (DbJoin join : toTargetJoins) {
- Object value = new PropagatedValueFactory(id2.getSourceId(), join.getTargetName());
- snapshot.put(join.getSourceName(), value);
- }
-
- return snapshot;
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java
deleted file mode 100644
index a461f1393..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.flush.DefaultDataDomainFlushAction;
-import org.apache.cayenne.graph.CompoundDiff;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.query.BatchQuery;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.tx.BaseTransaction;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A stateful commit handler used by DataContext to perform commit operation.
- * DataContextCommitAction resolves primary key dependencies, referential integrity
- * dependencies (including multi-reflexive entities), generates primary keys, creates
- * batches for massive data modifications, assigns operations to data nodes.
- *
- * @since 1.2
- * @deprecated this implementation is deprecated since 4.2, {@link DefaultDataDomainFlushAction} is used
- */
-@Deprecated
-public class LegacyDataDomainFlushAction implements org.apache.cayenne.access.flush.DataDomainFlushAction {
-
- private final DataDomain domain;
- private DataContext context;
- private Map<Object, ObjectDiff> changesByObjectId;
-
- private CompoundDiff resultDiff;
- private Collection<ObjectId> resultDeletedIds;
- private Map<ObjectId, DataRow> resultModifiedSnapshots;
- private Collection<ObjectId> resultIndirectlyModifiedIds;
-
- private DataDomainInsertBucket insertBucket;
- private DataDomainUpdateBucket updateBucket;
- private DataDomainDeleteBucket deleteBucket;
- private DataDomainFlattenedBucket flattenedBucket;
-
- private List<Query> queries;
-
- private JdbcEventLogger logger;
-
- public LegacyDataDomainFlushAction(DataDomain domain) {
- this.domain = domain;
- }
-
- DataDomain getDomain() {
- return domain;
- }
-
- DataContext getContext() {
- return context;
- }
-
- Collection<ObjectId> getResultDeletedIds() {
- return resultDeletedIds;
- }
-
- CompoundDiff getResultDiff() {
- return resultDiff;
- }
-
- Collection<ObjectId> getResultIndirectlyModifiedIds() {
- return resultIndirectlyModifiedIds;
- }
-
- Map<ObjectId, DataRow> getResultModifiedSnapshots() {
- return resultModifiedSnapshots;
- }
-
- public void setJdbcEventLogger(JdbcEventLogger logger) {
- this.logger = logger;
- }
-
- public JdbcEventLogger getJdbcEventLogger() {
- return this.logger;
- }
-
- ObjectDiff objectDiff(Object objectId) {
- return changesByObjectId.get(objectId);
- }
-
- void addFlattenedInsert(DbEntity flattenedEntity, FlattenedArcKey flattenedInsertInfo) {
- flattenedBucket.addInsertArcKey(flattenedEntity, flattenedInsertInfo);
- }
-
- void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo) {
- flattenedBucket.addFlattenedDelete(flattenedEntity, flattenedDeleteInfo);
- }
-
- public GraphDiff flush(DataContext context, GraphDiff changes) {
-
- if (changes == null) {
- return new CompoundDiff();
- }
-
- // TODO: Andrus, 3/13/2006 - support categorizing an arbitrary diff
- if (!(changes instanceof ObjectStoreGraphDiff)) {
- throw new IllegalArgumentException("Expected 'ObjectStoreGraphDiff', got: " + changes.getClass().getName());
- }
-
- this.context = context;
-
- // ObjectStoreGraphDiff contains changes already categorized by objectId...
- this.changesByObjectId = ((ObjectStoreGraphDiff) changes).getChangesByObjectId();
- this.insertBucket = new DataDomainInsertBucket(this);
- this.deleteBucket = new DataDomainDeleteBucket(this);
- this.updateBucket = new DataDomainUpdateBucket(this);
- this.flattenedBucket = new DataDomainFlattenedBucket(this);
-
- this.queries = new ArrayList<>();
- this.resultIndirectlyModifiedIds = new HashSet<>();
-
- preprocess(context, changes);
-
- if (queries.isEmpty()) {
- return new CompoundDiff();
- }
-
- this.resultDiff = new CompoundDiff();
- this.resultDeletedIds = new ArrayList<>();
- this.resultModifiedSnapshots = new HashMap<>();
-
- runQueries();
-
- postprocess(context);
- return resultDiff;
- }
-
- private void preprocess(DataContext context, GraphDiff changes) {
-
- // categorize dirty objects by state
-
- ObjectStore objectStore = context.getObjectStore();
-
- for (Object o : changesByObjectId.keySet()) {
- ObjectId id = (ObjectId) o;
- Persistent object = (Persistent) objectStore.getNode(id);
- ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(id.getEntityName());
-
- switch (object.getPersistenceState()) {
- case PersistenceState.NEW:
- insertBucket.addDirtyObject(object, descriptor);
- break;
- case PersistenceState.MODIFIED:
- updateBucket.addDirtyObject(object, descriptor);
- break;
- case PersistenceState.DELETED:
- deleteBucket.addDirtyObject(object, descriptor);
- break;
- }
- }
-
- new DataDomainIndirectDiffBuilder(this).processIndirectChanges(changes);
-
- insertBucket.appendQueries(queries);
-
- // TODO: the following line depends on the "queries" collection filled by insertBucket.. Moreover it may
- // potentially remove values from the passed collection. Replace with something with fewer unobvious
- // side-effects...
- flattenedBucket.appendInserts(queries);
-
- updateBucket.appendQueries(queries);
- flattenedBucket.appendDeletes(queries);
- deleteBucket.appendQueries(queries);
- }
-
- private void runQueries() {
- DataDomainFlushObserver observer = new DataDomainFlushObserver(
- domain.getJdbcEventLogger());
-
- // split query list by spanned nodes and run each single node range individually.
- // Since connections are reused per node within an open transaction, there should
- // not be much overhead in accessing the same node multiple times (may happen due
- // to imperfect sorting)
-
- try {
-
- DataNode lastNode = null;
- DbEntity lastEntity = null;
- int rangeStart = 0;
- int len = queries.size();
-
- for (int i = 0; i < len; i++) {
-
- BatchQuery query = (BatchQuery) queries.get(i);
- if (query.getDbEntity() != lastEntity) {
- lastEntity = query.getDbEntity();
-
- DataNode node = domain.lookupDataNode(lastEntity.getDataMap());
- if (node != lastNode) {
-
- if (i - rangeStart > 0) {
- lastNode.performQueries(queries.subList(rangeStart, i), observer);
- }
-
- rangeStart = i;
- lastNode = node;
- }
- }
- }
-
- // process last segment of the query list...
- lastNode.performQueries(queries.subList(rangeStart, len), observer);
- } catch (Throwable th) {
- BaseTransaction.getThreadTransaction().setRollbackOnly();
- throw new CayenneRuntimeException("Transaction was rolledback.", th);
- }
- }
-
- /*
- * Sends notification of changes to the DataRowStore, returns GraphDiff with replaced
- * ObjectIds.
- */
- private void postprocess(DataContext context) {
-
- deleteBucket.postprocess();
- updateBucket.postprocess();
- insertBucket.postprocess();
-
- // notify cache...
- if (!resultDeletedIds.isEmpty()
- || !resultModifiedSnapshots.isEmpty()
- || !resultIndirectlyModifiedIds.isEmpty()) {
-
- context
- .getObjectStore()
- .getDataRowCache()
- .processSnapshotChanges(
- context.getObjectStore(),
- resultModifiedSnapshots,
- resultDeletedIds,
- Collections.<ObjectId>emptyList(),
- resultIndirectlyModifiedIds);
- }
-
- context.getObjectStore().postprocessAfterCommit(resultDiff);
- }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java
deleted file mode 100644
index 5ac9b2c05..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.access.flush.DataDomainFlushAction;
-import org.apache.cayenne.access.flush.DataDomainFlushActionFactory;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-
-/**
- * Factory for {@link LegacyDataDomainFlushAction}.
- * A fallback factory to use deprecated implementation if absolutely needed.
- *
- * @since 4.2
- */
-@Deprecated
-public class LegacyDataDomainFlushActionFactory implements DataDomainFlushActionFactory {
-
- @Inject
- private JdbcEventLogger jdbcEventLogger;
-
- @Override
- public DataDomainFlushAction createFlushAction(DataDomain dataDomain) {
- LegacyDataDomainFlushAction action = new LegacyDataDomainFlushAction(dataDomain);
- action.setJdbcEventLogger(jdbcEventLogger);
- return action;
- }
-}