/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Florent Guillaume */ package org.eclipse.ecr.core.storage.sql.coremodel; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.api.DocumentException; import org.eclipse.ecr.core.api.DocumentModel; import org.eclipse.ecr.core.api.DocumentModelFactory; import org.eclipse.ecr.core.api.DocumentModelList; import org.eclipse.ecr.core.api.impl.DocumentModelListImpl; import org.eclipse.ecr.core.model.Document; import org.eclipse.ecr.core.model.DocumentIterator; import org.eclipse.ecr.core.model.EmptyDocumentIterator; import org.eclipse.ecr.core.query.QueryException; import org.eclipse.ecr.core.query.QueryResult; import org.eclipse.ecr.core.storage.PartialList; /** * @author Florent Guillaume */ public class SQLQueryResult implements QueryResult { private static final Log log = LogFactory.getLog(SQLQueryResult.class); protected final SQLSession session; protected final Iterator<Serializable> it; protected final long size; protected final long totalSize; /** When not null, order documents models by path asc (true) or desc (false) */ protected final Boolean orderByPath; protected final int limit; protected final int offset; protected Serializable currentId; public SQLQueryResult(SQLSession session, PartialList<Serializable> pl, Boolean orderByPath, long limit, long offset) { this.session = session; it = pl.list.iterator(); size = pl.list.size(); this.totalSize = pl.totalSize; this.orderByPath = orderByPath; this.limit = (int) limit; this.offset = (int) offset; } @Override public long count() { return size; } @Override public long getTotalSize() { return totalSize; } @Override public boolean isEmpty() { return size == 0; } @Override public DocumentModelList getDocumentModels() throws QueryException { // get ids List<Serializable> ids = new ArrayList<Serializable>((int) size); while (it.hasNext()) { ids.add(it.next()); } // get Documents in bulk List<Document> docs; try { docs = session.getDocumentsById(ids); } catch (DocumentException e) { log.error("Could not fetch documents for ids: " + ids, e); docs = Collections.emptyList(); } // build DocumentModels from Documents String[] schemas = { "common" }; List<DocumentModel> list = new ArrayList<DocumentModel>((int) size); for (Document doc : docs) { try { list.add(DocumentModelFactory.createDocumentModel(doc, schemas)); } catch (DocumentException e) { log.error("Could not create document model for doc: " + doc, e); } } // order / limit if (orderByPath != null) { Collections.sort(list, new PathComparator( orderByPath.booleanValue())); } if (limit != 0) { // do limit/offset by hand int size = list.size(); list.subList(0, offset > size ? size : offset).clear(); size = list.size(); if (limit < size) { list.subList(limit, size).clear(); } } return new DocumentModelListImpl(list, totalSize); } public static class PathComparator implements Comparator<DocumentModel> { private final int sign; public PathComparator(boolean asc) { this.sign = asc ? 1 : -1; } @Override public int compare(DocumentModel doc1, DocumentModel doc2) { String p1 = doc1.getPathAsString(); String p2 = doc2.getPathAsString(); if (p1 == null && p2 == null) { return sign * doc1.getId().compareTo(doc2.getId()); } else if (p1 == null) { return sign; } else if (p2 == null) { return -1 * sign; } return sign * p1.compareTo(p2); } } @Override public DocumentIterator getDocuments(int start) { // initial skip for (int i = 0; i < start; i++) { if (it.hasNext()) { it.next(); } else { return EmptyDocumentIterator.INSTANCE; } } return new DocumentIterator() { @Override public Document next() { currentId = it.next(); try { return session.getDocumentById(currentId); } catch (DocumentException e) { log.error(e.getMessage()); return next(); } } @Override public boolean hasNext() { return it.hasNext(); } @Override public long getSize() { return size; } @Override public void remove() { } }; } @Override public boolean next() { if (!it.hasNext()) { return false; } currentId = it.next(); return true; } @Override public Object getObject() throws QueryException { throw new UnsupportedOperationException(); } @Override public long row() { throw new UnsupportedOperationException(); } @Override public boolean getBoolean(int i) throws QueryException { throw new UnsupportedOperationException(); } @Override public boolean getBoolean(String column) throws QueryException { throw new UnsupportedOperationException(); } @Override public double getDouble(int i, double defaultValue) throws QueryException { throw new UnsupportedOperationException(); } @Override public double getDouble(String column, double defaultValue) throws QueryException { throw new UnsupportedOperationException(); } @Override public long getLong(int i, long defaultValue) throws QueryException { throw new UnsupportedOperationException(); } @Override public long getLong(String column, long defaultValue) throws QueryException { throw new UnsupportedOperationException(); } @Override public Object getObject(String column) throws QueryException { throw new UnsupportedOperationException(); } @Override public String getString(int i) throws QueryException { throw new UnsupportedOperationException(); } @Override public String getString(String column) throws QueryException { throw new UnsupportedOperationException(); } }