abstractjournal.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 323 行

JAVA
323
字号
/* * 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 EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;import java.util.Map;import java.util.HashMap;import java.util.Iterator;import java.io.InputStream;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.apache.jackrabbit.name.NamespaceResolver;/** * Base journal implementation. */public abstract class AbstractJournal implements Journal {    /**     * Logger.     */    private static Logger log = LoggerFactory.getLogger(AbstractJournal.class);    /**     * Journal id.     */    private String id;    /**     * Namespace resolver.     */    private NamespaceResolver resolver;    /**     * Map of registered consumers.     */    private final Map consumers = new HashMap();    /**     * Map of registered producers.     */    private final Map producers = new HashMap();    /**     * Journal lock, allowing multiple readers (synchronizing their contents)     * but only one writer (appending a new entry).     */    private final ReadWriteLock rwLock = new ReentrantWriterPreferenceReadWriteLock();    /**     * {@inheritDoc}     */    public void init(String id, NamespaceResolver resolver) throws JournalException {        this.id = id;        this.resolver = resolver;    }    /**     * {@inheritDoc}     */    public void register(RecordConsumer consumer) throws JournalException {        synchronized (consumers) {            String consumerId = consumer.getId();            if (consumers.containsKey(consumerId)) {                String msg = "Record consumer with identifier '" +                        consumerId + "' already registered.";                throw new JournalException(msg);            }            consumers.put(consumerId, consumer);        }    }    /**     * {@inheritDoc}     */    public boolean unregister(RecordConsumer consumer) {        synchronized (consumers) {            String consumerId = consumer.getId();            return consumers.remove(consumerId) != null;        }    }    /**     * Return the consumer given its identifier.     *     * @param identifier identifier     * @return consumer associated with identifier;     *         <code>null</code> if no consumer is associated with identifier     */    public RecordConsumer getConsumer(String identifier) {        synchronized (consumers) {            return (RecordConsumer) consumers.get(identifier);        }    }    /**     * {@inheritDoc}     */    public RecordProducer getProducer(String identifier) {        synchronized (producers) {            RecordProducer producer = (RecordProducer) producers.get(identifier);            if (producer == null) {                producer = createProducer(identifier);                producers.put(identifier, producer);            }            return producer;        }    }    /**     * Create the record producer for a given identifier. May be overridden     * by subclasses.     *     * @param identifier producer identifier     */    protected RecordProducer createProducer(String identifier) {        return new DefaultRecordProducer(this, identifier);    }    /**     * Return the minimal revision of all registered consumers.     */    private long getMinimalRevision() {        long minimalRevision = Long.MAX_VALUE;        synchronized (consumers) {            Iterator iter = consumers.values().iterator();            while (iter.hasNext()) {                RecordConsumer consumer = (RecordConsumer) iter.next();                if (consumer.getRevision() < minimalRevision) {                    minimalRevision = consumer.getRevision();                }            }        }        return minimalRevision;    }    /**     * {@inheritDoc}     */    public void sync() throws JournalException {        try {            rwLock.readLock().acquire();        } catch (InterruptedException e) {            String msg = "Unable to acquire read lock.";            throw new JournalException(msg, e);        }        try {            doSync(getMinimalRevision());        } finally {            rwLock.readLock().release();        }    }    /**     * Synchronize contents from journal. May be overridden by subclasses.     *     * @param startRevision start point (exlusive)     * @throws JournalException if an error occurs     */    protected void doSync(long startRevision) throws JournalException {        RecordIterator iterator = getRecords(startRevision);        long stopRevision = Long.MIN_VALUE;        try {            while (iterator.hasNext()) {                Record record = iterator.nextRecord();                if (record.getJournalId().equals(id)) {                    log.info("Record with revision '" + record.getRevision() +                            "' created by this journal, skipped.");                } else {                    RecordConsumer consumer = getConsumer(record.getProducerId());                    if (consumer != null) {                        consumer.consume(record);                    }                }                stopRevision = record.getRevision();            }        } finally {            iterator.close();        }        if (stopRevision > 0) {            Iterator iter = consumers.values().iterator();            while (iter.hasNext()) {                RecordConsumer consumer = (RecordConsumer) iter.next();                consumer.setRevision(stopRevision);            }            log.info("Synchronized to revision: " + stopRevision);        }    }    /**     * Return an iterator over all records after the specified revision.     * Subclass responsibility.     *     * @param startRevision start point (exlusive)     * @throws JournalException if an error occurs     */    protected abstract RecordIterator getRecords(long startRevision)            throws JournalException;    /**     * Lock the journal revision, disallowing changes from other sources until     * {@link #unlock has been called, and synchronizes to the latest change.     *     * @throws JournalException if an error occurs     */    public void lockAndSync() throws JournalException {        try {            rwLock.writeLock().acquire();        } catch (InterruptedException e) {            String msg = "Unable to acquire write lock.";            throw new JournalException(msg, e);        }        boolean succeeded = false;        try {            // lock            doLock();            try {                // and sync                doSync(getMinimalRevision());                succeeded = true;            } finally {                if (!succeeded) {                    doUnlock(false);                }            }        } finally {            if (!succeeded) {                rwLock.writeLock().release();            }        }    }    /**     * Unlock the journal revision.     *     * @param successful flag indicating whether the update process was     *                   successful     */    public void unlock(boolean successful) {        doUnlock(successful);        rwLock.writeLock().release();    }    /**     * Lock the journal revision. Subclass responsibility.     *     * @throws JournalException if an error occurs     */    protected abstract void doLock() throws JournalException;    /**     * Notification method called by an appended record at creation time.     * May be overridden by subclasses to save some context information     * inside the appended record.     *     * @param record record that was appended     */    protected void appending(AppendRecord record) {        // nothing to be done here    }    /**     * Append a record backed by a file. On exit, the new revision must have     * been set inside the appended record. Subclass responsibility.     *     * @param record record to append     * @param in input stream     * @param length number of bytes in input stream     *     * @throws JournalException if an error occurs     */    protected abstract void append(AppendRecord record, InputStream in, int length)            throws JournalException;    /**     * Unlock the journal revision. Subclass responsibility.     *     * @param successful flag indicating whether the update process was     *                   successful     */    protected abstract void doUnlock(boolean successful);    /**     * Return this journal's identifier.     *     * @return journal identifier     */    public String getId() {        return id;    }    /**     * Return this journal's namespace resolver.     *     * @return namespace resolver     */    public NamespaceResolver getResolver() {        return resolver;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?