Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/jndi/ldap/ClientId.java
38924 views
/*1* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.jndi.ldap;2627import java.util.Locale;28import java.util.Arrays; // JDK 1.229import java.io.OutputStream;30import javax.naming.ldap.Control;31import java.lang.reflect.Method;32import javax.net.SocketFactory;3334/**35* Represents identity information about an anonymous LDAP connection.36* This base class contains the following information:37* - protocol version number38* - server's hostname (case-insensitive)39* - server's port number40* - prototype type (plain or ssl)41* - controls to be sent with the LDAP bind request42*43* All other identity classes must be a subclass of ClientId.44* Identity subclasses would add more distinguishing information, depending45* on the type of authentication that the connection is to have.46*47* The equals() and hashCode() methods of this class and its subclasses are48* important because they are used to determine whether two requests for49* the same connection are identical, and thus whether the same connection50* may be shared. This is especially important for authenticated connections51* because a mistake would result in a serious security violation.52*53* @author Rosanna Lee54*/55class ClientId {56final private int version;57final private String hostname;58final private int port;59final private String protocol;60final private Control[] bindCtls;61final private OutputStream trace;62final private String socketFactory;63final private int myHash;64final private int ctlHash;6566private SocketFactory factory = null;67private Method sockComparator = null;68private boolean isDefaultSockFactory = false;69final public static boolean debug = false;7071ClientId(int version, String hostname, int port, String protocol,72Control[] bindCtls, OutputStream trace, String socketFactory) {73this.version = version;74this.hostname = hostname.toLowerCase(Locale.ENGLISH); // ignore case75this.port = port;76this.protocol = protocol;77this.bindCtls = (bindCtls != null ? bindCtls.clone() : null);78this.trace = trace;79//80// Needed for custom socket factory pooling81//82this.socketFactory = socketFactory;83if ((socketFactory != null) &&84!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {85try {86Class<?> socketFactoryClass =87Obj.helper.loadClass(socketFactory);88Class<?> objClass = Class.forName("java.lang.Object");89this.sockComparator = socketFactoryClass.getMethod(90"compare", new Class<?>[]{objClass, objClass});91Method getDefault = socketFactoryClass.getMethod(92"getDefault", new Class<?>[]{});93this.factory =94(SocketFactory)getDefault.invoke(null, new Object[]{});95} catch (Exception e) {96// Ignore it here, the same exceptions are/will be handled by97// LdapPoolManager and Connection classes.98if (debug) {99System.out.println("ClientId received an exception");100e.printStackTrace();101}102}103} else {104isDefaultSockFactory = true;105}106107// The SocketFactory field is not used in the myHash108// computation as there is no right way to compute the hash code109// for this field. There is no harm in skipping it from the hash110// computation111myHash = version + port112+ (trace != null ? trace.hashCode() : 0)113+ (this.hostname != null ? this.hostname.hashCode() : 0)114+ (protocol != null ? protocol.hashCode() : 0)115+ (ctlHash=hashCodeControls(bindCtls));116}117118public boolean equals(Object obj) {119if (!(obj instanceof ClientId)) {120return false;121}122123ClientId other = (ClientId)obj;124125return myHash == other.myHash126&& version == other.version127&& port == other.port128&& trace == other.trace129&& (hostname == other.hostname // null OK130|| (hostname != null && hostname.equals(other.hostname)))131&& (protocol == other.protocol // null OK132|| (protocol != null && protocol.equals(other.protocol)))133&& ctlHash == other.ctlHash134&& (equalsControls(bindCtls, other.bindCtls))135&& (equalsSockFactory(other));136}137138public int hashCode() {139return myHash;140}141142private static int hashCodeControls(Control[] c) {143if (c == null) {144return 0;145}146147int code = 0;148for (int i = 0; i < c.length; i++) {149code = code * 31 + c[i].getID().hashCode();150}151return code;152}153154private static boolean equalsControls(Control[] a, Control[] b) {155if (a == b) {156return true; // both null or same157}158if (a == null || b == null) {159return false; // one is non-null160}161if (a.length != b.length) {162return false;163}164165for (int i = 0; i < a.length; i++) {166if (!a[i].getID().equals(b[i].getID())167|| a[i].isCritical() != b[i].isCritical()168|| !Arrays.equals(a[i].getEncodedValue(),169b[i].getEncodedValue())) {170return false;171}172}173return true;174}175176private boolean equalsSockFactory(ClientId other) {177if (this.isDefaultSockFactory && other.isDefaultSockFactory) {178return true;179}180else if (!other.isDefaultSockFactory) {181return invokeComparator(other, this);182} else {183return invokeComparator(this, other);184}185}186187// delegate the comparison work to the SocketFactory class188// as there is no enough information here, to do the comparison189private boolean invokeComparator(ClientId c1, ClientId c2) {190Object ret;191try {192ret = (c1.sockComparator).invoke(193c1.factory, c1.socketFactory, c2.socketFactory);194} catch(Exception e) {195if (debug) {196System.out.println("ClientId received an exception");197e.printStackTrace();198}199// Failed to invoke the comparator; flag unequality200return false;201}202if (((Integer) ret) == 0) {203return true;204}205return false;206}207208private static String toStringControls(Control[] ctls) {209if (ctls == null) {210return "";211}212StringBuffer str = new StringBuffer();213for (int i = 0; i < ctls.length; i++) {214str.append(ctls[i].getID());215str.append(' ');216}217return str.toString();218}219220public String toString() {221return (hostname + ":" + port + ":" +222(protocol != null ? protocol : "") + ":" +223toStringControls(bindCtls) + ":" +224socketFactory);225}226}227228229