Package org.apache.harmony.rmi.transport

Source Code of org.apache.harmony.rmi.transport.Endpoint$FQDNGetter

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @author  Mikhail A. Markov
* @version $Revision: 1.1.2.3 $
*/
package org.apache.harmony.rmi.transport;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.ConnectIOException;
import java.rmi.RemoteException;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.security.AccessController;

import org.apache.harmony.rmi.common.CreateThreadAction;
import org.apache.harmony.rmi.common.GetBooleanPropAction;
import org.apache.harmony.rmi.common.GetLongPropAction;
import org.apache.harmony.rmi.common.GetStringPropAction;
import org.apache.harmony.rmi.common.RMIProperties;
import org.apache.harmony.rmi.internal.nls.Messages;


/**
* Endpoint implementation: it contains information about host, port,
* client-side and server-side socket factories.
*
* @author  Mikhail A. Markov
* @version $Revision: 1.1.2.3 $
*/
public class Endpoint {

    /** Indicates null client-side factory. */
    public static final int NULL_CSF = 0x00;

    /** Indicates non-null client-side factory. */
    public static final int NONNULL_CSF = 0x01;

    // Host address.
    private final String host;

    // Port number.
    private int port;

    // Client-side socket factory.
    private RMIClientSocketFactory csf;

    // Server-side socket factory.
    private RMIServerSocketFactory ssf;

    // Local host address.
    private static String localHost = getLocalHost();

    // True if local host has been obtained and is not equal to 127.0.0.1
    private static boolean isLocalHostIdentified = false;

    // If non-null then it'll be used as a result of getLocalHost() method call.
    private static String localHostPropVal =
            (String) AccessController.doPrivileged(new GetStringPropAction(
                    RMIProperties.HOSTNAME_PROP));

    // If true then we will forcibly use FQDN by default.
    private static boolean useLocalHostName =
            ((Boolean) AccessController.doPrivileged(new GetBooleanPropAction(
                    RMIProperties.USELOCALHOSTNAME_PROP))).booleanValue();

    /*
     * The time that we will wait to obtain FQDN for this local host (in ms).
     * The default value is 10000 ms (10 sec.).
     */
    private static int localHostNameTimeout =
            ((Long) AccessController.doPrivileged(
                new GetLongPropAction(RMIProperties.LOCALHOSTNAMETIMEOUT_PROP,
                        10000))).intValue();

    /**
     * Constructs Local Endpoint.
     *
     * @param port port number
     * @param csf client-side socket factory
     * @param ssf server-side socket factory
     */
    public Endpoint(int port,
                    RMIClientSocketFactory csf,
                    RMIServerSocketFactory ssf) {
        host = getLocalHost();
        this.port = port;
        this.csf = csf;
        this.ssf = ssf;
    }

    /**
     * Constructs Endpoint.
     *
     * @param host host address/name
     * @param port port number
     * @param csf client-side socket factory
     * @param ssf server-side socket factory
     */
    public Endpoint(String host,
                    int port,
                    RMIClientSocketFactory csf,
                    RMIServerSocketFactory ssf) {
        this.host = host;
        this.port = port;
        this.csf = csf;
        this.ssf = ssf;
    }

    /**
     * Returns Endpoint created from the given Endpoint but having null host
     * (Such Endpoints are used for local endpoints for comparison).
     *
     * @param ep Endpoint to create template from
     *
     * @return created Endpoint
     */
    public static Endpoint createTemplate(Endpoint ep) {
        return new Endpoint(null, ep.port, ep.csf, ep.ssf);
    }

    /**
     * Creates and returns server socket.
     *
     * @return created server socket
     */
    public ServerSocket createServerSocket() throws IOException {
        ServerSocket ss = DefaultRMISocketFactory.getNonNullServerFactory(ssf)
                .createServerSocket(port);

        if (port == 0) {
            port = ss.getLocalPort();
        }
        return ss;
    }

