Package org.apache.sling.jcr.base.internal

Source Code of org.apache.sling.jcr.base.internal.SessionPool

/*
* 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.sling.jcr.base.internal;

import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;

import javax.jcr.Credentials;
import javax.jcr.LoginException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.lock.Lock;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.EventListenerIterator;
import javax.jcr.observation.ObservationManager;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;

import org.apache.sling.jcr.api.TooManySessionsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* The <code>SessionPool</code> class
* implementins pooling and reusing sessions with the defined limits.
* See {@link #acquireSession(SimpleCredentials, String)}
* and {@link #acquireSession(Session, Credentials)} for details.
*
*/
public class SessionPool {

    /**
     * The default upper limit of simultaneously active sessions created by this
     * instance (value is Integer.MAX_VALUE).
     *
     * @see #setMaxActiveSessions(int)
     * @see #getMaxActiveSessions()
     */
    public static final int DEFAULT_MAX_ACTIVE_SESSIONS = Integer.MAX_VALUE;

    /**
     * The default maximum time in seconds to wait for the number of active
     * sessions to drop below the maximum.
     *
     * @see #getMaxActiveSessionsWait()
     * @see #setMaxActiveSessionsWait(int)
     */
    public static final int DEFAULT_MAX_ACTIVE_SESSIONS_WAIT = 10;

    /**
     * The default upper limit for the number of idle sessions to keep in the
     * pool (valie is "10").
     *
     * @see #setMaxIdleSessions(int)
     * @see #getMaxIdleSessions()
     */
    public static final int DEFAULT_MAX_IDLE_SESSIONS = 10;

    /** default log */
    private static final Logger log = LoggerFactory.getLogger(SessionPool.class);

    private SessionPoolManager poolManager;

    /**
     * The name of the user for which this pool has been created.
     */
    private String userName;

    private int[] passData;

    /**
     * The session pool. Access to this object must be synchronized to prevent
     * corruption of the data structures.
     */
    private final LinkedList<Session> idleSessions;

    /**
     * Active sessions issued by this session pool.
     */
    protected final IdentityHashMap<PooledSession, Session> activeSessions;

    /**
     * The maximum number of active sessions for this mapping.
     */
    private int maxActiveSessions;

    /** The maximum number of idle sessions stored in the idleSessions */
    private int maxIdleSessions;

    /** The singal object used for maxActiveSession wait/notify */
    private final Object activeSessionLock;

    /**
     * The number of milliseconds to wait for the number of currently active
     * sessions from this pool to drop below the configured number of maximum
     * active sessions.
     *
     * @see #PROPERTY_MAX_ACTIVE_SESSIONS_WAIT
     * @see #DEFAULT_MAX_ACTIVE_SESSIONS_WAIT
     * @see #getMaxActiveSessionsWait()
     * @see #setMaxActiveSessionsWait(long)
     * @see #checkActiveSessions()
     */
    private long maxActiveWait;

    /**
     * The counter for the number of sessions which could be served from the
     * pool.
     */
    private int poolHitCounter;

    /**
     * The counter for the number of sessions which have to be acquired through
     * repository login (login or impersonation).
     */
    private int poolMissCounter;

    /**
     * The counter for the number of sessions which cannot be returned to the
     * pool. See the {@link #getPoolDropCounter()} method for reasons why
     * sessions might be dropped.
     */
    private int poolDropCounter;

    /**
     * Flag indicating whether this pool has already been disposed off. If this
     * is <code>true</code>, no sessions will be provided by this pool anymore.
     */
    private boolean disposed;

    /**
     * Creates a new instance of this class presetting internal counters
     * and data structures.
     *
     */
    public SessionPool(SessionPoolManager poolManager, SimpleCredentials credentials) {
        this.poolManager = poolManager;
        this.userName = credentials.getUserID();
        this.passData = this.getPassData(credentials);
        this.idleSessions = new LinkedList<Session>();
        this.activeSessions = new IdentityHashMap<PooledSession, Session>();
        this.activeSessionLock = new Object();
        this.clearCounters();

        // explicitly set the default value here, as the setConfig
        // will not set the default if the configured value is <= 0
        this.setMaxActiveSessionsWait(DEFAULT_MAX_ACTIVE_SESSIONS_WAIT);
    }

