Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * $Id: FBManagedConnectionFactory.java 60307 2014-11-30 09:30:53Z mrotteveel $
   *
   * Firebird Open Source JavaEE Connector - JDBC Driver
   *
   * Distributable under LGPL license.
   * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
   *
   * This program 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
  * LGPL License for more details.
  *
  * This file was created by members of the firebird development team.
  * All individual contributions remain the Copyright (C) of those
  * individuals.  Contributors to this file are either listed here or
  * can be obtained from a source control history command.
  *
  * All rights reserved.
  */
 package org.firebirdsql.jca;
 
 import java.io.*;
 import java.util.*;
 
 
FBManagedConnectionFactory implements the jca ManagedConnectionFactory interface and also many of the internal functions of ManagedConnection. This nonstandard behavior is required due to firebird requiring all work done in a transaction to be done over one connection. To support xa semantics, the correct db handle must be located whenever a ManagedConnection is associated with an xid. WARNING: this adapter will probably not work properly in an environment where ManagedConnectionFactory is serialized and deserialized, and the deserialized copy is expected to function as anything other than a key.

Author(s):
David Jencks
 
 
     
     private static final long serialVersionUID = 7500832904323015501L;

    
The mcfInstances weak hash map is used in deserialization to find the correct instance of a mcf after deserializing.

It is also used to return a canonical instance to org.firebirdsql.jdbc.FBDriver.

 
     private static final ReferenceQueue<FBManagedConnectionFactorymcfReferenceQueue =
             new ReferenceQueue<FBManagedConnectionFactory>();
 
     // /**
     // * @todo Claudio suggests this should be 1024*64 -1, we should find out I
     // * thought this was the largest value I could make work, but I didn't
     // * write down my experiments.
     // */
     // public final static int MAX_BLOB_BUFFER_LENGTH = 1024 * 32 - 1;
     //
     // public final static int MIN_BLOB_BUFFER_LENGTH = 1024;
 
 
     private ConnectionManager defaultCm;
     private int hashCode;
     private GDSType gdsType;
 
     // Maps supplied XID to internal transaction handle.
     // a concurrent reader map would be better
     private transient final Map xidMap = Collections.synchronizedMap(new HashMap());
 
     private transient final Object startLock = new Object();
     private transient boolean started = false;
 
     private FBConnectionProperties connectionProperties;

    
Create a new pure-Java FBManagedConnectionFactory.
    public FBManagedConnectionFactory() {
        this(GDSFactory.getDefaultGDSType(), new FBConnectionProperties());
    }

    
Create a new FBManagedConnectionFactory based around the given GDSType.

Parameters:
gdsType The GDS implementation to use
    public FBManagedConnectionFactory(GDSType gdsType) {
        this(gdsTypenew FBConnectionProperties());
    }
    
    public FBManagedConnectionFactory(GDSType gdsTypeFBConnectionProperties connectionProperties) {
        this. = new FBStandAloneConnectionManager();
        this. = connectionProperties;
        setType(gdsType.toString());
    }
    public GDS getGDS() {
        return GDSFactory.getGDSForType(getGDSType());
    }

    
Get the GDS implementation type around which this factory is based.

Returns:
The GDS implementation type
    public GDSType getGDSType() {
        if ( != null)
            return ;
        
         = GDSType.getType(getType());
        
        return ;
    }
    
    

Deprecated:
use getBlobBufferSize()
    public int getBlobBufferLength() {
        return getBlobBufferSize();
    }
    
    

Deprecated:
use setBlobBufferSize(int)
    public void setBlobBufferLength(int value) {
        setBlobBufferSize(value);
    }
    
    
    public Integer getTransactionIsolation() {
        return Integer.valueOf(getDefaultTransactionIsolation());
    }
    
    
    public void setTransactionIsolation(Integer value) {
        if (value != null)
            setDefaultTransactionIsolation(value.intValue());
    }
    
    

Deprecated:
use getDefaultIsolation()
        return getDefaultIsolation();
    }

    
    public void setTransactionIsolationName(String name) {
        setDefaultIsolation(name);
    }
    
    

Deprecated:
use getCharSet() instead.
    public String getLocalEncoding() {
        return getCharSet();
    }
    
    

