Re: [13] RFR: 8216561: HttpClient: The logic of retry on connect exception is inverted

2019-01-18 Thread Andrej Golovnin
Hi Daniel,

> Right - here is a better implementation anyway:
> http://cr.openjdk.java.net/~dfuchs/webrev_8216561/webrev.02/
> 

Looks much better. Thanks a lot!

Best regards,
Andrej Golovnin



Re: [13] RFR: 8216561: HttpClient: The logic of retry on connect exception is inverted

2019-01-18 Thread Andrej Golovnin
Hi Daniel,

Yes that looks like my first implementation. But then
> I reflected that avoiding to map Optional to Duration
> and then back to a new Optional containing the same
> duration could be avoided by simply storing the original
> optional obtained from the HttpClient.
>
> The current code only creates a new instance of Optional
> when it needs to.
>

Is creating new Optionals a real problem? And before you answer please
remember what Donald Knuth said: The real problem is that programmers have
spent far too much time worrying about efficiency in the wrong places and
at the wrong times; premature optimization is the root of all evil (or at
least most of it) in programming. ;-)

Best regards and have a nice weekend,
Andrej Golovnin


Re: [13] RFR: 8216561: HttpClient: The logic of retry on connect exception is inverted

2019-01-18 Thread Andrej Golovnin
Hi Daniel,

> webrev:
> http://cr.openjdk.java.net/~dfuchs/webrev_8216561/webrev.01/
>
>
>
 126 private static class ConnectTimeoutTracker {
 127 final Optional max;
 128 final AtomicLong startTime = new AtomicLong();
 129 ConnectTimeoutTracker(Optional connectTimeout) {
 130 this.max = connectTimeout;
 131 }
 132
 133 Optional getRemaining() {
 134 if (max.isEmpty()) return max;
 135 long now = System.nanoTime();
 136 long previous = startTime.compareAndExchange(0, now);
 137 if (previous == 0 || max.get().isZero()) return max;
 138 Duration remaining = max.get().minus(Duration.ofNanos(now
- previous));
 139 assert remaining.compareTo(max.get()) <= 0;
 140 return Optional.of(remaining.isNegative() ? Duration.ZERO
: remaining);
 141 }
 142
 143 void reset() { startTime.set(0); }
 144 }

