001 package org.cumulus4j.store.model;
002
003 import javax.jdo.annotations.Discriminator;
004 import javax.jdo.annotations.DiscriminatorStrategy;
005 import javax.jdo.annotations.IdentityType;
006 import javax.jdo.annotations.Inheritance;
007 import javax.jdo.annotations.InheritanceStrategy;
008 import javax.jdo.annotations.NotPersistent;
009 import javax.jdo.annotations.PersistenceCapable;
010
011 import org.datanucleus.ExecutionContext;
012 import org.datanucleus.metadata.AbstractMemberMetaData;
013
014 @PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true")
015 @Inheritance(strategy=InheritanceStrategy.NEW_TABLE)
016 @Discriminator(strategy=DiscriminatorStrategy.VALUE_MAP, value="EmbeddedFieldMeta")
017 public class EmbeddedFieldMeta extends FieldMeta {
018
019 protected static final String UNIQUE_SCOPE_PREFIX_EMBEDDED_FIELD_META = EmbeddedFieldMeta.class.getSimpleName() + '.';
020
021 // @Persistent(nullValue=NullValue.EXCEPTION)
022 @NotPersistent
023 private FieldMeta nonEmbeddedFieldMeta;
024
025 private long nonEmbeddedFieldMeta_fieldID;
026
027 protected EmbeddedFieldMeta() { }
028
029 public EmbeddedFieldMeta(
030 EmbeddedClassMeta classMeta, EmbeddedFieldMeta ownerFieldMeta, FieldMeta nonEmbeddedFieldMeta
031 )
032 {
033 super(classMeta, ownerFieldMeta, nonEmbeddedFieldMeta.getFieldName(), nonEmbeddedFieldMeta.getRole());
034 this.nonEmbeddedFieldMeta = nonEmbeddedFieldMeta;
035 this.nonEmbeddedFieldMeta_fieldID = nonEmbeddedFieldMeta.getFieldID();
036
037 if (nonEmbeddedFieldMeta_fieldID < 0)
038 throw new IllegalStateException("nonEmbeddedFieldMeta not yet persisted: " + nonEmbeddedFieldMeta);
039
040 // setUniqueScope(null); // is set in jdoPreStore
041 FieldMeta embeddingFieldMeta = getEmbeddingFieldMeta();
042 long embeddingFieldMeta_fieldID = embeddingFieldMeta.getFieldID();
043 if (embeddingFieldMeta_fieldID < 0)
044 throw new IllegalStateException("embeddingFieldMeta not yet persisted: " + embeddingFieldMeta);
045
046 setUniqueScope(UNIQUE_SCOPE_PREFIX_EMBEDDED_FIELD_META + embeddingFieldMeta_fieldID);
047 }
048
049 @Override
050 public EmbeddedClassMeta getClassMeta() {
051 return (EmbeddedClassMeta) super.getClassMeta();
052 }
053
054 @Override
055 public void addSubFieldMeta(FieldMeta subFieldMeta) {
056 if (!(subFieldMeta instanceof EmbeddedFieldMeta)) // must not be null anyway!
057 throw new IllegalArgumentException("subFieldMeta is NOT an instance of EmbeddedFieldMeta: " + subFieldMeta);
058
059 super.addSubFieldMeta(subFieldMeta);
060 }
061
062 @Override
063 protected void setClassMeta(ClassMeta classMeta) {
064 if (classMeta != null && !(classMeta instanceof EmbeddedClassMeta))
065 throw new IllegalArgumentException("classMeta is NOT an instance of EmbeddedClassMeta: " + classMeta);
066
067 super.setClassMeta(classMeta);
068 }
069
070 @Override
071 protected void setOwnerFieldMeta(FieldMeta ownerFieldMeta) {
072 if (ownerFieldMeta != null && !(ownerFieldMeta instanceof EmbeddedFieldMeta))
073 throw new IllegalArgumentException("ownerFieldMeta is NOT an instance of EmbeddedFieldMeta: " + ownerFieldMeta);
074
075 super.setOwnerFieldMeta(ownerFieldMeta);
076 }
077
078 public FieldMeta getNonEmbeddedFieldMeta() {
079 if (nonEmbeddedFieldMeta == null) {
080 nonEmbeddedFieldMeta = new FieldMetaDAO(getPersistenceManager()).getFieldMeta(nonEmbeddedFieldMeta_fieldID, true);
081 }
082 return nonEmbeddedFieldMeta;
083 }
084
085 /**
086 * Get the field which is embedding the object having this field.
087 * <p>
088 * This is a convenience method for
089 * {@link #getClassMeta()}.{@link EmbeddedClassMeta#getEmbeddingFieldMeta() getEmbeddingFieldMeta()}.
090 * @return the field which is embedding the object having this field. Never <code>null</code>.
091 */
092 public FieldMeta getEmbeddingFieldMeta() {
093 return getClassMeta().getEmbeddingFieldMeta();
094 }
095
096 // @Override
097 // public void jdoPreStore() {
098 // super.jdoPreStore();
099 // if (getUniqueScope() == null || !getUniqueScope().startsWith(UNIQUE_SCOPE_PREFIX_EMBEDDED_FIELD_META)) {
100 // setUniqueScope("TEMPORARY_" + UUID.randomUUID());
101 //
102 // PostStoreRunnableManager.getInstance().addRunnable(new Runnable() {
103 // @Override
104 // public void run() {
105 // PersistenceManager pm = JDOHelper.getPersistenceManager(EmbeddedFieldMeta.this);
106 //
107 // if (nonEmbeddedFieldMeta_fieldID < 0 && nonEmbeddedFieldMeta != null) {
108 // nonEmbeddedFieldMeta = pm.makePersistent(nonEmbeddedFieldMeta);
109 // nonEmbeddedFieldMeta_fieldID = nonEmbeddedFieldMeta.getFieldID();
110 // }
111 //
112 // if (nonEmbeddedFieldMeta_fieldID < 0)
113 // throw new IllegalStateException("nonEmbeddedFieldMeta_fieldID < 0");
114 //
115 // EmbeddedClassMeta classMeta = pm.makePersistent(getClassMeta());
116 // FieldMeta embeddingFieldMeta = pm.makePersistent(classMeta.getEmbeddingFieldMeta());
117 // if (embeddingFieldMeta == null)
118 // setUniqueScopePostponedInPostStore(pm, 1);
119 // else
120 // setUniqueScope(UNIQUE_SCOPE_PREFIX_EMBEDDED_FIELD_META + embeddingFieldMeta.getFieldID());
121 //
122 // pm.flush();
123 // }
124 // });
125 // }
126 // }
127
128 // protected void setUniqueScopePostponedInPostStore(final PersistenceManager pm, final int postponeCounter) {
129 // PostStoreRunnableManager.getInstance().addRunnable(new Runnable() {
130 // @Override
131 // public void run() {
132 // FieldMeta embeddingFieldMeta = pm.makePersistent(getEmbeddingFieldMeta());
133 // if (embeddingFieldMeta == null) {
134 // final int maxPostponeCounter = 30;
135 // if (postponeCounter > maxPostponeCounter)
136 // throw new IllegalStateException("postponeCounter > maxPostponeCounter :: " + postponeCounter + " > " + maxPostponeCounter);
137 //
138 // setUniqueScopePostponedInPostStore(pm, postponeCounter + 1);
139 // }
140 // else
141 // setUniqueScope(UNIQUE_SCOPE_PREFIX_EMBEDDED_FIELD_META + embeddingFieldMeta.getFieldID());
142 // }
143 // });
144 // }
145
146 @Override
147 public void jdoPostDetach(Object o) {
148 final PostDetachRunnableManager postDetachRunnableManager = PostDetachRunnableManager.getInstance();
149 postDetachRunnableManager.enterScope();
150 try {
151 super.jdoPostDetach(o);
152 final EmbeddedFieldMeta detached = this;
153 final EmbeddedFieldMeta attached = (EmbeddedFieldMeta) o;
154
155 postDetachRunnableManager.addRunnable(new Runnable() {
156 @Override
157 public void run() {
158 DetachedClassMetaModel detachedClassMetaModel = DetachedClassMetaModel.getInstance();
159
160 if (detachedClassMetaModel == null) // we currently only detach with this being present - at least it should, hence we don't need to handle things differently.
161 throw new IllegalStateException("DetachedClassMetaModel.getInstance() returned null!");
162
163 if (detachedClassMetaModel != null) {
164 FieldMeta nonEmbeddedFieldMeta = attached.getNonEmbeddedFieldMeta();
165 ClassMeta detachedClassMeta = detachedClassMetaModel.getClassMeta(nonEmbeddedFieldMeta.getClassMeta().getClassID(), false);
166 if (detachedClassMeta == null) {
167 setNonEmbeddedFieldMetaPostponed(postDetachRunnableManager, detachedClassMetaModel, nonEmbeddedFieldMeta, 1);
168 }
169 else {
170 FieldMeta nefm = detachedClassMeta.getFieldMeta(nonEmbeddedFieldMeta_fieldID);
171 if (nefm == null)
172 throw new IllegalStateException("detachedClassMeta.getFieldMeta(...) returned null for " + nonEmbeddedFieldMeta);
173
174 detached.nonEmbeddedFieldMeta = nefm;
175 }
176 }
177 }
178 });
179 } finally {
180 postDetachRunnableManager.exitScope();
181 }
182 }
183
184 protected void setNonEmbeddedFieldMetaPostponed(final PostDetachRunnableManager postDetachRunnableManager, final DetachedClassMetaModel detachedClassMetaModel, final FieldMeta nonEmbeddedFieldMeta, final int postponeCounter) {
185 postDetachRunnableManager.addRunnable(new Runnable() {
186 @Override
187 public void run() {
188 if (detachedClassMetaModel != null) {
189 ClassMeta detachedClassMeta = detachedClassMetaModel.getClassMeta(nonEmbeddedFieldMeta.getClassMeta().getClassID(), false);
190 if (detachedClassMeta == null) {
191 final int maxPostponeCounter = 100;
192 if (postponeCounter > maxPostponeCounter)
193 throw new IllegalStateException("postponeCounter > " + maxPostponeCounter);
194
195 setNonEmbeddedFieldMetaPostponed(postDetachRunnableManager, detachedClassMetaModel, nonEmbeddedFieldMeta, postponeCounter + 1);
196 }
197 else {
198 FieldMeta nefm = detachedClassMeta.getFieldMeta(nonEmbeddedFieldMeta_fieldID);
199 if (nefm == null)
200 throw new IllegalStateException("detachedClassMeta.getFieldMeta(...) returned null for " + nonEmbeddedFieldMeta);
201
202 EmbeddedFieldMeta.this.nonEmbeddedFieldMeta = nefm;
203 }
204 }
205 }
206 });
207 }
208
209 @Override
210 public int getDataNucleusAbsoluteFieldNumber(ExecutionContext executionContext) {
211 return getNonEmbeddedFieldMeta().getDataNucleusAbsoluteFieldNumber(executionContext);
212 }
213
214 @Override
215 public int getDataNucleusAbsoluteFieldNumber() {
216 return getNonEmbeddedFieldMeta().getDataNucleusAbsoluteFieldNumber();
217 }
218
219 @Override
220 public void setDataNucleusAbsoluteFieldNumber(int dataNucleusAbsoluteFieldNumber) {
221 throw new UnsupportedOperationException("This delegate property cannot be set!");
222 }
223
224 @Override
225 public AbstractMemberMetaData getDataNucleusMemberMetaData(ExecutionContext executionContext) {
226 return getNonEmbeddedFieldMeta().getDataNucleusMemberMetaData(executionContext);
227 }
228
229 @Override
230 public String toString() {
231 return super.toString() + "\nembedded in\n" + getEmbeddingFieldMeta();
232 }
233 }