001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc2.bridge;
023:
024: import org.jboss.deployment.DeploymentException;
025: import org.jboss.ejb.EntityContainer;
026: import org.jboss.ejb.EntityEnterpriseContext;
027: import org.jboss.ejb.plugins.cmp.bridge.EntityBridgeInvocationHandler;
028: import org.jboss.ejb.plugins.cmp.bridge.FieldBridge;
029: import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
030: import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil;
031: import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge;
032: import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
033: import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge;
034: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
035: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
036: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData;
037: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCOptimisticLockingMetaData;
038: import org.jboss.ejb.plugins.cmp.jdbc2.JDBCStoreManager2;
039: import org.jboss.ejb.plugins.cmp.jdbc2.PersistentContext;
040: import org.jboss.ejb.plugins.cmp.jdbc2.schema.EntityTable;
041: import org.jboss.logging.Logger;
042: import org.jboss.proxy.compiler.InvocationHandler;
043: import org.jboss.proxy.compiler.Proxies;
044:
045: import javax.ejb.EJBException;
046: import javax.ejb.RemoveException;
047: import javax.sql.DataSource;
048: import java.util.ArrayList;
049: import java.util.Iterator;
050: import java.util.List;
051:
052: /**
053: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
054: * @version <tt>$Revision: 62386 $</tt>
055: */
056: public class JDBCEntityBridge2 implements JDBCAbstractEntityBridge {
057: private final JDBCStoreManager2 manager;
058: private final JDBCEntityMetaData metadata;
059: private final EntityTable table;
060: private final String tableName;
061: private final String qualifiedTableName;
062: private final Logger log;
063:
064: private JDBCCMPFieldBridge2[] pkFields;
065: private JDBCCMPFieldBridge2[] cmpFields;
066: private JDBCCMPFieldBridge2[] tableFields;
067: private JDBCCMRFieldBridge2[] cmrFields;
068: private JDBCCMPFieldBridge2 versionField;
069:
070: private int cmrCount;
071:
072: public JDBCEntityBridge2(JDBCStoreManager2 manager,
073: JDBCEntityMetaData metadata) throws DeploymentException {
074: this .manager = manager;
075: this .metadata = metadata;
076: log = Logger.getLogger(this .getClass().getName() + "."
077: + metadata.getName());
078:
079: table = manager.getSchema().createEntityTable(metadata, this );
080: tableName = SQLUtil.getTableNameWithoutSchema(metadata
081: .getDefaultTableName());
082: qualifiedTableName = SQLUtil.fixTableName(metadata
083: .getDefaultTableName(), table.getDataSource());
084: }
085:
086: // Public
087:
088: public void init() throws DeploymentException {
089: loadCMPFields(metadata);
090: loadCMRFields(metadata);
091:
092: JDBCOptimisticLockingMetaData olMD = metadata
093: .getOptimisticLocking();
094: if (olMD != null) {
095: if (olMD.getLockingStrategy() != JDBCOptimisticLockingMetaData.VERSION_COLUMN_STRATEGY) {
096: throw new DeploymentException(
097: "Only version-column optimistic locking strategy is supported at the moment.");
098: }
099:
100: JDBCCMPFieldMetaData versionMD = olMD.getLockingField();
101: versionField = (JDBCCMPFieldBridge2) getFieldByName(versionMD
102: .getFieldName());
103: }
104: }
105:
106: public JDBCCMPFieldBridge2 getVersionField() {
107: return versionField;
108: }
109:
110: public void resolveRelationships() throws DeploymentException {
111: for (int i = 0; i < cmrFields.length; ++i) {
112: cmrFields[i].resolveRelationship();
113: }
114: }
115:
116: public void start() throws DeploymentException {
117: if (versionField != null) {
118: versionField.initVersion();
119: }
120:
121: table.start();
122:
123: if (cmrFields != null) {
124: for (int i = 0; i < cmrFields.length; ++i) {
125: cmrFields[i].initLoader();
126: }
127: }
128: }
129:
130: public void stop() throws Exception {
131: table.stop();
132: }
133:
134: public JDBCEntityMetaData getMetaData() {
135: return metadata;
136: }
137:
138: public EntityTable getTable() {
139: return table;
140: }
141:
142: public JDBCFieldBridge[] getPrimaryKeyFields() {
143: return pkFields;
144: }
145:
146: public JDBCFieldBridge[] getTableFields() {
147: return tableFields;
148: }
149:
150: public JDBCAbstractCMRFieldBridge[] getCMRFields() {
151: return cmrFields;
152: }
153:
154: public JDBCEntityPersistenceStore getManager() {
155: return manager;
156: }
157:
158: public EntityContainer getContainer() {
159: return manager.getContainer();
160: }
161:
162: public Object extractPrimaryKeyFromInstance(
163: EntityEnterpriseContext ctx) {
164: try {
165: Object pk = null;
166: for (int i = 0; i < pkFields.length; ++i) {
167: JDBCCMPFieldBridge2 pkField = pkFields[i];
168: Object fieldValue = pkField.getValue(ctx);
169: pk = pkField.setPrimaryKeyValue(pk, fieldValue);
170: }
171: return pk;
172: } catch (EJBException e) {
173: throw e;
174: } catch (Exception e) {
175: throw new EJBException(
176: "Internal error extracting primary key from instance",
177: e);
178: }
179: }
180:
181: public static void destroyPersistenceContext(
182: EntityEnterpriseContext ctx) {
183: // If we have an EJB 2.0 dynaymic proxy,
184: // notify the handler of the assigned context.
185: Object instance = ctx.getInstance();
186: if (instance instanceof Proxies.ProxyTarget) {
187: InvocationHandler handler = ((Proxies.ProxyTarget) instance)
188: .getInvocationHandler();
189: if (handler instanceof EntityBridgeInvocationHandler) {
190: ((EntityBridgeInvocationHandler) handler)
191: .setContext(null);
192: }
193: }
194: ctx.setPersistenceContext(null);
195: }
196:
197: public void initPersistenceContext(EntityEnterpriseContext ctx) {
198: // If we have an EJB 2.0 dynaymic proxy,
199: // notify the handler of the assigned context.
200: Object instance = ctx.getInstance();
201: if (instance instanceof Proxies.ProxyTarget) {
202: InvocationHandler handler = ((Proxies.ProxyTarget) instance)
203: .getInvocationHandler();
204: if (handler instanceof EntityBridgeInvocationHandler) {
205: ((EntityBridgeInvocationHandler) handler)
206: .setContext(ctx);
207: }
208: }
209: }
210:
211: public void initInstance(EntityEnterpriseContext ctx) {
212: ctx.setPersistenceContext(new PersistentContext(this , table
213: .getRow(ctx.getId())));
214: for (int i = 0; i < tableFields.length; ++i) {
215: tableFields[i].initInstance(ctx);
216: }
217:
218: for (int i = 0; i < cmrFields.length; ++i) {
219: cmrFields[i].initInstance(ctx);
220: }
221: }
222:
223: /**
224: * hacky method needed at deployment time
225: */
226: public List getFields() {
227: List fields = new ArrayList();
228: for (int i = 0; i < pkFields.length; ++i) {
229: fields.add(pkFields[i]);
230: }
231:
232: for (int i = 0; i < cmpFields.length; ++i) {
233: fields.add(cmpFields[i]);
234: }
235:
236: for (int i = 0; i < cmrFields.length; ++i) {
237: fields.add(cmrFields[i]);
238: }
239:
240: return fields;
241: }
242:
243: public boolean isStoreRequired(EntityEnterpriseContext instance) {
244: PersistentContext pctx = (PersistentContext) instance
245: .getPersistenceContext();
246: return pctx.isDirty();
247: }
248:
249: public boolean isModified(EntityEnterpriseContext instance) {
250: PersistentContext pctx = (PersistentContext) instance
251: .getPersistenceContext();
252: boolean modified = pctx.isDirty();
253:
254: if (!modified && cmrFields != null) {
255: for (int i = 0; i < cmrFields.length; ++i) {
256: final JDBCCMRFieldBridge2.FieldState cmrState = pctx
257: .getCMRState(i);
258: if (cmrState != null && cmrState.isModified()) {
259: modified = true;
260: break;
261: }
262: }
263: }
264: return modified;
265: }
266:
267: public Class getPrimaryKeyClass() {
268: return metadata.getPrimaryKeyClass();
269: }
270:
271: public Class getHomeClass() {
272: return metadata.getHomeClass();
273: }
274:
275: public Class getLocalHomeClass() {
276: return metadata.getLocalHomeClass();
277: }
278:
279: public String getTableName() {
280: return tableName;
281: }
282:
283: public String getQualifiedTableName() {
284: return qualifiedTableName;
285: }
286:
287: public DataSource getDataSource() {
288: return table.getDataSource();
289: }
290:
291: public boolean[] getLoadGroupMask(String eagerLoadGroupName) {
292: // todo
293: throw new UnsupportedOperationException();
294: }
295:
296: public int getNextCMRIndex() {
297: return cmrCount++;
298: }
299:
300: public void remove(EntityEnterpriseContext ctx)
301: throws RemoveException {
302: if (cmrFields != null) {
303: for (int i = 0; i < cmrFields.length; ++i) {
304: cmrFields[i].remove(ctx);
305: }
306: }
307: }
308:
309: // EntityBridge implementation
310:
311: public String getEntityName() {
312: return metadata.getName();
313: }
314:
315: public String getAbstractSchemaName() {
316: return metadata.getAbstractSchemaName();
317: }
318:
319: public FieldBridge getFieldByName(String fieldName) {
320: FieldBridge field;
321: for (int i = 0; i < pkFields.length; ++i) {
322: field = pkFields[i];
323: if (field.getFieldName().equals(fieldName)) {
324: return field;
325: }
326: }
327:
328: for (int i = 0; i < cmpFields.length; ++i) {
329: field = cmpFields[i];
330: if (field.getFieldName().equals(fieldName)) {
331: return field;
332: }
333: }
334:
335: for (int i = 0; i < cmrFields.length; ++i) {
336: field = cmrFields[i];
337: if (field.getFieldName().equals(fieldName)) {
338: return field;
339: }
340: }
341:
342: throw new IllegalStateException("Field " + fieldName
343: + " not found in entity " + getEntityName());
344: }
345:
346: public Class getRemoteInterface() {
347: return metadata.getRemoteClass();
348: }
349:
350: public Class getLocalInterface() {
351: return metadata.getLocalClass();
352: }
353:
354: // Package
355:
356: JDBCCMPFieldBridge2 addTableField(JDBCCMPFieldMetaData metadata)
357: throws DeploymentException {
358: table.addField();
359: if (tableFields == null) {
360: tableFields = new JDBCCMPFieldBridge2[1];
361: } else {
362: JDBCCMPFieldBridge2[] tmp = tableFields;
363: tableFields = new JDBCCMPFieldBridge2[tableFields.length + 1];
364: System.arraycopy(tmp, 0, tableFields, 0, tmp.length);
365: }
366: int tableIndex = tableFields.length - 1;
367: JDBCCMPFieldBridge2 cmpField = new JDBCCMPFieldBridge2(manager,
368: this , metadata, tableIndex);
369: tableFields[tableFields.length - 1] = cmpField;
370: return cmpField;
371: }
372:
373: // Private
374:
375: private void loadCMPFields(JDBCEntityMetaData metadata)
376: throws DeploymentException {
377: // only non pk fields are stored here at first and then later
378: // the pk fields are added to the front (makes sql easier to read)
379: List cmpFieldsList = new ArrayList(metadata.getCMPFields()
380: .size());
381: // primary key cmp fields
382: List pkFieldsList = new ArrayList(metadata.getCMPFields()
383: .size());
384:
385: // create each field
386: Iterator iter = metadata.getCMPFields().iterator();
387: while (iter.hasNext()) {
388: JDBCCMPFieldMetaData cmpFieldMetaData = (JDBCCMPFieldMetaData) iter
389: .next();
390: JDBCCMPFieldBridge2 cmpField = addTableField(cmpFieldMetaData);
391: if (cmpFieldMetaData.isPrimaryKeyMember()) {
392: pkFieldsList.add(cmpField);
393: } else {
394: cmpFieldsList.add(cmpField);
395: }
396: }
397:
398: // save the pk fields in the pk field array
399: pkFields = new JDBCCMPFieldBridge2[pkFieldsList.size()];
400: for (int i = 0; i < pkFieldsList.size(); ++i) {
401: pkFields[i] = (JDBCCMPFieldBridge2) pkFieldsList.get(i);
402: }
403:
404: // add the pk fields to the front of the cmp list, per guarantee above
405: cmpFields = new JDBCCMPFieldBridge2[metadata.getCMPFields()
406: .size()
407: - pkFields.length];
408: int cmpFieldIndex = 0;
409: for (int i = 0; i < cmpFieldsList.size(); ++i) {
410: cmpFields[cmpFieldIndex++] = (JDBCCMPFieldBridge2) cmpFieldsList
411: .get(i);
412: }
413: }
414:
415: private void loadCMRFields(JDBCEntityMetaData metadata)
416: throws DeploymentException {
417: cmrFields = new JDBCCMRFieldBridge2[metadata
418: .getRelationshipRoles().size()];
419: // create each field
420: int cmrFieldIndex = 0;
421: for (Iterator iter = metadata.getRelationshipRoles().iterator(); iter
422: .hasNext();) {
423: JDBCRelationshipRoleMetaData relationshipRole = (JDBCRelationshipRoleMetaData) iter
424: .next();
425: JDBCCMRFieldBridge2 cmrField = new JDBCCMRFieldBridge2(
426: this, manager, relationshipRole);
427: cmrFields[cmrFieldIndex++] = cmrField;
428: }
429: }
430: }
|