FileDocCategorySizeDatePackage
AddressManager.javaAPI DocExample11733Tue May 29 16:57:16 BST 2007com.sun.xml.ws.tx.common

AddressManager.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.xml.ws.tx.common;

import com.sun.xml.ws.tx.webservice.member.at.CoordinatorPortType;
import com.sun.xml.ws.tx.webservice.member.at.ParticipantPortType;
import com.sun.xml.ws.tx.webservice.member.coord.RegistrationCoordinatorPortType;
import com.sun.xml.ws.tx.webservice.member.coord.RegistrationPortTypeRPC;
import com.sun.xml.ws.tx.webservice.member.coord.RegistrationRequesterPortType;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.logging.Level;

/**
 * This class handles all address calculations for the wstx-service enpoints
 *
 * @author Ryan.Shoemaker@Sun.COM
 * @version $Revision: 1.2.2.1 $
 * @since 1.0
 */
public class AddressManager {

    static final private TxLogger logger = TxLogger.getLogger(AddressManager.class);

    private static String hostAndPort;
    private static String secureHostAndPort;

    private static final String context = "/__wstx-services";

    // override props - default to https
    private static String preferredScheme = System.getProperty("com.sun.xml.ws.tx.preferredScheme", "https");
    private static String httpPortOverride = System.getProperty("com.sun.xml.ws.tx.httpPortOverride", null);
    private static String httpsPortOverride = System.getProperty("com.sun.xml.ws.tx.httpsPortOverride", null);
    private static String hostNameOverride = System.getProperty("com.sun.xml.ws.tx.hostNameOverride", null);

    static {
        // get the host and port info from GF
        callGetDefaultVirtualServerHostAndPort();

        // log a message if the preferred scheme has been overridden to http
        if ((preferredScheme.equals("http") && (logger.isLogging(Level.FINEST)))) {
            logger.fine("static initializer", "preferred scheme has been set to: " + preferredScheme);
        }

        // logic to override the dynamic settings
        // users can select a preferred scheme and override the http and https port numbers if necessary
        calculateHostAndPortOverrides();
    }

    private AddressManager() {
    }

    /**
     * Return an address for the specified port type using the preferred scheme.
     * <p/>
     * This method should be used most of the time unless you explicitly know which
     * scheme you want back.
     *
     * @param portType the endpoint port type
     * @return a URI representing the preferred endpoint address
     */
    public static URI getPreferredAddress(Class portType) {
        return "http".equals(preferredScheme) ? getAddress(portType, false) : getAddress(portType, true);
    }

    /**
     * Return an address for the specified port type based on the 'secure' flag.  If
     * the 'secure' flag is true, the address will begin with "https", otherwise it
     * will begin with "http".
     *
     * @param portType the endpoint port type
     * @param secure flag to control whether the address is secure or non-secure
     * @return a URI representing the endpoint address with the specified secure or non-secure scheme
     */
    public static URI getAddress(Class portType, boolean secure) {
        StringBuilder addr = new StringBuilder();

        if (secure) {
            addr.append("https://").append(secureHostAndPort).append(context);
        } else { // non-secure
            addr.append("http://").append(hostAndPort).append(context);
        }

        // assign the proper context path onto the end of the scheme, host, port, and context root
        // TODO: are there other addresses we need to generate?
        if (portType == RegistrationCoordinatorPortType.class) {
            addr.append("/wscoor/coordinator/register");
        } else if (portType == RegistrationRequesterPortType.class) {
            addr.append("/wscoor/coordinator/registerResponse");
        } else if (portType == RegistrationPortTypeRPC.class) {
            addr.append("/wscoor/coordinator/synchRegister");
        } else if (portType == CoordinatorPortType.class) {
            addr.append("/wsat/coordinator");
        } else if (portType == ParticipantPortType.class) {
            addr.append("/wsat/2pc");
        } else {
            return null;
        }

        URI uri = null;
        try {
            uri = new URI(addr.toString());
        } catch (URISyntaxException e) {
        }

        return uri;
    }

