org.protempa.backend.dsb.relationaldb.InboundReferenceResultSetIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of protempa-dsb-relationaldb Show documentation
Show all versions of protempa-dsb-relationaldb Show documentation
Implements support for retrieving data from relational
databases.
The newest version!
package org.protempa.backend.dsb.relationaldb;
/*
* #%L
* Protempa Relational Database Data Source Backend
* %%
* Copyright (C) 2012 - 2013 Emory University
* %%
* 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.
* #L%
*/
import org.protempa.DataSourceReadException;
import org.protempa.DataStreamingEvent;
import org.protempa.DataStreamingEventIterator;
import org.protempa.UniqueIdPair;
import org.protempa.proposition.UniqueId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Iterates over the references. This does not entirely adhere to the
* {@link java.util.Iterator} contract, because it relies on another class to
* populate it while iteration is occurring.
*
* @author Michel Mansour
*/
final class InboundReferenceResultSetIterator implements
DataStreamingEventIterator {
private static final Logger LOGGER = Logger.getLogger(InboundReferenceResultSetIterator.class.getName());
/*
* For many-to-one references, we will get multiple instances of the same
* reference back. This map ensures that we will only deliver one
* instance of each reference.
*/
private Map> referenceUniqueIds;
private Queue> dataStreamingEventQueue;
private String keyId;
private boolean end = false;
private final String entityName;
private String lastDelivered;
private boolean nextInvoked = false;
private boolean addUniqueIdsInvoked = false;
InboundReferenceResultSetIterator(String entityName) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Creating reference iterator for {0}", new Object[]{entityName});
}
this.entityName = entityName;
this.referenceUniqueIds = new HashMap<>();
this.dataStreamingEventQueue = new LinkedList<>();
}
void resultSetComplete() {
this.end = true;
createDataStreamingEvent();
}
private boolean isDone() {
return this.dataStreamingEventQueue.isEmpty() && this.end;
}
@Override
public boolean hasNext() throws DataSourceReadException {
return !isDone();
}
@Override
public DataStreamingEvent next() throws DataSourceReadException {
if (LOGGER.isLoggable(Level.FINEST)) {
if (!this.nextInvoked) {
this.nextInvoked = true;
LOGGER.log(Level.FINEST, "First invocation of next() for {0} reference iterator", this.entityName);
}
}
if (isDone()) {
throw new NoSuchElementException("dataStreamingEventQueue is "
+ "empty");
}
if (this.keyId == null) {
LOGGER.log(Level.SEVERE, "Fatal error in reference iterator {0}: keyId is null", this.entityName);
LOGGER.log(Level.SEVERE, "Queue has data: {0}", this.dataStreamingEventQueue.isEmpty() ? "no" : "yes");
LOGGER.log(Level.SEVERE, "Unique ids waiting: {0}", (this.referenceUniqueIds == null || this.referenceUniqueIds.isEmpty()) ? "no" : "yes");
}
DataStreamingEvent result;
if (this.dataStreamingEventQueue.isEmpty()) {
/*
* next() might get called ahead of addUniqueIds(). In that
* situation, the queue will be empty. If the queue is empty, then
* send back a DataStreamingEvent with no UniqueIdPairs.
*/
result = new DataStreamingEvent<>(this.keyId,
new ArrayList(0));
} else {
result = this.dataStreamingEventQueue.remove();
}
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST,
"Iterating over references for {0}: Current: {1}, Last Delivered: {2}",
new Object[]{this.entityName, result.getKeyId(),
this.lastDelivered});
}
this.lastDelivered = result.getKeyId();
return result;
}
private static final class DestructuredUniqueIdPair {
private final String referenceName;
private final UniqueId proposition;
DestructuredUniqueIdPair(String referenceName, UniqueId proposition) {
this.referenceName = referenceName;
this.proposition = proposition;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof DestructuredUniqueIdPair) {
DestructuredUniqueIdPair other = (DestructuredUniqueIdPair) o;
return referenceName.equals(other.referenceName)
&& proposition.equals(other.proposition);
}
return false;
}
@Override
public int hashCode() {
int result = 17;
int c = referenceName.hashCode();
result = 31 * result + c;
c = proposition.hashCode();
result = 31 * result + c;
return result;
}
}
private void handleKeyId(String keyId) {
if (this.keyId != null && !this.keyId.equals(keyId)) {
createDataStreamingEvent();
}
this.keyId = keyId;
}
void addUniqueIds(String keyId, UniqueIdPair[] uniqueIds) {
if (LOGGER.isLoggable(Level.FINEST)) {
if (!this.addUniqueIdsInvoked) {
this.addUniqueIdsInvoked = true;
LOGGER.log(Level.FINEST, "First invocation of addUniqueIds for {0}. keyId = {1}", new Object[]{this.entityName, keyId});
}
}
if (keyId == null) {
LOGGER.log(Level.SEVERE, "Adding unique ids for {0} with null keyId", this.entityName);
}
handleKeyId(keyId);
if (uniqueIds != null) {
for (UniqueIdPair uniqueId : uniqueIds) {
if (uniqueId != null) {
DestructuredUniqueIdPair lhs =
new DestructuredUniqueIdPair(
uniqueId.getReferenceName(),
uniqueId.getProposition());
if (!this.referenceUniqueIds.containsKey(lhs)) {
this.referenceUniqueIds.put(lhs,
new HashSet());
}
this.referenceUniqueIds.get(lhs).add(
uniqueId.getReference());
}
}
}
}
private void createDataStreamingEvent() {
if (this.keyId != null) {
List uniqueIds = new ArrayList<>();
for (Map.Entry> e :
this.referenceUniqueIds.entrySet()) {
for (UniqueId refId : e.getValue()) {
uniqueIds.add(new UniqueIdPair(e.getKey().referenceName,
e.getKey().proposition, refId));
}
}
this.dataStreamingEventQueue.offer(
new DataStreamingEvent<>(
this.keyId, uniqueIds));
}
this.referenceUniqueIds =
new HashMap<>();
}
@Override
public void close() throws DataSourceReadException {
this.referenceUniqueIds.clear();
this.referenceUniqueIds = null;
if (!this.dataStreamingEventQueue.isEmpty()) {
LOGGER.log(Level.WARNING, "Closing non-empty data streaming event"
+ " queue for entity {0}. {1} elements remain.",
new Object[]{this.entityName, this.dataStreamingEventQueue.size()});
}
this.dataStreamingEventQueue.clear();
this.dataStreamingEventQueue = null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy