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.schema;
023:
024: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
025: import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCEntityBridge2;
026: import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCCMRFieldBridge2;
027: import org.jboss.deployment.DeploymentException;
028: import org.jboss.tm.TransactionLocal;
029:
030: import javax.ejb.EJBException;
031: import javax.transaction.Synchronization;
032: import javax.transaction.RollbackException;
033: import javax.transaction.SystemException;
034: import javax.transaction.Status;
035: import javax.transaction.Transaction;
036: import java.sql.SQLException;
037:
038: /**
039: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
040: * @version <tt>$Revision: 57209 $</tt>
041: */
042: public class Schema {
043: private EntityTable[] entityTables;
044: private RelationTable[] relationTables;
045:
046: private TransactionLocal localViews = new TransactionLocal() {
047: protected Object initialValue() {
048: Transaction tx = getTransaction();
049:
050: if (tx == null) {
051: throw new IllegalStateException(
052: "An operation requires an active transaction!");
053: }
054:
055: Views views = new Views(tx);
056: Synchronization sync = new SchemaSynchronization(views);
057:
058: try {
059: tx.registerSynchronization(sync);
060: } catch (RollbackException e) {
061: throw new EJBException(
062: "Transaction already marked to roll back: "
063: + e.getMessage(), e);
064: } catch (SystemException e) {
065: e.printStackTrace();
066: throw new IllegalStateException(
067: "Failed to register transaction synchronization: "
068: + e.getMessage());
069: }
070:
071: return views;
072: }
073: };
074:
075: public EntityTable createEntityTable(JDBCEntityMetaData metadata,
076: JDBCEntityBridge2 entity) throws DeploymentException {
077: if (entityTables == null) {
078: entityTables = new EntityTable[1];
079: } else {
080: EntityTable[] tmp = entityTables;
081: entityTables = new EntityTable[tmp.length + 1];
082: System.arraycopy(tmp, 0, entityTables, 0, tmp.length);
083: }
084:
085: EntityTable table = new EntityTable(metadata, entity, this ,
086: entityTables.length - 1);
087: entityTables[entityTables.length - 1] = table;
088: return table;
089: }
090:
091: public RelationTable createRelationTable(
092: JDBCCMRFieldBridge2 leftField,
093: JDBCCMRFieldBridge2 rightField) throws DeploymentException {
094: if (relationTables == null) {
095: relationTables = new RelationTable[1];
096: } else {
097: RelationTable[] tmp = relationTables;
098: relationTables = new RelationTable[tmp.length + 1];
099: System.arraycopy(tmp, 0, relationTables, 0, tmp.length);
100: }
101:
102: RelationTable table = new RelationTable(leftField, rightField,
103: this , relationTables.length - 1);
104: relationTables[relationTables.length - 1] = table;
105: return table;
106: }
107:
108: public Table.View getView(EntityTable table) {
109: Views views = (Views) localViews.get();
110: Table.View view = views.entityViews[table.getTableId()];
111: if (view == null) {
112: view = table.createView(views.tx);
113: views.entityViews[table.getTableId()] = view;
114: }
115: return view;
116: }
117:
118: public Table.View getView(RelationTable table) {
119: Views views = (Views) localViews.get();
120: Table.View view = views.relationViews[table.getTableId()];
121: if (view == null) {
122: view = table.createView(views.tx);
123: views.relationViews[table.getTableId()] = view;
124: }
125: return view;
126: }
127:
128: public void flush() {
129: Views views = (Views) localViews.get();
130:
131: Table.View[] relationViews = views.relationViews;
132: if (relationViews != null) {
133: for (int i = 0; i < relationViews.length; ++i) {
134: final Table.View view = relationViews[i];
135: if (view != null) {
136: try {
137: view.flushDeleted(views);
138: } catch (SQLException e) {
139: throw new EJBException(
140: "Failed to delete many-to-many relationships: "
141: + e.getMessage(), e);
142: }
143: }
144: }
145: }
146:
147: final Table.View[] entityViews = views.entityViews;
148: for (int i = 0; i < entityViews.length; ++i) {
149: Table.View view = entityViews[i];
150: if (view != null) {
151: try {
152: view.flushDeleted(views);
153: } catch (SQLException e) {
154: throw new EJBException(
155: "Failed to delete instances: "
156: + e.getMessage(), e);
157: }
158: }
159: }
160:
161: for (int i = 0; i < entityViews.length; ++i) {
162: Table.View view = entityViews[i];
163: if (view != null) {
164: try {
165: view.flushCreated(views);
166: } catch (SQLException e) {
167: throw new EJBException(
168: "Failed to create instances: "
169: + e.getMessage(), e);
170: }
171: }
172: }
173:
174: for (int i = 0; i < entityViews.length; ++i) {
175: Table.View view = entityViews[i];
176: if (view != null) {
177: try {
178: view.flushUpdated();
179: } catch (SQLException e) {
180: throw new EJBException(
181: "Failed to update instances: "
182: + e.getMessage(), e);
183: }
184: }
185: }
186:
187: if (relationViews != null) {
188: for (int i = 0; i < relationViews.length; ++i) {
189: final Table.View view = relationViews[i];
190: if (view != null) {
191: try {
192: view.flushCreated(views);
193: } catch (SQLException e) {
194: throw new EJBException(
195: "Failed to create many-to-many relationships: "
196: + e.getMessage(), e);
197: }
198: }
199: }
200: }
201: }
202:
203: // Inner
204:
205: public class Views {
206: public final Transaction tx;
207: public final Table.View[] entityViews;
208: public final Table.View[] relationViews;
209:
210: public Views(Transaction tx) {
211: this .tx = tx;
212: this .entityViews = new Table.View[entityTables.length];
213: this .relationViews = relationTables == null ? null
214: : new Table.View[relationTables.length];
215: }
216: }
217:
218: private class SchemaSynchronization implements Synchronization {
219: private final Views views;
220:
221: public SchemaSynchronization(Views views) {
222: this .views = views;
223: }
224:
225: public void beforeCompletion() {
226: flush();
227:
228: for (int i = 0; i < views.entityViews.length; ++i) {
229: Table.View view = views.entityViews[i];
230: if (view != null) {
231: view.beforeCompletion();
232: }
233: }
234: }
235:
236: public void afterCompletion(int status) {
237: if (status == Status.STATUS_MARKED_ROLLBACK
238: || status == Status.STATUS_ROLLEDBACK
239: || status == Status.STATUS_ROLLING_BACK) {
240: for (int i = 0; i < views.entityViews.length; ++i) {
241: Table.View view = views.entityViews[i];
242: if (view != null) {
243: view.rolledback();
244: }
245: }
246: } else {
247: for (int i = 0; i < views.entityViews.length; ++i) {
248: Table.View view = views.entityViews[i];
249: if (view != null) {
250: view.committed();
251: }
252: }
253: }
254: }
255: }
256: }
|