clusternode.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 1,278 行 · 第 1/3 页

JAVA
1,278
字号
/* * 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.cluster;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.apache.jackrabbit.core.config.ClusterConfig;import org.apache.jackrabbit.core.config.ConfigurationException;import org.apache.jackrabbit.core.config.JournalConfig;import org.apache.jackrabbit.core.NodeId;import org.apache.jackrabbit.core.journal.Journal;import org.apache.jackrabbit.core.journal.RecordConsumer;import org.apache.jackrabbit.core.journal.Record;import org.apache.jackrabbit.core.journal.JournalException;import org.apache.jackrabbit.core.journal.FileRevision;import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;import org.apache.jackrabbit.core.nodetype.NodeTypeDef;import org.apache.jackrabbit.core.observation.EventState;import org.apache.jackrabbit.core.observation.EventStateCollection;import org.apache.jackrabbit.core.state.ChangeLog;import org.apache.jackrabbit.core.state.ItemState;import org.apache.jackrabbit.core.state.NodeState;import org.apache.jackrabbit.core.state.PropertyState;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.Path;import EDU.oswego.cs.dl.util.concurrent.Mutex;import javax.jcr.RepositoryException;import javax.jcr.Session;import javax.jcr.observation.Event;import java.util.List;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Collection;import java.util.Iterator;import java.util.Set;import java.util.HashSet;import java.io.File;/** * Default clustered node implementation. */public class ClusterNode implements Runnable,        NamespaceEventChannel, NodeTypeEventChannel, RecordConsumer  {    /**     * System property specifying a node id to use.     */    public static final String SYSTEM_PROPERTY_NODE_ID = "org.apache.jackrabbit.core.cluster.node_id";    /**     * Revision counter parameter name.     */    private static final String REVISION_NAME = "revision";    /**     * Used for padding short string representations.     */    private static final String SHORT_PADDING = "0000";    /**     * Producer identifier.     */    private static final String PRODUCER_ID = "JR";    /**     * Status constant.     */    private static final int NONE = 0;    /**     * Status constant.     */    private static final int STARTED = 1;    /**     * Status constant.     */    private static final int STOPPED = 2;    /**     * Bit indicating this is a registration operation.     */    private static final int NTREG_REGISTER = 0;    /**     * Bit indicating this is a reregistration operation.     */    private static final int NTREG_REREGISTER = (1 << 30);    /**     * Bit indicating this is an unregistration operation.     */    private static final int NTREG_UNREGISTER = (1 << 31);    /**     * Mask used in node type registration operations.     */    private static final int NTREG_MASK = (NTREG_REREGISTER | NTREG_UNREGISTER);    /**     * Logger.     */    private static Logger log = LoggerFactory.getLogger(ClusterNode.class);    /**     * Cluster context.     */    private ClusterContext clusterContext;    /**     * Cluster node id.     */    private String clusterNodeId;    /**     * Synchronization delay, in milliseconds.     */    private long syncDelay;    /**     * Journal used.     */    private Journal journal;    /**     * Mutex used when syncing.     */    private final Mutex syncLock = new Mutex();    /**     * Status flag, one of {@link #NONE}, {@link #STARTED} or {@link #STOPPED}.     */    private int status;    /**     * Map of available lock listeners, indexed by workspace name.     */    private final Map wspLockListeners = new HashMap();    /**     * Map of available update listeners, indexed by workspace name.     */    private final Map wspUpdateListeners = new HashMap();    /**     * Versioning update listener.     */    private UpdateEventListener versionUpdateListener;    /**     * Namespace listener.     */    private NamespaceEventListener namespaceListener;    /**     * Node type listener.     */    private NodeTypeEventListener nodeTypeListener;    /**     * Instance revision file.     */    private FileRevision instanceRevision;    /**     * Workspace name used when consuming records.     */    private String workspace;    /**     * Change log used when consuming records.     */    private ChangeLog changeLog;    /**     * List of recorded events; used when consuming records.     */    private List events;    /**     * Last used session for event sources.     */    private Session lastSession;    /**     * Initialize this cluster node.     *     * @throws ClusterException if an error occurs     */    public void init(ClusterContext clusterContext) throws ClusterException {        this.clusterContext = clusterContext;        init();    }    /**     * Initialize this cluster node (overridable).     *     * @throws ClusterException if an error occurs     */    protected void init() throws ClusterException {        ClusterConfig cc = clusterContext.getClusterConfig();        clusterNodeId = getClusterNodeId(cc.getId());        syncDelay = cc.getSyncDelay();        JournalConfig jc = cc.getJournalConfig();        String revisionName = jc.getParameters().getProperty(REVISION_NAME);        if (revisionName == null) {            String msg = "Revision not specified.";            throw new ClusterException(msg);        }        try {            instanceRevision = new FileRevision(new File(revisionName));            journal = (Journal) jc.newInstance();            journal.init(clusterNodeId, clusterContext.getNamespaceResovler());            journal.register(this);        } catch (ConfigurationException e) {            throw new ClusterException(e.getMessage(), e.getCause());        } catch (JournalException e) {            throw new ClusterException(e.getMessage(), e.getCause());        }    }    /**     * Starts this cluster node.     *     * @throws ClusterException if an error occurs     */    public synchronized void start() throws ClusterException {        if (status == NONE) {            sync();            Thread t = new Thread(this, "ClusterNode-" + clusterNodeId);            t.setDaemon(true);            t.start();            status = STARTED;        }    }    /**     * Run loop that will sync this node after some delay.     */    public void run() {        for (;;) {            synchronized (this) {                try {                    wait(syncDelay);                } catch (InterruptedException e) {}                if (status == STOPPED) {                    return;                }            }            try {                sync();            } catch (ClusterException e) {                String msg = "Periodic sync of journal failed: " + e.getMessage();                log.error(msg);            } catch (Exception e) {                String msg = "Unexpected error while syncing of journal: " + e.getMessage();                log.error(msg, e);            } catch (Error e) {                String msg = "Unexpected error while syncing of journal: " + e.getMessage();                log.error(msg, e);                throw e;            }        }    }    /**     * Synchronize contents from journal.     *     * @throws ClusterException if an error occurs     */    public void sync() throws ClusterException {        try {            syncLock.acquire();        } catch (InterruptedException e) {            String msg = "Interrupted while waiting for mutex.";            throw new ClusterException(msg);        }        try {            journal.sync();        } catch (JournalException e) {            throw new ClusterException(e.getMessage(), e.getCause());        } finally {            syncLock.release();        }    }    /**     * Stops this cluster node.     */    public synchronized void stop() {        if (status == STARTED) {            status = STOPPED;            journal.close();            notifyAll();        }    }    /**     * Create an {@link UpdateEventChannel} for some workspace.     *     * @param workspace workspace name     * @return lock event channel     */    public UpdateEventChannel createUpdateChannel(String workspace) {        return new WorkspaceUpdateChannel(workspace);    }    /**     * Create a {@link LockEventChannel} for some workspace.     *     * @param workspace workspace name     * @return lock event channel     */    public LockEventChannel createLockChannel(String workspace) {        return new WorkspaceLockChannel(workspace);    }    /**     * Return the instance id to be used for this node in the cluster.     * @param id configured id, <code>null</code> to take random id     */    private String getClusterNodeId(String id) {        if (id == null) {            id = System.getProperty(SYSTEM_PROPERTY_NODE_ID);            if (id == null) {                id = toHexString((short) (Math.random() * (Short.MAX_VALUE - Short.MIN_VALUE)));            }        }        return id;    }    /**     * Return a zero-padded short string representation.     *     * @param n short     * @return string representation     */    private static String toHexString(short n) {        String s = Integer.toHexString(n);        int padlen = SHORT_PADDING.length() - s.length();        if (padlen < 0) {            s = s.substring(-padlen);        } else if (padlen > 0) {            s = SHORT_PADDING.substring(0, padlen) + s;        }        return s;    }    //-----------------------------------------------< NamespaceEventListener >    /**     * {@inheritDoc}     */    public void remapped(String oldPrefix, String newPrefix, String uri) {        if (status != STARTED) {            log.info("not started: namespace operation ignored.");            return;        }        Record record = null;        boolean succeeded = false;        try {            record = journal.getProducer(PRODUCER_ID).append();            record.writeString(null);            write(record, oldPrefix, newPrefix, uri);            record.writeChar('\0');            record.update();            setRevision(record.getRevision());            succeeded = true;        } catch (JournalException e) {            String msg = "Unable to create log entry: " + e.getMessage();            log.error(msg);        } catch (Throwable e) {            String msg = "Unexpected error while creating log entry.";            log.error(msg, e);        } finally {            if (!succeeded && record != null) {                record.cancelUpdate();            }        }    }    public void setListener(NamespaceEventListener listener) {        namespaceListener = listener;    }    //------------------------------------------------< NodeTypeEventListener >    /**     * {@inheritDoc}     */    public void registered(Collection ntDefs) {        if (status != STARTED) {            log.info("not started: nodetype operation ignored.");            return;        }        Record record = null;        boolean succeeded = false;        try {            record = journal.getProducer(PRODUCER_ID).append();

⌨️ 快捷键说明

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