databasepersistencemanager.java

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

JAVA
1,245
字号
/* * 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.persistence.db;import org.apache.jackrabbit.core.NodeId;import org.apache.jackrabbit.core.PropertyId;import org.apache.jackrabbit.core.fs.FileSystem;import org.apache.jackrabbit.core.fs.local.LocalFileSystem;import org.apache.jackrabbit.core.persistence.AbstractPersistenceManager;import org.apache.jackrabbit.core.persistence.PMContext;import org.apache.jackrabbit.core.persistence.util.BLOBStore;import org.apache.jackrabbit.core.persistence.util.FileSystemBLOBStore;import org.apache.jackrabbit.core.persistence.util.Serializer;import org.apache.jackrabbit.core.state.ChangeLog;import org.apache.jackrabbit.core.state.ItemState;import org.apache.jackrabbit.core.state.ItemStateException;import org.apache.jackrabbit.core.state.NoSuchItemStateException;import org.apache.jackrabbit.core.state.NodeReferences;import org.apache.jackrabbit.core.state.NodeReferencesId;import org.apache.jackrabbit.core.state.NodeState;import org.apache.jackrabbit.core.state.PropertyState;import org.apache.jackrabbit.core.value.BLOBFileValue;import org.apache.jackrabbit.core.value.InternalValue;import org.apache.jackrabbit.util.Text;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jcr.PropertyType;import javax.jcr.RepositoryException;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.HashMap;import java.util.Iterator;/** * Abstract base class for database persistence managers. This class * contains common functionality for database persistence manager subclasses * that normally differ only in the way the database connection is acquired. * Subclasses should override the {@link #getConnection()} method to return * the configured database connection. * <p> * See the {@link SimpleDbPersistenceManager} for a detailed description * of the available configuration options and database behaviour. */public abstract class DatabasePersistenceManager extends AbstractPersistenceManager {    /**     * Logger instance     */    private static Logger log = LoggerFactory.getLogger(DatabasePersistenceManager.class);    protected static final String SCHEMA_OBJECT_PREFIX_VARIABLE =            "${schemaObjectPrefix}";    protected boolean initialized;    protected String schema;    protected String schemaObjectPrefix;    protected boolean externalBLOBs;    // initial size of buffer used to serialize objects    protected static final int INITIAL_BUFFER_SIZE = 1024;    // jdbc connection    protected Connection con;    // internal flag governing whether an automatic reconnect should be    // attempted after a SQLException had been encountered    protected boolean autoReconnect = true;    // time to sleep in ms before a reconnect is attempted    protected static final int SLEEP_BEFORE_RECONNECT = 10000;    // the map of prepared statements (key: sql stmt, value: prepared stmt)    private HashMap preparedStatements = new HashMap();    // SQL statements for NodeState management    protected String nodeStateInsertSQL;    protected String nodeStateUpdateSQL;    protected String nodeStateSelectSQL;    protected String nodeStateSelectExistSQL;    protected String nodeStateDeleteSQL;    // SQL statements for PropertyState management    protected String propertyStateInsertSQL;    protected String propertyStateUpdateSQL;    protected String propertyStateSelectSQL;    protected String propertyStateSelectExistSQL;    protected String propertyStateDeleteSQL;    // SQL statements for NodeReference management    protected String nodeReferenceInsertSQL;    protected String nodeReferenceUpdateSQL;    protected String nodeReferenceSelectSQL;    protected String nodeReferenceSelectExistSQL;    protected String nodeReferenceDeleteSQL;    // SQL statements for BLOB management    // (if <code>externalBLOBs==false</code>)    protected String blobInsertSQL;    protected String blobUpdateSQL;    protected String blobSelectSQL;    protected String blobSelectExistSQL;    protected String blobDeleteSQL;    /**     * file system where BLOB data is stored     * (if <code>externalBLOBs==true</code>)     */    protected FileSystem blobFS;    /**     * BLOBStore that manages BLOB data in the file system     * (if <code>externalBLOBs==true</code>)     */    protected BLOBStore blobStore;    /**     * Creates a new <code>DatabasePersistenceManager</code> instance.     */    public DatabasePersistenceManager() {        schema = "default";        schemaObjectPrefix = "";        externalBLOBs = true;        initialized = false;    }    //----------------------------------------------------< setters & getters >    public String getSchemaObjectPrefix() {        return schemaObjectPrefix;    }    public void setSchemaObjectPrefix(String schemaObjectPrefix) {        // make sure prefix is all uppercase        this.schemaObjectPrefix = schemaObjectPrefix.toUpperCase();    }    public String getSchema() {        return schema;    }    public void setSchema(String schema) {        this.schema = schema;    }    public boolean isExternalBLOBs() {        return externalBLOBs;    }    public void setExternalBLOBs(boolean externalBLOBs) {        this.externalBLOBs = externalBLOBs;    }    public void setExternalBLOBs(String externalBLOBs) {        this.externalBLOBs = Boolean.valueOf(externalBLOBs).booleanValue();    }    //---------------------------------------------------< PersistenceManager >    /**     * {@inheritDoc}     */    public void init(PMContext context) throws Exception {        if (initialized) {            throw new IllegalStateException("already initialized");        }        // setup jdbc connection        initConnection();        // make sure schemaObjectPrefix consists of legal name characters only        prepareSchemaObjectPrefix();        // check if schema objects exist and create them if necessary        checkSchema();        // build sql statements        buildSQLStatements();        // prepare statements        initPreparedStatements();        if (externalBLOBs) {            /**             * store BLOBs in local file system in a sub directory             * of the workspace home directory             */            LocalFileSystem blobFS = new LocalFileSystem();            blobFS.setRoot(new File(context.getHomeDir(), "blobs"));            blobFS.init();            this.blobFS = blobFS;            blobStore = new FileSystemBLOBStore(blobFS);        } else {            /**             * store BLOBs in db             */            blobStore = new DbBLOBStore();        }        initialized = true;    }    /**     * {@inheritDoc}     */    public synchronized void close() throws Exception {        if (!initialized) {            throw new IllegalStateException("not initialized");        }        try {            // close shared prepared statements            for (Iterator it = preparedStatements.values().iterator(); it.hasNext(); ) {                closeStatement((PreparedStatement) it.next());            }            preparedStatements.clear();            if (externalBLOBs) {                // close BLOB file system                blobFS.close();                blobFS = null;            }            blobStore = null;            // close jdbc connection            closeConnection(con);        } finally {            initialized = false;        }    }    /**     * {@inheritDoc}     */    public synchronized void store(ChangeLog changeLog)            throws ItemStateException {        // temporarily disable automatic reconnect feature        // since the changes need to be persisted atomically        autoReconnect = false;        try {            ItemStateException ise = null;            // number of attempts to store the changes            int trials = 2;            while (trials > 0) {                try {                    super.store(changeLog);                    break;                } catch (ItemStateException e) {                    // catch exception and fall through...                    ise = e;                }                if (ise != null && ise.getCause() instanceof SQLException                        && --trials > 0) {                    // a SQLException has been thrown, try to reconnect                    log.warn("storing changes failed, about to reconnect...", ise.getCause());                    // try to reconnect                    if (reestablishConnection()) {                        // now let's give it another try                        ise = null;                        continue;                    } else {                        // reconnect failed, proceed with error processing                        break;                    }                }            }            if (ise == null) {                // storing the changes succeeded, now commit the changes                try {                    con.commit();                } catch (SQLException e) {                    String msg = "committing change log failed";                    log.error(msg, e);                    throw new ItemStateException(msg, e);                }            } else {                // storing the changes failed, rollback changes                try {                    con.rollback();                } catch (SQLException e) {                    String msg = "rollback of change log failed";                    log.error(msg, e);                }                // re-throw original exception                throw ise;            }        } finally {            // re-enable automatic reconnect feature            autoReconnect = true;        }    }    /**     * {@inheritDoc}     */    public NodeState load(NodeId id)            throws NoSuchItemStateException, ItemStateException {        if (!initialized) {            throw new IllegalStateException("not initialized");        }        synchronized (nodeStateSelectSQL) {            ResultSet rs = null;            InputStream in = null;            try {                Statement stmt = executeStmt(nodeStateSelectSQL, new Object[]{id.toString()});                rs = stmt.getResultSet();                if (!rs.next()) {                    throw new NoSuchItemStateException(id.toString());                }                in = rs.getBinaryStream(1);                NodeState state = createNew(id);                Serializer.deserialize(state, in);                return state;            } catch (Exception e) {                if (e instanceof NoSuchItemStateException) {                    throw (NoSuchItemStateException) e;                }                String msg = "failed to read node state: " + id;                log.error(msg, e);                throw new ItemStateException(msg, e);            } finally {                closeStream(in);                closeResultSet(rs);            }        }    }    /**     * {@inheritDoc}     */    public PropertyState load(PropertyId id)            throws NoSuchItemStateException, ItemStateException {        if (!initialized) {            throw new IllegalStateException("not initialized");        }        synchronized (propertyStateSelectSQL) {            ResultSet rs = null;            InputStream in = null;            try {                Statement stmt = executeStmt(propertyStateSelectSQL, new Object[]{id.toString()});                rs = stmt.getResultSet();                if (!rs.next()) {                    throw new NoSuchItemStateException(id.toString());                }                in = rs.getBinaryStream(1);                PropertyState state = createNew(id);                Serializer.deserialize(state, in, blobStore);                return state;            } catch (Exception e) {                if (e instanceof NoSuchItemStateException) {                    throw (NoSuchItemStateException) e;                }                String msg = "failed to read property state: " + id;                log.error(msg, e);                throw new ItemStateException(msg, e);            } finally {                closeStream(in);                closeResultSet(rs);            }        }    }    /**     * {@inheritDoc}     * <p/>     * This method uses shared <code>PreparedStatement</code>s which must     * be executed strictly sequentially. Because this method synchronizes on     * the persistence manager instance there is no need to synchronize on the     * shared statement. If the method would not be sychronized the shared     * statements would have to be synchronized.     */    public synchronized void store(NodeState state) throws ItemStateException {        if (!initialized) {            throw new IllegalStateException("not initialized");        }        // check if insert or update        boolean update = state.getStatus() != ItemState.STATUS_NEW;

⌨️ 快捷键说明

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