/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. ****************************************************************/ package org.apache.cayenne.access; import java.util.List; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.DataRow; import org.apache.cayenne.ObjectId; import org.apache.cayenne.ResultIterator; import org.apache.cayenne.log.JdbcEventLogger; import org.apache.cayenne.map.DbAttribute; import org.apache.cayenne.query.BatchQuery; import org.apache.cayenne.query.InsertBatchQuery; import org.apache.cayenne.query.Query; import org.apache.cayenne.util.Util; /** * Used as an observer for DataContext commit operations. * * @since 1.2 */ class DataDomainFlushObserver implements OperationObserver { /** * @since 3.1 */ private JdbcEventLogger logger; DataDomainFlushObserver(JdbcEventLogger logger) { this.logger = logger; } @Override public void nextQueryException(Query query, Exception ex) { throw new CayenneRuntimeException("Raising from query exception.", Util.unwindException(ex)); } @Override public void nextGlobalException(Exception ex) { throw new CayenneRuntimeException("Raising from underlyingQueryEngine exception.", Util.unwindException(ex)); } /** * Processes generated keys. * * @since 1.2 */ @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public void nextGeneratedRows(Query query, ResultIterator keysIterator, ObjectId idToUpdate) { // read and close the iterator before doing anything else List<DataRow> keys; try { keys = (List<DataRow>) keysIterator.allRows(); } finally { keysIterator.close(); } if (!(query instanceof InsertBatchQuery)) { throw new CayenneRuntimeException("Generated keys only supported for InsertBatchQuery, instead got %s", query); } if (idToUpdate == null || !idToUpdate.isTemporary()) { // why would this happen? return; } if (keys.size() != 1) { throw new CayenneRuntimeException("One and only one PK row is expected, instead got %d", keys.size()); } DataRow key = keys.get(0); // empty key? if (key.size() == 0) { throw new CayenneRuntimeException("Empty key generated."); } // determine DbAttribute name... // As of now (01/2005) all tested drivers don't provide decent // descriptors of // identity result sets, so a data row will contain garbage labels. Also // most // DBs only support one autogenerated key per table... So here we will // have to // infer the key name and currently will only support a single column... if (key.size() > 1) { throw new CayenneRuntimeException("Only a single column autogenerated PK is supported. " + "Generated key: %s", key); } BatchQuery batch = (BatchQuery) query; for (DbAttribute attribute : batch.getDbEntity().getGeneratedAttributes()) { // batch can have generated attributes that are not PKs, e.g. // columns with // DB DEFAULT values. Ignore those. if (attribute.isPrimaryKey()) { Object value = key.values().iterator().next(); // Log the generated PK logger.logGeneratedKey(attribute, value); // I guess we should override any existing value, // as generated key is the latest thing that exists in the DB. idToUpdate.getReplacementIdMap().put(attribute.getName(), value); break; } } } public void setJdbcEventLogger(JdbcEventLogger logger) { this.logger = logger; } public JdbcEventLogger getJdbcEventLogger() { return this.logger; } @Override public void nextBatchCount(Query query, int[] resultCount) { } @Override public void nextCount(Query query, int resultCount) { } @Override public void nextRows(Query query, List<?> dataRows) { } @Override @SuppressWarnings("rawtypes") public void nextRows(Query q, ResultIterator it) { throw new UnsupportedOperationException( "'nextDataRows(Query,ResultIterator)' is unsupported (and unexpected) on commit."); } @Override public boolean isIteratedResult() { return false; } }