    /**
     * Disposes off this pool and logs out all idle sessions in the pool. As
     * the pool does not have any registry of non-idle sessions, those will
     * only be logged out if the sessions are requested to be logged out.
     */
    void dispose() {
        // stop providing sessions and force logging out released sessions
        this.disposed = true;

        synchronized (this.idleSessions) {
            // logout all sessions in the pool
            this.logoutSessions(this.idleSessions.iterator());
            this.idleSessions.clear();
        }

        synchronized (this.activeSessions) {
            // logout all sessions in the pool
            this.logoutSessions(this.activeSessions.values().iterator());
            this.activeSessions.clear();
        }
    }

    /**
     * Returns <code>true</code> if this pool has been disposed off by the
     * {@link #dispose()} method.
     */
    boolean isDisposed() {
        return this.disposed;
    }

    SessionPoolManager getPoolManager() {
        return this.poolManager;
    }

    /**
     * Returns a session providing access to the given ContentBus user to the
     * given <code>workSpace</code> of the given <code>repository</code>. The
     * user ID and password are mapped to the repository user ID and password
     * as configured for this instance.
     * <p>
     * In addition to just converting the credentials and returning the session,
     * this implementation has two additional features:
     * <ul>
     * <li>If the number of active session acquired through this instance has
     *  reached the maximum number of active sessions, the methods wait at most
     *  {@link #getMaxActiveSessionsWait()} seconds for sessions to be released.
     *  If no session becomes available a <code>RepositoryException</code> is
     *  thrown.
     * <li>Before really creating a session by calling the base class
     *  implementation of this method, the session pool is checked for an idle
     *  session to the desired <code>workspace</code>. If available, the idle
     *  session is returned.
     * </ul>
     * <p>
     * Only when the number of active sessions is below the maximum number of
     * active sessions and no session is available from the pool, the base class
     * implementation is called to actually login to the repository.
     * <p>
     * This method does not check, whether the user name from the
     * <code>cbCredentials</code> actually matches this instances pattern. The
     * method assumes, this has been done beforehand.
     *
     * @param credentials The <code>javax.jcr.Credentials</code> to authenticate
     *      with.
     * @param workSpace The name of the workspace to connect to.
     *
     * @return A session to the desired workspace to be used as the basis for
     *      the ticket of the given ContentBus user. The session returned is
     *      a pooled session, such that the session is put into the pool instead
     *      of being logged out, when not used anymore.
     *
     * @throws javax.jcr.LoginException If the login fails.
     * @throws TooManySessionsException If the maximum number of active
     *             sessions has been reached and no session was released while
     *             waiting for it.
     * @throws NoSuchWorkspaceException If the specified <code>workSpace</code>
     *      is not recognized.
     * @throws RepositoryException if another error occurs.
     * @throws IllegalStateException If this pool has already been disposed off.
     *
     * @see PooledSession
     */
    Session acquireSession(SimpleCredentials credentials, String workSpace)
            throws LoginException, NoSuchWorkspaceException, RepositoryException {

        this.checkActiveSessions();

        // only try to get from the pool, if the password matches
        if (this.passDataMatch(credentials, this.passData)) {
            Session session = this.getFromPool(workSpace);
            if (session != null) {
                return session;
            }
        }

        // login new session (fails if password has changed but is not valid)
        Session session = this.poolManager.getRepository().login(credentials, workSpace);
        return this.createPooledSession(session);
    }