An Optional in a class field or in a data structure, is considered a misuse
of the API (see the explanation by Stuart Marks:
https://stackoverflow.com/questions/23454952/uses-for-optional/23464794#23464794).
I would write it this way:

  private static class ConnectTimeoutTracker {
  final Duration max;
  final AtomicLong startTime = new AtomicLong();
  ConnectTimeoutTracker(Duration connectTimeout) {
  this.max = connectTimeout;
  }

  Optional getRemaining() {
  return Optional.ofNullable(max)
  .map(m -> {
  long now = System.nanoTime();
  long previous = startTime.compareAndExchange(0, now);
  if (previous == 0 || m.isZero()) {
  return m;
  }
  Duration remaining = m.minus(Duration.ofNanos(now -
previous));
  assert remaining.compareTo(m) <= 0;
  return remaining.isNegative() ? Duration.ZERO :
remaining;
  });
  }

  void reset() { startTime.set(0); }
  }

Best regards,
Andrej Golovnin


Re: RFE: Add PATCH to the list of the supported HTTP methods

2018-03-07 Thread Andrej Golovnin
Hi Chris,

> The JDK HTTP Client has:
>   `HttpRequest.Builder::method(String method, BodyPublisher publisher)`
>
>  ,so it is currently possible to use the `PATCH` method.
>
> Is `PATCH` sufficiently popular to warrant its own self-named
> method in the request builder?

I don't know how popular is it. We have just started to use it with
one of our services and discovered that we cannot use it with
HttpURLConnection at all. And I thought when we add the support for
PATCH to HttpURLConnection, then it would be nice to have it in HTTP
Client too. When you decided not to add it to HTTP Client, then it is
OK for me too. But I think that HttpURLConnection should be changed.

Best regards,
Andrej Golovnin


RFE: Add PATCH to the list of the supported HTTP methods

2018-03-02 Thread Andrej Golovnin
Hi all,

it would be nice if could add PATCH
(https://tools.ietf.org/html/rfc5789) to the list of the supported
HTTP methods in the HttpURLConnection class.

I have attached two patches:

- one for the HttpURLConnection class:
  java_net_HttpURLConnection_PATCH_method.diff

- and one for the HTTP Client branch in the JDK sandbox repository
which adds PATCH to the HttpRequest builder:
  java_net_http_HttpRequest_PATCH_method.diff

Best regards,
Andrej Golovnin


java_net_HttpURLConnection_PATCH_method.diff
Description: Binary data


java_net_http_HttpRequest_PATCH_method.diff
Description: Binary data


Re: RFR JDK-8087113: Websocket API and implementation

2016-04-10 Thread Andrej Golovnin
> On Sun, Apr 10, 2016 at 2:00 PM, Andrej Golovnin
> <andrej.golov...@gmail.com> wrote:
>> BTW, someone should describe in the JavaDocs of CompletableFuture#orTimeout()
>> what would happen when this method is called multiple times on the same
>> CompletableFuture with different arguments.
>
> Hmmm the javadoc seems clear enough to me. CF can only be completed
> once.  First to complete wins.

What is the first: the first call to #orTimeout() or the call with the
lowest timeout?

CompletableFuture cf = ...
cf.onTimeout(10L, TimeUnit.MINUTES); // 1. call
cf.onTimeout(10L, TimeUnit.SECONDS); // 2. call
cf.onTimeout(10L, TimeUnit.HOURS); // 3. call

As far as I understand the implementation, the second call wins.
What I miss from the JavaDocs is following:
It is allowed to call the #onTimeout()-methods multiple times. But it does
not mean that subsequent calls would override already defined timeout and
that the lowest timeout wins.


Re: RFR JDK-8087113: Websocket API and implementation

2016-03-29 Thread Andrej Golovnin
n
you can change this method to:

onClose(WebSocket webSocket, Optional closeReason)

I think it makes the API much better and it is clear that the reason phrase is 
only
available when you have a close code too.

And I think there should be a way to configure a timeout for sending messages.

One minor thing off-topic:
While changing my code I noticed that the class 
ProxySelector$StaticProxySelector
and the JavaDocs of the ProxySelector#of-method can be improved a little bit:

diff -r 589795e4cd38 src/java.base/share/classes/java/net/ProxySelector.java
--- a/src/java.base/share/classes/java/net/ProxySelector.java   Wed Mar 23 
19:33:39 2016 -0700
+++ b/src/java.base/share/classes/java/net/ProxySelector.java   Mon Mar 28 
19:30:24 2016 +0200
@@ -165,7 +165,8 @@

 /**
  * Returns a ProxySelector which uses the given proxy address for all HTTP
- * and HTTPS requests. If proxy is {@code null} then proxying is disabled.
+ * and HTTPS requests. If the given proxy address is {@code null}
+ * then proxying is disabled.
  *
  * @param proxyAddress
  *The address of the proxy
@@ -178,9 +179,9 @@
 return new StaticProxySelector(proxyAddress);
 }

-static class StaticProxySelector extends ProxySelector {
+private static final class StaticProxySelector extends ProxySelector {
 private static final List NO_PROXY_LIST = 
List.of(Proxy.NO_PROXY);
-final List list;
+private final List list;

 StaticProxySelector(InetSocketAddress address){
 Proxy p;
@@ -198,9 +199,9 @@
 }

 @Override
-public synchronized List select(URI uri) {
-String scheme = uri.getScheme().toLowerCase();
-if (scheme.equals("http") || scheme.equals("https")) {
+public List select(URI uri) {
+String scheme = uri.getScheme();
+if (scheme.equalsIgnoreCase("http") || 
scheme.equalsIgnoreCase("https")) {
 return list;
 } else {
 return NO_PROXY_LIST;

Best regards,
Andrej Golovnin

Re: WebSocket client API

2015-10-19 Thread Andrej Golovnin
Hi Pavel,

the JavaDocs for the method
HttpClient.Builder#proxy(java.net.ProxySelector selector) say:

Sets a ProxySelector for this client. If no selector is set, then no
proxies are used. If a null parameter is supplied then the system wide
default proxy selector is used.

Really? For me it means that nearly every application which would like
to use the new HttpClient/WebSocket must call this method with null
value. Just think about Java WebStart applications and applets: you
never know if there is a proxy or not.

IMHO the JavaDocs for this method should look like this:

Sets a ProxySelector for this client. If no proxy selector is set,
then the system wide default proxy selector is used.

@throws IllegalArgumentException if selector is null.

I'm sure the most developers out there should be able to provide their
own implementation of the java.net.ProxySelector class which just
returns Collections.singletonList(Proxy.NO_PROXY) in the method
ProxySelector#select(URI uri) if they need direct access to a server.
And if you would like to simplify the life of the developers which
need a direct access to a server, then you could add a new method to
the builder:

HttpClient.Builder#noProxy()

I think it is better than to add a special meaning to the null value.

And I think that the phrase with "If no proxy selector is set, then
the system wide default proxy selector is used." should be a part of
the JavaDocs of the class HttpClient.Builder and the method
HttpClient.getDefault() to make clear the behaviour of the
created/returned HttpClient.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-04 Thread Andrej Golovnin
Hi Chris,

>>> Will adding the ability to send ping(ByteBuffer) be sufficient for your 
>>> usage? If so, then I think we should add it, but not pong.  The 
>>> implementation will automatically send a pong message in response to 
>>> receiving a ping. OK?
>>
>> Yes, ping(ByteBuffer) is sufficient for us.
>
> I assume you will also need a way to distinguish that the incoming data is 
> from a pong message, in response to your ping, right?

I'm not sure what you mean. If you mean, that we need to distinguish
it in the method WebSocket.Incoming.onBinary(WebSocket, ByteBuffer),
then no. I expect that this method is only used to process binary
message. For pong messages I would expect a new method:
WebSocket.Incoming.onPong(WebSocket, ByteBuffer). Currently we don't
process the pong messages on the client. And there are no plans to do
it in the near future.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-04 Thread Andrej Golovnin
Hi Pavel,


>> - WebSocket.onClose() should contain the close reason code.
>
> What is it useful for? Is it ok to provide it as a part of description?
>
> String description = char code + ": " + String reason
>

Please don't do that! We definitely don't want to parse it. What we
need is a method with this signature:

WebSocket.Incoming.onClose(int statusCode, String reason)

In our application an administrator may close a connection due to
server maintenance or some other reason and in this case we use an
application specific statusCode (e.g. 4001). Depending on the status
code we show the user appropriate messages and the reason submitted by
the administrator.

What we also need, is the method WebSocket.close(int statusCode,
String reason) because the client may also close the connection for
some application specific reason.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-03 Thread Andrej Golovnin
Hi Michael,

> Can you explain why you need j.n.Proxy rather than the
> String/InetSocketAddress
> combination proposed for HttpClient?

String is not type safe. And allowing to define proxy only for the
specific protocol is not enough from my experience. Sometimes you have
to choose proxy based on the host of the URL you try to connect to.
What HttpClient.Builder.proxy() should really take as parameter, is
the j.n.ProxySelector. The most code, I have seen so far, does not
really care about proxies. But everyone expects that it still works
with proxies. j.n.URL.openConnection() gives us this magic because at
some point in sun.net.www.protocol.http.HttpURLConnection the method
ProxySelector.getDefault().select(URI) is called for the URL and the
connection is established using the proxy. The same behaviour I expect
from HttpClient and WebSocket. Therefore I think you have to deal with
j.n.Proxy and j.n.ProxySelector in the HttpClient code anyway. And
that's why I think you should use them in the Public API of HttpClient
and WebSocket as well.

Here is a small summary of the API I would like to see:

/**
 * Defines a selector to be used by this client to select the proxy
server for a request.
 * If no selector is defined for this client, the client will use
{@link j.n.ProxySelector.getDefault()} as it's selector.
 *
 * @param selectorthe selector to be used by this client; may not be null.
 *
 * @throws IllegalArgumentException if selector is null.
 */
j.n.HttpClient.Builder.proxySelector(j.n.ProxySelector selector)

/**
 * Defines the proxy to be used by this request.
 * If no proxy is defined for this request, the selector from the
HttpClient will be used to select the proxy.
 *
 * @param proxy   the proxy to be used by this request; may not be null.
 *
 * @throws IllegalArgumentException if proxy is null.
 */
j.n.HttpRequest.Builder.proxy(j.n.Proxy proxy)

/**
 * Defines the proxy to be used by this WebSocket.
 * If no proxy is defined for this WebSocket, the default selector
{@link j.n.ProxySelector.getDefault()} will be used to select the
proxy.
 *
 * @param proxy   the proxy to be used by this WebSocket; may not be null.
 *
 * @throws IllegalArgumentException if proxy is null.
 */
j.n.WebSocket.Builder.proxy(j.n.Proxy proxy)


As always fell free to use it or to ignore it. My code is already in
production and works. :-)

I hope this helps.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-03 Thread Andrej Golovnin
Hi Pavel,

> So you need the ability to send pings and unsolicited pongs. Do you handle 
> pong
> replies from the server? If so, do you control their arrival times and their
> consistency with previous pings sent? What about unsolicited pongs from the
> server?

We use pings to ensure that firewalls do not close inactive (from
their point of view) connections. And we send some useful data with
the ping which is then processed on the server. Currently all pong
messages from the server are ignored on the client.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-03 Thread Andrej Golovnin
Hi Chris,

> Will adding the ability to send ping(ByteBuffer) be sufficient for your 
> usage? If so, then I think we should add it, but not pong.  The 
> implementation will automatically send a pong message in response to 
> receiving a ping. OK?

Yes, ping(ByteBuffer) is sufficient for us.

Best regards,
Andrej Golovnin


Re: WebSocket client API

2015-09-02 Thread Andrej Golovnin
Hi Pavel,

>> - Where's the .ping() or .pong() ?
> 
> * @apiNote Keep-alive features of WebSocket protocol are taken care of
> * completely by implementations and are not exposed in this API.
> 
> We thought that a high-level API could live without this burden for the user. 
> At
> the same time the implementation will definitely have several configuration
> parameters, tweaking its behaviour in respect to keep-alive features.
> 
> Yes, we've thought about application data that can be carried by those types 
> of
> messages, but due to restrictions to their size (125 bytes) and potential
> out-of-order delivery we've decided not to expose them as data carriers.

Just because you don’t see usages for it, it does not mean that others don’t 
need
it. We have an application which already make use of it. And if you don’t add
at least the #ping(ByteBuffer) method, it would not be usable for us and we will
stay with JSR 356. What I also miss, is the ability to define custom HTTP header
values which should be transmitted during the handshake.

And I think you should add an API to define the proxy in case some one use just
WebSocket.newBuilder(String). And please use the class java.net.Proxy to define
a proxy and not just a String and a InetSocketAddress as it is done in 
HttpClient.

Best regards,
Andrej Golovnin