/* * Copyright 2004-2009 the original author or authors. * * Licensed 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.compass.gps.device.jdbc; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.compass.core.CompassCallbackWithoutResult; import org.compass.core.CompassException; import org.compass.core.CompassSession; import org.compass.core.Resource; import org.compass.core.spi.InternalCompassSession; import org.compass.gps.device.jdbc.dialect.JdbcDialect; import org.compass.gps.device.jdbc.mapping.IdColumnToPropertyMapping; import org.compass.gps.device.jdbc.mapping.ResultSetToResourceMapping; import org.compass.gps.device.jdbc.snapshot.ConfigureSnapshotEvent; import org.compass.gps.device.jdbc.snapshot.CreateAndUpdateSnapshotEvent; import org.compass.gps.device.jdbc.snapshot.DeleteSnapshotEvent; import org.compass.gps.device.jdbc.snapshot.JdbcAliasRowSnapshot; import org.compass.gps.device.jdbc.snapshot.JdbcSnapshotEventListener; import org.compass.gps.spi.CompassGpsInterfaceDevice; /** * A * {@link org.compass.gps.device.jdbc.snapshot.JdbcSnapshotEventListener} * that works with * {@link org.compass.gps.device.jdbc.ResultSetJdbcGpsDevice} and * performs the changes to the compass index after the change snapshots have * been detected by the device. * * @author kimchy */ public class ResultSetSnapshotEventListener implements JdbcSnapshotEventListener { private static Log log = LogFactory.getLog(ResultSetSnapshotEventListener.class); private HashMap<String, String> createAndUpdateQueries; public void configure(ConfigureSnapshotEvent configureSnapshotEvent) throws JdbcGpsDeviceException { createAndUpdateQueries = new HashMap<String, String>(); for (Iterator it = configureSnapshotEvent.getMappings().iterator(); it.hasNext();) { ResultSetToResourceMapping mapping = (ResultSetToResourceMapping) it.next(); if (!mapping.supportsVersioning()) { continue; } // TODO If there is only one id, need to check if select ID ... IN // () is faster, need also to find how to do it in JDBC StringBuffer sb = new StringBuffer(); String selectQuery = mapping.getSelectQuery(); sb.append(selectQuery); if (selectQuery.indexOf(" where") != -1) { sb.append(" and ("); } else { sb.append(" where ("); } boolean first = true; for (Iterator idIt = mapping.idMappingsIt(); idIt.hasNext();) { IdColumnToPropertyMapping idMapping = (IdColumnToPropertyMapping) idIt.next(); if (idMapping.getColumnNameForVersion() == null) { throw new IllegalArgumentException("Id Mapping " + idMapping + " must have column name for versioning." + " If you set the column index, you must set the version as well"); } if (first) { first = false; } else { sb.append(" and "); } sb.append(idMapping.getColumnNameForVersion()); sb.append(" = ?"); } sb.append(")"); String query = sb.toString(); if (log.isDebugEnabled()) { log.debug("Using create/update query [" + query + "] for alias [" + mapping.getAlias() + "]"); } createAndUpdateQueries.put(mapping.getAlias(), query); } } public void onDelete(final DeleteSnapshotEvent deleteSnapshotEvent) throws JdbcGpsDeviceException { final ResultSetToResourceMapping mapping = deleteSnapshotEvent.getMapping(); CompassGpsInterfaceDevice compassGps = deleteSnapshotEvent.getCompassGps(); compassGps.executeForMirror(new CompassCallbackWithoutResult() { protected void doInCompassWithoutResult(CompassSession session) throws CompassException { for (Iterator it = deleteSnapshotEvent.getDeleteSnapshots().iterator(); it.hasNext();) { JdbcAliasRowSnapshot rowSnapshot = (JdbcAliasRowSnapshot) it.next(); List ids = rowSnapshot.getIds(); if (ids.size() == 1) { session.delete(mapping.getAlias(), ids.get(0)); } else { String[] idsArr = (String[]) ids.toArray(new String[ids.size()]); session.delete(mapping.getAlias(), (Object) idsArr); } } } }); } public void onCreateAndUpdate(final CreateAndUpdateSnapshotEvent createAndUpdateSnapshotEvent) throws JdbcGpsDeviceException { doCreateAndUpdateFor(createAndUpdateSnapshotEvent.getCreateSnapshots(), createAndUpdateSnapshotEvent, true); doCreateAndUpdateFor(createAndUpdateSnapshotEvent.getUpdateSnapshots(), createAndUpdateSnapshotEvent, false); } private void doCreateAndUpdateFor(final List snapshots, final CreateAndUpdateSnapshotEvent createAndUpdateSnapshotEvent, final boolean useCreate) throws JdbcGpsDeviceException { final ResultSetToResourceMapping mapping = createAndUpdateSnapshotEvent.getMapping(); final JdbcDialect dialect = createAndUpdateSnapshotEvent.getDialect(); CompassGpsInterfaceDevice compassGps = createAndUpdateSnapshotEvent.getCompassGps(); compassGps.executeForMirror(new CompassCallbackWithoutResult() { protected void doInCompassWithoutResult(CompassSession session) throws CompassException { String query = createAndUpdateQueries.get(mapping.getAlias()); PreparedStatement ps = null; try { ps = createAndUpdateSnapshotEvent.getConnection().prepareStatement(query); for (Iterator it = snapshots.iterator(); it.hasNext();) { JdbcAliasRowSnapshot rowSnapshot = (JdbcAliasRowSnapshot) it.next(); Resource resource = ((InternalCompassSession) session).getCompass().getResourceFactory().createResource(mapping.getAlias()); ResultSetRowMarshallHelper marshallHelper = new ResultSetRowMarshallHelper(mapping, session, dialect, resource); ps.clearParameters(); List ids = rowSnapshot.getIds(); for (int i = 0; i < ids.size(); i++) { String idValue = (String) ids.get(i); dialect.setParameter(ps, i + 1, idValue); } ResultSet rs = ps.executeQuery(); if (!rs.next()) { // it was deleted between the calls, do nothing continue; } marshallHelper.marshallResultSet(rs); if (useCreate) { session.create(resource); } else { session.save(resource); } session.evictAll(); } } catch (SQLException e) { throw new JdbcGpsDeviceException("Failed to execute query for create/update", e); } finally { JdbcUtils.closeStatement(ps); } } }); } }