001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.gps.device.jdbc;
018:
019: import java.sql.PreparedStatement;
020: import java.sql.ResultSet;
021: import java.sql.SQLException;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.compass.core.CompassCallbackWithoutResult;
029: import org.compass.core.CompassException;
030: import org.compass.core.CompassSession;
031: import org.compass.core.Resource;
032: import org.compass.core.spi.InternalCompassSession;
033: import org.compass.gps.device.jdbc.dialect.JdbcDialect;
034: import org.compass.gps.device.jdbc.mapping.IdColumnToPropertyMapping;
035: import org.compass.gps.device.jdbc.mapping.ResultSetToResourceMapping;
036: import org.compass.gps.device.jdbc.snapshot.ConfigureSnapshotEvent;
037: import org.compass.gps.device.jdbc.snapshot.CreateAndUpdateSnapshotEvent;
038: import org.compass.gps.device.jdbc.snapshot.DeleteSnapshotEvent;
039: import org.compass.gps.device.jdbc.snapshot.JdbcAliasRowSnapshot;
040: import org.compass.gps.device.jdbc.snapshot.JdbcSnapshotEventListener;
041: import org.compass.gps.spi.CompassGpsInterfaceDevice;
042:
043: /**
044: * A
045: * {@link org.compass.gps.device.jdbc.snapshot.JdbcSnapshotEventListener}
046: * that works with
047: * {@link org.compass.gps.device.jdbc.ResultSetJdbcGpsDevice} and
048: * performs the changes to the compass index after the change snapshots have
049: * been detected by the device.
050: *
051: * @author kimchy
052: */
053: public class ResultSetSnapshotEventListener implements
054: JdbcSnapshotEventListener {
055:
056: private static Log log = LogFactory
057: .getLog(ResultSetSnapshotEventListener.class);
058:
059: private HashMap<String, String> createAndUpdateQueries;
060:
061: public void configure(ConfigureSnapshotEvent configureSnapshotEvent)
062: throws JdbcGpsDeviceException {
063: createAndUpdateQueries = new HashMap<String, String>();
064: for (Iterator it = configureSnapshotEvent.getMappings()
065: .iterator(); it.hasNext();) {
066: ResultSetToResourceMapping mapping = (ResultSetToResourceMapping) it
067: .next();
068: if (!mapping.supportsVersioning()) {
069: continue;
070: }
071: // TODO If there is only one id, need to check if select ID ... IN
072: // () is faster, need also to find how to do it in JDBC
073: StringBuffer sb = new StringBuffer();
074: String selectQuery = mapping.getSelectQuery();
075: sb.append(selectQuery);
076: if (selectQuery.indexOf(" where") != -1) {
077: sb.append(" and (");
078: } else {
079: sb.append(" where (");
080: }
081: boolean first = true;
082: for (Iterator idIt = mapping.idMappingsIt(); idIt.hasNext();) {
083: IdColumnToPropertyMapping idMapping = (IdColumnToPropertyMapping) idIt
084: .next();
085: if (idMapping.getColumnNameForVersion() == null) {
086: throw new IllegalArgumentException(
087: "Id Mapping "
088: + idMapping
089: + " must have column name for versioning."
090: + " If you set the column index, you must set the version as well");
091: }
092: if (first) {
093: first = false;
094: } else {
095: sb.append(" and ");
096: }
097: sb.append(idMapping.getColumnNameForVersion());
098: sb.append(" = ?");
099: }
100: sb.append(")");
101: String query = sb.toString();
102: if (log.isDebugEnabled()) {
103: log.debug("Using create/update query [" + query
104: + "] for alias [" + mapping.getAlias() + "]");
105: }
106: createAndUpdateQueries.put(mapping.getAlias(), query);
107: }
108: }
109:
110: public void onDelete(final DeleteSnapshotEvent deleteSnapshotEvent)
111: throws JdbcGpsDeviceException {
112: final ResultSetToResourceMapping mapping = deleteSnapshotEvent
113: .getMapping();
114: CompassGpsInterfaceDevice compassGps = deleteSnapshotEvent
115: .getCompassGps();
116: compassGps.executeForMirror(new CompassCallbackWithoutResult() {
117: protected void doInCompassWithoutResult(
118: CompassSession session) throws CompassException {
119: for (Iterator it = deleteSnapshotEvent
120: .getDeleteSnapshots().iterator(); it.hasNext();) {
121: JdbcAliasRowSnapshot rowSnapshot = (JdbcAliasRowSnapshot) it
122: .next();
123: List ids = rowSnapshot.getIds();
124: if (ids.size() == 1) {
125: session.delete(mapping.getAlias(), ids.get(0));
126: } else {
127: String[] idsArr = (String[]) ids
128: .toArray(new String[ids.size()]);
129: session.delete(mapping.getAlias(),
130: (Object) idsArr);
131: }
132: }
133: }
134: });
135: }
136:
137: public void onCreateAndUpdate(
138: final CreateAndUpdateSnapshotEvent createAndUpdateSnapshotEvent)
139: throws JdbcGpsDeviceException {
140: doCreateAndUpdateFor(createAndUpdateSnapshotEvent
141: .getCreateSnapshots(), createAndUpdateSnapshotEvent,
142: true);
143: doCreateAndUpdateFor(createAndUpdateSnapshotEvent
144: .getUpdateSnapshots(), createAndUpdateSnapshotEvent,
145: false);
146: }
147:
148: private void doCreateAndUpdateFor(
149: final List snapshots,
150: final CreateAndUpdateSnapshotEvent createAndUpdateSnapshotEvent,
151: final boolean useCreate) throws JdbcGpsDeviceException {
152: final ResultSetToResourceMapping mapping = createAndUpdateSnapshotEvent
153: .getMapping();
154: final JdbcDialect dialect = createAndUpdateSnapshotEvent
155: .getDialect();
156: CompassGpsInterfaceDevice compassGps = createAndUpdateSnapshotEvent
157: .getCompassGps();
158: compassGps.executeForMirror(new CompassCallbackWithoutResult() {
159: protected void doInCompassWithoutResult(
160: CompassSession session) throws CompassException {
161: String query = createAndUpdateQueries.get(mapping
162: .getAlias());
163: PreparedStatement ps = null;
164: try {
165: ps = createAndUpdateSnapshotEvent.getConnection()
166: .prepareStatement(query);
167: for (Iterator it = snapshots.iterator(); it
168: .hasNext();) {
169: JdbcAliasRowSnapshot rowSnapshot = (JdbcAliasRowSnapshot) it
170: .next();
171: Resource resource = ((InternalCompassSession) session)
172: .getCompass().getResourceFactory()
173: .createResource(mapping.getAlias());
174: ResultSetRowMarshallHelper marshallHelper = new ResultSetRowMarshallHelper(
175: mapping, session, dialect, resource);
176: ps.clearParameters();
177: List ids = rowSnapshot.getIds();
178: for (int i = 0; i < ids.size(); i++) {
179: String idValue = (String) ids.get(i);
180: dialect.setParameter(ps, i + 1, idValue);
181: }
182: ResultSet rs = ps.executeQuery();
183: if (!rs.next()) {
184: // it was deleted between the calls, do nothing
185: continue;
186: }
187: marshallHelper.marshallResultSet(rs);
188: if (useCreate) {
189: session.create(resource);
190: } else {
191: session.save(resource);
192: }
193: session.evictAll();
194: }
195: } catch (SQLException e) {
196: throw new JdbcGpsDeviceException(
197: "Failed to execute query for create/update",
198: e);
199: } finally {
200: JdbcUtils.closeStatement(ps);
201: }
202: }
203: });
204: }
205: }
|