1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http.internal.websocket; 27 28 import jdk.incubator.http.HttpClient; 29 import jdk.incubator.http.WebSocket; 30 import jdk.incubator.http.WebSocket.Builder; 31 import jdk.incubator.http.WebSocket.Listener; 32 import jdk.incubator.http.internal.common.Pair; 33 34 import java.net.ProxySelector; 35 import java.net.URI; 36 import java.time.Duration; 37 import java.util.Collection; 38 import java.util.LinkedList; 39 import java.util.List; 40 import java.util.Optional; 41 import java.util.concurrent.CompletableFuture; 42 43 import static java.util.Objects.requireNonNull; 44 import static jdk.incubator.http.internal.common.Pair.pair; 45 46 public final class BuilderImpl implements Builder { 47 48 private final HttpClient client; 49 private URI uri; 50 private Listener listener; 51 private final Optional<ProxySelector> proxySelector; 52 private final Collection<Pair<String, String>> headers; 53 private final Collection<String> subprotocols; 54 private Duration timeout; 55 56 public BuilderImpl(HttpClient client, ProxySelector proxySelector) 57 { 58 this(client, null, null, Optional.ofNullable(proxySelector), 59 new LinkedList<>(), new LinkedList<>(), null); 60 } 61 62 private BuilderImpl(HttpClient client, 63 URI uri, 64 Listener listener, 65 Optional<ProxySelector> proxySelector, 66 Collection<Pair<String, String>> headers, 67 Collection<String> subprotocols, 68 Duration timeout) { 69 this.client = client; 70 this.uri = uri; 71 this.listener = listener; 72 this.proxySelector = proxySelector; 73 // If a proxy selector was supplied by the user, it should be present 74 // on the client and should be the same that what we got as an argument 75 assert !client.proxy().isPresent() 76 || client.proxy().equals(proxySelector); 77 this.headers = headers; 78 this.subprotocols = subprotocols; 79 this.timeout = timeout; 80 } 81 82 @Override 83 public Builder header(String name, String value) { 84 requireNonNull(name, "name"); 85 requireNonNull(value, "value"); 86 headers.add(pair(name, value)); 87 return this; 88 } 89 90 @Override 91 public Builder subprotocols(String mostPreferred, String... lesserPreferred) 92 { 93 requireNonNull(mostPreferred, "mostPreferred"); 94 requireNonNull(lesserPreferred, "lesserPreferred"); 95 List<String> subprotocols = new LinkedList<>(); 96 subprotocols.add(mostPreferred); 97 for (int i = 0; i < lesserPreferred.length; i++) { 98 String p = lesserPreferred[i]; 99 requireNonNull(p, "lesserPreferred[" + i + "]"); 100 subprotocols.add(p); 101 } 102 this.subprotocols.clear(); 103 this.subprotocols.addAll(subprotocols); 104 return this; 105 } 106 107 @Override 108 public Builder connectTimeout(Duration timeout) { 109 this.timeout = requireNonNull(timeout, "timeout"); 110 return this; 111 } 112 113 @Override 114 public CompletableFuture<WebSocket> buildAsync(URI uri, Listener listener) { 115 this.uri = requireNonNull(uri, "uri"); 116 this.listener = requireNonNull(listener, "listener"); 117 // A snapshot of builder inaccessible for further modification 118 // from the outside 119 BuilderImpl copy = immutableCopy(); 120 return WebSocketImpl.newInstanceAsync(copy); 121 } 122 123 HttpClient getClient() { return client; } 124 125 URI getUri() { return uri; } 126 127 Listener getListener() { return listener; } 128 129 Collection<Pair<String, String>> getHeaders() { return headers; } 130 131 Collection<String> getSubprotocols() { return subprotocols; } 132 133 Duration getConnectTimeout() { return timeout; } 134 135 Optional<ProxySelector> getProxySelector() { return proxySelector; } 136 137 private BuilderImpl immutableCopy() { 138 @SuppressWarnings({"unchecked", "rawtypes"}) 139 BuilderImpl copy = new BuilderImpl( 140 client, 141 uri, 142 listener, 143 proxySelector, 144 List.of(this.headers.toArray(new Pair[0])), 145 List.of(this.subprotocols.toArray(new String[0])), 146 timeout); 147 return copy; 148 } 149 }