/*
* Copyright 2008 The Topaz Foundation
*
* Licensed 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.
*
* Contributions:
*/
package org.mulgara.resolver.distributed;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.log4j.Logger;
import org.mulgara.query.QueryException;
import org.mulgara.server.Session;
import org.mulgara.server.SessionFactory;
import org.mulgara.server.NonRemoteSessionException;
import org.mulgara.server.driver.SessionFactoryFinder;
import org.mulgara.server.driver.SessionFactoryFinderException;
/**
* A simple cache of {@link SessionFactory}'s and {@link Session}'s. Note that there is currently
* no cache eviction policy, as the assumption is that this will hold a relatively small set of
* session's.
*
* @created 2008-02-16
* @author Ronald Tschalär
* @copyright ©2008 <a href="http://www.topazproject.org/">Topaz Project</a>
* @licence Apache License v2.0
*/
public class SessionCache {
private static final Logger logger = Logger.getLogger(SessionCache.class);
private final Map<URI,SessionFactory> factoryCache = new HashMap<URI,SessionFactory>();
private final ConcurrentMap<URI,List<Session>> sessionCache = new ConcurrentHashMap<URI,List<Session>>();
private SessionFactory getSessionFactory(URI serverUri)
throws SessionFactoryFinderException, NonRemoteSessionException {
synchronized (factoryCache) {
SessionFactory sessionFactory = factoryCache.get(serverUri);
if (sessionFactory == null) {
if (logger.isDebugEnabled()) {
logger.debug("Creating session-factory for server '" + serverUri + "'");
}
factoryCache.put(serverUri,
sessionFactory = SessionFactoryFinder.newSessionFactory(serverUri, true));
}
return sessionFactory;
}
}
/**
* Get a session from the cache. A new session will be created none are available.
*
* @param serverUri the server for which to get the session
* @return the session
* @throws SessionFactoryFinderException if an error occurred creating the session-factory
* @throws NonRemoteSessionException if an error occurred creating the session-factory
* @throws QueryException if an error occurred creating the session
* @see #returnSession(URI, Session)
*/
public Session getSession(URI serverUri)
throws SessionFactoryFinderException, NonRemoteSessionException, QueryException {
List<Session> sessions = sessionCache.get(serverUri);
if (sessions == null) {
sessionCache.putIfAbsent(serverUri, new ArrayList<Session>());
sessions = sessionCache.get(serverUri);
}
synchronized (sessions) {
if (sessions.size() > 0) {
return sessions.remove(sessions.size() - 1);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Creating session for server '" + serverUri + "'");
}
return getSessionFactory(serverUri).newSession();
}
}
}
/**
* Return a session to the cache.
*
* @param serverUri the server this session belongs to
* @param session the session to return
*/
public void returnSession(URI serverUri, Session session) {
synchronized (serverUri.toString().intern()) {
sessionCache.get(serverUri).add(session);
}
}
/**
* Closes all sessions and factories.
*/
public void close() {
synchronized (factoryCache) {
for (SessionFactory sf : factoryCache.values()) {
try {
sf.close();
} catch (QueryException qe) {
logger.error("Exception while closing session-factory", qe);
}
}
factoryCache.clear();
for (List<Session> sl : sessionCache.values()) {
for (Session s : sl) {
try {
s.close();
} catch (QueryException qe) {
logger.error("Exception while closing session", qe);
}
}
}
sessionCache.clear();
}
}
}