    /**
     * Call appserv-core/com.sun.enterprise.webservice.WsTxUtils in GF to get the host and port information.
     */
    private static void callGetDefaultVirtualServerHostAndPort() {
        try {
            if (logger.isLogging(Level.FINEST)) {
                logger.finest("static initializer", "getting host and port from AS...");
            }
            Class c = Class.forName("com.sun.enterprise.webservice.WsTxUtils");
            Object instance = c.newInstance();
            Method m = c.getMethod("getDefaultVirtualServerHostAndPort", boolean.class);
            hostAndPort = (String) m.invoke(instance, false);
            secureHostAndPort = (String) m.invoke(instance, true);

            if (secureHostAndPort == null || hostAndPort == null) {
                // there must have been an error on the GF-side, so fallback to a default
                fallback();
                logger.warning("getAddress",
                        LocalizationMessages.HOST_AND_PORT_LOOKUP_FAILURE_2015(preferredScheme + "://" + secureHostAndPort));
            }

            // this is an undocumented override
            if (hostNameOverride != null) {
                hostAndPort = hostNameOverride + hostAndPort.substring(hostAndPort.indexOf(':'), hostAndPort.length());
                secureHostAndPort = hostNameOverride + secureHostAndPort.substring(secureHostAndPort.indexOf(':'), secureHostAndPort.length());
                logger.finest("static initializer", "manual hostname overridden to: " + hostNameOverride);
            }

            if (logger.isLogging(Level.FINEST)) {
                logger.finest("static initializer", "hostAndPort: " + hostAndPort);
                logger.finest("static initializer", "secureHostAndPort: " + secureHostAndPort);
            }
        } catch (Throwable t) {  // trap every possible failure calling the gf code
            fallback();
            logger.info("static initializer",
                    LocalizationMessages.HOST_AND_PORT_LOOKUP_FAILURE_2015(preferredScheme + "://" + secureHostAndPort));
            logger.finest("static initializer",
                    LocalizationMessages.HOST_AND_PORT_LOOKUP_FAILURE_2015(preferredScheme + "://" + secureHostAndPort),
                    t);
        }
    }

    /**
     * Lookup any system props that override the preferred scheme, and http/s ports
     */
    private static void calculateHostAndPortOverrides() {
        final String hostName = hostAndPort.substring(0, hostAndPort.indexOf(':'));
        if ("http".equals(preferredScheme)) {
            if (httpPortOverride != null) {
                if (logger.isLogging(Level.FINEST)) {
                    logger.finest("static initializer", "http port overriden to: " + httpPortOverride);
                }
                hostAndPort = hostName + ':' + httpPortOverride;
            }
        } else if ("https".equals(preferredScheme)) {
            if (httpsPortOverride != null) {
                if (logger.isLogging(Level.FINEST)) {
                    logger.finest("static initializer", "https port overriden to: " + httpsPortOverride);
                }
                secureHostAndPort = hostName + ':' + httpsPortOverride;
            }
        } else {
            logger.warning("static initializer", LocalizationMessages.PREFERRED_SCHEME_ERROR_2016(preferredScheme));
            preferredScheme = "https";
            if (httpsPortOverride != null) {
                if (logger.isLogging(Level.FINEST)) {
                    logger.finest("static initializer", "https port overriden to: " + httpsPortOverride);
                }
                secureHostAndPort = hostName + ':' + httpsPortOverride;
            }
        }
    }

    /**
     * Set the static fields to sane value that might work as a last-ditch effort.
     */
    private static void fallback() {
        // worst-case scenario: fall back to https://canonicalhostname:8181, but also set
        // hostAndPort since it is used to ping the services.
        preferredScheme = "https";
        final String hostName = getServiceHostName();
        hostAndPort = hostName + ":8080";
        secureHostAndPort = hostName + ":8181";
    }

    /**
     * This method returns the fully qualified name of the host.  If
     * the name can't be resolved (on windows if there isn't a domain specified), just
     * host name is returned
     *
     * @return the host name
     */
    private static String getServiceHostName() {
        String hostname = null;
        try {
            // look for full name
            hostname = InetAddress.getLocalHost().getCanonicalHostName();
        } catch (UnknownHostException ex) {
            logger.warning("getServiceHostName", LocalizationMessages.FQDN_LOOKUP_FAILURE_2012(), ex);
            try {
                // fallback to ip address
                hostname = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.warning("getServiceHostName", LocalizationMessages.FQDN_LOOKUP_FAILURE_2012(), e);
            }
        }

        return hostname;
    }

}