blob: 26bef62ea36ddfb7c4ab2b00c34a24647a7e5c32 [file] [log] [blame]
kmoorec9c9e2b2011-02-06 02:07:28 +00001/*******************************************************************************
2 * Copyright (c) 2006, 2011 Oracle. All rights reserved.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v1.0, which accompanies this distribution
5 * and is available at http://www.eclipse.org/legal/epl-v10.html.
6 *
7 * Contributors:
8 * Oracle - initial API and implementation
9 ******************************************************************************/
10package org.eclipse.jpt.jpa.core.internal.context.orm;
11
kmoorec9c9e2b2011-02-06 02:07:28 +000012import java.util.List;
13import org.eclipse.jdt.core.IPackageFragment;
14import org.eclipse.jdt.core.IType;
15import org.eclipse.jpt.common.core.utility.TextRange;
kmoorebbf1de62011-08-25 20:29:52 +000016import org.eclipse.jpt.common.utility.internal.StringTools;
kmoorec9c9e2b2011-02-06 02:07:28 +000017import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable;
18import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
19import org.eclipse.jpt.common.utility.internal.iterables.SingleElementIterable;
kmoore3d505d22011-08-02 13:24:47 +000020import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable;
kmoorec9c9e2b2011-02-06 02:07:28 +000021import org.eclipse.jpt.jpa.core.context.AttributeMapping;
22import org.eclipse.jpt.jpa.core.context.Entity;
23import org.eclipse.jpt.jpa.core.context.FetchType;
24import org.eclipse.jpt.jpa.core.context.PersistentAttribute;
25import org.eclipse.jpt.jpa.core.context.PersistentType;
26import org.eclipse.jpt.jpa.core.context.ReadOnlyPersistentAttribute;
27import org.eclipse.jpt.jpa.core.context.RelationshipMapping;
28import org.eclipse.jpt.jpa.core.context.TypeMapping;
29import org.eclipse.jpt.jpa.core.context.orm.OrmCascade;
30import org.eclipse.jpt.jpa.core.context.orm.OrmMappingRelationship;
31import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentAttribute;
32import org.eclipse.jpt.jpa.core.context.orm.OrmRelationshipMapping;
33import org.eclipse.jpt.jpa.core.internal.context.AttributeMappingTools;
34import org.eclipse.jpt.jpa.core.internal.jpa1.context.orm.GenericOrmCascade;
35import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages;
36import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages;
37import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField;
38import org.eclipse.jpt.jpa.core.resource.orm.AbstractXmlRelationshipMapping;
39import org.eclipse.text.edits.ReplaceEdit;
40import org.eclipse.wst.validation.internal.provisional.core.IMessage;
41import org.eclipse.wst.validation.internal.provisional.core.IReporter;
42
43/**
44 * <code>orm.xml</code> relationship mapping (1:1, 1:m, m:1, m:m)
45 */
46public abstract class AbstractOrmRelationshipMapping<X extends AbstractXmlRelationshipMapping>
47 extends AbstractOrmAttributeMapping<X>
48 implements OrmRelationshipMapping
49{
50 protected String specifiedTargetEntity;
51 protected String defaultTargetEntity;
52
53 protected final OrmMappingRelationship relationship;
54
55 protected final OrmCascade cascade;
56
57 protected FetchType specifiedFetch;
58 protected FetchType defaultFetch;
59
60
61 protected AbstractOrmRelationshipMapping(OrmPersistentAttribute parent, X xmlMapping) {
62 super(parent, xmlMapping);
63 this.specifiedTargetEntity = xmlMapping.getTargetEntity();
64 this.relationship = this.buildRelationship();
65 this.cascade = this.buildCascade();
66 this.specifiedFetch = this.buildSpecifiedFetch();
67 }
68
69
70 // ********** synchronize/update **********
71
72 @Override
73 public void synchronizeWithResourceModel() {
74 super.synchronizeWithResourceModel();
75 this.setSpecifiedTargetEntity_(this.xmlAttributeMapping.getTargetEntity());
76 this.relationship.synchronizeWithResourceModel();
77 this.cascade.synchronizeWithResourceModel();
78 this.setSpecifiedFetch_(this.buildSpecifiedFetch());
79 }
80
81 @Override
82 public void update() {
83 super.update();
84 this.setDefaultTargetEntity(this.buildDefaultTargetEntity());
85 this.relationship.update();
86 this.cascade.update();
87 this.setDefaultFetch(this.buildDefaultFetch());
88 }
89
90
91 // ********** target entity **********
92
93 public String getTargetEntity() {
94 return (this.specifiedTargetEntity != null) ? this.specifiedTargetEntity : this.defaultTargetEntity;
95 }
96
97 public String getSpecifiedTargetEntity() {
98 return this.specifiedTargetEntity;
99 }
100
101 public void setSpecifiedTargetEntity(String entity) {
102 this.setSpecifiedTargetEntity_(entity);
103 this.xmlAttributeMapping.setTargetEntity(entity);
104 }
105
106 protected void setSpecifiedTargetEntity_(String entity) {
107 String old = this.specifiedTargetEntity;
108 this.specifiedTargetEntity = entity;
109 this.firePropertyChanged(SPECIFIED_TARGET_ENTITY_PROPERTY, old, entity);
110 }
111
112 public String getDefaultTargetEntity() {
113 return this.defaultTargetEntity;
114 }
115
116 protected void setDefaultTargetEntity(String entity) {
117 String old = this.defaultTargetEntity;
118 this.defaultTargetEntity = entity;
119 this.firePropertyChanged(DEFAULT_TARGET_ENTITY_PROPERTY, old, entity);
120 }
121
122 protected String buildDefaultTargetEntity() {
123 return (this.getJavaPersistentAttribute() == null) ? null : this.getJavaTargetType();
124 }
125
126 /**
127 * pre-condition: the mapping's Java persistent attribute is not
128 * <code>null</code>.
129 */
130 protected abstract String getJavaTargetType();
131
132 public Entity getResolvedTargetEntity() {
133 TypeMapping typeMapping = this.getResolvedTargetTypeMapping();
134 return (typeMapping instanceof Entity) ? (Entity) typeMapping : null;
135 }
136
137 protected TypeMapping getResolvedTargetTypeMapping() {
138 PersistentType resolvedTargetType = this.getResolvedTargetType();
139 return (resolvedTargetType == null) ? null : resolvedTargetType.getMapping();
140 }
141
142 // sub-classes like this to be public
143 public PersistentType getResolvedTargetType() {
144 return this.resolvePersistentType(this.getTargetEntity());
145 }
146
147 public char getTargetEntityEnclosingTypeSeparator() {
148 return '$';
149 }
150
151
152 // ********** relationship reference **********
153
154 public OrmMappingRelationship getRelationship() {
155 return this.relationship;
156 }
157
158 protected abstract OrmMappingRelationship buildRelationship();
159
160
161 // ********** cascade **********
162
163 public OrmCascade getCascade() {
164 return this.cascade;
165 }
166
167 protected OrmCascade buildCascade() {
168 // NB: we don't use the platform
169 return new GenericOrmCascade(this);
170 }
171
172
173 // ********** fetch **********
174
175 public FetchType getFetch() {
176 return (this.specifiedFetch != null) ? this.specifiedFetch : this.defaultFetch;
177 }
178
179 public FetchType getSpecifiedFetch() {
180 return this.specifiedFetch;
181 }
182
183 public void setSpecifiedFetch(FetchType fetch) {
184 this.setSpecifiedFetch_(fetch);
185 this.xmlAttributeMapping.setFetch(FetchType.toOrmResourceModel(fetch));
186 }
187
188 protected void setSpecifiedFetch_(FetchType fetch) {
189 FetchType old = this.specifiedFetch;
190 this.specifiedFetch = fetch;
191 this.firePropertyChanged(SPECIFIED_FETCH_PROPERTY, old, fetch);
192 }
193
194 protected FetchType buildSpecifiedFetch() {
195 return FetchType.fromOrmResourceModel(this.xmlAttributeMapping.getFetch());
196 }
197
198 public FetchType getDefaultFetch() {
199 return this.defaultFetch;
200 }
201
202 protected void setDefaultFetch(FetchType fetch) {
203 FetchType old = this.defaultFetch;
204 this.defaultFetch = fetch;
205 this.firePropertyChanged(DEFAULT_FETCH_PROPERTY, old, fetch);
206 }
207
208 protected abstract FetchType buildDefaultFetch();
209
210
211 // ********** misc **********
212
213 @Override
214 public boolean isRelationshipOwner() {
215 return this.relationship.isOwner();
216 }
217
218 @Override
219 public boolean isOwnedBy(AttributeMapping mapping) {
220 return mapping.isRelationshipOwner() &&
221 this.relationship.isOwnedBy((RelationshipMapping) mapping);
222 }
223
224 public RelationshipMapping getRelationshipOwner() {
225 Entity entity = this.getResolvedTargetEntity();
226 if (entity == null) {
227 return null;
228 }
kmoorec7a08672011-08-01 15:10:18 +0000229 for (ReadOnlyPersistentAttribute attribute : entity.getPersistentType().getAllAttributes()) {
kmoorec9c9e2b2011-02-06 02:07:28 +0000230 AttributeMapping mapping = attribute.getMapping();
231 if (this.isOwnedBy(mapping)) {
232 return (RelationshipMapping) mapping;
233 }
234 }
235 return null;
236 }
237
238 @Override
239 public boolean isOverridableAssociationMapping() {
240 return this.relationship.isOverridable();
241 }
242
243 @Override
244 protected void initializeFromOrmRelationshipMapping(OrmRelationshipMapping oldMapping) {
245 super.initializeFromOrmRelationshipMapping(oldMapping);
246 this.setSpecifiedTargetEntity(oldMapping.getSpecifiedTargetEntity());
247 this.setSpecifiedFetch(oldMapping.getSpecifiedFetch());
248 oldMapping.getRelationship().initializeOn(this.relationship);
249 this.cascade.initializeFrom(oldMapping.getCascade());
250 //TODO should we set the fetch type from a BasicMapping??
251 }
252
kmoore3d505d22011-08-02 13:24:47 +0000253 public Iterable<String> getAllTargetEntityAttributeNames() {
254 return new CompositeIterable<String>(this.getAllTargetEntityAttributeNamesLists());
kmoorec9c9e2b2011-02-06 02:07:28 +0000255 }
256
kmoore3d505d22011-08-02 13:24:47 +0000257 protected Iterable<Iterable<String>> getAllTargetEntityAttributeNamesLists() {
258 return new TransformationIterable<AttributeMapping, Iterable<String>>(this.getAllTargetEntityAttributeMappings(), AttributeMappingTools.ALL_MAPPING_NAMES_TRANSFORMER);
kmoorec9c9e2b2011-02-06 02:07:28 +0000259 }
260
kmoore3d505d22011-08-02 13:24:47 +0000261 protected Iterable<AttributeMapping> getAllTargetEntityAttributeMappings() {
kmoorec9c9e2b2011-02-06 02:07:28 +0000262 Entity entity = this.getResolvedTargetEntity();
kmoore3d505d22011-08-02 13:24:47 +0000263 return (entity != null) ? entity.getAllAttributeMappings() : EmptyIterable.<AttributeMapping>instance();
kmoorec9c9e2b2011-02-06 02:07:28 +0000264 }
265
266 protected String getTargetEntityIdAttributeName() {
267 PersistentAttribute attribute = this.getTargetEntityIdAttribute();
268 return (attribute == null) ? null : attribute.getName();
269 }
270
271 protected PersistentAttribute getTargetEntityIdAttribute() {
272 Entity entity = this.getResolvedTargetEntity();
273 return (entity == null) ? null : entity.getIdAttribute();
274 }
275
276
277 //************ refactoring ************
278
279 @Override
280 @SuppressWarnings("unchecked")
281 public Iterable<ReplaceEdit> createRenameTypeEdits(IType originalType, String newName) {
282 return new CompositeIterable<ReplaceEdit>(
283 super.createRenameTypeEdits(originalType, newName),
284 this.createTargetEntityRenameTypeEdits(originalType, newName)
285 );
286 }
287
288 protected Iterable<ReplaceEdit> createTargetEntityRenameTypeEdits(IType originalType, String newName) {
289 if (this.specifiedTargetEntity != null) {
290 PersistentType targetType = this.getResolvedTargetType();
291 if ((targetType != null) && targetType.isFor(originalType.getFullyQualifiedName('.'))) {
292 return new SingleElementIterable<ReplaceEdit>(this.createTargetEntityRenameTypeEdit(originalType, newName));
293 }
294 }
295 return EmptyIterable.instance();
296 }
297
298 protected ReplaceEdit createTargetEntityRenameTypeEdit(IType originalType, String newName) {
299 return this.xmlAttributeMapping.createRenameTargetEntityEdit(originalType, newName);
300 }
301
302 @Override
303 @SuppressWarnings("unchecked")
304 public Iterable<ReplaceEdit> createMoveTypeEdits(IType originalType, IPackageFragment newPackage) {
305 return new CompositeIterable<ReplaceEdit>(
306 super.createMoveTypeEdits(originalType, newPackage),
307 this.createTargetEntityMoveTypeEdits(originalType, newPackage)
308 );
309 }
310
311 protected Iterable<ReplaceEdit> createTargetEntityMoveTypeEdits(IType originalType, IPackageFragment newPackage) {
312 if (this.specifiedTargetEntity != null) {
313 PersistentType targetType = this.getResolvedTargetType();
314 if ((targetType != null) && targetType.isFor(originalType.getFullyQualifiedName('.'))) {
315 return new SingleElementIterable<ReplaceEdit>(this.createTargetEntityRenamePackageEdit(newPackage.getElementName()));
316 }
317 }
318 return EmptyIterable.instance();
319 }
320
321 @Override
322 @SuppressWarnings("unchecked")
323 public Iterable<ReplaceEdit> createRenamePackageEdits(IPackageFragment originalPackage, String newName) {
324 return new CompositeIterable<ReplaceEdit>(
325 super.createRenamePackageEdits(originalPackage, newName),
326 this.createTargetEntityRenamePackageEdits(originalPackage, newName)
327 );
328 }
329
330 protected Iterable<ReplaceEdit> createTargetEntityRenamePackageEdits(IPackageFragment originalPackage, String newName) {
331 if (this.specifiedTargetEntity != null) {
332 PersistentType targetType = this.getResolvedTargetType();
333 if ((targetType != null) && targetType.isIn(originalPackage)) {
334 return new SingleElementIterable<ReplaceEdit>(this.createTargetEntityRenamePackageEdit(newName));
335 }
336 }
337 return EmptyIterable.instance();
338 }
339
340 protected ReplaceEdit createTargetEntityRenamePackageEdit(String newName) {
341 return this.xmlAttributeMapping.createRenameTargetEntityPackageEdit(newName);
342 }
343
344
345 // ********** validation **********
346
347 @Override
348 public void validate(List<IMessage> messages, IReporter reporter) {
349 super.validate(messages, reporter);
350 this.validateTargetEntity(messages);
351 this.relationship.validate(messages, reporter);
352 }
353
354 protected void validateTargetEntity(List<IMessage> messages) {
kmoorebbf1de62011-08-25 20:29:52 +0000355 if (StringTools.stringIsEmpty(this.getTargetEntity())) {
kmoorec9c9e2b2011-02-06 02:07:28 +0000356 messages.add(
357 DefaultJpaValidationMessages.buildMessage(
358 IMessage.HIGH_SEVERITY,
bvosburgh91d39dc2011-04-28 02:00:43 +0000359 JpaValidationMessages.TARGET_ENTITY_NOT_DEFINED,
kmoorebbf1de62011-08-25 20:29:52 +0000360 EMPTY_STRING_ARRAY,
kmoorec9c9e2b2011-02-06 02:07:28 +0000361 this,
kmoorebbf1de62011-08-25 20:29:52 +0000362 this.getTargetEntityTextRange()
363 )
364 );
365 return;
366 }
367 if ( ! this.targetEntityExists()) {
368 messages.add(
369 DefaultJpaValidationMessages.buildMessage(
370 IMessage.HIGH_SEVERITY,
371 JpaValidationMessages.TARGET_ENTITY_NOT_EXIST,
372 EMPTY_STRING_ARRAY,
373 this,
374 this.getTargetEntityTextRange()
kmoorec9c9e2b2011-02-06 02:07:28 +0000375 )
376 );
bvosburgh91d39dc2011-04-28 02:00:43 +0000377 return;
kmoorec9c9e2b2011-02-06 02:07:28 +0000378 }
bvosburgh91d39dc2011-04-28 02:00:43 +0000379 if (this.getResolvedTargetEntity() == null) {
380 messages.add(
381 DefaultJpaValidationMessages.buildMessage(
382 IMessage.HIGH_SEVERITY,
383 JpaValidationMessages.TARGET_ENTITY_IS_NOT_AN_ENTITY,
kmoorebbf1de62011-08-25 20:29:52 +0000384 new String[] {this.getTargetEntity()},
bvosburgh91d39dc2011-04-28 02:00:43 +0000385 this,
386 this.getTargetEntityTextRange()
387 )
388 );
kmoorec9c9e2b2011-02-06 02:07:28 +0000389 }
390 }
391
kmoorebbf1de62011-08-25 20:29:52 +0000392 protected boolean targetEntityExists() {
393 return getEntityMappings().resolveJdtType(this.getTargetEntity()) != null;
394 }
395
396
kmoorec9c9e2b2011-02-06 02:07:28 +0000397 protected TextRange getTargetEntityTextRange() {
bvosburgh91d39dc2011-04-28 02:00:43 +0000398 return this.getValidationTextRange(this.xmlAttributeMapping.getTargetEntityTextRange());
kmoorec9c9e2b2011-02-06 02:07:28 +0000399 }
400
401
402 // ********** metamodel **********
403
404 @Override
405 public String getMetamodelTypeName() {
406 PersistentType resolvedTargetType = this.getResolvedTargetType();
407 if (resolvedTargetType == null) {
408 return MetamodelField.DEFAULT_TYPE_NAME;
409 }
410 String targetTypeName = resolvedTargetType.getName();
411 return (targetTypeName != null) ? targetTypeName : MetamodelField.DEFAULT_TYPE_NAME;
412 }
413
414}