    /**
     * Returns a session providing access to the given ContentBus user to the
     * same workspace as the given <code>baseSession</code> by impersonating the
     * session as the new user. The <code>cqUserId</code> is mapped to the
     * repository user ID and password as configured for this instance.
     * <p>
     * In addition to just converting the user ID and returning the session,
     * this implementation has two additional features:
     * <ul>
     * <li>If the number of active session acquired through this instance has
     *  reached the maximum number of active sessions, the methods wait at most
     *  {@link #getMaxActiveSessionsWait()} seconds for sessions to be released.
     *  If no session becomes available a <code>RepositoryException</code> is
     *  thrown.
     * <li>Before really creating a session by calling the base class
     *  implementation of this method, the session pool is checked for an idle
     *  session to the desired <code>workspace</code>. If available, the idle
     *  session is returned.
     * </ul>
     * <p>
     * Only when the number of active sessions is below the maximum number of
     * active sessions and no session is available from the pool, the base class
     * implementation is called to actually login to the repository.
     * <p>
     * This method does not check, whether the <code>cqUserId</code> actually
     * matches this instances pattern. The method assumes, this has been done
     * beforehand.
     *
     * @param baseSession The repository session used for impersonation as the
     *      new user.
     * @param credentials The <code>javax.jcr.Credentials</code> to authenticate
     *      with.
     *
     * @return A session to the desired workspace to be used as the basis for
     *      the ticket of the given ContentBus user. The session returned is
     *      a pooled session, such that the session is put into the pool instead
     *      of being logged out, when not used anymore.
     *
     * @throws javax.jcr.LoginException if the <code>baseSession</code> does not
     *          have sufficient rights to impersonate.
     * @throws TooManySessionsException If the maximum number of active
     *             sessions has been reached and no session was released while
     *             waiting for it.
     * @throws RepositoryException If another error occurs.
     * @throws IllegalStateException If this pool has already been disposed off.
     *
     * @see PooledSession
     */
    Session acquireSession(Session baseSession, Credentials credentials)
            throws LoginException, RepositoryException {

        this.checkActiveSessions();

        Session session = this.getFromPool(baseSession.getWorkspace().getName());
        if (session != null) {
            return session;
        }

        session = baseSession.impersonate(credentials);
        return this.createPooledSession(session);
    }

    //---------- JMX ----------------------------------------------------------

    /**
     * Returns the name of user for which this pool has been created. This may
     * be <code>null</code> if the owner name of the pool is not known.
     */
    public String getUserName() {
        return this.userName;
    }

    /**
     * Returns the maximum number of simultaneously active sessions.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     *
     * @see #DEFAULT_MAX_ACTIVE_SESSIONS
     * @see #setMaxActiveSessions(int)
     */
    public int getMaxActiveSessions() {
        return this.maxActiveSessions;
    }

    /**
     * Sets the maximum number of simultaneously active sessions.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     *
     * @param maxActiveSessions The new maximum number of active sessions. If
     *          less than or equal to zero, the default value (Integer.MAX_VALUE)
     *          is assumed.
     *
     * @see #DEFAULT_MAX_ACTIVE_SESSIONS
     * @see #getMaxActiveSessions()
     */
    public void setMaxActiveSessions(int maxActiveSessions) {
        this.maxActiveSessions = (maxActiveSessions <= 0)
                ? DEFAULT_MAX_ACTIVE_SESSIONS
                : maxActiveSessions;
    }

    /**
     * Returns the maximum number of idle sessions to store in the pool.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     *
     * @see #DEFAULT_MAX_IDLE_SESSIONS
     * @see #getMaxIdleSessions()
     */
    public int getMaxIdleSessions() {
        return this.maxIdleSessions;
    }

    /**
     * Sets the maximum number of idle sessions to store in the pool.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     *
     * @param maxIdleSessions The new maximum number of idle sessions. If less
     *          than zero, the default value of 10 is assumed. If zero, session
     *          pooling will actually be disabled.
     *
     * @see #DEFAULT_MAX_IDLE_SESSIONS
     * @see #getMaxIdleSessions()
     */
    public void setMaxIdleSessions(int maxIdleSessions) {
        this.maxIdleSessions = (maxIdleSessions < 0)
                ? DEFAULT_MAX_IDLE_SESSIONS
                : maxIdleSessions;
    }

