/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.ejb.plugins.cmp.jdbc2.schema; import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData; import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCEntityBridge2; import org.jboss.ejb.plugins.cmp.jdbc2.bridge.JDBCCMRFieldBridge2; import org.jboss.deployment.DeploymentException; import org.jboss.tm.TransactionLocal; import javax.ejb.EJBException; import javax.transaction.Synchronization; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.Status; import javax.transaction.Transaction; import java.sql.SQLException; /** * @author Alexey Loubyansky * @version $Revision: 57209 $ */ public class Schema { private EntityTable[] entityTables; private RelationTable[] relationTables; private TransactionLocal localViews = new TransactionLocal() { protected Object initialValue() { Transaction tx = getTransaction(); if(tx == null) { throw new IllegalStateException("An operation requires an active transaction!"); } Views views = new Views(tx); Synchronization sync = new SchemaSynchronization(views); try { tx.registerSynchronization(sync); } catch(RollbackException e) { throw new EJBException("Transaction already marked to roll back: " + e.getMessage(), e); } catch(SystemException e) { e.printStackTrace(); throw new IllegalStateException("Failed to register transaction synchronization: " + e.getMessage()); } return views; } }; public EntityTable createEntityTable(JDBCEntityMetaData metadata, JDBCEntityBridge2 entity) throws DeploymentException { if(entityTables == null) { entityTables = new EntityTable[1]; } else { EntityTable[] tmp = entityTables; entityTables = new EntityTable[tmp.length + 1]; System.arraycopy(tmp, 0, entityTables, 0, tmp.length); } EntityTable table = new EntityTable(metadata, entity, this, entityTables.length - 1); entityTables[entityTables.length - 1] = table; return table; } public RelationTable createRelationTable(JDBCCMRFieldBridge2 leftField, JDBCCMRFieldBridge2 rightField) throws DeploymentException { if(relationTables == null) { relationTables = new RelationTable[1]; } else { RelationTable[] tmp = relationTables; relationTables = new RelationTable[tmp.length + 1]; System.arraycopy(tmp, 0, relationTables, 0, tmp.length); } RelationTable table = new RelationTable(leftField, rightField, this, relationTables.length - 1); relationTables[relationTables.length - 1] = table; return table; } public Table.View getView(EntityTable table) { Views views = (Views) localViews.get(); Table.View view = views.entityViews[table.getTableId()]; if(view == null) { view = table.createView(views.tx); views.entityViews[table.getTableId()] = view; } return view; } public Table.View getView(RelationTable table) { Views views = (Views) localViews.get(); Table.View view = views.relationViews[table.getTableId()]; if(view == null) { view = table.createView(views.tx); views.relationViews[table.getTableId()] = view; } return view; } public void flush() { Views views = (Views) localViews.get(); Table.View[] relationViews = views.relationViews; if(relationViews != null) { for(int i = 0; i < relationViews.length; ++i) { final Table.View view = relationViews[i]; if(view != null) { try { view.flushDeleted(views); } catch(SQLException e) { throw new EJBException("Failed to delete many-to-many relationships: " + e.getMessage(), e); } } } } final Table.View[] entityViews = views.entityViews; for(int i = 0; i < entityViews.length; ++i) { Table.View view = entityViews[i]; if(view != null) { try { view.flushDeleted(views); } catch(SQLException e) { throw new EJBException("Failed to delete instances: " + e.getMessage(), e); } } } for(int i = 0; i < entityViews.length; ++i) { Table.View view = entityViews[i]; if(view != null) { try { view.flushCreated(views); } catch(SQLException e) { throw new EJBException("Failed to create instances: " + e.getMessage(), e); } } } for(int i = 0; i < entityViews.length; ++i) { Table.View view = entityViews[i]; if(view != null) { try { view.flushUpdated(); } catch(SQLException e) { throw new EJBException("Failed to update instances: " + e.getMessage(), e); } } } if(relationViews != null) { for(int i = 0; i < relationViews.length; ++i) { final Table.View view = relationViews[i]; if(view != null) { try { view.flushCreated(views); } catch(SQLException e) { throw new EJBException("Failed to create many-to-many relationships: " + e.getMessage(), e); } } } } } // Inner public class Views { public final Transaction tx; public final Table.View[] entityViews; public final Table.View[] relationViews; public Views(Transaction tx) { this.tx = tx; this.entityViews = new Table.View[entityTables.length]; this.relationViews = relationTables == null ? null : new Table.View[relationTables.length]; } } private class SchemaSynchronization implements Synchronization { private final Views views; public SchemaSynchronization(Views views) { this.views = views; } public void beforeCompletion() { flush(); for(int i = 0; i < views.entityViews.length; ++i) { Table.View view = views.entityViews[i]; if(view != null) { view.beforeCompletion(); } } } public void afterCompletion(int status) { if(status == Status.STATUS_MARKED_ROLLBACK || status == Status.STATUS_ROLLEDBACK || status == Status.STATUS_ROLLING_BACK) { for(int i = 0; i < views.entityViews.length; ++i) { Table.View view = views.entityViews[i]; if(view != null) { view.rolledback(); } } } else { for(int i = 0; i < views.entityViews.length; ++i) { Table.View view = views.entityViews[i]; if(view != null) { view.committed(); } } } } } }