All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.FailOverInfo Maven / Gradle / Ivy

//---------------------------------------------------------------------------------------------------------------------------------
// File: FailOverInfo.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 

package com.microsoft.sqlserver.jdbc;
import java.util.logging.*;
import java.text.*;


/**
* This class keeps the failover server info and if the mirror has become the primary.
* For synchronizing better and not to keep a lock in the class through a connection open
* a placeholder class is used to get the failover info in one shot. This class should never directly expose its
* members.
*/

final class FailoverInfo  
{
    private String 		failoverPartner;        
    private int 		portNumber;	
    private String 		failoverInstance;
    private boolean      setUpInfocalled; 

    // This member is exposed outside for reading, we need to know in advance if the
    // failover partner is the currently active server before making a DNS resolution and a connect attempt.
    private boolean 	useFailoverPartner;
    boolean getUseFailoverPartner() 	{return useFailoverPartner;}


    FailoverInfo(String failover, SQLServerConnection con, boolean actualFailoverPartner)
    {
        failoverPartner 	= failover;		
        useFailoverPartner 	= actualFailoverPartner;
        portNumber=-1; // init to -1 to make sure that the user of this class calls the failover check before getting the port number.
    }

    // the members of this class are not exposed so inorder to log we call this function.
    void log(SQLServerConnection con)
    {
        if(con.getConnectionLogger().isLoggable(Level.FINE))
            con.getConnectionLogger().fine (con.toString() + " Failover server :" + failoverPartner + " Failover partner is primary : " 
                +useFailoverPartner );
    }

    // this function gets the failover server port and sets up the security manager
    // note calls to these should be synchronized or guaranteed to happen from only one thread.
    private void setupInfo(SQLServerConnection con) throws SQLServerException
    {
        if (setUpInfocalled)
            return;

        if (0 == failoverPartner.length()) 
        {
            portNumber=SQLServerConnection.DEFAULTPORT;
        }
        else
        {
            //3.3006 get the instance name
            int px = failoverPartner.indexOf('\\');
            String instancePort=null;
            String instanceValue=null;

            // found the instance name with the severname
            if (px>=0) 
            {
                if(con.getConnectionLogger().isLoggable(Level.FINE))
                    con.getConnectionLogger().fine (con.toString() + " Failover server :" + failoverPartner );
                instanceValue = failoverPartner.substring(px+1, failoverPartner.length());
                failoverPartner = failoverPartner.substring(0, px);
                con.ValidateMaxSQLLoginName(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceValue);
                failoverInstance = instanceValue;
                instancePort = con.getInstancePort(failoverPartner, instanceValue);

                try 
                {
                    portNumber = (new Integer(instancePort)).intValue();
                }
                catch (NumberFormatException e) 
                {
                    // Should not get here as the server should give a proper port number anyway. 
                    MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber"));
                    Object[] msgArgs = {instancePort};
                    SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, false);
                }
            }
            else
                portNumber= SQLServerConnection.DEFAULTPORT;
        }
        setUpInfocalled = true;
    }
	
    synchronized ServerPortPlaceHolder failoverPermissionCheck(SQLServerConnection con, boolean link)  throws SQLServerException
    {
        setupInfo(con);
        return new ServerPortPlaceHolder(failoverPartner, portNumber, failoverInstance, link);
    }

    // Add/replace the failover server, 
    synchronized void failoverAdd(SQLServerConnection connection, boolean actualUseFailoverPartner,  String actualFailoverPartner)  throws SQLServerException
    {
        if (useFailoverPartner != actualUseFailoverPartner) 
        {
            if(connection.getConnectionLogger().isLoggable(Level.FINE))
            	connection.getConnectionLogger().fine (connection.toString() + " Failover detected. failover partner=" + actualFailoverPartner);
            useFailoverPartner = actualUseFailoverPartner;
        }
        // The checking for actualUseFailoverPartner may look weird but this is required 
        // We only change the failoverpartner info when we connect to the primary 
        // if we connect to the secondary and it sends a failover partner 
        // we wont store that information.
        if (!actualUseFailoverPartner && !failoverPartner.equals(actualFailoverPartner))
        {
            failoverPartner = actualFailoverPartner;
            // new FO partner need to setup again.
            setUpInfocalled = false;
        }
    }
}

// A simple readonly placeholder class to store the current server info. 
// We need this class so during a connection open we can keep a copy of the current failover info stable
// This is also used to keep the standalone primary server connection information.
//  
final class ServerPortPlaceHolder
{
    private final String serverName;
    private final int port;
    private final String instanceName;
    private final  boolean checkLink; 
    private final SQLServerConnectionSecurityManager  securityManager;
    
    ServerPortPlaceHolder(String name, int conPort, String instance, boolean fLink)
    {
        serverName = name;		
        port 			= conPort;
        instanceName = instance;
        checkLink = fLink;
        securityManager = new SQLServerConnectionSecurityManager(serverName, port);
        doSecurityCheck();
    }

    // accessors
    int getPortNumber()		{return port;}
    String getServerName()		{return serverName;}
    String getInstanceName()		{return instanceName;}
    void doSecurityCheck()
    {
        securityManager.checkConnect();
        if(checkLink)   
            securityManager.checkLink();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy