/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
* Free SoftwareFoundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.jca.ra;
import com.caucho.config.ConfigException;
import com.caucho.env.dbpool.ConnectionPool;
import com.caucho.loader.*;
import com.caucho.transaction.UserTransactionProxy;
import com.caucho.util.L10N;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Implementation of the resource manager.
*/
public class ResourceManagerImpl implements BootstrapContext {
private static final L10N L = new L10N(ResourceManagerImpl.class);
private static final Logger log
= Logger.getLogger(ResourceManagerImpl.class.getName());
private static EnvironmentLocal<ResourceManagerImpl> _localManager
= new EnvironmentLocal<ResourceManagerImpl>();
private final EnvironmentClassLoader _loader;
private UserTransactionProxy _tm;
private ArrayList<ResourceAdapter> _resources
= new ArrayList<ResourceAdapter>();
private ArrayList<ConnectionPool> _connectionManagers
= new ArrayList<ConnectionPool>();
private ArrayList<SoftReference<Timer>> _timers
= new ArrayList<SoftReference<Timer>>();
private WorkManagerImpl _workManager;
private boolean _isInit;
private boolean _isClosed;
/**
* Constructor.
*/
private ResourceManagerImpl()
{
_loader = Environment.getEnvironmentClassLoader();
Environment.addClassLoaderListener(new CloseListener(this));
_tm = UserTransactionProxy.getInstance();
if (_tm == null)
throw new IllegalStateException();
}
/**
* Returns the impl.
*/
public static ResourceManagerImpl createLocalManager()
{
return create();
}
/**
* Returns the impl.
*/
public static ResourceManagerImpl create()
{
ResourceManagerImpl rm;
synchronized (_localManager) {
rm = _localManager.getLevel();
if (rm == null) {
rm = new ResourceManagerImpl();
_localManager.set(rm);
}
}
return rm;
}
/**
* Returns the impl.
*/
public static ResourceManagerImpl getLocalManager()
{
return _localManager.getLevel();
}
/**
* Adds a resource to the manager.
*/
public static void addResource(ResourceAdapter resource)
throws ConfigException
{
ResourceManagerImpl rm = createLocalManager();
rm.addResourceImpl(resource);
}
/**
* Adds a resource to the resource manager.
*/
private void addResourceImpl(ResourceAdapter resource)
{
try {
resource.start(this);
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
}
_resources.add(resource);
}
/**
* Returns a connection manager
*/
public ConnectionPool createConnectionPool()
{
ConnectionPool cm = new ConnectionPool();
cm.setTransactionManager(_tm);
_connectionManagers.add(cm);
return cm;
}
/**
* Returns a WorkManager instance.
*/
public WorkManager getWorkManager()
{
synchronized (this) {
if (_workManager == null)
_workManager = new WorkManagerImpl();
}
return _workManager;
}
/**
* Returns an XATerminator. The XATerminator could be used for
* transaction completion and crash recovery.
*/
public XATerminator getXATerminator()
{
return null;
}
/**
* Creates a new Timer instance.
*/
public Timer createTimer() throws javax.resource.spi.UnavailableException
{
TimerImpl timer = new TimerImpl(this);
synchronized (_timers) {
SoftReference<Timer> timerRef = new SoftReference<Timer>(timer);
_timers.add(timerRef);
}
return timer;
}
/**
* Removes a new Timer instance.
*/
void removeTimer(Timer timer)
{
if (_timers == null)
return;
synchronized (_timers) {
for (int i = _timers.size(); i >= 0; i--) {
SoftReference<Timer> timerRef = _timers.get(i);
Timer oldTimer = timerRef.get();
if (oldTimer == null)
_timers.remove(i);
else if (oldTimer == timer)
_timers.remove(i);
}
}
}
/**
* Handles the case where a class loader is activated.
*/
public void classLoaderInit(DynamicClassLoader loader)
{
}
/**
* Handles the case where a class loader is dropped.
*/
public void classLoaderDestroy(DynamicClassLoader loader)
{
destroy();
}
/**
* Closes the resource manager.
*/
public void destroy()
{
ArrayList<ConnectionPool> connectionManagers;
ArrayList<ResourceAdapter> resources;
ArrayList<SoftReference<Timer>> timers;
synchronized (this) {
if (_isClosed)
return;
_isClosed = true;
connectionManagers = _connectionManagers;
_connectionManagers = null;
resources = _resources;
_resources = null;
timers = _timers;
_timers = null;
}
// Kill timers first, so they won't try to spawn work tasks
for (int i = 0; i < timers.size(); i++) {
SoftReference<Timer> timerRef = timers.get(i);
Timer timer = timerRef.get();
try {
if (timer != null)
timer.cancel();
} catch (Throwable e) {
log.log(Level.WARNING, e.toString(), e);
}
}
// cancel the work managers
if (_workManager != null)
_workManager.destroy();
for (int i = 0; i < connectionManagers.size(); i++) {
ConnectionPool connectionManager = connectionManagers.get(i);
try {
connectionManager.destroy();
} catch (Throwable e) {
log.log(Level.WARNING, e.toString(), e);
}
}
// finally, close the resources
for (int i = 0; i < resources.size(); i++) {
ResourceAdapter resource = resources.get(i);
try {
resource.stop();
} catch (Throwable e) {
log.log(Level.WARNING, e.toString(), e);
}
}
}
public class TimerImpl extends Timer {
private ResourceManagerImpl _rm;
TimerImpl(ResourceManagerImpl rm)
{
super(true);
_rm = rm;
}
public void cancel()
{
_rm.removeTimer(this);
super.cancel();
}
}
public String toString()
{
if (_loader != null)
return getClass().getSimpleName() + "[" + _loader.getId() + "]";
else
return getClass().getSimpleName() + "[]";
}
}