    /**
     * The number of seconds to wait for the number of active sessions to drop
     * below the configured maximum number of active sessions.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getMaxActiveSessionsWait() {
        return (int) (this.maxActiveWait / 1000L);
    }

    /**
     * Sets the number of seconds to wait for the number of active sessions to
     * drop below the configured maximum number of active sessions.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     *
     * @param maxActiveWait The number of seconds to wait. This method has no
     *          effect if this value is less than or equal to zero.
     *
     */
    public void setMaxActiveSessionsWait(int maxActiveWait) {
        if (maxActiveWait > 0) {
            this.maxActiveWait = 1000L * maxActiveWait;
        }
    }

    /**
     * Returns the number of currently active sessions.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getNumActiveSessions() {
        synchronized (this.activeSessions) {
            return this.activeSessions.size();
        }
    }

    /**
     * Returns the number of idle sessions stored in this pool.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getIdleSessions() {
        return this.idleSessions.size();
    }

    /**
     * Returns the number session acquisitions served from the pool.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getPoolHitCounter() {
        return this.poolHitCounter;
    }

    /**
     * Returns the number session acquisitions not served from the pool.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getPoolMissCounter() {
        return this.poolMissCounter;
    }

    /**
     * Returns the number session not added to the pool after release or dropped
     * while trying to retrieve a session from the pool. Dropping sessions may
     * have a number of reasons:
     * <ul>
     * <li>The session is not alive anymore
     * <li>The session should be taken from the pool but is attached to the
     *  wrong workspace.
     * <li>The maximum number of idle sessions in the pool has been reached.
     * </ul>
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public int getPoolDropCounter() {
        return this.poolDropCounter;
    }

    /**
     * Clears the session pool statistics counters.
     * <p>
     * This method is not part of the public API of this class and is present
     * solely for the purposes of JMX support.
     */
    public void clearCounters() {
        this.poolHitCounter = 0;
        this.poolMissCounter = 0;
        this.poolDropCounter = 0;
    }

    //---------- Support for PooledSession

