Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.rya.mongodb.iter; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; import org.apache.accumulo.core.security.Authorizations; import org.apache.log4j.Logger; import org.apache.rya.api.RdfCloudTripleStoreUtils; import org.apache.rya.api.domain.RyaStatement; import org.apache.rya.api.domain.RyaType; import org.apache.rya.api.persist.RyaDAOException; import org.apache.rya.mongodb.dao.MongoDBStorageStrategy; import org.apache.rya.mongodb.document.operators.aggregation.AggregationUtil; import org.bson.Document; import org.openrdf.query.BindingSet; import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterators; import com.google.common.collect.Multimap; import com.mongodb.DBObject; import com.mongodb.client.AggregateIterable; import com.mongodb.client.MongoCollection; import com.mongodb.util.JSON; import info.aduna.iteration.CloseableIteration; public class RyaStatementBindingSetCursorIterator implements CloseableIteration<Entry<RyaStatement, BindingSet>, RyaDAOException> { private static final Logger log = Logger.getLogger(RyaStatementBindingSetCursorIterator.class); private static final int QUERY_BATCH_SIZE = 50; private final MongoCollection<Document> coll; private final Multimap<RyaStatement, BindingSet> rangeMap; private final Multimap<RyaStatement, BindingSet> executedRangeMap = HashMultimap.create(); private final Iterator<RyaStatement> queryIterator; private Iterator<Document> batchQueryResultsIterator; private RyaStatement currentResultStatement; private Iterator<BindingSet> currentBindingSetIterator; private final MongoDBStorageStrategy<RyaStatement> strategy; private final Authorizations auths; public RyaStatementBindingSetCursorIterator(final MongoCollection<Document> coll, final Multimap<RyaStatement, BindingSet> rangeMap, final MongoDBStorageStrategy<RyaStatement> strategy, final Authorizations auths) { this.coll = coll; this.rangeMap = rangeMap; queryIterator = rangeMap.keySet().iterator(); this.strategy = strategy; this.auths = auths; } @Override public boolean hasNext() { if (!currentBindingSetIteratorIsValid()) { findNextResult(); } return currentBindingSetIteratorIsValid(); } @Override public Entry<RyaStatement, BindingSet> next() { if (!currentBindingSetIteratorIsValid()) { findNextResult(); } if (currentBindingSetIteratorIsValid()) { final BindingSet currentBindingSet = currentBindingSetIterator.next(); return new RdfCloudTripleStoreUtils.CustomEntry<RyaStatement, BindingSet>(currentResultStatement, currentBindingSet); } return null; } private boolean currentBindingSetIteratorIsValid() { return (currentBindingSetIterator != null) && currentBindingSetIterator.hasNext(); } private void findNextResult() { if (!currentBatchQueryResultCursorIsValid()) { submitBatchQuery(); } if (currentBatchQueryResultCursorIsValid()) { // convert to Rya Statement final Document queryResult = batchQueryResultsIterator.next(); final DBObject dbo = (DBObject) JSON.parse(queryResult.toJson()); currentResultStatement = strategy.deserializeDBObject(dbo); // Find all of the queries in the executed RangeMap that this result matches // and collect all of those binding sets Set<BindingSet> bsList = new HashSet<>(); for (RyaStatement executedQuery : executedRangeMap.keys()) { if (isResultForQuery(executedQuery, currentResultStatement)) { bsList.addAll(executedRangeMap.get(executedQuery)); } } currentBindingSetIterator = bsList.iterator(); } // Handle case of invalid currentResultStatement or no binding sets returned if ((currentBindingSetIterator == null || !currentBindingSetIterator.hasNext()) && (currentBatchQueryResultCursorIsValid() || queryIterator.hasNext())) { findNextResult(); } } private static boolean isResultForQuery(RyaStatement query, RyaStatement result) { return isResult(query.getSubject(), result.getSubject()) && isResult(query.getPredicate(), result.getPredicate()) && isResult(query.getObject(), result.getObject()) && isResult(query.getContext(), result.getContext()); } private static boolean isResult(RyaType query, RyaType result) { return (query == null) || query.equals(result); } private void submitBatchQuery() { int count = 0; executedRangeMap.clear(); final List<Document> pipeline = new ArrayList<>(); final List<DBObject> match = new ArrayList<>(); while (queryIterator.hasNext() && count < QUERY_BATCH_SIZE) { count++; RyaStatement query = queryIterator.next(); executedRangeMap.putAll(query, rangeMap.get(query)); final DBObject currentQuery = strategy.getQuery(query); match.add(currentQuery); } if (match.size() > 1) { pipeline.add(new Document("$match", new Document("$or", match))); } else if (match.size() == 1) { pipeline.add(new Document("$match", match.get(0))); } else { batchQueryResultsIterator = Iterators.emptyIterator(); return; } // Executing redact aggregation to only return documents the user has access to. pipeline.addAll(AggregationUtil.createRedactPipeline(auths)); log.info(pipeline); final AggregateIterable<Document> aggIter = coll.aggregate(pipeline); aggIter.batchSize(1000); batchQueryResultsIterator = aggIter.iterator(); } private boolean currentBatchQueryResultCursorIsValid() { return (batchQueryResultsIterator != null) && batchQueryResultsIterator.hasNext(); } @Override public void close() throws RyaDAOException { // TODO don't know what to do here } @Override public void remove() throws RyaDAOException { next(); } }