PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/google/appengine/datanucleus/mapping/DatastoreMappingManager.java

http://datanucleus-appengine.googlecode.com/
Java | 303 lines | 219 code | 28 blank | 56 comment | 71 complexity | 94f7ece1abd694f779a2e91d73681216 MD5 | raw file
Possible License(s): Apache-2.0
  1. /**********************************************************************
  2. Copyright (c) 2009 Google Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. **********************************************************************/
  13. package com.google.appengine.datanucleus.mapping;
  14. import com.google.appengine.api.datastore.Key;
  15. import org.datanucleus.ClassLoaderResolver;
  16. import org.datanucleus.metadata.AbstractMemberMetaData;
  17. import org.datanucleus.metadata.ColumnMetaData;
  18. import org.datanucleus.metadata.ColumnMetaDataContainer;
  19. import org.datanucleus.metadata.EmbeddedMetaData;
  20. import org.datanucleus.metadata.FieldRole;
  21. import org.datanucleus.metadata.MetaDataManager;
  22. import org.datanucleus.metadata.NullValue;
  23. import org.datanucleus.plugin.PluginManager;
  24. import org.datanucleus.store.mapped.DatastoreContainerObject;
  25. import org.datanucleus.store.mapped.DatastoreField;
  26. import org.datanucleus.store.mapped.DatastoreIdentifier;
  27. import org.datanucleus.store.mapped.IdentifierFactory;
  28. import org.datanucleus.store.mapped.IdentifierType;
  29. import org.datanucleus.store.mapped.MappedStoreManager;
  30. import org.datanucleus.store.mapped.mapping.AbstractMappingManager;
  31. import org.datanucleus.store.mapped.mapping.DatastoreMappingFactory;
  32. import org.datanucleus.store.mapped.mapping.EmbeddedPCMapping;
  33. import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
  34. import org.datanucleus.store.mapped.mapping.SerialisedMapping;
  35. /**
  36. * MappingManager for the datastore. Most of this code is taken from RDBMSMappingManager.
  37. *
  38. * TODO(maxr): Refactor RDBMSMappingManager so that we can reuse more.
  39. *
  40. * @author Max Ross <maxr@google.com>
  41. */
  42. public class DatastoreMappingManager extends AbstractMappingManager {
  43. public DatastoreMappingManager(MappedStoreManager mappedStoreManager) {
  44. super(mappedStoreManager);
  45. }
  46. public org.datanucleus.store.mapped.mapping.DatastoreMapping createDatastoreMapping(
  47. JavaTypeMapping javaTypeMapping, AbstractMemberMetaData abstractMemberMetaData, int ignored,
  48. DatastoreField datastoreField) {
  49. return createDatastoreMapping(javaTypeMapping, datastoreField);
  50. }
  51. public org.datanucleus.store.mapped.mapping.DatastoreMapping createDatastoreMapping(
  52. JavaTypeMapping mapping, DatastoreField prop, String javaType) {
  53. return createDatastoreMapping(mapping, prop);
  54. }
  55. private org.datanucleus.store.mapped.mapping.DatastoreMapping createDatastoreMapping(
  56. JavaTypeMapping mapping, DatastoreField prop) {
  57. // for now we're just usting a single DatastoreMapping impl for everything.
  58. org.datanucleus.store.mapped.mapping.DatastoreMapping datastoreMapping =
  59. DatastoreMappingFactory.createMapping(DatastoreFKMapping.class, mapping, storeMgr, prop);
  60. if (prop != null) {
  61. prop.setDatastoreMapping(datastoreMapping);
  62. }
  63. return datastoreMapping;
  64. }
  65. // Mostly copied from RDBMSMappingManager.createDatastoreField
  66. public DatastoreField createDatastoreField(JavaTypeMapping mapping, String javaType,
  67. int datastoreFieldIndex) {
  68. AbstractMemberMetaData fmd = mapping.getMemberMetaData();
  69. int roleForField = mapping.getRoleForMember();
  70. DatastoreContainerObject datastoreContainer = mapping.getDatastoreContainer();
  71. // Take the column MetaData from the component that this mappings role relates to
  72. ColumnMetaData colmd;
  73. ColumnMetaDataContainer columnContainer = fmd;
  74. if (roleForField == FieldRole.ROLE_COLLECTION_ELEMENT ||
  75. roleForField == FieldRole.ROLE_ARRAY_ELEMENT) {
  76. columnContainer = fmd.getElementMetaData();
  77. } else if (roleForField == FieldRole.ROLE_MAP_KEY) {
  78. columnContainer = fmd.getKeyMetaData();
  79. } else if (roleForField == FieldRole.ROLE_MAP_VALUE) {
  80. columnContainer = fmd.getValueMetaData();
  81. }
  82. DatastoreProperty prop;
  83. ColumnMetaData[] colmds;
  84. if (columnContainer != null
  85. && columnContainer.getColumnMetaData() != null
  86. && columnContainer.getColumnMetaData().length > datastoreFieldIndex) {
  87. colmd = columnContainer.getColumnMetaData()[datastoreFieldIndex];
  88. colmds = columnContainer.getColumnMetaData();
  89. } else {
  90. // If column specified add one (use any column name specified on field element)
  91. colmd = new ColumnMetaData();
  92. colmd.setName(fmd.getColumn());
  93. if (columnContainer != null) {
  94. columnContainer.addColumn(colmd);
  95. colmds = columnContainer.getColumnMetaData();
  96. } else {
  97. colmds = new ColumnMetaData[1];
  98. colmds[0] = colmd;
  99. }
  100. }
  101. // Generate the column identifier
  102. MappedStoreManager storeMgr = datastoreContainer.getStoreManager();
  103. IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
  104. DatastoreIdentifier identifier = null;
  105. if (colmd.getName() == null) {
  106. // No name specified, so generate the identifier from the field name
  107. if (roleForField == FieldRole.ROLE_FIELD) {
  108. identifier = idFactory.newIdentifier(IdentifierType.COLUMN, fmd.getName());
  109. int i = 0;
  110. while (datastoreContainer.hasDatastoreField(identifier)) {
  111. identifier = idFactory.newIdentifier(IdentifierType.COLUMN, fmd.getName() + "_" + i);
  112. i++;
  113. }
  114. } else if (roleForField == FieldRole.ROLE_COLLECTION_ELEMENT) {
  115. // Join table collection element
  116. identifier = idFactory.newJoinTableFieldIdentifier(fmd, null, null, true,
  117. FieldRole.ROLE_COLLECTION_ELEMENT);
  118. } else if (roleForField == FieldRole.ROLE_ARRAY_ELEMENT) {
  119. // Join table array element
  120. identifier = idFactory.newJoinTableFieldIdentifier(fmd, null, null, true,
  121. FieldRole.ROLE_ARRAY_ELEMENT);
  122. } else if (roleForField == FieldRole.ROLE_MAP_KEY) {
  123. // Join table map key
  124. identifier = idFactory.newJoinTableFieldIdentifier(fmd, null, null, true,
  125. FieldRole.ROLE_MAP_KEY);
  126. } else if (roleForField == FieldRole.ROLE_MAP_VALUE) {
  127. // Join table map value
  128. identifier = idFactory.newJoinTableFieldIdentifier(fmd, null, null, true,
  129. FieldRole.ROLE_MAP_VALUE);
  130. }
  131. colmd.setName(identifier.getIdentifierName());
  132. } else {
  133. // User has specified a name, so try to keep this unmodified
  134. identifier = idFactory.newDatastoreFieldIdentifier(colmds[datastoreFieldIndex].getName(),
  135. storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fmd.getType()),
  136. FieldRole.ROLE_CUSTOM);
  137. }
  138. // Create the column
  139. prop = (DatastoreProperty) datastoreContainer.addDatastoreField(javaType, identifier, mapping, colmd);
  140. if (fmd.isPrimaryKey()) {
  141. prop.setAsPrimaryKey();
  142. }
  143. // setDatastoreFieldNullability(fmd, colmd, col);
  144. if (fmd.getNullValue() == NullValue.DEFAULT) {
  145. // Users default should be applied if a null is to be inserted
  146. prop.setDefaultable();
  147. if (colmd.getDefaultValue() != null) {
  148. throw new UnsupportedOperationException("User-defined default not supported.");
  149. }
  150. }
  151. return prop;
  152. }
  153. public DatastoreField createDatastoreField(JavaTypeMapping mapping, String javaType,
  154. ColumnMetaData colmd) {
  155. AbstractMemberMetaData fmd = mapping.getMemberMetaData();
  156. DatastoreContainerObject datastoreContainer = mapping.getDatastoreContainer();
  157. MappedStoreManager storeMgr = datastoreContainer.getStoreManager();
  158. DatastoreField prop;
  159. if (colmd == null) {
  160. // If column specified add one (use any column name specified on field element)
  161. colmd = new ColumnMetaData();
  162. colmd.setName(fmd.getColumn());
  163. fmd.addColumn(colmd);
  164. }
  165. IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
  166. if (colmd.getName() == null) {
  167. // No name specified, so generate the identifier from the field name
  168. DatastoreIdentifier identifier = idFactory
  169. .newIdentifier(IdentifierType.COLUMN, fmd.getName());
  170. int i = 0;
  171. while (datastoreContainer.hasDatastoreField(identifier)) {
  172. identifier = idFactory.newIdentifier(IdentifierType.COLUMN, fmd.getName() + "_" + i);
  173. i++;
  174. }
  175. colmd.setName(identifier.getIdentifierName());
  176. prop = datastoreContainer.addDatastoreField(javaType, identifier, mapping, colmd);
  177. } else {
  178. // User has specified a name, so try to keep this unmodified
  179. prop = datastoreContainer.addDatastoreField(
  180. javaType,
  181. idFactory.newDatastoreFieldIdentifier(colmd.getName(),
  182. storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fmd.getType()),
  183. FieldRole.ROLE_CUSTOM),
  184. mapping,
  185. colmd);
  186. }
  187. // setDatastoreFieldNullability(fmd, colmd, prop);
  188. if (fmd.getNullValue() == NullValue.DEFAULT) {
  189. // Users default should be applied if a null is to be inserted
  190. prop.setDefaultable();
  191. if (colmd.getDefaultValue() != null) {
  192. throw new UnsupportedOperationException("User-defined default not supported.");
  193. }
  194. }
  195. return prop;
  196. }
  197. public DatastoreField createDatastoreField(AbstractMemberMetaData fmd,
  198. DatastoreContainerObject datastoreContainer, JavaTypeMapping mapping, ColumnMetaData colmd,
  199. DatastoreField reference, ClassLoaderResolver clr) {
  200. MappedStoreManager storeMgr = datastoreContainer.getStoreManager();
  201. IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
  202. DatastoreIdentifier identifier = null;
  203. if (colmd.getName() == null) {
  204. // No name specified, so generate the identifier from the field name
  205. AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
  206. identifier = idFactory.newForeignKeyFieldIdentifier(
  207. relatedMmds != null ? relatedMmds[0] : null,
  208. fmd, reference.getIdentifier(),
  209. storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fmd.getType()),
  210. FieldRole.ROLE_OWNER);
  211. colmd.setName(identifier.getIdentifierName());
  212. } else {
  213. // User has specified a name, so try to keep this unmodified
  214. identifier = idFactory
  215. .newDatastoreFieldIdentifier(colmd.getName(), false, FieldRole.ROLE_CUSTOM);
  216. }
  217. DatastoreField prop = datastoreContainer
  218. .addDatastoreField(fmd.getType().getName(), identifier, mapping, colmd);
  219. // Copy the characteristics of the reference column to this one
  220. reference.copyConfigurationTo(prop);
  221. if (fmd.isPrimaryKey()) {
  222. prop.setAsPrimaryKey();
  223. }
  224. if (fmd.getNullValue() == NullValue.DEFAULT) {
  225. // Users default should be applied if a null is to be inserted
  226. prop.setDefaultable();
  227. if (colmd.getDefaultValue() != null) {
  228. throw new UnsupportedOperationException("User-defined default not supported.");
  229. }
  230. }
  231. return prop;
  232. }
  233. @Override
  234. public void loadDatastoreMapping(PluginManager mgr, ClassLoaderResolver clr, String vendorId) {
  235. }
  236. @Override
  237. protected Class getOverrideMappingClass(Class mappingClass, AbstractMemberMetaData fmd, int roleForField) {
  238. if (roleForField == FieldRole.ROLE_FIELD && fmd.isPrimaryKey() && mappingClass.equals(
  239. SerialisedMapping.class) && fmd.getType().equals(Key.class)) {
  240. // Do I fully comprehend what I'm doing here? No. But I do know that
  241. // this change enables us to have relations where the pk of the child is of type
  242. // Key, and that's a good thing.
  243. return KeyMapping.class;
  244. } else if (mappingClass.equals(EmbeddedPCMapping.class)) {
  245. // As of DataNuc 1.1.3, Embedded fields in JPA don't have their
  246. // EmbeddedMetaData set. Our embedded field logic requires this,
  247. // so in order to preserve this invariant we instantiate our own
  248. // subclass of EmbeddedPCMapping that always has EmbeddedMetaData
  249. // set.
  250. return DatastoreEmbeddedPCMapping.class;
  251. }
  252. return mappingClass;
  253. }
  254. /**
  255. * An extension of {@link EmbeddedPCMapping} that always has its EmbeddedMetaData set.
  256. */
  257. public static final class DatastoreEmbeddedPCMapping extends EmbeddedPCMapping {
  258. @Override
  259. public void initialize(AbstractMemberMetaData mmd, DatastoreContainerObject container,
  260. ClassLoaderResolver clr) {
  261. MetaDataManager mmgr = container.getStoreManager().getMetaDataManager();
  262. if (mmd.getEmbeddedMetaData() == null) {
  263. EmbeddedMetaData embmd = new EmbeddedMetaData();
  264. embmd.setOwnerMember(mmd.getName());
  265. mmd.setEmbeddedMetaData(embmd);
  266. embmd.populate(clr, null, mmgr);
  267. embmd.initialise(clr, mmgr);
  268. }
  269. super.initialize(mmd, container, clr);
  270. }
  271. }
  272. }