PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/jboss-as-7.1.1.Final/cmp/src/main/java/org/jboss/as/cmp/jdbc/metadata/JDBCRelationshipRoleMetaData.java

#
Java | 431 lines | 240 code | 66 blank | 125 comment | 47 complexity | 3953e3778d208b8833d47b0c962fbe2d MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. /*
  2. * JBoss, Home of Professional Open Source.
  3. * Copyright 2008, Red Hat Middleware LLC, and individual contributors
  4. * as indicated by the @author tags. See the copyright.txt file in the
  5. * distribution for a full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jboss.as.cmp.jdbc.metadata;
  23. import java.util.ArrayList;
  24. import java.util.Collection;
  25. import java.util.Collections;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import org.jboss.as.cmp.CmpMessages;
  30. import static org.jboss.as.cmp.CmpMessages.MESSAGES;
  31. import org.jboss.as.cmp.jdbc.metadata.parser.ParsedCmpField;
  32. import org.jboss.as.cmp.jdbc.metadata.parser.ParsedRelationshipRole;
  33. import org.jboss.metadata.ejb.spec.RelationRoleMetaData;
  34. /**
  35. * Immutable class which represents one ejb-relationship-role element found in
  36. * the ejb-jar.xml file's ejb-relation elements.
  37. *
  38. * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
  39. * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
  40. * @version $Revision: 81030 $
  41. */
  42. public final class JDBCRelationshipRoleMetaData {
  43. /**
  44. * Relation to which this role belongs.
  45. */
  46. private final JDBCRelationMetaData relationMetaData;
  47. /**
  48. * Role name
  49. */
  50. private final String relationshipRoleName;
  51. /**
  52. * Should this role have a foreign key constraint?
  53. */
  54. private final boolean foreignKeyConstraint;
  55. /**
  56. * Should the cascade-delete be batched.
  57. */
  58. private final boolean batchCascadeDelete;
  59. private boolean genIndex;
  60. /**
  61. * Type of the cmr field (i.e., collection or set)
  62. */
  63. private JDBCReadAheadMetaData readAhead;
  64. /**
  65. * Is the multiplicity one? If not, multiplicity is many.
  66. */
  67. private final boolean multiplicityOne;
  68. /**
  69. * Should this entity be deleted when related entity is deleted.
  70. */
  71. private final boolean cascadeDelete;
  72. /**
  73. * The entity that has this role.
  74. */
  75. private final JDBCEntityMetaData entity;
  76. /**
  77. * Name of the entity's cmr field for this role.
  78. */
  79. private final String cmrFieldName;
  80. /**
  81. * true if this side is navigable
  82. */
  83. private final boolean navigable;
  84. /**
  85. * Type of the cmr field (i.e., collection or set)
  86. */
  87. private final String cmrFieldType;
  88. /**
  89. * The other role in this relationship.
  90. */
  91. private JDBCRelationshipRoleMetaData relatedRole;
  92. /**
  93. * The key fields used by this role by field name.
  94. */
  95. private Map<String, JDBCCMPFieldMetaData> keyFields = new HashMap<String, JDBCCMPFieldMetaData>();
  96. public JDBCRelationshipRoleMetaData(final JDBCRelationMetaData relationMetaData, final JDBCApplicationMetaData application, final RelationRoleMetaData role) {
  97. this.relationMetaData = relationMetaData;
  98. relationshipRoleName = role.getEjbRelationshipRoleName();
  99. multiplicityOne = role.isMultiplicityOne();
  100. cascadeDelete = role.isCascadedDelete();
  101. batchCascadeDelete = false;
  102. foreignKeyConstraint = false;
  103. readAhead = null;
  104. String fieldName = role.getCmrField() != null ? role.getCmrField().getCmrFieldName() : null;
  105. if (fieldName == null) {
  106. cmrFieldName = generateNonNavigableCMRName(role);
  107. navigable = false;
  108. } else {
  109. cmrFieldName = fieldName;
  110. navigable = true;
  111. }
  112. cmrFieldType = role.getCmrField() != null ? role.getCmrField().getCmrFieldType() : null;
  113. // get the entity for this role
  114. entity = application.getBeanByEjbName(role.getRoleSource().getEjbName());
  115. if (entity == null) {
  116. throw MESSAGES.entityNotFoundForRelation(role.getRoleSource().getEjbName(), role.getRelation().getEjbRelationName());
  117. }
  118. }
  119. public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData, JDBCApplicationMetaData application, JDBCRelationshipRoleMetaData defaultValues) {
  120. this.relationMetaData = relationMetaData;
  121. this.entity = application.getBeanByEjbName(defaultValues.getEntity().getName());
  122. relationshipRoleName = defaultValues.getRelationshipRoleName();
  123. multiplicityOne = defaultValues.isMultiplicityOne();
  124. cascadeDelete = defaultValues.isCascadeDelete();
  125. cmrFieldName = defaultValues.getCMRFieldName();
  126. navigable = defaultValues.isNavigable();
  127. cmrFieldType = defaultValues.getCMRFieldType();
  128. foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
  129. readAhead = entity.getReadAhead();
  130. batchCascadeDelete = defaultValues.isBatchCascadeDelete();
  131. if (batchCascadeDelete) {
  132. if (!cascadeDelete)
  133. throw MESSAGES.cascadeDeleteInJbossXmlButNoEjbJar(relationMetaData.getRelationName(), relationshipRoleName);
  134. if (relationMetaData.isTableMappingStyle()) {
  135. throw MESSAGES.batchCascadeDeleteOnlyForFkMapping(relationMetaData.getRelationName());
  136. }
  137. }
  138. }
  139. public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData, JDBCApplicationMetaData application, ParsedRelationshipRole parsedRelationshipRole, JDBCRelationshipRoleMetaData defaultValues) {
  140. this.relationMetaData = relationMetaData;
  141. this.entity = application.getBeanByEjbName(defaultValues.getEntity().getName());
  142. relationshipRoleName = defaultValues.getRelationshipRoleName();
  143. multiplicityOne = defaultValues.isMultiplicityOne();
  144. cascadeDelete = defaultValues.isCascadeDelete();
  145. cmrFieldName = defaultValues.getCMRFieldName();
  146. navigable = defaultValues.isNavigable();
  147. cmrFieldType = defaultValues.getCMRFieldType();
  148. // foreign key constraint? If not provided, keep default.
  149. if (parsedRelationshipRole.getForeignKeyConstraint() != null) {
  150. foreignKeyConstraint = parsedRelationshipRole.getForeignKeyConstraint();
  151. } else {
  152. foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
  153. }
  154. // read-ahead
  155. if (parsedRelationshipRole.getReadAhead() != null) {
  156. readAhead = new JDBCReadAheadMetaData(parsedRelationshipRole.getReadAhead(), entity.getReadAhead());
  157. } else {
  158. readAhead = entity.getReadAhead();
  159. }
  160. batchCascadeDelete = parsedRelationshipRole.getBatchCascadeDelete() != null && parsedRelationshipRole.getBatchCascadeDelete();
  161. if (batchCascadeDelete) {
  162. if (!cascadeDelete)
  163. throw CmpMessages.MESSAGES.invalidCascadeDeleteForRelation(relationMetaData.getRelationName(), relationshipRoleName);
  164. if (relationMetaData.isTableMappingStyle()) {
  165. throw MESSAGES.batchCascadeDeleteOnlyForFkMapping(relationMetaData.getRelationName());
  166. }
  167. }
  168. }
  169. public void init(final JDBCRelationshipRoleMetaData relatedRole) {
  170. this.relatedRole = relatedRole;
  171. keyFields.putAll(loadKeyFields());
  172. }
  173. public void init(final JDBCRelationshipRoleMetaData relatedRole, final ParsedRelationshipRole parsedRole) {
  174. this.relatedRole = relatedRole;
  175. keyFields.putAll(loadKeyFields(parsedRole));
  176. }
  177. /**
  178. * Gets the relation to which this role belongs.
  179. */
  180. public JDBCRelationMetaData getRelationMetaData() {
  181. return relationMetaData;
  182. }
  183. /**
  184. * Gets the name of this role.
  185. */
  186. public String getRelationshipRoleName() {
  187. return relationshipRoleName;
  188. }
  189. /**
  190. * Should this role use a foreign key constraint.
  191. *
  192. * @return true if the store manager will execute an ALTER TABLE ADD
  193. * CONSTRAINT statement to add a foreign key constraint.
  194. */
  195. public boolean hasForeignKeyConstraint() {
  196. return foreignKeyConstraint;
  197. }
  198. public boolean isBatchCascadeDelete() {
  199. return batchCascadeDelete;
  200. }
  201. /**
  202. * Gets the read ahead meta data
  203. */
  204. public JDBCReadAheadMetaData getReadAhead() {
  205. return readAhead;
  206. }
  207. public JDBCEntityMetaData getEntity() {
  208. return entity;
  209. }
  210. /**
  211. * Gets the key fields of this role.
  212. *
  213. * @return an unmodifiable collection of JDBCCMPFieldMetaData objects
  214. */
  215. public Collection<JDBCCMPFieldMetaData> getKeyFields() {
  216. return Collections.unmodifiableCollection(keyFields.values());
  217. }
  218. public boolean isIndexed() {
  219. return genIndex;
  220. }
  221. private static String generateNonNavigableCMRName(final RelationRoleMetaData role) {
  222. RelationRoleMetaData relatedRole = role.getRelatedRole();
  223. return relatedRole.getRoleSource().getEjbName() + "_" + relatedRole.getCmrField().getCmrFieldName();
  224. }
  225. /**
  226. * Checks if the multiplicity is one.
  227. */
  228. public boolean isMultiplicityOne() {
  229. return multiplicityOne;
  230. }
  231. /**
  232. * Checks if the multiplicity is many.
  233. */
  234. public boolean isMultiplicityMany() {
  235. return !multiplicityOne;
  236. }
  237. /**
  238. * Should this entity be deleted when related entity is deleted.
  239. */
  240. public boolean isCascadeDelete() {
  241. return cascadeDelete;
  242. }
  243. /**
  244. * Gets the name of the entity's cmr field for this role.
  245. */
  246. public String getCMRFieldName() {
  247. return cmrFieldName;
  248. }
  249. public boolean isNavigable() {
  250. return navigable;
  251. }
  252. /**
  253. * Gets the type of the cmr field (i.e., collection or set)
  254. */
  255. public String getCMRFieldType() {
  256. return cmrFieldType;
  257. }
  258. /**
  259. * Gets the related role's jdbc meta data.
  260. */
  261. public JDBCRelationshipRoleMetaData getRelatedRole() {
  262. return relationMetaData.getOtherRelationshipRole(this);
  263. }
  264. /**
  265. * Loads the key fields for this role based on the primary keys of the
  266. * this entity.
  267. */
  268. private Map<String, JDBCCMPFieldMetaData> loadKeyFields() {
  269. // with foreign key mapping, foreign key fields are no added if
  270. // - it is the many side of one-to-many relationship
  271. // - it is the one side of one-to-one relationship and related side is not navigable
  272. if (relationMetaData.isForeignKeyMappingStyle()) {
  273. if (isMultiplicityMany())
  274. return Collections.emptyMap();
  275. else if (getRelatedRole().isMultiplicityOne() && !getRelatedRole().isNavigable())
  276. return Collections.emptyMap();
  277. }
  278. // get all of the pk fields
  279. List<JDBCCMPFieldMetaData> pkFields = new ArrayList<JDBCCMPFieldMetaData>();
  280. for (JDBCCMPFieldMetaData cmpField : entity.getCMPFields()) {
  281. if (cmpField.isPrimaryKeyMember()) {
  282. pkFields.add(cmpField);
  283. }
  284. }
  285. // generate a new key field for each pk field
  286. Map<String, JDBCCMPFieldMetaData> fields = new HashMap<String, JDBCCMPFieldMetaData>(pkFields.size());
  287. for (JDBCCMPFieldMetaData cmpField : pkFields) {
  288. String columnName;
  289. if (relationMetaData.isTableMappingStyle()) {
  290. if (entity.equals(relatedRole.getEntity()))
  291. columnName = getCMRFieldName();
  292. else
  293. columnName = entity.getName();
  294. } else {
  295. columnName = relatedRole.getCMRFieldName();
  296. }
  297. if (pkFields.size() > 1) {
  298. columnName += "_" + cmpField.getFieldName();
  299. }
  300. genIndex = (genIndex) || cmpField.isIndexed();
  301. cmpField = new JDBCCMPFieldMetaData(
  302. entity,
  303. cmpField,
  304. columnName,
  305. false,
  306. relationMetaData.isTableMappingStyle(),
  307. relationMetaData.isReadOnly(),
  308. relationMetaData.getReadTimeOut(),
  309. relationMetaData.isTableMappingStyle());
  310. fields.put(cmpField.getFieldName(), cmpField);
  311. }
  312. return Collections.unmodifiableMap(fields);
  313. }
  314. private Map<String, JDBCCMPFieldMetaData> loadKeyFields(final ParsedRelationshipRole parsedRole) {
  315. // no field overrides, we're done
  316. final List<ParsedCmpField> keyFields = parsedRole.getKeyFields();
  317. if (keyFields == null) {
  318. return loadKeyFields();
  319. }
  320. if(keyFields.isEmpty()) {
  321. return Collections.EMPTY_MAP;
  322. }
  323. if (relationMetaData.isForeignKeyMappingStyle() && isMultiplicityMany()) {
  324. throw CmpMessages.MESSAGES.relationshipRoleCanNotHaveKeyFields(relationshipRoleName);
  325. }
  326. // load the default field values
  327. Map<String, JDBCCMPFieldMetaData> defaultFields = getPrimaryKeyFields();
  328. // load overrides
  329. Map<String, JDBCCMPFieldMetaData> fields = new HashMap<String, JDBCCMPFieldMetaData>(defaultFields.size());
  330. for (ParsedCmpField keyField : keyFields) {
  331. String fieldName = keyField.getFieldName();
  332. JDBCCMPFieldMetaData cmpField = defaultFields.remove(fieldName);
  333. if (cmpField == null) {
  334. throw MESSAGES.cmpFieldNotFoundForRole(relationshipRoleName, entity.getName(), fieldName);
  335. }
  336. genIndex = keyField.getGenIndex() != null && keyField.getGenIndex();
  337. cmpField = new JDBCCMPFieldMetaData(
  338. entity,
  339. keyField,
  340. cmpField,
  341. false,
  342. relationMetaData.isTableMappingStyle(),
  343. relationMetaData.isReadOnly(),
  344. relationMetaData.getReadTimeOut(),
  345. relationMetaData.isTableMappingStyle());
  346. fields.put(cmpField.getFieldName(), cmpField);
  347. }
  348. // all fields must be overridden
  349. if (!defaultFields.isEmpty()) {
  350. throw MESSAGES.mappingsNotProvidedForAllFieldsForRole(defaultFields.keySet(), relationshipRoleName);
  351. }
  352. return Collections.unmodifiableMap(fields);
  353. }
  354. /**
  355. * Returns the primary key fields of the entity mapped by field name.
  356. */
  357. private Map<String, JDBCCMPFieldMetaData> getPrimaryKeyFields() {
  358. Map<String, JDBCCMPFieldMetaData> pkFields = new HashMap<String, JDBCCMPFieldMetaData>();
  359. for (JDBCCMPFieldMetaData cmpField : entity.getCMPFields()) {
  360. if (cmpField.isPrimaryKeyMember())
  361. pkFields.put(cmpField.getFieldName(), cmpField);
  362. }
  363. return pkFields;
  364. }
  365. }