187 lines · 5.3 KB · Java
RawDownload
/* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.pkcs11; import java.lang.ref.*;import java.util.*;import java.util.concurrent.atomic.AtomicInteger; import java.security.*; import sun.security.pkcs11.wrapper.*; /** * A session object. Sessions are obtained via the SessionManager, * see there for details. Most code will only ever need one method in * this class, the id() method to obtain the session id. * * @author  Andreas Sterbenz * @since   1.5 */final class Session implements Comparable<Session> {     // time after which to close idle sessions, in milliseconds (3 minutes)    private final static long MAX_IDLE_TIME = 3 * 60 * 1000;     // token instance    final Token token;     // session id    private final long id;     // number of objects created within this session    private final AtomicInteger createdObjects;     // time this session was last used    // not synchronized/volatile for performance, so may be unreliable    // this could lead to idle sessions being closed early, but that is harmless    private long lastAccess;     private final SessionRef sessionRef;     Session(Token token, long id) {        this.token = token;        this.id = id;        createdObjects = new AtomicInteger();        id();        sessionRef = new SessionRef(this, id, token);    }     public int compareTo(Session other) {        if (this.lastAccess == other.lastAccess) {            return 0;        } else {            return (this.lastAccess < other.lastAccess) ? -1 : 1;        }    }     boolean isLive(long currentTime) {        return currentTime - lastAccess < MAX_IDLE_TIME;    }     long idInternal() {        return id;    }     long id() {        if (token.isPresent(this) == false) {            throw new ProviderException("Token has been removed");        }        lastAccess = System.currentTimeMillis();        return id;    }     void addObject() {        int n = createdObjects.incrementAndGet();        // XXX update statistics in session manager if n == 1    }     void removeObject() {        int n = createdObjects.decrementAndGet();        if (n == 0) {            token.sessionManager.demoteObjSession(this);        } else if (n < 0) {            throw new ProviderException("Internal error: objects created " + n);        }    }     boolean hasObjects() {        return createdObjects.get() != 0;    }     void close() {        if (hasObjects()) {            throw new ProviderException(                "Internal error: close session with active objects");        }        sessionRef.dispose();    }} /* * NOTE: Use PhantomReference here and not WeakReference * otherwise the sessions maybe closed before other objects * which are still being finalized. */final class SessionRef extends PhantomReference<Session>        implements Comparable<SessionRef> {     private static ReferenceQueue<Session> refQueue =        new ReferenceQueue<Session>();     private static Set<SessionRef> refList =        Collections.synchronizedSortedSet(new TreeSet<SessionRef>());     static ReferenceQueue<Session> referenceQueue() {        return refQueue;    }     static int totalCount() {        return refList.size();    }     private static void drainRefQueueBounded() {        while (true) {            SessionRef next = (SessionRef) refQueue.poll();            if (next == null) break;            next.dispose();        }    }     // handle to the native session    private long id;    private Token token;     SessionRef(Session session, long id, Token token) {        super(session, refQueue);        this.id = id;        this.token = token;        refList.add(this);        // TBD: run at some interval and not every time?        drainRefQueueBounded();    }     void dispose() {        refList.remove(this);        try {            token.p11.C_CloseSession(id);        } catch (PKCS11Exception e1) {            // ignore        } catch (ProviderException e2) {            // ignore        } finally {            this.clear();        }    }     public int compareTo(SessionRef other) {        if (this.id == other.id) {            return 0;        } else {            return (this.id < other.id) ? -1 : 1;        }    }}