001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.conn.scheme; 028 029import java.util.Locale; 030 031import org.apache.http.annotation.Contract; 032import org.apache.http.annotation.ThreadingBehavior; 033import org.apache.http.util.Args; 034import org.apache.http.util.LangUtils; 035 036/** 037 * Encapsulates specifics of a protocol scheme such as "http" or "https". Schemes are identified 038 * by lowercase names. Supported schemes are typically collected in a {@link SchemeRegistry 039 * SchemeRegistry}. 040 * <p> 041 * For example, to configure support for "https://" URLs, you could write code like the following: 042 * </p> 043 * <pre> 044 * Scheme https = new Scheme("https", 443, new MySecureSocketFactory()); 045 * SchemeRegistry registry = new SchemeRegistry(); 046 * registry.register(https); 047 * </pre> 048 * 049 * @since 4.0 050 * 051 * @deprecated (4.3) use {@link org.apache.http.conn.SchemePortResolver} for default port 052 * resolution and {@link org.apache.http.config.Registry} for socket factory lookups. 053 */ 054@Contract(threading = ThreadingBehavior.IMMUTABLE) 055@Deprecated 056public final class Scheme { 057 058 /** The name of this scheme, in lowercase. (e.g. http, https) */ 059 private final String name; 060 061 /** The socket factory for this scheme */ 062 private final SchemeSocketFactory socketFactory; 063 064 /** The default port for this scheme */ 065 private final int defaultPort; 066 067 /** Indicates whether this scheme allows for layered connections */ 068 private final boolean layered; 069 070 /** A string representation, for {@link #toString toString}. */ 071 private String stringRep; 072 /* 073 * This is used to cache the result of the toString() method 074 * Since the method always generates the same value, there's no 075 * need to synchronize, and it does not affect immutability. 076 */ 077 078 /** 079 * Creates a new scheme. 080 * Whether the created scheme allows for layered connections 081 * depends on the class of {@code factory}. 082 * 083 * @param name the scheme name, for example "http". 084 * The name will be converted to lowercase. 085 * @param port the default port for this scheme 086 * @param factory the factory for creating sockets for communication 087 * with this scheme 088 * 089 * @since 4.1 090 */ 091 public Scheme(final String name, final int port, final SchemeSocketFactory factory) { 092 Args.notNull(name, "Scheme name"); 093 Args.check(port > 0 && port <= 0xffff, "Port is invalid"); 094 Args.notNull(factory, "Socket factory"); 095 this.name = name.toLowerCase(Locale.ENGLISH); 096 this.defaultPort = port; 097 if (factory instanceof SchemeLayeredSocketFactory) { 098 this.layered = true; 099 this.socketFactory = factory; 100 } else if (factory instanceof LayeredSchemeSocketFactory) { 101 this.layered = true; 102 this.socketFactory = new SchemeLayeredSocketFactoryAdaptor2((LayeredSchemeSocketFactory) factory); 103 } else { 104 this.layered = false; 105 this.socketFactory = factory; 106 } 107 } 108 109 /** 110 * Creates a new scheme. 111 * Whether the created scheme allows for layered connections 112 * depends on the class of {@code factory}. 113 * 114 * @param name the scheme name, for example "http". 115 * The name will be converted to lowercase. 116 * @param factory the factory for creating sockets for communication 117 * with this scheme 118 * @param port the default port for this scheme 119 * 120 * @deprecated (4.1) Use {@link #Scheme(String, int, SchemeSocketFactory)} 121 */ 122 @Deprecated 123 public Scheme(final String name, 124 final SocketFactory factory, 125 final int port) { 126 127 Args.notNull(name, "Scheme name"); 128 Args.notNull(factory, "Socket factory"); 129 Args.check(port > 0 && port <= 0xffff, "Port is invalid"); 130 131 this.name = name.toLowerCase(Locale.ENGLISH); 132 if (factory instanceof LayeredSocketFactory) { 133 this.socketFactory = new SchemeLayeredSocketFactoryAdaptor( 134 (LayeredSocketFactory) factory); 135 this.layered = true; 136 } else { 137 this.socketFactory = new SchemeSocketFactoryAdaptor(factory); 138 this.layered = false; 139 } 140 this.defaultPort = port; 141 } 142 143 /** 144 * Obtains the default port. 145 * 146 * @return the default port for this scheme 147 */ 148 public final int getDefaultPort() { 149 return defaultPort; 150 } 151 152 153 /** 154 * Obtains the socket factory. 155 * If this scheme is {@link #isLayered layered}, the factory implements 156 * {@link LayeredSocketFactory LayeredSocketFactory}. 157 * 158 * @return the socket factory for this scheme 159 * 160 * @deprecated (4.1) Use {@link #getSchemeSocketFactory()} 161 */ 162 @Deprecated 163 public final SocketFactory getSocketFactory() { 164 if (this.socketFactory instanceof SchemeSocketFactoryAdaptor) { 165 return ((SchemeSocketFactoryAdaptor) this.socketFactory).getFactory(); 166 } else { 167 if (this.layered) { 168 return new LayeredSocketFactoryAdaptor( 169 (LayeredSchemeSocketFactory) this.socketFactory); 170 } else { 171 return new SocketFactoryAdaptor(this.socketFactory); 172 } 173 } 174 } 175 176 /** 177 * Obtains the socket factory. 178 * If this scheme is {@link #isLayered layered}, the factory implements 179 * {@link LayeredSocketFactory LayeredSchemeSocketFactory}. 180 * 181 * @return the socket factory for this scheme 182 * 183 * @since 4.1 184 */ 185 public final SchemeSocketFactory getSchemeSocketFactory() { 186 return this.socketFactory; 187 } 188 189 /** 190 * Obtains the scheme name. 191 * 192 * @return the name of this scheme, in lowercase 193 */ 194 public final String getName() { 195 return name; 196 } 197 198 /** 199 * Indicates whether this scheme allows for layered connections. 200 * 201 * @return {@code true} if layered connections are possible, 202 * {@code false} otherwise 203 */ 204 public final boolean isLayered() { 205 return layered; 206 } 207 208 /** 209 * Resolves the correct port for this scheme. 210 * Returns the given port if it is valid, the default port otherwise. 211 * 212 * @param port the port to be resolved, 213 * a negative number to obtain the default port 214 * 215 * @return the given port or the defaultPort 216 */ 217 public final int resolvePort(final int port) { 218 return port <= 0 ? defaultPort : port; 219 } 220 221 /** 222 * Return a string representation of this object. 223 * 224 * @return a human-readable string description of this scheme 225 */ 226 @Override 227 public final String toString() { 228 if (stringRep == null) { 229 final StringBuilder buffer = new StringBuilder(); 230 buffer.append(this.name); 231 buffer.append(':'); 232 buffer.append(Integer.toString(this.defaultPort)); 233 stringRep = buffer.toString(); 234 } 235 return stringRep; 236 } 237 238 @Override 239 public final boolean equals(final Object obj) { 240 if (this == obj) { 241 return true; 242 } 243 if (obj instanceof Scheme) { 244 final Scheme that = (Scheme) obj; 245 return this.name.equals(that.name) 246 && this.defaultPort == that.defaultPort 247 && this.layered == that.layered; 248 } else { 249 return false; 250 } 251 } 252 253 @Override 254 public int hashCode() { 255 int hash = LangUtils.HASH_SEED; 256 hash = LangUtils.hashCode(hash, this.defaultPort); 257 hash = LangUtils.hashCode(hash, this.name); 258 hash = LangUtils.hashCode(hash, this.layered); 259 return hash; 260 } 261 262}