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.hibernate.scrollable;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.compass.core.CompassCallbackWithoutResult;
026: import org.compass.core.CompassException;
027: import org.compass.core.CompassSession;
028: import org.compass.core.Resource;
029: import org.compass.core.spi.InternalCompassSession;
030: import org.compass.gps.device.hibernate.HibernateGpsDeviceException;
031: import org.compass.gps.device.hibernate.scrollable.snapshot.ConfigureSnapshotEvent;
032: import org.compass.gps.device.hibernate.scrollable.snapshot.CreateAndUpdateSnapshotEvent;
033: import org.compass.gps.device.hibernate.scrollable.snapshot.DeleteSnapshotEvent;
034: import org.compass.gps.device.hibernate.scrollable.snapshot.HibernateAliasRowSnapshot;
035: import org.compass.gps.device.hibernate.scrollable.snapshot.HibernateSnapshotEventListener;
036: import org.compass.gps.device.jdbc.mapping.IdColumnToPropertyMapping;
037: import org.compass.gps.device.jdbc.mapping.ResultSetToResourceMapping;
038: import org.compass.gps.spi.CompassGpsInterfaceDevice;
039: import org.hibernate.Query;
040: import org.hibernate.ScrollMode;
041: import org.hibernate.ScrollableResults;
042: import org.hibernate.Session;
043:
044: /**
045: * A
046: * {@link org.compass.gps.device.hibernate.scrollable.snapshot.HibernateSnapshotEventListener}
047: * that works with
048: * {@link org.compass.gps.device.hibernate.scrollable.Hibernate3ScrollableResultsGpsDevice} and
049: * performs the changes to the compass index after the change snapshots have
050: * been detected by the device.
051: *
052: * @author kimchy
053: */
054: public class ScrollableResultsSnapshotEventListener implements
055: HibernateSnapshotEventListener {
056:
057: private static Log log = LogFactory
058: .getLog(ScrollableResultsSnapshotEventListener.class);
059:
060: private HashMap createAndUpdateQueries;
061:
062: public void configure(ConfigureSnapshotEvent configureSnapshotEvent)
063: throws HibernateGpsDeviceException {
064: createAndUpdateQueries = new HashMap();
065: for (Iterator it = configureSnapshotEvent.getMappings()
066: .iterator(); it.hasNext();) {
067: ResultSetToResourceMapping mapping = (ResultSetToResourceMapping) it
068: .next();
069: if (!mapping.supportsVersioning()) {
070: continue;
071: }
072: // TODO If there is only one id, need to check if select ID ... IN
073: // () is faster, need also to find how to do it in HQL
074: StringBuffer sb = new StringBuffer();
075: String selectQuery = mapping.getSelectQuery();
076: sb.append(selectQuery);
077: if (selectQuery.indexOf(" where") != -1) {
078: sb.append(" and (");
079: } else {
080: sb.append(" where (");
081: }
082: boolean first = true;
083: for (Iterator idIt = mapping.idMappingsIt(); idIt.hasNext();) {
084: IdColumnToPropertyMapping idMapping = (IdColumnToPropertyMapping) idIt
085: .next();
086: if (idMapping.getColumnNameForVersion() == null) {
087: throw new IllegalArgumentException(
088: "Id Mapping "
089: + idMapping
090: + " must have column name for versioning."
091: + " If you set the column index, you must set the version as well");
092: }
093: if (first) {
094: first = false;
095: } else {
096: sb.append(" and ");
097: }
098: //Note that columnNameForVersion should contain a 'property' expression, not column name!
099: sb.append(idMapping.getColumnNameForVersion());
100: sb.append(" = ?");
101: }
102: sb.append(")");
103: String query = sb.toString();
104: if (log.isDebugEnabled()) {
105: log.debug("Using create/update query [" + query
106: + "] for alias [" + mapping.getAlias() + "]");
107: }
108: createAndUpdateQueries.put(mapping.getAlias(), query);
109: }
110: }
111:
112: public void onDelete(final DeleteSnapshotEvent deleteSnapshotEvent)
113: throws HibernateGpsDeviceException {
114: final ResultSetToResourceMapping mapping = deleteSnapshotEvent
115: .getMapping();
116: CompassGpsInterfaceDevice compassGps = deleteSnapshotEvent
117: .getCompassGps();
118: compassGps.executeForMirror(new CompassCallbackWithoutResult() {
119: protected void doInCompassWithoutResult(
120: CompassSession session) throws CompassException {
121: for (Iterator it = deleteSnapshotEvent
122: .getDeleteSnapshots().iterator(); it.hasNext();) {
123: HibernateAliasRowSnapshot rowSnapshot = (HibernateAliasRowSnapshot) it
124: .next();
125: List ids = rowSnapshot.getIds();
126: if (ids.size() == 1) {
127: session.delete(mapping.getAlias(), ids.get(0));
128: } else {
129: Object[] idsArr = ids.toArray();
130: session.delete(mapping.getAlias(), idsArr);
131: }
132: }
133: }
134: });
135: }
136:
137: public void onCreateAndUpdate(
138: final CreateAndUpdateSnapshotEvent createAndUpdateSnapshotEvent)
139: throws HibernateGpsDeviceException {
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 HibernateGpsDeviceException {
152: final ResultSetToResourceMapping mapping = createAndUpdateSnapshotEvent
153: .getMapping();
154: CompassGpsInterfaceDevice compassGps = createAndUpdateSnapshotEvent
155: .getCompassGps();
156: compassGps.executeForMirror(new CompassCallbackWithoutResult() {
157: protected void doInCompassWithoutResult(
158: CompassSession session) throws CompassException {
159: String query = (String) createAndUpdateQueries
160: .get(mapping.getAlias());
161:
162: try {
163: Session s = createAndUpdateSnapshotEvent
164: .getSession();
165: Query hibernateQuery = s.createQuery(query);
166: for (Iterator it = snapshots.iterator(); it
167: .hasNext();) {
168: HibernateAliasRowSnapshot rowSnapshot = (HibernateAliasRowSnapshot) it
169: .next();
170: Resource resource = ((InternalCompassSession) session)
171: .getCompass().getResourceFactory()
172: .createResource(mapping.getAlias());
173: Hibernate3ScrollableResultsRowMarshallHelper marshallHelper = new Hibernate3ScrollableResultsRowMarshallHelper(
174: mapping, session, resource);
175: //XXX: clearParameters of hibernateQuery?
176: List ids = rowSnapshot.getIds();
177: for (int i = 0; i < ids.size(); i++) {
178: Object idValue = ids.get(i);
179: hibernateQuery.setParameter(i, idValue);
180: }
181:
182: String[] returnAliases = hibernateQuery
183: .getReturnAliases();
184: ScrollableResults rs = hibernateQuery
185: .scroll(ScrollMode.FORWARD_ONLY);
186: if (!rs.next()) {
187: // it was deleted between the calls, do nothing
188: continue;
189: }
190: rs.close();
191:
192: marshallHelper.marshallResultSet(rs,
193: returnAliases);
194: if (useCreate) {
195: session.create(resource);
196: } else {
197: session.save(resource);
198: }
199: session.evictAll();
200: }
201: } catch (Exception e) {
202: throw new HibernateGpsDeviceException(
203: "Failed to execute query for create/update",
204: e);
205: } finally {
206: //TODO: close Session?
207: // maybe keeping Session in the events is not a good idea
208: // -> keep the SessionWrapper in event?
209: // or close session somewhere else
210: //(session will also be closed on committing the transaction)
211: }
212: }
213: });
214: }
215: }
|