    /**
     * Creates and returns socket.
     *
     * @return created socket
     */
    public Socket createSocket() throws RemoteException {
        Socket s;

        try {
            s = DefaultRMISocketFactory.getNonNullClientFactory(csf)
                    .createSocket(host, port);
        } catch (java.net.UnknownHostException uhe) {
            // rmi.80=Unable to connect to server {0}
            throw new java.rmi.UnknownHostException(
                    Messages.getString("rmi.80", toString()), uhe); //$NON-NLS-1$
        } catch (java.net.ConnectException ce) {
            throw new java.rmi.ConnectException(
                    Messages.getString("rmi.80", toString()), ce); //$NON-NLS-1$
        } catch (IOException ioe) {
            throw new ConnectIOException(
                    Messages.getString("rmi.80", toString()), ioe); //$NON-NLS-1$
        }
        return s;
    }

    /**
     * Returns client-side socket factory of this endpoint.
     *
     * @return client-side socket factory of this endpoint
     */
    public RMIClientSocketFactory getClientSocketFactory() {
        return csf;
    }

    /**
     * Returns server-side socket factory of this endpoint.
     *
     * @return server-side socket factory of this endpoint
     */
    public RMIServerSocketFactory getServerSocketFactory() {
        return ssf;
    }

    /**
     * Returns the port of this endpoint.
     *
     * @return the port of this endpoint
     */
    public int getPort() {
        return port;
    }

    /**
     * Returns the host address of this endpoint.
     *
     * @return the host address of this endpoint
     */
    public String getHost() {
        return host;
    }

    /**
     * Compares this Endpoint with another object. Returns true if the given
     * object is an instance of TcpEndpoint and has the same host, port, csf and
     * ssf fields.
     *
     * @return true if objects are equal and false otherwise
     */
    public boolean equals(Object obj) {
        if (!(obj instanceof Endpoint)) {
            return false;
        }
        Endpoint anotherEp = (Endpoint) obj;


        if (port != anotherEp.port) {
            return false;
        }

        if ((host == null) ? (host != anotherEp.host)
                : !host.equals(anotherEp.host)) {
            return false;
        }

        if ((csf == null) ? (csf != anotherEp.csf)
                : !csf.equals(anotherEp.csf)) {
            return false;
        }

        if ((ssf == null) ? (ssf != anotherEp.ssf)
                : !ssf.equals(anotherEp.ssf)) {
            return false;
        }
        return true;
    }

    /**
     * Returns hashCode for this Endpoint.
     *
     * @return hashCode for this Endpoint
     */
    public int hashCode() {
        return port;
    }

    /**
     * Writes this Endpoint to the given ObjectOutput.
     *
     * @param out ObjectOutput to write this Endpoint to
     * @param writeCsf do we need to write client-side factory or not
     *
     * @throws IOException if any I/O error occurred during writing
     */
    public void writeExternal(ObjectOutput out, boolean writeCsf)
            throws IOException {
        if (writeCsf) {
            if (csf == null) {
                out.writeByte(NULL_CSF);
            } else {
                out.writeByte(NONNULL_CSF);
            }
        }
        out.writeUTF(host);
        out.writeInt(port);

        if (writeCsf && csf != null) {
            out.writeObject(csf);
        }
    }

    /**
     * Reads data for creating Endpoint object from the specified input stream.
     *
     * @param in the stream to read data from
     * @param readCsf do we need to read client-side factory or not
     *
     * @return created Endpoint
     *
     * @throws IOException if any I/O error occurred
     * @throws ClassNotFoundException if class could not be loaded by current
     *         class loader
     */
    public static Endpoint readExternal(ObjectInput in, boolean readCsf)
            throws IOException, ClassNotFoundException {
        int inCsf = NULL_CSF;

        if (readCsf) {
            inCsf = in.readUnsignedByte();
        }
        String host = (String) in.readUTF();
        int port = in.readInt();
        RMIClientSocketFactory csf = null;

        if (readCsf && inCsf == NONNULL_CSF) {
            csf = (RMIClientSocketFactory) in.readObject();
        }
        return new Endpoint(host, port, csf, null);
    }

