1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.caleigo.core;
20
21 import java.util.*;
22
23 import org.caleigo.core.exception.*;
24
25 /*** <Description for Relations>
26 *
27 * @author Dennis Zikovic
28 * @version 1.00
29 *
30 *//*
31 *
32 * WHEN WHO WHY & WHAT
33 * -----------------------------------------------------------------------------
34 * 2002-05-14 Dennis Zikovic Creation
35 */
36 public final class Relations
37 {
38
39
40 /*** Constructor is private to avoid inproper instatiations.
41 */
42 private Relations()
43 {
44 }
45
46
47
48 public static boolean isIntersection(IEntityDescriptor descriptor1, IEntityDescriptor descriptor2)
49 {
50 boolean found = false;
51 for(int j=0; j<descriptor1.getFieldCount() && !found; j++)
52 found = descriptor2.contains(descriptor1.getFieldDescriptor(j));
53 return found;
54 }
55
56 public static boolean isIdentityIntersection(IEntityDescriptor descriptor1, IEntityDescriptor descriptor2)
57 {
58 boolean found = descriptor1==descriptor2;
59 IFieldDescriptor[] identityFields = Relations.getIdentityFields(descriptor1);
60 for(int j=0; j<identityFields.length && !found; j++)
61 found = descriptor2.contains(identityFields[j]);
62 return found;
63 }
64
65 /*** Returns true if the provided entity descriptors are related.
66 */
67 public static boolean isRelated(IEntityDescriptor startDescriptor, IEntityDescriptor endDescriptor)
68 {
69 try
70 {
71 return EntityRelationPath.create(startDescriptor, endDescriptor)!=null;
72 }
73 catch(InvalidRelationException e)
74 {
75 return false;
76 }
77 }
78
79 /*** Returns true if the provided entity descriptors are reference related,
80 * meaning that there can be endDescriptor entity for any given
81 * startDescriptor entity.
82 */
83 public static boolean isReferenceRelated(IEntityDescriptor startDescriptor, IEntityDescriptor endDescriptor)
84 {
85 try
86 {
87 IEntityRelationPath path = EntityRelationPath.create(startDescriptor, endDescriptor);
88 return path.getForwardCardinality()==IEntityRelationPath.ONE;
89 }
90 catch(InvalidRelationException e)
91 {
92 return false;
93 }
94 }
95
96 /*** Returns true if the provided entity descriptor is related to other
97 * entity descriptors as the target of the relation. The method can used
98 * to determine if it is safe to delete or change an etity's identity fields
99 * whitout the risk of causing a foreign key violation in slave entities.
100 */
101 public static boolean isReferenceTarget(IEntityDescriptor descriptor)
102 {
103 for(int j=0; j<descriptor.getEntityRelationCount(); j++)
104 if(descriptor.getEntityRelation(j).canBeTarget(descriptor))
105 return true;
106 return false;
107 }
108
109 /*** Returns true if the provided relation path is a "link" relation meaning
110 * that the path is defined by two and only two entity relations with
111 * an entity descriptor of the type LINK_ENTITY between the relations.
112 */
113 public static boolean isLinkRelation(IEntityRelationPath relationPath)
114 {
115 if(relationPath.getRelationCount()==2 && relationPath.getRelation(0).getRelatedEntityDescriptor(relationPath.getFirstEntityDescriptor()).getEntityType()==IEntityDescriptor.LINK_ENTITY)
116 return true;
117 else
118 return false;
119 }
120
121 public static int getIdentityFieldCount(IEntityDescriptor entityDescriptor)
122 {
123 int count = 0;
124 for(int j=0; j<entityDescriptor.getFieldCount(); j++)
125 if(entityDescriptor.getFieldDescriptor(j).isIdentityField())
126 count++;
127 return count;
128 }
129
130 public static IFieldDescriptor[] getIdentityFields(IEntityDescriptor entityDescriptor)
131 {
132 int count = getIdentityFieldCount(entityDescriptor);
133
134 IFieldDescriptor[] fields = new IFieldDescriptor[count];
135 for(int j=entityDescriptor.getFieldCount()-1; j>=0; j--)
136 if(entityDescriptor.getFieldDescriptor(j).isIdentityField())
137 fields[--count] = entityDescriptor.getFieldDescriptor(j);
138
139 return fields;
140 }
141
142 /*** creates a subpath of the provided entity relation path starting at
143 * the provided index to the end of the provided path.
144 */
145 public static IEntityRelationPath getSubRelationPath(IEntityRelationPath path, int start)
146 {
147 return getSubRelationPath(path, start, path.getRelationCount()-1);
148 }
149
150 /*** creates a subpath of the provided entity relation path starting at
151 * the start-index and ending at tha end-index.
152 */
153 public static IEntityRelationPath getSubRelationPath(IEntityRelationPath path, int start, int end)
154 {
155 if(start<0 || end>=path.getRelationCount() || start>end)
156 throw new IllegalArgumentException();
157
158 EntityRelationPath relationPath = new EntityRelationPath(path.getRelation(start), path.isRelationByReference(start));
159 for(int j=start+1; start<end; j++)
160 relationPath.appendRelation(path.getRelation(j), path.isRelationByReference(j));
161
162 return relationPath;
163 }
164
165 public static IEntity loadReferredEntity(IEntity sourceEntity, IFieldDescriptor referenceFieldDescriptor)
166 {
167 IFieldRelation refRelation = referenceFieldDescriptor.getReferenceFieldRelation();
168 if(refRelation==null)
169 return null;
170
171 Qualifier refQualifier = null;
172 try
173 {
174 Iterator it = refRelation.getEntityRelation().getFieldRelations();
175 while(it.hasNext())
176 {
177 refRelation = (IFieldRelation)it.next();
178 refQualifier = Qualifier.combine(refQualifier, Qualifier.create(refRelation.getTargetField(), sourceEntity.getData(refRelation.getReferenceField())));
179 }
180 }
181 catch(InvalidFieldException e)
182 {
183 return null;
184 }
185
186 if(refQualifier!=null)
187 return refRelation.getTargetField().getEntityDescriptor().loadEntity(refQualifier);
188 else
189 return null;
190 }
191
192 public static ISelection loadRelatedEntities(IEntity sourceEntity, IEntityDescriptor targetDescriptor)
193 {
194 return loadRelatedEntities(sourceEntity, targetDescriptor, null);
195 }
196
197 public static ISelection loadRelatedEntities(IEntity sourceEntity, IEntityDescriptor targetDescriptor, IFieldDescriptor[] wayPoints)
198 {
199 IEntityRelationPath path = EntityRelationPath.create(sourceEntity.getEntityDescriptor(), wayPoints, targetDescriptor);
200 return targetDescriptor.loadSelection(sourceEntity.getOriginQualifier().and(path.getRelationQualifier()));
201 }
202
203 /*** Loads an uniquely identifiable entity based on the data in the source.
204 * entity. If no such entity can logicaly be identified null is rerturned.
205 */
206 public static IEntity loadIntersectEntity(IEntity sourceEntity, IEntityDescriptor targetDescriptor)
207 {
208 Qualifier identityQualifier = makeIdentityQualifier(sourceEntity, targetDescriptor);
209 if(identityQualifier!=null)
210 return targetDescriptor.loadEntity(identityQualifier);
211 else
212 return null;
213 }
214
215 /*** Makes a qualifer of the provided field descriptors and entity.
216 * The qualifier will use relation qualifers using EQUAL to qualify
217 * the field data. The relation qualifiers will be placed in a composite
218 * qualifier using INTERSECTION. If not all fields could be qualified by
219 * the provided entity null is returned.
220 * <p>
221 * The fields must be directly conatined in the entity or have refernece
222 * fields in the entity that directly refers to a provided field.
223 */
224 public static Qualifier makeFieldQualifier(IFieldDescriptor[] descriptors, IEntity entity)
225 {
226 Object[] fieldData = new Object[descriptors.length];
227 int foundCount = 0;
228
229
230 for(int j=0; j<descriptors.length; j++)
231 if(entity.getEntityDescriptor().contains(descriptors[j]))
232 {
233 fieldData[j] = entity.getData(descriptors[j]);
234 foundCount++;
235 }
236
237
238 if(foundCount<descriptors.length)
239 {
240 IEntityDescriptor entityDescriptor = entity.getEntityDescriptor();
241 for(int j=0; j<descriptors.length; j++)
242 {
243 for(int k=0; fieldData[j]==null && k<entityDescriptor.getFieldCount(); k++)
244 {
245 if(entityDescriptor.getFieldDescriptor(k).isReferenceField()
246 && entityDescriptor.getFieldDescriptor(k).getReferenceFieldRelation().getTargetField()==descriptors[j])
247 {
248 fieldData[j] = entity.getData(entityDescriptor.getFieldDescriptor(k));
249 foundCount++;
250 }
251 }
252 }
253 }
254
255
256 if(foundCount==descriptors.length)
257 {
258 Qualifier qualifier = null;
259 for(int j=0; j<descriptors.length; j++)
260 qualifier = Qualifier.combine(qualifier, Qualifier.create(descriptors[j], fieldData[j]));
261 return qualifier;
262 }
263 else
264 return null;
265 }
266
267 /*** Makes an identity qualifier for an entity of the targetDescriptor type
268 * using the fields in the sourceEntity. If not all identity fields can be
269 * satisfied a null value is returned.
270 */
271 public static Qualifier makeIdentityQualifier(IEntity sourceEntity, IEntityDescriptor targetDescriptor)
272 {
273 if(sourceEntity.getEntityDescriptor()==targetDescriptor)
274 return sourceEntity.getOriginQualifier();
275 else
276 return makeFieldQualifier(getIdentityFields(targetDescriptor), sourceEntity);
277 }
278
279 /*** Makes a qualifier that qualifies entities of the oposite end of the
280 * provided relation object. Qualification data will be taken from the
281 * provided source entity. The method can be used to resolve single step
282 * relations by direclty qualifiyng qualifier.
283 */
284 public static Qualifier makeRelationQualifier(IEntity sourceEntity, IEntityRelation entityRelation)
285 {
286 if(entityRelation==null || !entityRelation.isRelationNode(sourceEntity.getEntityDescriptor()))
287 throw new InvalidRelationException("Entity relation not related to "+sourceEntity);
288
289 Qualifier qualifier = null;
290 java.util.Iterator it = entityRelation.getFieldRelations();
291 boolean sourceIsTarget = entityRelation.getTargetEntityDescriptor()==sourceEntity.getEntityDescriptor();
292 while(it.hasNext())
293 {
294 IFieldRelation fieldRelation = (IFieldRelation)it.next();
295 if(sourceIsTarget)
296 qualifier = Qualifier.combine(qualifier, Qualifier.create(fieldRelation.getReferenceField(), sourceEntity.getData(fieldRelation.getTargetField())));
297 else
298 qualifier = Qualifier.combine(qualifier, Qualifier.create(fieldRelation.getTargetField(), sourceEntity.getData(fieldRelation.getReferenceField())));
299 }
300 return qualifier;
301 }
302
303 /*** Sets all field data that can be extracted from the source data entity
304 * using the provided relation. If the provided relation is null then the
305 * first usable direct relation between the entities is used.
306 */
307 public static void setReferenceData(IEntity dataTargetEntity, IEntity dataSourceEntity, IEntityRelation relation)
308 {
309
310 for(int j=0; relation==null && j<dataTargetEntity.getEntityDescriptor().getEntityRelationCount(); j++)
311 if(dataTargetEntity.getEntityDescriptor().getEntityRelation(j).canBeReference(dataTargetEntity.getEntityDescriptor())
312 && dataTargetEntity.getEntityDescriptor().getEntityRelation(j).canBeTarget(dataSourceEntity.getEntityDescriptor()))
313 relation = dataTargetEntity.getEntityDescriptor().getEntityRelation(j);
314
315
316 if(relation==null || !relation.isRelationNode(dataSourceEntity.getEntityDescriptor()))
317 throw new InvalidRelationException("Entity relation not valid "+relation);
318
319
320 for(int j=0; j<relation.getFieldCount(); j++)
321 {
322 if(!dataSourceEntity.isPersistent())
323 {
324 if(dataSourceEntity instanceof IProxyEntity)
325 dataTargetEntity.setData(relation.getFieldRelation(j).getReferenceField(), new EntityFieldProxyData(relation.getFieldRelation(j).getTargetField(), ((IProxyEntity)dataSourceEntity).getSourceEntity()));
326 else
327 dataTargetEntity.setData(relation.getFieldRelation(j).getReferenceField(), new EntityFieldProxyData(relation.getFieldRelation(j).getTargetField(), dataSourceEntity));
328 }
329 else
330 dataTargetEntity.setData(relation.getFieldRelation(j).getReferenceField(), dataSourceEntity.getData(relation.getFieldRelation(j).getTargetField()));
331 }
332 }
333 }
334
335
336
337