/**
* Copyright (c) Codice Foundation
* <p/>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p/>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.catalog.operation;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.slf4j.LoggerFactory;
import org.slf4j.ext.XLogger;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
/**
*
* @deprecated As of release 2.3.0, replaced by
* ddf.catalog.operation.impl.QueryResponseImpl
*
*/
@Deprecated
public class QueryResponseImpl extends ResponseImpl<QueryRequest> implements QueryResponse {
private static final XLogger LOGGER = new XLogger(
LoggerFactory.getLogger(QueryResponseImpl.class));
protected static Result poisonPillResult = new POISON_PILL_RESULT();
protected long hits;
protected Set<ProcessingDetails> details = new HashSet<ProcessingDetails>();
protected boolean isQueueClosed = false;
LinkedBlockingQueue<Result> queue = null;
List<Result> resultList = null;
/**
* Instantiates a new QueryResponseImpl with a $(@link QueryRequest)
*
* @param request
* the request
*/
public QueryResponseImpl(QueryRequest request) {
this(request, new HashMap<String, Serializable>());
}
/**
* Instantiates a new QueryResponseImpl with a $(@link QueryRequest) and and a ${@link Map} of
* properties
*
* @param request
* the request
* @param properties
*/
public QueryResponseImpl(QueryRequest request, Map<String, Serializable> properties) {
this(request, null, false, 0, properties);
}
/**
* Instantiates a new QueryResponseImpl with a $(@link QueryRequest) and and a ${@link List} of
* results
*
* @param request
* the request
* @param results
* the results
*/
public QueryResponseImpl(QueryRequest request, List<Result> results, long totalHits) {
this(request, results, true, totalHits, null);
}
/**
* Instantiates a new QueryResponseImpl with a $(@link QueryRequest), a ${@link List} of
* results, a closeResultQueue indicator, and a number of hits to return
*
* @param request
* the request
* @param results
* the results
* @param hits
* the hits
*/
public QueryResponseImpl(QueryRequest request, List<Result> results, boolean closeResultQueue,
long hits) {
this(request, results, closeResultQueue, hits, null);
}
/**
* Instantiates a new QueryResponseImpl with a $(@link QueryRequest), a ${@link List} of
* results, a closeResultQueue indicator, a number of hits to return, and a ${@link Map} of
* properties
*
* @param request
* the request
* @param results
* the results
* @param hits
* the hits
* @param properties
* the properties
*/
public QueryResponseImpl(QueryRequest request, List<Result> results, boolean closeResultQueue,
long hits, Map<String, Serializable> properties) {
super(request, properties);
this.hits = hits;
queue = results == null ?
new LinkedBlockingQueue<Result>() :
new LinkedBlockingQueue<Result>(results);
resultList = new ArrayList<Result>();
if (closeResultQueue) {
closeResultQueue();
}
}
/**
* Construct from an underlying {@link SourceResponse}
*
* @param response
* @param sourceId
*/
public QueryResponseImpl(SourceResponse response, String sourceId) {
this(response == null ? null : response.getRequest(),
response == null ? null : response.getResults(),
response == null ? -1 : response.getHits());
Set<? extends SourceProcessingDetails> sourceDetails = null;
if (response != null) {
sourceDetails = response.getProcessingDetails();
this.setProperties(response.getProperties());
} else {
setProperties(new HashMap<String, Serializable>());
}
// Not every response will contain details
if (sourceDetails != null) {
for (SourceProcessingDetails detail : sourceDetails) {
this.details.add(new ProcessingDetailsImpl(detail, sourceId));
}
}
}
// /**
// * Wrap a {@link QueryResponse} and add additional {@link
// ProcessingDetails}
// *
// * @param response
// * @param exceptions
// */
// public QueryResponseImpl(QueryResponse response,
// Set<ProcessingDetails> exceptions) {
//
//
// }
@Override
public long getHits() {
return hits;
}
public void setHits(long hits) {
this.hits = hits;
}
@Override
public Set<ProcessingDetails> getProcessingDetails() {
return details;
}
public void setProcessingDetails(Set<ProcessingDetails> set) {
this.details = set;
}
@Override
public List<Result> getResults() {
Result result = null;
while (hasMoreResults() && (result = take()) != null) {
resultList.add(result);
}
return resultList;
}
/**
* Adds a ${@link Result} to this QueryResponse, and specifies whether or not to close the queue
*
* @param result
* the result
* @param closeQueue
* the indicator for closing of the queue
*/
public void addResult(Result result, boolean closeQueue) {
if (result != null) {
if (isQueueClosed) {
throw new IllegalStateException(
"Cannot add new Results after the Queue has been closed");
} else {
if (closeQueue) {
queue.add(result);
closeResultQueue();
} else {
queue.add(result);
}
}
} else {
throw new IllegalArgumentException("Result cannot be null");
}
}
/**
* Adds a ${@link List} of ${@link Result}s to this QueryResponse, and specifies whether or not
* to close the queue
*
* @param results
* the results
* @param closeQueue
* the indicator for closing of the queue
*/
public void addResults(List<Result> results, boolean closeQueue) {
if (results != null) {
if (isQueueClosed) {
throw new IllegalStateException(
"Cannot add new Results after the Queue has been closed");
} else {
if (closeQueue) {
queue.addAll(results);
closeResultQueue();
} else {
queue.addAll(results);
}
}
}
}
@Override
public boolean hasMoreResults() {
return !queue.isEmpty() || !isQueueClosed;
}
public void closeResultQueue() {
isQueueClosed = true;
queue.add(poisonPillResult);
}
@Override
public Result poll() {
return hasMoreResults() ? queue.poll() : null;
}
@Override
public Result poll(long timeout) {
Result result = null;
if (hasMoreResults()) {
try {
result = queue.poll(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
LOGGER.warn(
"QueryResponseImpl queue thread was interrputed. Returning null for last result");
}
}
return result;
}
@Override
public Result take() {
return hasMoreResults() ? handleTake() : null;
}
@Override
public List<Result> take(long size) {
List<Result> results = new ArrayList<Result>();
if (hasMoreResults()) {
Result result = null;
for (int i = 0; i < size && (result = handleTake()) != null; i++) {
results.add(result);
}
}
return results;
}
/**
* Returns a result off of the queue
*
* @return result the result
*/
private Result handleTake() {
Result result = null;
try {
result = queue.take();
if (result == poisonPillResult) {
result = null;
}
} catch (InterruptedException e) {
LOGGER.warn(
"QueryResponseImpl queue thread was interrputed. Returning null for last result");
}
return result;
}
protected static class POISON_PILL_RESULT implements Result {
@Override
public Double getRelevanceScore() {
return null;
}
@Override
public Double getDistanceInMeters() {
return null;
}
@Override
public Metacard getMetacard() {
return null;
}
}
}