    /**
     * Returns string representation of this Endpoint.
     *
     * @return string representation of this Endpoint
     */
    public String toString() {
        String str = "[" + host + ":" + port; //$NON-NLS-1$ //$NON-NLS-2$

        if (csf != null) {
            str += ", csf: " + csf; //$NON-NLS-1$
        }

        if (ssf != null) {
            str += ", ssf: " + ssf; //$NON-NLS-1$
        }
        return str  + "]"; //$NON-NLS-1$
    }

    /*
     * Returns local host. If local host was already obtained, then return it
     * as a result. Otherwise perform the following steps:
     * 1) Reads java.rmi.server.hostname property if it is not equal to zero
     *    then returns it's value
     * 2) Obtains local host by calling InetAddress.getLocalHost()
     * 3) If java.rmi.server.useLocalHostname property is set to true then tries
     *    to obtain FQDN (fully qualified domain name) for hostname obtained
     *    in step 2 and returns it as a result.
     * 4) If property above is not set (or set to false) then returns the result
     *    of InetAddress.getLocalHost().getHostAddress() method call.
     *
     * @return local host
     */
    private static synchronized String getLocalHost() {
        if (isLocalHostIdentified) {
            return localHost;
        }
        if (localHostPropVal != null) {
            isLocalHostIdentified = true;
            localHost = localHostPropVal;
            return localHost;
        }

        try {
            InetAddress iaddr = InetAddress.getLocalHost();
            byte[] addr = iaddr.getAddress();

            if (useLocalHostName) {
                localHost = getFQDN(iaddr);
            } else {
                localHost = iaddr.getHostAddress();
            }
            isLocalHostIdentified = true;
        } catch (Exception ex) {
            localHost = null;
        }
        return localHost;
    }

    /*
     * Returns Fully Qualified Domain Name (FQDN) for the specified InetAddress.
     * It'll try to obtain this name no longer then the time specified
     * in harmony.rmi.transport.tcp.localHostNameTimeOut property.
     *
     * @param iaddr InetAddress to obtain FQDN
     *
     * @return obtained FQDN for the given InetAddress
     */
    private static String getFQDN(InetAddress iaddr)
            throws UnknownHostException {
        String hostName = iaddr.getHostName();

        if (hostName.indexOf('.') >= 0) {
            // contains dots (so we think that it is a FQDN already)
            return hostName;
        }

        // does not contain dots, so we presume that getHostName()
        // did not return fqdn
        String addr = iaddr.getHostAddress();
        FQDNGetter getter = new FQDNGetter(addr);
        Thread fqdnThread = (Thread) AccessController.doPrivileged(
                new CreateThreadAction(getter, "FQDN getter.", true)); //$NON-NLS-1$

        try {
            synchronized (getter) {
                fqdnThread.start();
                getter.wait(localHostNameTimeout);
            }
        } catch (InterruptedException ie) {
        }
        String fqdn = getter.getFQDN();

        if (fqdn == null || fqdn.indexOf('.') < 0) {
            return addr;
        }
        return fqdn;
    }


    /*
     * Obtains Fully Qualified Domain Name.
     */
    private static class FQDNGetter implements Runnable {
        private String addr;
        private String name;

        FQDNGetter(String addr) {
            this.addr = addr;
        }

        public void run() {
            try {
                name = InetAddress.getByName(addr).getHostName();
            } catch (UnknownHostException uhe) {
            } finally {
                synchronized (this) {
                    notify();
                }
            }
        }

        private String getFQDN() {
            return name;
        }
    }
}
TOP

Related Classes of org.apache.harmony.rmi.transport.Endpoint$FQDNGetter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.