    /**
     * Releases the repository session encapsulated by the {@link PooledSession}
     * to the pool or logs the session out if it is not live any more or the
     * maximum number of idle sessions in this pool has been reached.
     * <p>
     * This method also notifies any threads waiting for the number active
     * sessions to drop below the maximum number of sessions.
     * <p>
     * This method is called by the {@link PooledSession#logout()} method to
     * release the session.
     *
     * @param pooledSession The {@link PooledSession} to release.
     */
    void release(PooledSession pooledSession) {
        // remove the pooled session. If it is not in the activeSessions
        // map, it has been removed by one of the acquireSession methods
        // due to changed passwords. In this case, the delegate session
        // is not idled but immediately logged out
        boolean forcedLogout;
        synchronized (this.activeSessions) {
            forcedLogout = this.activeSessions.remove(pooledSession) == null;
        }

        synchronized (this.activeSessionLock) {
            this.activeSessionLock.notifyAll();
        }

        // unwrap the repository session
        Session session = pooledSession.getSession();

        // cache the session owner for messages and more
        String userId = session.getUserID();

        // if the session is to be logged out forcibly
        if (forcedLogout) {
            log.debug("Logging out session {}; password has changed", userId);
            session.logout();
            return;
        }

        // if the pool has been disposed off, the session will be logged out
        if (this.isDisposed()) {
            log.debug("Logging out session {}; pool has been disposed off",
                userId);
            session.logout();
            return;
        }

        // if the pool is full or the session is already dead, logout and return
        // this results in the session not being added to the pool
        if (this.idleSessions.size() >= this.getMaxIdleSessions() || !session.isLive()) {
            log.debug("Logging out session {}; pool is full or session is not alive",
                userId);
            this.poolDropCounter++;
            session.logout();
            return;
        }

        // if the session has locks, we logout the session and drop it,
        // as there is no easy way of finding the temporary locks and
        // unlocking them, we could use the search, however ???
        try {
            QueryManager qm = session.getWorkspace().getQueryManager();
            // FIXME - this search searches for all locks for the user of the session
            //         so if the user has more than one session, locks from other
            //         sessions will be delivered as well.
            Query q = qm.createQuery(
                "/jcr:root//element(*,mix:lockable)[@jcr:lockOwner='"
                    + session.getUserID() + "']", Query.XPATH);
            NodeIterator ni = q.execute().getNodes();
            while (ni.hasNext()) {
                Node node = ni.nextNode();
                String path = node.getPath();
                try {
                    final Lock lock = node.getLock();
                    if (lock.getLockToken() == null) {
                        log.debug("Ignoring lock on {} held by {}, not held by this session",
                            path, userId);
                    } else if (lock.isSessionScoped()) {
                        log.info("Unlocking session-scoped lock on {} held by {}",
                            path, userId);
                        node.unlock();
                    } else {
                        log.warn("Dropping lock token of permanent lock on {} held by {}",
                            path, userId);
                        session.removeLockToken(lock.getLockToken());
                    }
                } catch (RepositoryException re) {
                    log.debug("Ignoring lock on {} held by {}, not held by this session",
                            path, userId);
                }
            }

            String[] lockTokens = session.getLockTokens();
            if (lockTokens != null && lockTokens.length > 0) {
                log.warn("Session still has lock tokens !");
                for (int i=0; i < lockTokens.length; i++) {
                    log.warn("Dropping lock token {} held by {}",
                        lockTokens[i], userId);
                    session.removeLockToken(lockTokens[i]);
                }
            }
        } catch (RepositoryException re) {
            if ( log.isDebugEnabled() ) {
                log.debug("Cannot cleanup lockes of session " + userId + ", logging out", re);
            } else {
                log.info("Cannot cleanup lockes of session {}, logging out", userId);
            }
            this.poolDropCounter++;
            session.logout();
            return;
        }


        // make sure the session has no more registered event listeners which
        // may be notified on changes, and - worse - prevent the objects from
        // being collected
        try {
            ObservationManager om = session.getWorkspace().getObservationManager();
            EventListenerIterator eli = om.getRegisteredEventListeners();
            if (eli.hasNext()) {
                log.debug("Unregistering remaining EventListeners of {}", userId);
                while (eli.hasNext()) {
                    EventListener el = (EventListener) eli.next();
                    om.removeEventListener(el);
                }
            }
        } catch (RepositoryException re) {
            log.info("Cannot check or unregister event listeners of session " +
                "{}, logging out", userId);
            this.poolDropCounter++;
            session.logout();
            return;
        }

        // Otherwise clean up the session if there are any pending changes.
        // Those changes are not persisted, but dropped. If this fails, the
        // session is logged out and not returned/added to the pool
        try {
            if (session.hasPendingChanges()) {
                session.refresh(false);
            }
        } catch (RepositoryException re) {
            log.info("Cannot check or drop pending changes of session " +
                "{}, logging out", userId);
            this.poolDropCounter++;
            session.logout();
            return;
        }

        // now the session is "clean" and may be added to the pool
        log.debug("Returning session {} to the pool, now with {} entries",
            userId, new Integer(this.idleSessions.size()));

        // add to the pool and notify waiting session acquiry
        //    ==> checkActiveSessions()
        synchronized (this.idleSessions) {
            this.idleSessions.add(session);
        }
    }

    //---------- internal -----------------------------------------------------

    /**
     * Wraps the repository session as a pooled session and increments the
     * counter of active sessions before returning the {@link PooledSession}.
     * <p>
     * This method knows about the JCR standard <code>Session</code>
     * interfaces and wraps the <code>delegatee</code> in a
     * {@link PooledSession}.
     *
     * @param delegatee The <code>Session</code> to wrap as a pooled session.
     * @see PooledSession
     */
    protected PooledSession createPooledSession(Session delegatee) throws RepositoryException {
        PooledSession pooledSession = new PooledSession(this, delegatee);

        // keep the pooled session
        synchronized (this.activeSessions) {
            this.activeSessions.put(pooledSession, delegatee);
        }

        return pooledSession;
    }