Deprecated:
use setCharSet(java.lang.String) instead.
    public void setLocalEncoding(String localEncoding) {
        setCharSet(localEncoding);
    }
    
    public int getBlobBufferSize() {
        return .getBlobBufferSize();
    }
    public int getBuffersNumber() {
        return .getBuffersNumber();
    }
    public String getCharSet() {
        return .getCharSet();
    }
    public String getDatabase() {
        return .getDatabase();
    }
    }
    public String getDefaultIsolation() {
        return .getDefaultIsolation();
    }
    public int getDefaultTransactionIsolation() {
    }
    public String getEncoding() {
        return .getEncoding();
    }
    public String getNonStandardProperty(String key) {
        return .getNonStandardProperty(key);
    }
    public String getPassword() {
        return .getPassword();
    }
    public String getRoleName() {
        return .getRoleName();
    }
    public int getSocketBufferSize() {
        return .getSocketBufferSize();
    }
    public String getSqlDialect() {
        return .getSqlDialect();
    }
    public String getTpbMapping() {
        return .getTpbMapping();
    }
    public TransactionParameterBuffer getTransactionParameters(int isolation) {
        return .getTransactionParameters(isolation);
    }
    public String getType() {
        return .getType();
    }
    public String getUserName() {
        return .getUserName();
    }
    public String getUseTranslation() {
        return .getUseTranslation();
    }
    public boolean isTimestampUsesLocalTimezone() {
    }
    public boolean isUseStandardUdf() {
        return .isUseStandardUdf();
    }
    public boolean isUseStreamBlobs() {
        return .isUseStreamBlobs();
    }
    public void setBlobBufferSize(int bufferSize) {
        .setBlobBufferSize(bufferSize);
    }
    public void setBuffersNumber(int buffersNumber) {
        .setBuffersNumber(buffersNumber);
    }
    public void setCharSet(String charSet) {
        .setCharSet(charSet);
    }
    public void setDatabase(String database) {
        .setDatabase(database);
    }
    public void setDefaultIsolation(String isolation) {
        .setDefaultIsolation(isolation);
    }
    public void setDefaultTransactionIsolation(int defaultIsolationLevel) {
        .setDefaultTransactionIsolation(defaultIsolationLevel);
    }
    public void setEncoding(String encoding) {
        .setEncoding(encoding);
    }
    public void setNonStandardProperty(String keyString value) {
        .setNonStandardProperty(keyvalue);        
    }
    public void setNonStandardProperty(String propertyMapping) {
        .setNonStandardProperty(propertyMapping);
    }
    public void setPassword(String password) {
        .setPassword(password);
    }
    public void setRoleName(String roleName) {
        .setRoleName(roleName);        
    }
    public void setSocketBufferSize(int socketBufferSize) {
        .setSocketBufferSize(socketBufferSize);        
    }
    public void setSqlDialect(String sqlDialect) {
        .setSqlDialect(sqlDialect);
    }
    public void setTimestampUsesLocalTimezone(boolean timestampUsesLocalTimezone) {
        .setTimestampUsesLocalTimezone(timestampUsesLocalTimezone);        
    }
    public void setTpbMapping(String tpbMapping) {
        .setTpbMapping(tpbMapping);        
    }
    public void setTransactionParameters(int isolationTransactionParameterBuffer tpb) {
        .setTransactionParameters(isolationtpb);        
    }
    public void setType(String type) {
        if ( != null)
            throw new java.lang.IllegalStateException(
                    "Cannot change GDS type at runtime.");
        
        .setType(type);
    }
    public void setUserName(String userName) {
        .setUserName(userName);        
    }
    public void setUseStandardUdf(boolean useStandardUdf) {
        .setUseStandardUdf(useStandardUdf);        
    }
    public void setUseStreamBlobs(boolean useStreamBlobs) {
        .setUseStreamBlobs(useStreamBlobs);        
    }
    public void setUseTranslation(String translationPath) {
        .setUseTranslation(translationPath);        
    }
    public boolean isDefaultResultSetHoldable() {
    }
    public void setDefaultResultSetHoldable(boolean isHoldable) {
    }
    public void setDefaultConnectionManager(ConnectionManager defaultCm) {
        this. = defaultCm;
    }
    
    public int getSoTimeout() {
        return .getSoTimeout();
    }
    public void setSoTimeout(int soTimeout) {
        .setSoTimeout(soTimeout);
    }
    
    public int getConnectTimeout() {
        return .getConnectTimeout();
    }
    
    public void setConnectTimeout(int connectTimeout) {
        .setConnectTimeout(connectTimeout);
    }
    public int hashCode() {
        if ( != 0) 
            return ;
        int result = 17;
        result = 37 * result + .hashCode();
        if (result == 0)
            result = 17;
        
        if ( != null)
             = result;
        
        return result;
    }
    public boolean equals(Object other) {
        if (other == thisreturn true;
        if (!(other instanceof FBManagedConnectionFactory)) return false;
        FBManagedConnectionFactory that = (FBManagedConnectionFactoryother;
        return this..equals(that.connectionProperties);
    }
    
        try {
            return new FBConnectionRequestInfo(getDatabaseParameterBuffer().deepCopy());
        } catch(SQLException ex) {
            throw new FBResourceException(ex);
        }
    }
    
    public FBTpb getDefaultTpb() throws ResourceException {
        int defaultTransactionIsolation = 
        return getTpb(defaultTransactionIsolation);
    }
    public FBTpb getTpb(int defaultTransactionIsolationthrows FBResourceException {
        return new FBTpb(.getMapper().getMapping(
                defaultTransactionIsolation));
    }

    
The createConnectionFactory method creates a DataSource using the supplied ConnectionManager.

Parameters:
cxManager a ConnectionManager value
Returns:
a java.lang.Object value
Throws:
javax.resource.ResourceException if an error occurs
            throws ResourceException {
        start();
        return new FBDataSource(thiscxManager);
    }

    
The createConnectionFactory method creates a DataSource with a default stand alone ConnectionManager. Ours can implement pooling.

Returns:
a new javax.sql.DataSource based around this connection factory
Throws:
javax.resource.ResourceException if an error occurs
    public Object createConnectionFactory() throws ResourceException {
        start();
        return new FBDataSource(this);
    }

    
Creates a new physical connection to the underlying EIS resource manager, ManagedConnectionFactory uses the security information (passed as Subject) and additional ConnectionRequestInfo (which is specific to ResourceAdapter and opaque to application server) to create this new connection.

Parameters:
subject Caller's security information
cri Additional resource adapter specific connection request information
Returns:
ManagedConnection instance
Throws:
javax.resource.ResourceException generic exception
javax.resource.spi.SecurityException security related error
javax.resource.spi.ResourceAllocationException failed to allocate system resources for connection request
javax.resource.spi.ResourceAdapterInternalException resource adapter related error condition
javax.resource.spi.EISSystemException internal error condition in EIS instance
            ConnectionRequestInfo crithrows ResourceException {
        start();
        return new FBManagedConnection(subjectcrithis);
    }

    
Returns a matched connection from the candidate set of connections. ManagedConnectionFactory uses the security info (as in Subject) and information provided through ConnectionRequestInfo and additional Resource Adapter specific criteria to do matching. Note that criteria used for matching is specific to a resource adapter and is not prescribed by the Connector specification.

This method returns a ManagedConnection instance that is the best match for handling the connection allocation request.

Parameters:
connectionSet candidate connection set
subject caller's security information
cxRequestInfo additional resource adapter specific connection request information
Returns:
ManagedConnection if resource adapter finds an acceptable match otherwise null
Throws:
javax.resource.ResourceException - generic exception
javax.resource.spi.SecurityException - security related error
javax.resource.spi.ResourceAdapterInternalException - resource adapter related error condition
javax.resource.NotSupportedException - if operation is not supported
    public ManagedConnection matchManagedConnections(Set connectionSet,
            javax.security.auth.Subject subject,
            ConnectionRequestInfo cxRequestInfothrows ResourceException {
        
        Iterator i = connectionSet.iterator();
        while (i.hasNext()) {
            FBManagedConnection mc = (FBManagedConnectioni.next();
            if (mc.matches(subject, (FBConnectionRequestInfocxRequestInfo))
                return mc;
        }
        return null;
    }

    
Set the log writer for this ManagedConnectionFactory instance. The log writer is a character output stream to which all logging and tracing messages for this ManagedConnectionFactory instance will be printed. ApplicationServer manages the association of output stream with the ManagedConnectionFactory. When a ManagedConnectionFactory object is created the log writer is initially null, in other words, logging is disabled. Once a log writer is associated with a ManagedConnectionFactory, logging and tracing for ManagedConnectionFactory instance is enabled.

The ManagedConnection instances created by ManagedConnectionFactory "inherits" the log writer, which can be overridden by ApplicationServer using javax.resource.spi.ManagedConnection.setLogWriter(java.io.PrintWriter)to set ManagedConnection specific logging and tracing.

Parameters:
out an out stream for error logging and tracing
Throws:
javax.resource.ResourceException generic exception
javax.resource.spi.ResourceAdapterInternalException resource adapter related error condition
    public void setLogWriter(PrintWriter outthrows ResourceException {
        // ignore - we're using log4j
    }

    
Get the log writer for this ManagedConnectionFactory instance. The log writer is a character output stream to which all logging and tracing messages for this ManagedConnectionFactory instance will be printed. ApplicationServer manages the association of output stream with the ManagedConnectionFactory. When a ManagedConnectionFactory object is created the log writer is initially null, in other words, logging is disabled.

Returns:
PrintWriter instance
Throws:
javax.resource.ResourceException generic exception
    public PrintWriter getLogWriter() {
        return null;// we're using log4j
    }
    // Serialization support
    private Object readResolve() throws ObjectStreamException {
        if (mcf != null)  return mcf;
        return mcf;
    }

    
The canonicalize method is used in FBDriver to reuse previous fbmcf instances if they have been create. It should really be package access level

Returns:
a FBManagedConnectionFactory value
        final FBManagedConnectionFactory mcf = internalCanonicalize();
        if (mcf != nullreturn mcf;
        start();
        return this;
    }
        final SoftReference<FBManagedConnectionFactoryfactoryReference = .get(getCacheKey());
        return factoryReference != null ? factoryReference.get() : null;
    }

    
Starts this MCF and adds this instance to #mcfInstances cache.

This implementation (together with canonicalize() has a race condition with regard to the instance cache. As this is a relatively harmless one, we leave it as is.

    private void start() {
        synchronized () {
            if (return;
             = true;
        }
        cleanMcfInstances();
    }

    
Removes cleared references from the mcfInstances cache.
    private void cleanMcfInstances() {
        Reference<? extends FBManagedConnectionFactoryreference;
        while ((reference = .poll()) != null) {
            .values().remove(reference);
        }
    }
    void notifyStart(FBManagedConnection mcXid xidthrows GDSException {
        .put(xidmc);
    }
    void notifyEnd(FBManagedConnection mcXid xidthrows XAException {
        // empty
    }
    int notifyPrepare(FBManagedConnection mcXid xidthrows GDSException,
            XAException {
        FBManagedConnection targetMc = (FBManagedConnection.get(xid);
        if (targetMc == null)
            throw new FBXAException("Commit called with unknown transaction",
                    .);
        return targetMc.internalPrepare(xid);
    }
    void notifyCommit(FBManagedConnection mcXid xidboolean onePhase)
            throws GDSExceptionXAException {
        FBManagedConnection targetMc = (FBManagedConnection.get(xid);
        if (targetMc == null)
            tryCompleteInLimboTransaction(getGDS(), xidtrue);
        else
            targetMc.internalCommit(xidonePhase);
        .remove(xid);
    }
    void notifyRollback(FBManagedConnection mcXid xidthrows GDSException,
            XAException {
        FBManagedConnection targetMc = (FBManagedConnection.get(xid);
        if (targetMc == null)
            tryCompleteInLimboTransaction(getGDS(), xidfalse);
        else
            targetMc.internalRollback(xid);
        .remove(xid);
    }
    public void forget(FBManagedConnection mcXid xidthrows GDSException {
        .remove(xid);
    }
    public void recover(FBManagedConnection mcXid xidthrows GDSException {
    }

    
Try to complete the "in limbo" transaction. This method tries to reconnect an "in limbo" transaction and complete it either by commit or rollback. If no "in limbo" transaction can be found, or error happens during completion, an exception is thrown.

Parameters:
gds instance of org.firebirdsql.gds.GDS that will be used to reconnect transaction.
xid Xid of the transaction to reconnect.
commit true if "in limbo" transaction should be committed, otherwise false.
Throws:
javax.transaction.xa.XAException if "in limbo" transaction cannot be completed.
    private void tryCompleteInLimboTransaction(GDS gdsXid xidboolean commit)
            throws XAException {
        try {
            FBManagedConnection tempMc = null;
            FirebirdLocalTransaction tempLocalTx = null;
            try {
                tempMc = new FBManagedConnection(nullnullthis);
                tempLocalTx = (FirebirdLocalTransactiontempMc.getLocalTransaction();
                tempLocalTx.begin();
                long fbTransactionId = 0;
                boolean found = false;
                if (tempMc.getGDSHelper().compareToVersion(2, 0) < 0) {
                    // Find Xid by scanning
                    FBXid[] inLimboIds = (FBXid[]) tempMc.recover(.);
                    for (int i = 0; i < inLimboIds.lengthi++) {
                        if (inLimboIds[i].equals(xid)) {
                            found = true;
                            fbTransactionId = inLimboIds[i].getFirebirdTransactionId();
                        }
                    }
                } else {
                    // Find Xid by intelligent scan
                    FBXid foundXid = (FBXidtempMc.findSingleXid(xid);
                    if (foundXid != null && foundXid.equals(xid)) {
                        found = true;
                        fbTransactionId = foundXid.getFirebirdTransactionId();
                    }
                }
                if (!found)
                    throw new FBXAException((commit ? "Commit" : "Rollback")
                            + " called with unknown transaction.",
                            .);
                IscDbHandle dbHandle = tempMc.getGDSHelper().getCurrentDbHandle();
                IscTrHandle trHandle = gds.createIscTrHandle();
                gds.iscReconnectTransaction(trHandledbHandle,
                                fbTransactionId);
                // complete transaction by commit or rollback
                if (commit)
                    gds.iscCommitTransaction(trHandle);
                else
                    gds.iscRollbackTransaction(trHandle);
                if (tempMc.getGDSHelper().compareToVersion(3, 0) < 0) {
                    // remove heuristic data from rdb$transactions (only possible in versions before Firebird 3)
                    try {
                        String query = "delete from rdb$transactions where rdb$transaction_id = " + fbTransactionId;
                        GDSHelper gdsHelper = new GDSHelper(gdsgetDatabaseParameterBuffer(), dbHandlenull);
                        AbstractIscTrHandle trHandle2 = (AbstractIscTrHandlegds.createIscTrHandle();
                        gds.iscStartTransaction(trHandle2gdsHelper.getCurrentDbHandle(), getDefaultTpb().getTransactionParameterBuffer());
                        gdsHelper.setCurrentTrHandle(trHandle2);
                        AbstractIscStmtHandle stmtHandle2 = (AbstractIscStmtHandlegds.createIscStmtHandle();
                        gds.iscDsqlAllocateStatement(gdsHelper.getCurrentDbHandle(), stmtHandle2);
                        gdsHelper.prepareStatement(stmtHandle2queryfalse);
                        gdsHelper.executeStatement(stmtHandle2false);
                        gdsHelper.closeStatement(stmtHandle2true);
                        gds.iscCommitTransaction(trHandle2);
                    } catch (SQLException sqle) {
                        throw new FBXAException("unable to remove in limbo transaction from rdb$transactions where rdb$transaction_id = " + fbTransactionId.);
                    }
                }
            } catch (GDSException ex) {
                /*
                 * if ex.getIntParam() is 335544353 (transaction is not in limbo) and next ex.getIntParam() is 335544468 (transaction {0} is {1})
                 *  => detected heuristic
                 */
                int errorCode = .;
                int intParam = ex.getIntParam();
                int nextIntParam = ex.getNext().getIntParam();
                
                if (intParam == . && nextIntParam == .) {
                    String param = ex.getNext().getNext().getNext().getParam();
                    if ("committed".equals(param))
                        errorCode = .;
                    else if ("rolled back".equals(param))
                        errorCode = .;
                }
                
                throw new FBXAException("unable to complete in limbo transaction"errorCodeex);
            } finally {
                try {
                    if (tempLocalTx != null && tempLocalTx.inTransaction())
                        tempLocalTx.commit();
                } finally {
                    if (tempMc != nulltempMc.destroy();
                }
            }
        } catch (ResourceException ex) {
            throw new FBXAException(.ex);
        }
    }
            throws ResourceException {
        Class connectionClass = GDSFactory.getConnectionClass(getGDSType());
        if (!AbstractConnection.class.isAssignableFrom(connectionClass))
            throw new IllegalArgumentException("Specified connection class"
                    + " does not extend " + AbstractConnection.class.getName()
                    + " class");
        try {
            Constructor constructor = connectionClass
                    .getConstructor(new Class[] { FBManagedConnection.class});
            return (AbstractConnectionconstructor
                    .newInstance(new Object[] { mc});
        } catch (NoSuchMethodException ex) {
            throw new FBResourceException(
                    "Cannot instantiate connection class "
                            + connectionClass.getName()
                            + ", no constructor accepting "
                            + FBManagedConnection.class
                            + " class as single parameter was found.");
        } catch (InvocationTargetException ex) {
            if (ex.getTargetException() instanceof RuntimeException)
                throw (RuntimeExceptionex.getTargetException();
            if (ex.getTargetException() instanceof Error)
                throw (Errorex.getTargetException();
            throw new FBResourceException((Exceptionex.getTargetException());
        } catch (IllegalAccessException ex) {
            throw new FBResourceException("Constructor for class "
                    + connectionClass.getName() + " is not accessible.");
        } catch (InstantiationException ex) {
            throw new FBResourceException("Cannot instantiate class"
                    + connectionClass.getName());
        }
    }
    public final FBConnectionProperties getCacheKey() {
    }
New to GrepCode? Check out our FAQ X