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 }