    /**
     * Checks the number of currently active sessions - sessions which have been
     * acquired but not yet released - against the maximum number of session
     * allowed as per the configuration. If the number is not reached yet, the
     * method silently returns.
     * <p>
     * If the maximum number of active sessions has been reached, this method
     * waits for at most 10 seconds for a session to be released. If after that
     * time or after a notification or an interrupt the number of sessions is
     * not below the maximum number of sessions, a
     * <code>RepositoryException</code> is thrown.
     *
     * @throws TooManySessionsException If the maximum number of active
     *             sessions has been reached and no session was released while
     *             waiting for it.
     * @throws IllegalStateException If this pool has already been disposed off.
     */
    private void checkActiveSessions() throws TooManySessionsException {
        // fail if diposed already
        if (this.isDisposed()) {
            throw new IllegalStateException("Pool has already been disposed off");
        }

        // check whether maxActiveSession is exhausted
        int maxActiveSessions = this.getMaxActiveSessions();
        if (this.getNumActiveSessions() < maxActiveSessions) {
            return;
        }

        // sessions exhausted, wait for sessions to be released
        try {
            synchronized (this.activeSessionLock) {
                this.activeSessionLock.wait(this.maxActiveWait);
            }
        } catch (InterruptedException ie) {
            log.debug("Interrupted while waiting for session to " +
                "become available");
        }

        // if the number of active sessions has still not dropped, fail
        if (this.getNumActiveSessions() >= maxActiveSessions) {
            throw new TooManySessionsException(this.getUserName());
        }
    }

    /**
     * Returns a session for the given workspace from the pool of sessions or
     * <code>null</code> if the pool is empty or has no sessions for the
     * given workspace.
     * <p>
     * Any sessions checked while looking for a valid - live session for the
     * correct workspace - session, which is not live or is attached to another
     * than the requested workspace is logged out and removed from the pool.
     * <p>
     * This is of course only a poor man's clean up mechanism which has at least
     * two flaws: (1) Sessions may remain in the pool for ever and (2) sessions
     * are removed from the pool which just do not qulaify for the desired
     * workspace but would qualify later. The reason for the second issue being
     * no problem at the moment, is that the JCR adapter is attached to a single
     * workspace and only during startup will the workspace name be different.
     *
     * @param workSpaceName The name of the workspace to which the sesion
     *          retrieved from the pool must be attached.
     *
     * @return A live session for the given workspace from the pool or
     *          <code>null</code> if no session for the workspace is available
     *          from the pool.
     */
    private Session getFromPool(String workSpaceName) throws RepositoryException {
        // check with pool
        for (;;) {

            // get a session from the, return if empty
            Session session;
            synchronized (this.idleSessions) {
                if (this.idleSessions.isEmpty()) {
                    log.debug("getFromPool: No idle session in pool");
                    this.poolMissCounter++;
                    return null;
                }

                // get the first entry from the pool
                session = this.idleSessions.removeFirst();
            }

            // check the session and the session's workspace
            if (session.isLive()
                    && session.getWorkspace().getName().equals(workSpaceName)) {
                this.poolHitCounter++;
                return this.createPooledSession(session);
            }

            // session is not alive anymore or has the wrong workspace name,
            // logout and try next from pool
            this.poolDropCounter++;
            session.logout();
        }
    }

    //---------- internal helper ----------------------------------------------

    private void logoutSessions(Iterator<Session> sessions) {
        // logout all sessions in the pool
        while (sessions.hasNext()) {
            Session session = sessions.next();
            try {
                if (session.isLive()) {
                    session.logout();
                }
            } catch (Exception e) {
                log.info("Unexpected problem logging out session " + session, e);
            }
        }
    }

    private int[] getPassData(SimpleCredentials credentials) {
        char[] passwd = credentials.getPassword();
        if (passwd == null) {
            return null;
        }

        int[] passdt = new int[passwd.length];
        for (int i=0; i < passdt.length; i++) {
            passdt[i] = passwd[i];
        }

        return passdt;
    }

    private boolean passDataMatch(SimpleCredentials credentials, int[] passdt) {
        char[] passwd = credentials.getPassword();
        if (passwd == null) {
            return passdt == null;
        } else if (passdt == null) {
            return false;
        }

        if (passwd.length != passdt.length) {
            return false;
        }

        for (int i=0; i < passwd.length; i++) {
            if (passwd[i] != passdt[i]) {
                return false;
            }
        }

        return true;
    }
}
TOP

Related Classes of org.apache.sling.jcr.base.internal.SessionPool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.