/* * 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.jackrabbit.core.journal; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver; import java.io.File; import java.io.IOException; import java.util.NoSuchElementException; /** * Record cursor that returns unseen revisions in ascending order on every * iteration. */ public class FileRecordIterator implements RecordIterator { /** * Log files to scan for revisions. */ private File[] logFiles; /** * Current revision being visited. */ private long revision; /** * Last revision to visit. */ private long stopRevision; /** * Namespace resolver. */ private NamespaceResolver resolver; /** * Name and Path resolver. */ private NamePathResolver npResolver; /** * Current record log, containing file records. */ private FileRecordLog recordLog; /** * Current record. */ private ReadRecord record; /** * Creates a new instance of this class. * * @param logFiles available log files, sorted ascending by age * @param startRevision start point (exclusive) * @param stopRevision stop point (inclusive) */ public FileRecordIterator(File[] logFiles, long startRevision, long stopRevision, NamespaceResolver resolver, NamePathResolver npResolver) { this.logFiles = logFiles; this.revision = startRevision; this.stopRevision = stopRevision; this.resolver = resolver; this.npResolver = npResolver; } /** * Return a flag indicating whether there are next records. */ public boolean hasNext() { return revision < stopRevision; } /** * {@inheritDoc} */ public Record nextRecord() throws NoSuchElementException, JournalException { if (!hasNext()) { String msg = "No next revision."; throw new NoSuchElementException(msg); } try { if (record != null) { record.close(); record = null; } } catch (IOException e) { close(); String msg = "Unable to skip over record."; throw new JournalException(msg, e); } if (recordLog != null) { if (!recordLog.contains(revision)) { recordLog.close(); recordLog = null; } } try { if (recordLog == null) { recordLog = getRecordLog(revision); } } catch (IOException e) { String msg = "Unable to open record log with revision: " + revision; throw new JournalException(msg, e); } try { record = recordLog.read(resolver, npResolver); revision = record.getRevision(); return record; } catch (IOException e) { String msg = "Unable to read record with revision: " + revision; throw new JournalException(msg, e); } } /** * Close this cursor, releasing its resources. */ public void close() { if (recordLog != null) { recordLog.close(); } } /** * Return record log containing a given revision. * * @param revision revision to locate * @return record log containing that revision * @throws IOException if an I/O error occurs */ private FileRecordLog getRecordLog(long revision) throws IOException { for (int i = 0; i < logFiles.length; i++) { FileRecordLog recordLog = new FileRecordLog(logFiles[i]); if (recordLog.contains(revision)) { recordLog.seek(revision); return recordLog; } } String msg = "No log file found containing revision: " + revision; throw new IOException(msg); } }