1 19 20 package org.apache.cayenne.access; 21 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.Map ; 27 28 import org.apache.cayenne.CayenneRuntimeException; 29 import org.apache.cayenne.ObjectId; 30 import org.apache.cayenne.access.DataDomainSyncBucket.PropagatedValueFactory; 31 import org.apache.cayenne.access.util.DefaultOperationObserver; 32 import org.apache.cayenne.dba.PkGenerator; 33 import org.apache.cayenne.exp.Expression; 34 import org.apache.cayenne.exp.ExpressionFactory; 35 import org.apache.cayenne.map.DbAttribute; 36 import org.apache.cayenne.map.DbEntity; 37 import org.apache.cayenne.map.DbJoin; 38 import org.apache.cayenne.map.DbRelationship; 39 import org.apache.cayenne.map.ObjRelationship; 40 import org.apache.cayenne.query.Query; 41 import org.apache.cayenne.query.SelectQuery; 42 43 49 final class FlattenedArcKey { 50 51 ObjectId sourceId; 52 ObjectId destinationId; 53 ObjRelationship relationship; 54 ObjRelationship reverseRelationship; 55 String compareToken; 56 57 FlattenedArcKey(ObjectId sourceId, ObjectId destinationId, 58 ObjRelationship relationship) { 59 60 this.sourceId = sourceId; 61 this.destinationId = destinationId; 62 this.relationship = relationship; 63 this.reverseRelationship = relationship.getReverseRelationship(); 64 65 String relName1 = relationship.getName(); 68 if (reverseRelationship != null) { 69 String relName2 = reverseRelationship.getName(); 70 71 if (relName1.compareTo(relName2) <= 0) { 75 this.compareToken = relName1 + "." + relName2; 76 } 77 else { 78 this.compareToken = relName2 + "." + relName1; 79 } 80 } 81 else { 82 this.compareToken = relName1; 83 } 84 } 85 86 89 DbEntity getJoinEntity() { 90 List relList = relationship.getDbRelationships(); 91 if (relList.size() != 2) { 92 throw new CayenneRuntimeException( 93 "Only single-step flattened relationships are supported in this operation: " 94 + relationship); 95 } 96 97 DbRelationship firstDbRel = (DbRelationship) relList.get(0); 98 return (DbEntity) firstDbRel.getTargetEntity(); 99 } 100 101 106 Map buildJoinSnapshotForInsert(DataNode node) { 107 Map snapshot = lazyJoinSnapshot(); 108 109 boolean autoPkDone = false; 110 DbEntity joinEntity = getJoinEntity(); 111 List pkAttributes = joinEntity.getPrimaryKey(); 112 Iterator it = pkAttributes.iterator(); 113 114 while (it.hasNext()) { 115 DbAttribute dbAttr = (DbAttribute) it.next(); 116 String dbAttrName = dbAttr.getName(); 117 if (snapshot.containsKey(dbAttrName)) { 118 continue; 119 } 120 121 if (autoPkDone) { 122 throw new CayenneRuntimeException( 123 "Primary Key autogeneration only works for a single attribute."); 124 } 125 126 try { 128 PkGenerator pkGenerator = node.getAdapter().getPkGenerator(); 129 Object pkValue = pkGenerator.generatePkForDbEntity(node, joinEntity); 130 snapshot.put(dbAttrName, pkValue); 131 autoPkDone = true; 132 } 133 catch (Exception ex) { 134 throw new CayenneRuntimeException("Error generating PK: " 135 + ex.getMessage(), ex); 136 } 137 } 138 139 return snapshot; 140 } 141 142 147 List buildJoinSnapshotsForDelete(DataNode node) { 148 Map snapshot = eagerJoinSnapshot(); 149 150 DbEntity joinEntity = getJoinEntity(); 151 List pkAttributes = joinEntity.getPrimaryKey(); 152 153 boolean fetchKey = false; 154 Iterator it = pkAttributes.iterator(); 155 while (it.hasNext()) { 156 DbAttribute dbAttr = (DbAttribute) it.next(); 157 String dbAttrName = dbAttr.getName(); 158 if (!snapshot.containsKey(dbAttrName)) { 159 fetchKey = true; 160 break; 161 } 162 } 163 164 if (!fetchKey) { 165 return Collections.singletonList(snapshot); 166 } 167 168 172 SelectQuery query = new SelectQuery(joinEntity, ExpressionFactory.matchAllDbExp( 173 snapshot, 174 Expression.EQUAL_TO)); 175 query.setFetchingDataRows(true); 176 177 it = pkAttributes.iterator(); 178 while (it.hasNext()) { 179 DbAttribute dbAttr = (DbAttribute) it.next(); 180 query.addCustomDbAttribute(dbAttr.getName()); 181 } 182 183 final List [] result = new List [1]; 184 185 node.performQueries(Collections.singleton(query), new DefaultOperationObserver() { 186 187 public void nextDataRows(Query query, List dataRows) { 188 result[0] = dataRows; 189 } 190 }); 191 192 return result[0]; 193 } 194 195 boolean isBidirectional() { 196 return reverseRelationship != null; 197 } 198 199 public int hashCode() { 200 return sourceId.hashCode() + destinationId.hashCode() + compareToken.hashCode(); 202 } 203 204 207 public boolean equals(Object object) { 208 209 if (this == object) { 210 return true; 211 } 212 213 if (!(object instanceof FlattenedArcKey)) { 214 return false; 215 } 216 217 FlattenedArcKey update = (FlattenedArcKey) object; 218 219 if (!this.compareToken.equals(update.compareToken)) { 220 return false; 221 } 222 223 boolean bidi = isBidirectional(); 224 if (bidi != update.isBidirectional()) { 225 return false; 226 } 227 228 return (bidi) ? bidiEquals(update) : uniEquals(update); 229 } 230 231 private boolean bidiEquals(FlattenedArcKey update) { 232 return (sourceId.equals(update.sourceId) && destinationId 233 .equals(update.destinationId)) 234 || (this.sourceId.equals(update.destinationId) && this.destinationId 235 .equals(update.sourceId)); 236 } 237 238 private boolean uniEquals(FlattenedArcKey update) { 239 return (this.sourceId.equals(update.sourceId) && this.destinationId 240 .equals(update.destinationId)); 241 } 242 243 private Map eagerJoinSnapshot() { 244 245 List relList = relationship.getDbRelationships(); 246 if (relList.size() != 2) { 247 throw new CayenneRuntimeException( 248 "Only single-step flattened relationships are supported in this operation: " 249 + relationship); 250 } 251 252 DbRelationship firstDbRel = (DbRelationship) relList.get(0); 253 DbRelationship secondDbRel = (DbRelationship) relList.get(1); 254 255 Map sourceId = this.sourceId.getIdSnapshot(); 256 Map destinationId = this.destinationId.getIdSnapshot(); 257 258 Map snapshot = new HashMap (sourceId.size() + destinationId.size(), 1); 259 List joins = firstDbRel.getJoins(); 260 for (int i = 0, numJoins = joins.size(); i < numJoins; i++) { 261 DbJoin join = (DbJoin) joins.get(i); 262 snapshot.put(join.getTargetName(), sourceId.get(join.getSourceName())); 263 } 264 265 joins = secondDbRel.getJoins(); 266 for (int i = 0, numJoins = joins.size(); i < numJoins; i++) { 267 DbJoin join = (DbJoin) joins.get(i); 268 snapshot.put(join.getSourceName(), destinationId.get(join.getTargetName())); 269 } 270 271 return snapshot; 272 } 273 274 private Map lazyJoinSnapshot() { 275 276 List relList = relationship.getDbRelationships(); 277 if (relList.size() != 2) { 278 throw new CayenneRuntimeException( 279 "Only single-step flattened relationships are supported in this operation: " 280 + relationship); 281 } 282 283 DbRelationship firstDbRel = (DbRelationship) relList.get(0); 284 DbRelationship secondDbRel = (DbRelationship) relList.get(1); 285 286 List fromSourceJoins = firstDbRel.getJoins(); 287 List toTargetJoins = secondDbRel.getJoins(); 288 289 Map snapshot = new HashMap (fromSourceJoins.size() + toTargetJoins.size(), 1); 290 291 for (int i = 0, numJoins = fromSourceJoins.size(); i < numJoins; i++) { 292 DbJoin join = (DbJoin) fromSourceJoins.get(i); 293 294 Object value = new PropagatedValueFactory(sourceId, join.getSourceName()); 295 snapshot.put(join.getTargetName(), value); 296 } 297 298 for (int i = 0, numJoins = toTargetJoins.size(); i < numJoins; i++) { 299 DbJoin join = (DbJoin) toTargetJoins.get(i); 300 Object value = new PropagatedValueFactory(destinationId, join.getTargetName()); 301 snapshot.put(join.getSourceName(), value); 302 } 303 304 return snapshot; 305 } 306 } 307 | Popular Tags |