blob: eaac727cf721d9b244c20d62c1c3e24abfc27a69 [file] [log] [blame]
/*
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.enterprise.resource;
import com.sun.enterprise.resource.allocator.ResourceAllocator;
import com.sun.enterprise.resource.allocator.LocalTxConnectorAllocator;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.logging.LogDomains;
import com.sun.appserv.connectors.internal.api.PoolingException;
import com.sun.enterprise.transaction.spi.TransactionalResource;
import jakarta.resource.spi.ConnectionEventListener;
import javax.security.auth.Subject;
import javax.transaction.xa.XAResource;
import jakarta.transaction.Transaction;
import java.util.logging.Logger;
import java.util.logging.Level;
/**
* ResourceHandle encapsulates a resource connection.
* Equality on the handle is based on the id field
*
* @author Tony Ng
*/
public class ResourceHandle implements
com.sun.appserv.connectors.internal.api.ResourceHandle, TransactionalResource {
// unique ID for resource handles
static private long idSequence;
private long id;
private ClientSecurityInfo info;
private Object resource; // represents MC
private ResourceSpec spec;
private XAResource xares;
private Object usercon; // represents connection-handle to user
private ResourceAllocator alloc;
private Object instance; // the component instance holding this resource
private int shareCount; // sharing within a component (XA only)
private boolean supportsXAResource = false;
private volatile boolean busy;
private Subject subject = null;
private ResourceState state = null;
private ConnectionEventListener listener = null;
private boolean enlistmentSuspended = false;
private boolean supportsLazyEnlistment_ = false;
private boolean supportsLazyAssoc_ = false;
private static Logger logger = LogDomains.getLogger(ResourceHandle.class, LogDomains.RSR_LOGGER);
public final Object lock = new Object();
private long lastValidated; //holds the latest time at which the connection was validated.
private int usageCount; //holds the no. of times the handle(connection) is used so far.
private int partition;
private boolean isDestroyByLeakTimeOut = false;
static private long getNextId() {
synchronized (ResourceHandle.class) {
idSequence++;
return idSequence;
}
}
private boolean markedReclaim = false;
public ResourceHandle(Object resource,
ResourceSpec spec,
ResourceAllocator alloc,
ClientSecurityInfo info) {
this.id = getNextId();
this.spec = spec;
this.info = info;
this.resource = resource;
this.alloc = alloc;
if (alloc instanceof LocalTxConnectorAllocator)
supportsXAResource = false;
else
supportsXAResource = true;
if (resource instanceof
jakarta.resource.spi.LazyEnlistableManagedConnection) {
supportsLazyEnlistment_ = true;
}
if (resource instanceof
jakarta.resource.spi.DissociatableManagedConnection) {
supportsLazyAssoc_ = true;
}
}
/* public ResourceHandle(Object resource,
ResourceSpec spec,
ResourceAllocator alloc,
ClientSecurityInfo info,
boolean supportsXA) {
this.id = getNextId();
this.spec = spec;
this.info = info;
this.resource = resource;
this.alloc = alloc;
supportsXAResource = supportsXA;
if (resource instanceof
jakarta.resource.spi.LazyEnlistableManagedConnection) {
supportsLazyEnlistment_ = true;
}
if (resource instanceof
jakarta.resource.spi.DissociatableManagedConnection) {
supportsLazyAssoc_ = true;
}
} */
/**
* Does this resource need enlistment to transaction manager?
*/
public boolean isTransactional() {
return alloc.isTransactional();
}
/**
* To check whether lazy enlistment is suspended or not.<br>
* If true, TM will not do enlist/lazy enlist.
*
* @return boolean
*/
public boolean isEnlistmentSuspended() {
return enlistmentSuspended;
}
public void setEnlistmentSuspended(boolean enlistmentSuspended) {
this.enlistmentSuspended = enlistmentSuspended;
}
public void markForReclaim(boolean reclaim) {
this.markedReclaim = reclaim;
}
/**
* To check if the resourceHandle is marked for leak reclaim or not. <br>
*
* @return boolean
*/
public boolean isMarkedForReclaim() {
return markedReclaim;
}
public boolean supportsXA() {
return supportsXAResource;
}
public ResourceAllocator getResourceAllocator() {
return alloc;
}
public Object getResource() {
return resource;
}
public ClientSecurityInfo getClientSecurityInfo() {
return info;
}
public void setResourceSpec(ResourceSpec spec) {
this.spec = spec;
}
public ResourceSpec getResourceSpec() {
return spec;
}
public XAResource getXAResource() {
return xares;
}
public Object getUserConnection() {
return usercon;
}
public void setComponentInstance(Object instance) {
this.instance = instance;
}
public void closeUserConnection() throws PoolingException {
getResourceAllocator().closeUserConnection(this);
}
public Object getComponentInstance() {
return instance;
}
public long getId() {
return id;
}
public void fillInResourceObjects(Object userConnection,
XAResource xaRes) {
if (userConnection != null) usercon = userConnection;
if (xaRes != null) {
if (logger.isLoggable(Level.FINEST)) {
//When Log level is Finest, XAResourceWrapper is used to log
//all XA interactions - Don't wrap XAResourceWrapper if it is
//already wrapped
if ((xaRes instanceof XAResourceWrapper) ||
(xaRes instanceof ConnectorXAResource)) {
this.xares = xaRes;
} else {
this.xares = new XAResourceWrapper(xaRes);
}
} else {
this.xares = xaRes;
}
}
}
// For XA-capable connections, multiple connections within a
// component are collapsed into one. shareCount keeps track of
// the number of additional shared connections
public void incrementCount() {
shareCount++;
}
public void decrementCount() {
if (shareCount == 0) {
throw new IllegalStateException("shareCount cannot be negative");
} else {
shareCount--;
}
}
public int getShareCount() {
return shareCount;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
public Subject getSubject() {
return subject;
}
public boolean equals(Object other) {
if (other == null) return false;
if (other instanceof ResourceHandle) {
return this.id == (((ResourceHandle) other).id);
}
return false;
}
public int hashCode() {
return Long.valueOf(id).hashCode();
}
public String toString() {
return String.valueOf(id);
}
private boolean connectionErrorOccurred = false;
public void setConnectionErrorOccurred() {
connectionErrorOccurred = true;
}
public boolean hasConnectionErrorOccurred() {
return connectionErrorOccurred;
}
public void setResourceState(ResourceState state) {
this.state = state;
}
public ResourceState getResourceState() {
return state;
}
public void setListener(ConnectionEventListener l) {
this.listener = l;
}
public ConnectionEventListener getListener() {
return listener;
}
public boolean isShareable() {
return alloc.shareableWithinComponent();
}
public void destroyResource() {
throw new UnsupportedOperationException("Transaction is not supported yet");
}
public boolean isEnlisted() {
return state != null && state.isEnlisted();
}
public long getLastValidated() {
return lastValidated;
}
public void setLastValidated(long lastValidated) {
this.lastValidated = lastValidated;
}
public int getUsageCount() {
return usageCount;
}
public void incrementUsageCount() {
usageCount++;
}
public int getPartition() {
return partition;
}
public void setPartition(int partition) {
this.partition = partition;
}
public String getName() {
return spec.getResourceId();
}
public boolean supportsLazyEnlistment() {
return supportsLazyEnlistment_;
}
public boolean supportsLazyAssociation() {
return supportsLazyAssoc_;
}
public void enlistedInTransaction(Transaction tran) throws IllegalStateException {
ConnectorRuntime.getRuntime().getPoolManager().resourceEnlisted(tran, this);
}
public void setBusy(boolean isBusy){
busy = isBusy;
}
public boolean isBusy(){
return busy;
}
public boolean getDestroyByLeakTimeOut(){
return isDestroyByLeakTimeOut;
}
public void setDestroyByLeakTimeOut(boolean isDestroyByLeakTimeOut){
this.isDestroyByLeakTimeOut = isDestroyByLeakTimeOut;
}
}