1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.meta;
20
21 import org.apache.openjpa.lib.util.Localizer;
22 import org.apache.openjpa.util.MetaDataException;
23 import org.apache.openjpa.util.UserException;
24
25 /**
26 * Default {@link ValueMetaData} implementation.
27 *
28 * @author Abe White
29 * @nojavadoc
30 */
31 public class ValueMetaDataImpl
32 implements ValueMetaData {
33
34 private static final Localizer _loc = Localizer.forPackage
35 (ValueMetaDataImpl.class);
36
37 ///////////////////////////////////////////////////////////////
38 // Note: if you add additional state that should be copied to
39 // embedded metadata, make sure to add it to the copy() method
40 ///////////////////////////////////////////////////////////////
41
42 private FieldMetaData _owner;
43 private Class _decType = Object.class;
44 private int _decCode = JavaTypes.OBJECT;
45 private ClassMetaData _decTypeMeta = null;
46 private Class _type = null;
47 private int _code = JavaTypes.OBJECT;
48 private ClassMetaData _typeMeta = null;
49 private Class _typeOverride = null;
50 private int _delete = CASCADE_NONE;
51 private int _persist = CASCADE_AUTO;
52 private int _attach = CASCADE_IMMEDIATE;
53 private int _refresh = CASCADE_AUTO;
54 private boolean _serialized = false;
55 private Boolean _embedded = null;
56 private ClassMetaData _embeddedMeta = null;
57 private int _resMode = MODE_NONE;
58 private String _mappedBy = null;
59 private FieldMetaData _mappedByMeta = null;
60
61 protected ValueMetaDataImpl(FieldMetaData owner) {
62 _owner = owner;
63 }
64
65 /**
66 * Constructor for serialization.
67 */
68 protected ValueMetaDataImpl() {
69 }
70
71 public FieldMetaData getFieldMetaData() {
72 return _owner;
73 }
74
75 public MetaDataRepository getRepository() {
76 return _owner.getRepository();
77 }
78
79 public Class getType() {
80 return (_type == null) ? _decType : _type;
81 }
82
83 public void setType(Class type) {
84 _type = type;
85 _typeMeta = null;
86 if (type != null)
87 setTypeCode(JavaTypes.getTypeCode(type));
88 }
89
90 public int getTypeCode() {
91 return (_type == null) ? _decCode : _code;
92 }
93
94 public void setTypeCode(int code) {
95 _code = code;
96 }
97
98 public boolean isTypePC() {
99 return getTypeCode() == JavaTypes.PC
100 || getTypeCode() == JavaTypes.PC_UNTYPED;
101 }
102
103 public ClassMetaData getTypeMetaData() {
104 if (_type == null)
105 return getDeclaredTypeMetaData();
106 if (_typeMeta == null && _code == JavaTypes.PC) {
107 ClassMetaData meta = _owner.getDefiningMetaData();
108 _typeMeta = meta.getRepository().getMetaData(_type,
109 meta.getEnvClassLoader(), true);
110 }
111 return _typeMeta;
112 }
113
114 public Class getDeclaredType() {
115 return _decType;
116 }
117
118 public void setDeclaredType(Class type) {
119 _decType = type;
120 _decTypeMeta = null;
121 _decCode = JavaTypes.getTypeCode(type);
122 if (_embeddedMeta != null)
123 _embeddedMeta.setDescribedType(type);
124 }
125
126 public int getDeclaredTypeCode() {
127 return _decCode;
128 }
129
130 public void setDeclaredTypeCode(int code) {
131 _decCode = code;
132 }
133
134 public boolean isDeclaredTypePC() {
135 return _decCode == JavaTypes.PC || _decCode == JavaTypes.PC_UNTYPED;
136 }
137
138 public ClassMetaData getDeclaredTypeMetaData() {
139 if (_decTypeMeta == null && _decCode == JavaTypes.PC) {
140 if (isEmbedded())
141 _decTypeMeta = getEmbeddedMetaData();
142 else {
143 ClassMetaData meta = _owner.getDefiningMetaData();
144 _decTypeMeta = meta.getRepository().getMetaData(_decType,
145 meta.getEnvClassLoader(), true);
146 }
147 }
148 return _decTypeMeta;
149 }
150
151 public boolean isEmbedded() {
152 if (_owner.getManagement() != _owner.MANAGE_PERSISTENT)
153 return false;
154 if (_embedded == null) {
155 // field left as default; embedded setting depends on type
156 switch (_decCode) {
157 case JavaTypes.PC:
158 case JavaTypes.COLLECTION:
159 case JavaTypes.MAP:
160 case JavaTypes.PC_UNTYPED:
161 _embedded = Boolean.FALSE;
162 break;
163 default:
164 _embedded = Boolean.TRUE;
165 }
166 }
167 return _embedded.booleanValue();
168 }
169
170 public void setEmbedded(boolean embedded) {
171 if (embedded && _embedded != Boolean.TRUE) {
172 _decTypeMeta = null;
173 _typeMeta = null;
174 }
175 _embedded = (embedded) ? Boolean.TRUE : Boolean.FALSE;
176 }
177
178 public boolean isEmbeddedPC() {
179 return _decCode == JavaTypes.PC && isEmbedded();
180 }
181
182 public ClassMetaData getEmbeddedMetaData() {
183 if (_embeddedMeta == null && isEmbeddedPC())
184 addEmbeddedMetaData();
185 return _embeddedMeta;
186 }
187
188 public ClassMetaData addEmbeddedMetaData() {
189 MetaDataRepository repos = _owner.getRepository();
190 _embeddedMeta = repos.newEmbeddedClassMetaData(this);
191 _embeddedMeta.setDescribedType(_decType);
192 repos.getMetaDataFactory().getDefaults().populate(_embeddedMeta,
193 ClassMetaData.ACCESS_UNKNOWN);
194
195 setEmbedded(true);
196 return _embeddedMeta;
197 }
198
199 public int getCascadeDelete() {
200 if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
201 return CASCADE_NONE;
202 if (isEmbeddedPC())
203 return CASCADE_IMMEDIATE;
204
205 switch (_delete) {
206 case CASCADE_NONE:
207 // if the user marks the owning field dependent and we
208 // externalize to a pc type, then become dependent
209 if (this != _owner.getValue() && isTypePC()
210 && ((ValueMetaDataImpl) _owner.getValue())._delete
211 == CASCADE_AUTO)
212 return CASCADE_AUTO;
213 break;
214 case CASCADE_AUTO:
215 if (isTypePC())
216 return CASCADE_AUTO;
217 break;
218 case CASCADE_IMMEDIATE:
219 if (isDeclaredTypePC())
220 return CASCADE_IMMEDIATE;
221 break;
222 }
223 return CASCADE_NONE;
224 }
225
226 public void setCascadeDelete(int delete) {
227 _delete = delete;
228 }
229
230 public int getCascadePersist() {
231 if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
232 return CASCADE_NONE;
233 if (isDeclaredTypePC())
234 return _persist;
235 if (!isTypePC())
236 return CASCADE_NONE;
237 // if only externalized type is pc, can't cascade immediate
238 return (_persist == CASCADE_IMMEDIATE) ? CASCADE_AUTO : _persist;
239 }
240
241 public void setCascadePersist(int persist) {
242 _persist = persist;
243 }
244
245 public int getCascadeAttach() {
246 if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT
247 || !isDeclaredTypePC()) // attach acts on declared type
248 return CASCADE_NONE;
249 if (isEmbeddedPC())
250 return CASCADE_IMMEDIATE;
251 return _attach;
252 }
253
254 public void setCascadeAttach(int attach) {
255 if (attach == CASCADE_AUTO)
256 throw new IllegalArgumentException("CASCADE_AUTO");
257 _attach = attach;
258 }
259
260 public int getCascadeRefresh() {
261 if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT
262 || !isDeclaredTypePC()) // refresh acts on declared type
263 return CASCADE_NONE;
264 return _refresh;
265 }
266
267 public void setCascadeRefresh(int refresh) {
268 _refresh = refresh;
269 }
270
271 public boolean isSerialized() {
272 return _serialized;
273 }
274
275 public void setSerialized(boolean serialized) {
276 _serialized = serialized;
277 }
278
279 public String getValueMappedBy() {
280 if (_mappedBy == MAPPED_BY_PK) {
281 // use this instead of getting meta from element b/c that
282 // requires element to be resolved
283 ClassMetaData meta = getRepository().getMetaData
284 (_owner.getElement().getType(), null, false);
285 if (meta == null)
286 throw new MetaDataException(_loc.get("val-not-pc", _owner));
287 if (meta.getPrimaryKeyFields().length != 1)
288 throw new MetaDataException(_loc.get("val-not-one-pk",
289 _owner));
290 _mappedByMeta = meta.getPrimaryKeyFields()[0];
291 _mappedBy = _mappedByMeta.getName();
292 }
293 return _mappedBy;
294 }
295
296 public void setValueMappedBy(String mapped) {
297 if (_owner.getKey() != this && mapped != null)
298 throw new UserException(_loc.get("mapped-by-not-key", this));
299 else {
300 _mappedBy = mapped;
301 _mappedByMeta = null;
302 }
303 }
304
305 public FieldMetaData getValueMappedByMetaData() {
306 if (getValueMappedBy() != null && _mappedByMeta == null) {
307 ClassMetaData meta = _owner.getElement().getTypeMetaData();
308 FieldMetaData field = (meta == null) ? null
309 : meta.getField(getValueMappedBy());
310 if (field == null)
311 throw new MetaDataException(_loc.get("no-mapped-by", this,
312 getValueMappedBy()));
313 if (field.getMappedBy() != null)
314 throw new MetaDataException(_loc.get("circ-mapped-by", this,
315 getValueMappedBy()));
316 _mappedByMeta = field;
317 }
318 return _mappedByMeta;
319 }
320
321 public Class getTypeOverride() {
322 return _typeOverride;
323 }
324
325 public void setTypeOverride(Class val) {
326 _typeOverride = val;
327 }
328
329 public String toString() {
330 String ret = _owner.getFullName(true);
331 if (this == _owner.getKey())
332 return ret + "<key:" + _decType + ">";
333 if (this == _owner.getElement()) {
334 if (_owner.getTypeCode() == JavaTypes.MAP)
335 return ret + "<value:" + _decType + ">";
336 return ret + "<element:" + _decType + ">";
337 }
338 return ret + "<" + _decType + ">";
339 }
340
341 ////////////////////////
342 // Resolve and validate
343 ////////////////////////
344
345 public int getResolve() {
346 return _resMode;
347 }
348
349 public void setResolve(int mode) {
350 _resMode = mode;
351 }
352
353 public void setResolve(int mode, boolean on) {
354 if (mode == MODE_NONE)
355 _resMode = mode;
356 else if (on)
357 _resMode |= mode;
358 else
359 _resMode &= ~mode;
360 }
361
362 public boolean resolve(int mode) {
363 if ((_resMode & mode) == mode)
364 return true;
365 int cur = _resMode;
366 _resMode |= mode;
367
368 // we only perform actions for meta mode
369 if ((mode & MODE_META) == 0 || (cur & MODE_META) != 0)
370 return false;
371
372 // check for type extension
373 int codeOverride = JavaTypes.OBJECT;
374 if (_typeOverride != null) {
375 codeOverride = JavaTypes.getTypeCode(_typeOverride);
376
377 // if there is no externalizer method or this value is a key or
378 // element, set our type to the type extension; otherwise, use the
379 // type extension as a hint to the actual type of the declared
380 // value (e.g. marking an interface as non-pc)
381 if (_owner.getExternalizerMethod() == null
382 || _owner.getValue() != this) {
383 _type = _typeOverride;
384 _code = codeOverride;
385 } else {
386 _decCode = codeOverride;
387 if (JavaTypes.maybePC(codeOverride, _typeOverride))
388 resolveDeclaredType(_typeOverride);
389 }
390 }
391
392 // see if actual type is pc
393 if (JavaTypes.maybePC(_code, _type)) {
394 _typeMeta = _owner.getRepository().getMetaData(_type,
395 _owner.getDefiningMetaData().getEnvClassLoader(), false);
396 if (_typeMeta != null)
397 _code = JavaTypes.PC;
398 }
399
400 // if there is no externalizer, set our declared type code to the
401 // actual type so that we treat the value correctly at runtime
402 // (pers by reach, etc)
403 if (_typeOverride != null && _owner.getExternalizerMethod() == null
404 && _owner.getExternalValues() == null) {
405 // cache the metadata immediately since we won't be able to get
406 // it lazily, since we're not resetting _decType to _type
407 _decCode = _code;
408 _decTypeMeta = _typeMeta;
409 } else if (JavaTypes.maybePC(_decCode, _decType))
410 resolveDeclaredType(_decType);
411
412 // resolves mapped by
413 getValueMappedBy();
414
415 ClassMetaData embed = getEmbeddedMetaData();
416 if (embed != null)
417 embed.resolve(MODE_META);
418
419 // oid as primary key field?
420 if (_decCode == JavaTypes.PC && isEmbedded()
421 && _owner.isPrimaryKey() && _owner.getValue() == this)
422 _code = _decCode = JavaTypes.OID;
423
424 return false;
425 }
426
427 /**
428 * Resolve the declared type.
429 */
430 private void resolveDeclaredType(Class type) {
431 ClassMetaData meta = _owner.getRepository().getMetaData(type,
432 _owner.getDefiningMetaData().getEnvClassLoader(), false);
433 if (meta != null)
434 _decCode = JavaTypes.PC;
435 if (!isEmbedded())
436 _decTypeMeta = meta;
437 }
438
439 public void copy(ValueMetaData vmd) {
440 // copy declared types, but if OID revert to PC until we resolve
441 // to OID ourselves
442 _decType = vmd.getDeclaredType();
443 _decCode = vmd.getDeclaredTypeCode();
444 if (_decCode == JavaTypes.OID)
445 _decCode = JavaTypes.PC;
446
447 _delete = vmd.getCascadeDelete();
448 _persist = vmd.getCascadePersist();
449 _attach = vmd.getCascadeAttach();
450 _refresh = vmd.getCascadeRefresh();
451 _typeOverride = vmd.getTypeOverride();
452 _serialized = vmd.isSerialized();
453 if (_embeddedMeta != null)
454 _embeddedMeta.setDescribedType(vmd.getDeclaredType());
455
456 // don't allow copy to override embedded
457 if (_embedded == null)
458 setEmbedded(vmd.isEmbedded());
459 }
460 }