ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/session/DataSourceStore.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/session/DataSourceStore.java
Status
scanned
Type
file
Name
DataSourceStore.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
25408 (24.8 KB)
MD5
d2e4e8d549db40a2a7c9274ea6d7603b
SHA1
e224d63722e6ca6d9792732d285b1ea905143683
SHA256
e9d3285b331e97c5f821683b6752b777c9aedb1d58bb90b656245c2453bcea51
SHA512

      
    
SHA1_git
b5e8782fb4a3466331d649ea894236411ba52619
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
DataSourceStore.java | 24.8 KB |

/* * 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.catalina.session; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.catalina.Container; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.Session; import org.apache.juli.logging.Log; /** * Implementation of the {@link org.apache.catalina.Store Store} interface that stores serialized session objects in a * database. Sessions that are saved are still subject to being expired based on inactivity. */ public class DataSourceStore extends StoreBase { /** * Context name associated with this Store */ private String name = null; /** * Name to register for this Store, used for logging. */ protected static final String storeName = "dataSourceStore"; /** * name of the JNDI resource */ protected String dataSourceName = null; /** * Context local datasource. */ private boolean localDataSource = false; /** * DataSource to use */ protected DataSource dataSource = null; // ------------------------------------------------------------ Table & cols /** * Table to use. */ protected String sessionTable = "tomcat$sessions"; /** * Column to use for /Engine/Host/Context name */ protected String sessionAppCol = "app"; /** * Id column to use. */ protected String sessionIdCol = "id"; /** * Data column to use. */ protected String sessionDataCol = "data"; /** * {@code Is Valid} column to use. */ protected String sessionValidCol = "valid"; /** * Max Inactive column to use. */ protected String sessionMaxInactiveCol = "maxinactive"; /** * Last Accessed column to use. */ protected String sessionLastAccessedCol = "lastaccess"; // -------------------------------------------------------------- Properties /** * @return the name for this instance (built from container name) */ public String getName() { if (name == null) { Container container = manager.getContext(); String contextName = container.getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } String hostName = ""; String engineName = ""; if (container.getParent() != null) { Container host = container.getParent(); hostName = host.getName(); if (host.getParent() != null) { engineName = host.getParent().getName(); } } name = "/" + engineName + "/" + hostName + contextName; } return name; } @Override public String getStoreName() { return storeName; } /** * Set the table for this Store. * * @param sessionTable The new table */ public void setSessionTable(String sessionTable) { String oldSessionTable = this.sessionTable; this.sessionTable = sessionTable; support.firePropertyChange("sessionTable", oldSessionTable, this.sessionTable); } /** * @return the table for this Store. */ public String getSessionTable() { return sessionTable; } /** * Set the App column for the table. * * @param sessionAppCol the column name */ public void setSessionAppCol(String sessionAppCol) { String oldSessionAppCol = this.sessionAppCol; this.sessionAppCol = sessionAppCol; support.firePropertyChange("sessionAppCol", oldSessionAppCol, this.sessionAppCol); } /** * @return the web application name column for the table. */ public String getSessionAppCol() { return this.sessionAppCol; } /** * Set the Id column for the table. * * @param sessionIdCol the column name */ public void setSessionIdCol(String sessionIdCol) { String oldSessionIdCol = this.sessionIdCol; this.sessionIdCol = sessionIdCol; support.firePropertyChange("sessionIdCol", oldSessionIdCol, this.sessionIdCol); } /** * @return the Id column for the table. */ public String getSessionIdCol() { return this.sessionIdCol; } /** * Set the Data column for the table * * @param sessionDataCol the column name */ public void setSessionDataCol(String sessionDataCol) { String oldSessionDataCol = this.sessionDataCol; this.sessionDataCol = sessionDataCol; support.firePropertyChange("sessionDataCol", oldSessionDataCol, this.sessionDataCol); } /** * @return the data column for the table */ public String getSessionDataCol() { return this.sessionDataCol; } /** * Set the {@code Is Valid} column for the table * * @param sessionValidCol The column name */ public void setSessionValidCol(String sessionValidCol) { String oldSessionValidCol = this.sessionValidCol; this.sessionValidCol = sessionValidCol; support.firePropertyChange("sessionValidCol", oldSessionValidCol, this.sessionValidCol); } /** * @return the {@code Is Valid} column */ public String getSessionValidCol() { return this.sessionValidCol; } /** * Set the {@code Max Inactive} column for the table * * @param sessionMaxInactiveCol The column name */ public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) { String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol; this.sessionMaxInactiveCol = sessionMaxInactiveCol; support.firePropertyChange("sessionMaxInactiveCol", oldSessionMaxInactiveCol, this.sessionMaxInactiveCol); } /** * @return the {@code Max Inactive} column */ public String getSessionMaxInactiveCol() { return this.sessionMaxInactiveCol; } /** * Set the {@code Last Accessed} column for the table * * @param sessionLastAccessedCol The column name */ public void setSessionLastAccessedCol(String sessionLastAccessedCol) { String oldSessionLastAccessedCol = this.sessionLastAccessedCol; this.sessionLastAccessedCol = sessionLastAccessedCol; support.firePropertyChange("sessionLastAccessedCol", oldSessionLastAccessedCol, this.sessionLastAccessedCol); } /** * @return the {@code Last Accessed} column */ public String getSessionLastAccessedCol() { return this.sessionLastAccessedCol; } /** * Set the JNDI name of a DataSource-factory to use for db access * * @param dataSourceName The JNDI name of the DataSource-factory */ public void setDataSourceName(String dataSourceName) { if (dataSourceName == null || dataSourceName.trim().isEmpty()) { manager.getContext().getLogger().warn(sm.getString(getStoreName() + ".missingDataSourceName")); return; } this.dataSourceName = dataSourceName; } /** * @return the name of the JNDI DataSource-factory */ public String getDataSourceName() { return this.dataSourceName; } /** * @return if the datasource will be looked up in the webapp JNDI Context. */ public boolean getLocalDataSource() { return localDataSource; } /** * Set to {@code true} to cause the datasource to be looked up in the webapp JNDI Context. * * @param localDataSource the new flag value */ public void setLocalDataSource(boolean localDataSource) { this.localDataSource = localDataSource; } // --------------------------------------------------------- Public Methods @Override public String[] expiredKeys() throws IOException { return keys(true); } @Override public String[] keys() throws IOException { return keys(false); } /** * Return an array containing the session identifiers of all Sessions currently saved in this Store. If there are no * such Sessions, a zero-length array is returned. * * @param expiredOnly flag, whether only keys of expired sessions should be returned * * @return array containing the list of session IDs */ private String[] keys(boolean expiredOnly) { String[] keys = null; int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return new String[0]; } try { String keysSql = "SELECT " + sessionIdCol + " FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; if (expiredOnly) { keysSql += " AND (" + sessionLastAccessedCol + " + " + sessionMaxInactiveCol + " * 1000 < ?)"; } try (PreparedStatement preparedKeysSql = _conn.prepareStatement(keysSql)) { preparedKeysSql.setString(1, getName()); if (expiredOnly) { preparedKeysSql.setLong(2, System.currentTimeMillis()); } try (ResultSet rst = preparedKeysSql.executeQuery()) { List<String> tmpkeys = new ArrayList<>(); if (rst != null) { while (rst.next()) { tmpkeys.add(rst.getString(1)); } } keys = tmpkeys.toArray(new String[0]); // Break out after the finally block numberOfTries = 0; } } } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e); keys = new String[0]; // Close the connection so that it gets reopened next time } finally { release(_conn); } numberOfTries--; } return keys; } @Override public int getSize() throws IOException { int size = 0; String sizeSql = "SELECT COUNT(" + sessionIdCol + ") FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return size; } try (PreparedStatement preparedSizeSql = _conn.prepareStatement(sizeSql)) { preparedSizeSql.setString(1, getName()); try (ResultSet rst = preparedSizeSql.executeQuery()) { if (rst.next()) { size = rst.getInt(1); } // Break out after the finally block numberOfTries = 0; } } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e); } finally { release(_conn); } numberOfTries--; } return size; } @Override public Session load(String id) throws ClassNotFoundException, IOException { StandardSession _session = null; org.apache.catalina.Context context = getManager().getContext(); Log contextLog = context.getLogger(); int numberOfTries = 2; String loadSql = "SELECT " + sessionIdCol + ", " + sessionDataCol + " FROM " + sessionTable + " WHERE " + sessionIdCol + " = ? AND " + sessionAppCol + " = ?"; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return null; } ClassLoader oldThreadContextCL = context.bind(null); try (PreparedStatement preparedLoadSql = _conn.prepareStatement(loadSql)) { preparedLoadSql.setString(1, id); preparedLoadSql.setString(2, getName()); try (ResultSet rst = preparedLoadSql.executeQuery()) { if (rst.next()) { try (ObjectInputStream ois = getObjectInputStream(rst.getBinaryStream(2))) { if (contextLog.isTraceEnabled()) { contextLog.trace(sm.getString("dataSourceStore.loading", id, sessionTable)); } _session = (StandardSession) manager.createEmptySession(); _session.readObjectData(ois); _session.setManager(manager); } } else if (context.getLogger().isDebugEnabled()) { contextLog.debug(sm.getString("dataSourceStore.noObject", id)); } // Break out after the finally block numberOfTries = 0; } } catch (SQLException e) { contextLog.error(sm.getString("dataSourceStore.SQLException"), e); } finally { context.unbind(oldThreadContextCL); release(_conn); } numberOfTries--; } return _session; } @Override public void remove(String id) throws IOException { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try { remove(id, _conn); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e); } finally { release(_conn); } numberOfTries--; } if (manager.getContext().getLogger().isTraceEnabled()) { manager.getContext().getLogger().trace(sm.getString("dataSourceStore.removing", id, sessionTable)); } } /** * Remove the Session with the specified session identifier from this Store, if present. If no such Session is * present, this method takes no action. * * @param id Session identifier of the Session to be removed * @param _conn open connection to be used * * @throws SQLException if an error occurs while talking to the database */ private void remove(String id, Connection _conn) throws SQLException { String removeSql = "DELETE FROM " + sessionTable + " WHERE " + sessionIdCol + " = ? AND " + sessionAppCol + " = ?"; try (PreparedStatement preparedRemoveSql = _conn.prepareStatement(removeSql)) { preparedRemoveSql.setString(1, id); preparedRemoveSql.setString(2, getName()); preparedRemoveSql.execute(); } } @Override public void clear() throws IOException { String clearSql = "DELETE FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try (PreparedStatement preparedClearSql = _conn.prepareStatement(clearSql)) { preparedClearSql.setString(1, getName()); preparedClearSql.execute(); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e); } finally { release(_conn); } numberOfTries--; } } @Override public void save(Session session) throws IOException { String saveSql = "INSERT INTO " + sessionTable + " (" + sessionIdCol + ", " + sessionAppCol + ", " + sessionDataCol + ", " + sessionValidCol + ", " + sessionMaxInactiveCol + ", " + sessionLastAccessedCol + ") VALUES (?, ?, ?, ?, ?, ?)"; synchronized (session) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try { // Remove session if it exists and insert again. remove(session.getIdInternal(), _conn); ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) { ((StandardSession) session).writeObjectData(oos); } byte[] obs = bos.toByteArray(); int size = obs.length; try (ByteArrayInputStream bis = new ByteArrayInputStream(obs, 0, size); InputStream in = new BufferedInputStream(bis, size); PreparedStatement preparedSaveSql = _conn.prepareStatement(saveSql)) { preparedSaveSql.setString(1, session.getIdInternal()); preparedSaveSql.setString(2, getName()); preparedSaveSql.setBinaryStream(3, in, size); preparedSaveSql.setString(4, session.isValid() ? "1" : "0"); preparedSaveSql.setInt(5, session.getMaxInactiveInterval()); preparedSaveSql.setLong(6, session.getLastAccessedTime()); preparedSaveSql.execute(); // Break out after the finally block numberOfTries = 0; } } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e); } catch (IOException ioe) { // Ignore } finally { release(_conn); } numberOfTries--; } } if (manager.getContext().getLogger().isTraceEnabled()) { manager.getContext().getLogger() .trace(sm.getString("dataSourceStore.saving", session.getIdInternal(), sessionTable)); } } // --------------------------------------------------------- Protected Methods /** * Check the connection associated with this store, if it's <code>null</code> or closed try to reopen it. Returns * <code>null</code> if the connection could not be established. * * @return <code>Connection</code> if the connection succeeded */ protected Connection getConnection() { Connection conn = null; try { conn = open(); if (conn == null || conn.isClosed()) { manager.getContext().getLogger().info(sm.getString("dataSourceStore.checkConnectionDBClosed")); conn = open(); if (conn == null || conn.isClosed()) { manager.getContext().getLogger().info(sm.getString("dataSourceStore.checkConnectionDBReOpenFail")); } } } catch (SQLException ex) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.checkConnectionSQLException"), ex); } return conn; } /** * Open (if necessary) and return a database connection for use by this Store. * * @return database connection ready to use * * @exception SQLException if a database error occurs */ protected Connection open() throws SQLException { if (dataSourceName != null && dataSource == null) { org.apache.catalina.Context context = getManager().getContext(); if (getLocalDataSource()) { ClassLoader oldThreadContextCL = context.bind(null); try { Context envCtx = (Context) (new InitialContext()).lookup("java:comp/env"); this.dataSource = (DataSource) envCtx.lookup(this.dataSourceName); } catch (NamingException e) { context.getLogger().error(sm.getString("dataSourceStore.wrongDataSource", this.dataSourceName), e); } finally { context.unbind(oldThreadContextCL); } } else { try { // This should be the normal way to lookup for the global in the global context (no comp/env) Service service = Container.getService(context); if (service != null) { Server server = service.getServer(); if (server != null) { Context namingContext = server.getGlobalNamingContext(); this.dataSource = (DataSource) namingContext.lookup(dataSourceName); } } } catch (NamingException e) { // Ignore, try another way for compatibility } if (this.dataSource == null) { try { Context envCtx = (Context) (new InitialContext()).lookup("java:comp/env"); this.dataSource = (DataSource) envCtx.lookup(this.dataSourceName); } catch (NamingException e) { context.getLogger().error(sm.getString("dataSourceStore.wrongDataSource", this.dataSourceName), e); } } } } if (dataSource != null) { return dataSource.getConnection(); } else { throw new IllegalStateException(sm.getString("dataSourceStore.missingDataSource")); } } /** * Close the specified database connection. * * @param dbConnection The connection to be closed */ protected void close(Connection dbConnection) { // Do nothing if the database connection is already closed if (dbConnection == null) { return; } // Commit if autoCommit is false try { if (!dbConnection.getAutoCommit()) { dbConnection.commit(); } } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.commitSQLException"), e); } // Close this database connection, and log any errors try { dbConnection.close(); } catch (SQLException e) { manager.getContext().getLogger().error(sm.getString("dataSourceStore.close"), e); } } /** * Release the connection, if it is associated with a connection pool. * * @param conn The connection to be released */ protected void release(Connection conn) { if (dataSource != null) { close(conn); } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
5.91
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9