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.metadata.AbstractMemberMetaData;
012    import org.datanucleus.store.ExecutionContext;
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    }