diff --git a/pom.xml b/pom.xml index e99b39365..8ee75c594 100644 --- a/pom.xml +++ b/pom.xml @@ -133,21 +133,6 @@ THE SOFTWARE. 2.16.1 test - - org.junit.jupiter - junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.junit.vintage - junit-vintage-engine - test - org.bouncycastle bcpkix-jdk18on @@ -170,6 +155,21 @@ THE SOFTWARE. test-annotations test + + org.junit.jupiter + junit-jupiter + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.junit.vintage + junit-vintage-engine + test + org.mockito mockito-core @@ -333,7 +333,8 @@ THE SOFTWARE. src/assembly/agent-load-test.xml false - posix + posix + @@ -347,7 +348,8 @@ THE SOFTWARE. - + + org.codehaus.mojo build-helper-maven-plugin @@ -396,11 +398,9 @@ THE SOFTWARE. 4 - - junit.jupiter.execution.timeout.default=15s + junit.jupiter.execution.timeout.default=15s junit.jupiter.execution.timeout.mode=disabled_on_debug - junit.jupiter.execution.timeout.thread.mode.default=SEPARATE_THREAD - + junit.jupiter.execution.timeout.thread.mode.default=SEPARATE_THREAD diff --git a/src/main/java/hudson/remoting/AbstractByteBufferCommandTransport.java b/src/main/java/hudson/remoting/AbstractByteBufferCommandTransport.java index bee4cf930..d30553fc2 100644 --- a/src/main/java/hudson/remoting/AbstractByteBufferCommandTransport.java +++ b/src/main/java/hudson/remoting/AbstractByteBufferCommandTransport.java @@ -69,12 +69,14 @@ public abstract class AbstractByteBufferCommandTransport extends CommandTranspor * Our channel. */ private Channel channel; + @Deprecated private final ByteBuffer writeChunkHeader; /** * The transport frame size. */ private int transportFrameSize = 8192; + @Deprecated private ByteBuffer writeChunkBody; /** @@ -354,5 +356,4 @@ public final void write(Command cmd, boolean last) throws IOException { public void terminate(IOException e) { receiver.terminate(e); } - } diff --git a/src/main/java/hudson/remoting/AsyncFutureImpl.java b/src/main/java/hudson/remoting/AsyncFutureImpl.java index 234cf04d5..e78f8a90e 100644 --- a/src/main/java/hudson/remoting/AsyncFutureImpl.java +++ b/src/main/java/hudson/remoting/AsyncFutureImpl.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, CloudBees, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,7 +33,7 @@ * {@link Future} implementation whose computation is carried out elsewhere. * * Call the {@link #set(Object)} method or {@link #set(Throwable)} method to set the value to the future. - * + * * @author Kohsuke Kawaguchi */ public class AsyncFutureImpl implements Future { @@ -50,9 +50,11 @@ public class AsyncFutureImpl implements Future { private boolean cancelled; public AsyncFutureImpl() {} + public AsyncFutureImpl(V value) { set(value); } + public AsyncFutureImpl(Throwable value) { set(value); } @@ -74,18 +76,22 @@ public synchronized boolean isDone() { @Override public synchronized V get() throws InterruptedException, ExecutionException { - while(!completed) + while (!completed) { wait(); - if(problem!=null) + } + if (problem != null) { throw new ExecutionException(problem); - if(cancelled) + } + if (cancelled) { throw new CancellationException(); + } return value; } @Override @CheckForNull - public synchronized V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public synchronized V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { // The accuracy of wait(long) operation is milliseconds anyway, but ok. long endWaitTime = System.nanoTime() + unit.toNanos(timeout); while (!completed) { @@ -94,15 +100,17 @@ public synchronized V get(long timeout, TimeUnit unit) throws InterruptedExcepti break; } - wait(timeToWait / 1000000, (int)(timeToWait % 1000000)); + wait(timeToWait / 1000000, (int) (timeToWait % 1000000)); } - if(!completed) + if (!completed) { throw new TimeoutException(); - if(cancelled) + } + if (cancelled) { throw new CancellationException(); + } - //TODO: we may be calling a complex get() implementation in the override, which may hang the code + // TODO: we may be calling a complex get() implementation in the override, which may hang the code // The only missing behavior is "problem!=null" branch, but probably we cannot just replace the code without // an override issue risk. return get(); diff --git a/src/main/java/hudson/remoting/Asynchronous.java b/src/main/java/hudson/remoting/Asynchronous.java index 4df6a6f14..8e03208b5 100644 --- a/src/main/java/hudson/remoting/Asynchronous.java +++ b/src/main/java/hudson/remoting/Asynchronous.java @@ -39,5 +39,4 @@ @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) -public @interface Asynchronous { -} +public @interface Asynchronous {} diff --git a/src/main/java/hudson/remoting/AtmostOneThreadExecutor.java b/src/main/java/hudson/remoting/AtmostOneThreadExecutor.java index b161fd52f..f9710ed12 100644 --- a/src/main/java/hudson/remoting/AtmostOneThreadExecutor.java +++ b/src/main/java/hudson/remoting/AtmostOneThreadExecutor.java @@ -44,8 +44,9 @@ public AtmostOneThreadExecutor() { public void shutdown() { synchronized (q) { shutdown = true; - if (isAlive()) + if (isAlive()) { worker.interrupt(); + } } } @@ -53,7 +54,7 @@ public void shutdown() { * Do we have a worker thread and is it running? */ private boolean isAlive() { - return worker!=null && worker.isAlive(); + return worker != null && worker.isAlive(); } @NonNull @@ -111,7 +112,7 @@ public void run() { while (true) { Runnable task; synchronized (q) { - if (q.isEmpty()) {// no more work + if (q.isEmpty()) { // no more work worker = null; return; } diff --git a/src/main/java/hudson/remoting/Base64.java b/src/main/java/hudson/remoting/Base64.java index 41d6d0f28..7c6be3fc0 100644 --- a/src/main/java/hudson/remoting/Base64.java +++ b/src/main/java/hudson/remoting/Base64.java @@ -37,7 +37,7 @@ * @deprecated Use {@link java.util.Base64} instead */ @Deprecated -public final class Base64 { +public final class Base64 { /** * Encodes hex octets into Base64 @@ -48,8 +48,9 @@ public final class Base64 { @Nullable public static String encode(byte[] binaryData) { - if (binaryData == null) + if (binaryData == null) { return null; + } return java.util.Base64.getEncoder().encodeToString(binaryData); } @@ -61,12 +62,14 @@ public static String encode(byte[] binaryData) { * @return Array containing decoded data. {@code null} if the data cannot be decoded. */ @CheckForNull - @SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", + @SuppressFBWarnings( + value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", justification = "Null arrays are the part of the library API") public static byte[] decode(String encoded) { - if (encoded == null) + if (encoded == null) { return null; + } return java.util.Base64.getDecoder().decode(encoded); } diff --git a/src/main/java/hudson/remoting/BinarySafeStream.java b/src/main/java/hudson/remoting/BinarySafeStream.java index 70cdc0ff3..0c559642d 100644 --- a/src/main/java/hudson/remoting/BinarySafeStream.java +++ b/src/main/java/hudson/remoting/BinarySafeStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -46,7 +46,7 @@ * If the writing side flush, the reading side should see everything * written by then, without blocking (even if this happens outside the 3-byte boundary) *
  • - * Reading side won't block unnecessarily. + * Reading side won't block unnecessarily. * * * @author Kohsuke Kawaguchi @@ -71,34 +71,38 @@ public static InputStream wrap(InputStream in) { * -1 to indicate EOF. Otherwise always 0-2. * Valid data starts at triplet[3-remaining] */ - int remaining=0; + int remaining = 0; final byte[] qualtet = new byte[4]; int input = 0; @Override public int read() throws IOException { - if(remaining==0) { - remaining = _read(triplet,0,3); - if(00; + } + assert remaining > 0; return ((int) triplet[3 - remaining--]) & 0xFF; } @Override public int read(@NonNull byte[] b, int off, int len) throws IOException { - if(remaining==-1) return -1; // EOF + if (remaining == -1) { + return -1; // EOF + } - if(len<4) { + if (len < 4) { // not enough space to process encoded data in the given buffer, so revert to the read-by-char int read = 0; int ch; - while(len>0 && (ch=read())!=-1) { - b[off++] = (byte)ch; + while (len > 0 && (ch = read()) != -1) { + b[off++] = (byte) ch; read++; len--; } @@ -106,26 +110,31 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { } // first copy any remaining bytes in triplet to output - int l = Math.min(len,remaining); - if(l>0) { - System.arraycopy(triplet,3-remaining,b,off,l); - off+=l; - len-=l; - remaining=0; - if(super.available()==0) + int l = Math.min(len, remaining); + if (l > 0) { + System.arraycopy(triplet, 3 - remaining, b, off, l); + off += l; + len -= l; + remaining = 0; + if (super.available() == 0) { // the next read() may block, so let's return now return l; - if(len<4) + } + if (len < 4) { // not enough space to call _read(). abort. return l; - + } + // otherwise try to read more - int r = _read(b,off,len); - if(r==-1) return l; - else return l+r; + int r = _read(b, off, len); + if (r == -1) { + return l; + } else { + return l + r; + } } - return _read(b,off,len); + return _read(b, off, len); } /** @@ -133,43 +142,46 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { * longer than off+4, */ private int _read(byte[] b, int off, int len) throws IOException { - assert remaining==0; - assert b.length>=off+4; + assert remaining == 0; + assert b.length >= off + 4; int totalRead = 0; // read in the rest - if(len>0) { + if (len > 0) { // put the remaining data from previous run at the top. - if(input>0) - System.arraycopy(qualtet,0, b, off,input); + if (input > 0) { + System.arraycopy(qualtet, 0, b, off, input); + } // for us to return any byte we need to at least read 4 bytes, // so insist on getting four bytes at least. When stream is flushed // we get extra '=' in the middle. - int l=input; // l = # of total encoded bytes to be processed in this round - while(l<4) { - int r = super.read(b, off + l, Math.max(len,4) - l); - if(r==-1) { - if(l%4!=0) + int l = input; // l = # of total encoded bytes to be processed in this round + while (l < 4) { + int r = super.read(b, off + l, Math.max(len, 4) - l); + if (r == -1) { + if (l % 4 != 0) { throw new IOException("Unexpected stream termination"); - if(l==0) + } + if (l == 0) { return -1; // EOF, and no data to process + } } l += r; } // we can only decode multiple of 4, so write back any remaining data to qualtet. // this also updates 'input' correctly. - input = l%4; - if(input>0) { - System.arraycopy(b, off +l-input,qualtet,0,input); - l-=input; + input = l % 4; + if (input > 0) { + System.arraycopy(b, off + l - input, qualtet, 0, input); + l -= input; } // now we just need to convert four at a time - assert l%4==0; - for( int base= off; l>0; l-=4 ) { + assert l % 4 == 0; + for (int base = off; l > 0; l -= 4) { // convert b[base...base+3] to b[off...off+2] // note that the buffer can be overlapping @@ -177,32 +189,33 @@ private int _read(byte[] b, int off, int len) throws IOException { int c1 = DECODING_TABLE[b[base++]]; int c2 = DECODING_TABLE[b[base++]]; int c3 = DECODING_TABLE[b[base++]]; - if(c0<0 || c1<0 || c2<-1 || c3<-1) { + if (c0 < 0 || c1 < 0 || c2 < -1 || c3 < -1) { // illegal input. note that '=' never shows up as 1st or 2nd char // hence the check for the 1st half and 2nd half are different. // now try to report what we saw. // the remaining buffer is b[base-4 ... base-4+l] ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write(b,base-4,l); + baos.write(b, base - 4, l); // plus we might be able to read more bytes from the underlying stream int avail = super.available(); - if(avail >0) { + if (avail > 0) { byte[] buf = new byte[avail]; - baos.write(buf,0,super.read(buf)); + baos.write(buf, 0, super.read(buf)); } StringBuilder buf = new StringBuilder("Invalid encoded sequence encountered:"); - for (byte ch : baos.toByteArray()) - buf.append(String.format(" %02X",ch)); + for (byte ch : baos.toByteArray()) { + buf.append(String.format(" %02X", ch)); + } throw new IOException(buf.toString()); } - b[off++] = (byte) ((c0<<2) | (c1>>4)); + b[off++] = (byte) ((c0 << 2) | (c1 >> 4)); totalRead++; - if(c2!=-1) { - b[off++] = (byte) ((c1<<4) | (c2>>2)); + if (c2 != -1) { + b[off++] = (byte) ((c1 << 4) | (c2 >> 2)); totalRead++; - if(c3!=-1) { - b[off++] = (byte) ((c2<<6) | c3); + if (c3 != -1) { + b[off++] = (byte) ((c2 << 6) | c3); totalRead++; } } @@ -215,7 +228,7 @@ private int _read(byte[] b, int off, int len) throws IOException { @Override public int available() throws IOException { // roughly speaking we got 3/4 of the underlying available bytes - return super.available()*3/4; + return super.available() * 3 / 4; } }; } @@ -229,52 +242,52 @@ public int available() throws IOException { public static OutputStream wrap(OutputStream out) { return new FilterOutputStream(out) { private final byte[] triplet = new byte[3]; - private int remaining=0; + private int remaining = 0; private final byte[] out = new byte[4]; @Override public void write(int b) throws IOException { - if(remaining==2) { - _write(triplet[0],triplet[1],(byte)b); - remaining=0; + if (remaining == 2) { + _write(triplet[0], triplet[1], (byte) b); + remaining = 0; } else { - triplet[remaining++]=(byte)b; + triplet[remaining++] = (byte) b; } } @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { // if there's anything left in triplet from the last write, try to write them first - if(remaining>0) { - while(len>0 && remaining<3) { + if (remaining > 0) { + while (len > 0 && remaining < 3) { triplet[remaining++] = b[off++]; len--; } - if(remaining==3) { - _write(triplet[0],triplet[1],triplet[2]); + if (remaining == 3) { + _write(triplet[0], triplet[1], triplet[2]); remaining = 0; } } // then convert chunks as much as possible - while(len>=3) { - _write(b[off++],b[off++],b[off++]); - len-=3; + while (len >= 3) { + _write(b[off++], b[off++], b[off++]); + len -= 3; } // store remaining stuff back to triplet - while(len>0) { + while (len > 0) { triplet[remaining++] = b[off++]; len--; } } private void _write(byte a, byte b, byte c) throws IOException { - out[0] = ENCODING_TABLE[(a>>2)&0x3F]; - out[1] = ENCODING_TABLE[((a<<4)&0x3F|(b>>4)&0x0F)]; - out[2] = ENCODING_TABLE[((b<<2)&0x3F|(c>>6)&0x03)]; - out[3] = ENCODING_TABLE[c&0x3F]; - super.out.write(out,0,4); + out[0] = ENCODING_TABLE[(a >> 2) & 0x3F]; + out[1] = ENCODING_TABLE[((a << 4) & 0x3F | (b >> 4) & 0x0F)]; + out[2] = ENCODING_TABLE[((b << 2) & 0x3F | (c >> 6) & 0x03)]; + out[3] = ENCODING_TABLE[c & 0x3F]; + super.out.write(out, 0, 4); } @Override @@ -282,31 +295,31 @@ public void flush() throws IOException { int a = triplet[0]; int b = triplet[1]; - a&=0xFF; - b&=0xFF; - - switch(remaining) { - case 0: - // noop - break; - case 1: - out[0] = ENCODING_TABLE[(a>>2)&0x3F]; - out[1] = ENCODING_TABLE[(a<<4)&0x3F]; - out[2] = '='; - out[3] = '='; - super.out.write(out,0,4); - remaining = 0; - break; - case 2: - out[0] = ENCODING_TABLE[(a>>2)&0x3F]; - out[1] = ENCODING_TABLE[((a<<4)|(b>>4))&0x3F]; - out[2] = ENCODING_TABLE[(b<<2)&0x3F]; - out[3] = '='; - super.out.write(out,0,4); - remaining = 0; - break; - default: - throw new AssertionError(); + a &= 0xFF; + b &= 0xFF; + + switch (remaining) { + case 0: + // noop + break; + case 1: + out[0] = ENCODING_TABLE[(a >> 2) & 0x3F]; + out[1] = ENCODING_TABLE[(a << 4) & 0x3F]; + out[2] = '='; + out[3] = '='; + super.out.write(out, 0, 4); + remaining = 0; + break; + case 2: + out[0] = ENCODING_TABLE[(a >> 2) & 0x3F]; + out[1] = ENCODING_TABLE[((a << 4) | (b >> 4)) & 0x3F]; + out[2] = ENCODING_TABLE[(b << 2) & 0x3F]; + out[3] = '='; + super.out.write(out, 0, 4); + remaining = 0; + break; + default: + throw new AssertionError(); } super.flush(); } @@ -321,11 +334,13 @@ public void flush() throws IOException { private static final int[] DECODING_TABLE = new int[128]; static { - ENCODING_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(StandardCharsets.US_ASCII); + ENCODING_TABLE = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(StandardCharsets.US_ASCII); - Arrays.fill(DECODING_TABLE,-2); - for (int i = 0; i < ENCODING_TABLE.length; i++) + Arrays.fill(DECODING_TABLE, -2); + for (int i = 0; i < ENCODING_TABLE.length; i++) { DECODING_TABLE[ENCODING_TABLE[i]] = i; + } DECODING_TABLE['='] = -1; } } diff --git a/src/main/java/hudson/remoting/Callable.java b/src/main/java/hudson/remoting/Callable.java index bc4c6e0db..2c6db538f 100644 --- a/src/main/java/hudson/remoting/Callable.java +++ b/src/main/java/hudson/remoting/Callable.java @@ -29,9 +29,10 @@ import org.jenkinsci.remoting.RoleSensitive; import org.jenkinsci.remoting.SerializableOnlyOverRemoting; -//TODO: Make it SerializableOnlyOverRemoting? +// TODO: Make it SerializableOnlyOverRemoting? // Oleg Nenashev: Formally there is no reason for that, you can serialize object over whatever binary stream and then -// execute it on remote side if it has channel instance. Likely YAGNI, but I can imagine such Pipeline context class implementation. +// execute it on remote side if it has channel instance. Likely YAGNI, but I can imagine such Pipeline context class +// implementation. /** * Represents computation to be done on a remote system. * @@ -41,7 +42,7 @@ * @see Channel * @author Kohsuke Kawaguchi */ -public interface Callable extends Serializable, RoleSensitive { +public interface Callable extends Serializable, RoleSensitive { /** * Performs computation and returns the result, * or throws some exception. @@ -61,11 +62,13 @@ default Channel getChannelOrFail() throws ChannelStateException { // This logic does not prevent from improperly serializing objects within Remoting calls. // If it happens in API calls in external usages, we wish good luck with diagnosing Remoting issues // and leaks in ExportTable. - //TODO: maybe there is a way to actually diagnose this case? + // TODO: maybe there is a way to actually diagnose this case? final Thread t = Thread.currentThread(); - throw new ChannelStateException(null, "The calling thread " + t + " has no associated channel. " - + "The current object " + this + " is " + SerializableOnlyOverRemoting.class + - ", but it is likely being serialized/deserialized without the channel"); + throw new ChannelStateException( + null, + "The calling thread " + t + " has no associated channel. " + + "The current object " + this + " is " + SerializableOnlyOverRemoting.class + + ", but it is likely being serialized/deserialized without the channel"); } return ch; } @@ -85,7 +88,10 @@ default Channel getChannelOrFail() throws ChannelStateException { default Channel getOpenChannelOrFail() throws ChannelStateException { final Channel ch = getChannelOrFail(); if (ch.isClosingOrClosed()) { - throw new ChannelClosedException(ch, "The associated channel " + ch + " is closing down or has closed down", ch.getCloseRequestCause()); + throw new ChannelClosedException( + ch, + "The associated channel " + ch + " is closing down or has closed down", + ch.getCloseRequestCause()); } return ch; } diff --git a/src/main/java/hudson/remoting/CallableDecoratorAdapter.java b/src/main/java/hudson/remoting/CallableDecoratorAdapter.java index 125e7904d..e068be1ef 100644 --- a/src/main/java/hudson/remoting/CallableDecoratorAdapter.java +++ b/src/main/java/hudson/remoting/CallableDecoratorAdapter.java @@ -26,7 +26,7 @@ public int hashCode() { @Override public boolean equals(Object obj) { if (obj != null && obj.getClass() == this.getClass()) { - return ((CallableDecoratorAdapter)obj).filter.equals(filter); + return ((CallableDecoratorAdapter) obj).filter.equals(filter); } return false; } diff --git a/src/main/java/hudson/remoting/CallableDecoratorList.java b/src/main/java/hudson/remoting/CallableDecoratorList.java index cb1f945f7..32f772aff 100644 --- a/src/main/java/hudson/remoting/CallableDecoratorList.java +++ b/src/main/java/hudson/remoting/CallableDecoratorList.java @@ -10,20 +10,23 @@ */ class CallableDecoratorList extends CopyOnWriteArrayList { java.util.concurrent.Callable wrapCallable(java.util.concurrent.Callable r) { - for (CallableDecorator d : this) + for (CallableDecorator d : this) { r = applyDecorator(r, d); + } return r; } - private java.util.concurrent.Callable applyDecorator(final java.util.concurrent.Callable inner, final CallableDecorator filter) { + private java.util.concurrent.Callable applyDecorator( + final java.util.concurrent.Callable inner, final CallableDecorator filter) { return () -> filter.call(inner); } - Callable wrapUserRequest(final Callable c) { - Callable decorated = c; + Callable wrapUserRequest(final Callable c) { + Callable decorated = c; - for (CallableDecorator d : this) - decorated = d.userRequest(c,decorated); + for (CallableDecorator d : this) { + decorated = d.userRequest(c, decorated); + } return decorated; } diff --git a/src/main/java/hudson/remoting/Capability.java b/src/main/java/hudson/remoting/Capability.java index d39fb402d..72b2936c6 100644 --- a/src/main/java/hudson/remoting/Capability.java +++ b/src/main/java/hudson/remoting/Capability.java @@ -42,7 +42,14 @@ public final class Capability implements Serializable { } public Capability() { - this(MASK_MULTI_CLASSLOADER | MASK_PIPE_THROTTLING | MASK_MIMIC_EXCEPTION | MASK_PREFETCH | GREEDY_REMOTE_INPUTSTREAM | MASK_PROXY_WRITER_2_35 | MASK_CHUNKED_ENCODING | PROXY_EXCEPTION_FALLBACK); + this(MASK_MULTI_CLASSLOADER + | MASK_PIPE_THROTTLING + | MASK_MIMIC_EXCEPTION + | MASK_PREFETCH + | GREEDY_REMOTE_INPUTSTREAM + | MASK_PROXY_WRITER_2_35 + | MASK_CHUNKED_ENCODING + | PROXY_EXCEPTION_FALLBACK); } /** @@ -52,7 +59,7 @@ public Capability() { * @see MultiClassLoaderSerializer */ public boolean supportsMultiClassLoaderRPC() { - return (mask&MASK_MULTI_CLASSLOADER)!=0; + return (mask & MASK_MULTI_CLASSLOADER) != 0; } /** @@ -61,13 +68,13 @@ public boolean supportsMultiClassLoaderRPC() { * @see ProxyOutputStream */ public boolean supportsPipeThrottling() { - return (mask& MASK_PIPE_THROTTLING)!=0; + return (mask & MASK_PIPE_THROTTLING) != 0; } /** @deprecated no longer used */ @Deprecated public boolean hasMimicException() { - return (mask&MASK_MIMIC_EXCEPTION)!=0; + return (mask & MASK_MIMIC_EXCEPTION) != 0; } /** @@ -126,7 +133,7 @@ public boolean supportsProxyExceptionFallback() { return (mask & PROXY_EXCEPTION_FALLBACK) != 0; } - //TODO: ideally preamble handling needs to be reworked in order to avoid FB suppression + // TODO: ideally preamble handling needs to be reworked in order to avoid FB suppression /** * Writes {@link #PREAMBLE} then uses {@link #write}. */ @@ -143,9 +150,11 @@ private void write(OutputStream os) throws IOException { @Override public void close() throws IOException { flush(); - // TODO: Cannot invoke the private clear() method, but GC well do it for us. Not worse than the original solution + // TODO: Cannot invoke the private clear() method, but GC well do it for us. Not worse than the original + // solution // Here the code does not close the proxied stream OS on completion } + @Override protected void annotateClass(Class c) throws IOException { AnonymousClassWarnings.check(c); @@ -160,30 +169,36 @@ protected void annotateClass(Class c) throws IOException { /** * The opposite operation of {@link #write}. */ - @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION", justification = "Capability is used for negotiating channel between authorized agent and server. Whitelisting and proper deserialization hygiene are used.") + @SuppressFBWarnings( + value = "OBJECT_DESERIALIZATION", + justification = + "Capability is used for negotiating channel between authorized agent and server. Whitelisting and proper deserialization hygiene are used.") public static Capability read(InputStream is) throws IOException { try (ObjectInputStream ois = new ObjectInputStream(Channel.Mode.TEXT.wrap(is)) { - // during deserialization, only accept Capability to protect ourselves - // from malicious payload. Allow java.lang.String so that - // future versions of Capability can send more complex data structure. - // If we decide to do so in the future, the payload will contain those instances - // even though our version of Capability class will discard them after deserialization. - @Override - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - String n = desc.getName(); - if (n.equals("java.lang.String") || n.equals("[Ljava.lang.String;") || n.equals(Capability.class.getName())) - return super.resolveClass(desc); - throw new SecurityException("Rejected: "+n); + // during deserialization, only accept Capability to protect ourselves + // from malicious payload. Allow java.lang.String so that + // future versions of Capability can send more complex data structure. + // If we decide to do so in the future, the payload will contain those instances + // even though our version of Capability class will discard them after deserialization. + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + String n = desc.getName(); + if (n.equals("java.lang.String") + || n.equals("[Ljava.lang.String;") + || n.equals(Capability.class.getName())) { + return super.resolveClass(desc); } + throw new SecurityException("Rejected: " + n); + } - @Override - public void close() throws IOException { - // Do not close the stream since we continue reading from the input stream "is" - } - }) { - return (Capability)ois.readObject(); + @Override + public void close() throws IOException { + // Do not close the stream since we continue reading from the input stream "is" + } + }) { + return (Capability) ois.readObject(); } catch (ClassNotFoundException e) { - throw (Error)new NoClassDefFoundError(e.getMessage()).initCause(e); + throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e); } } diff --git a/src/main/java/hudson/remoting/Channel.java b/src/main/java/hudson/remoting/Channel.java index 957921246..892952067 100644 --- a/src/main/java/hudson/remoting/Channel.java +++ b/src/main/java/hudson/remoting/Channel.java @@ -136,8 +136,10 @@ public class Channel implements VirtualChannel, IChannel, Closeable { * and error reports. */ private final String name; + private volatile boolean remoteClassLoadingAllowed, arbitraryCallableAllowed; /*package*/ final CallableDecoratorList decorators = new CallableDecoratorList(); + @Restricted(NoExternalUse.class) public final ExecutorService executor; @@ -158,7 +160,8 @@ public class Channel implements VirtualChannel, IChannel, Closeable { * Requests that are sent to the remote side for execution, yet we are waiting locally until * we hear back their responses. */ - /*package*/ final Map> pendingCalls = new ConcurrentHashMap<>(); + /*package*/ final Map> pendingCalls = + new ConcurrentHashMap<>(); /** * Remembers last I/O ID issued from locally to the other side, per thread. @@ -169,7 +172,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable { /** * Records the {@link Request}s being executed on this channel, sent by the remote peer. */ - /*package*/ final Map> executingCalls = new ConcurrentHashMap<>(); + /*package*/ final Map> executingCalls = new ConcurrentHashMap<>(); /** * {@link ClassLoader}s that are proxies of the remote classloaders. @@ -212,6 +215,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable { * Registered listeners. */ private final List listeners = new CopyOnWriteArrayList<>(); + private int gcCounter; /** @@ -240,6 +244,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable { * return right away, and the socket only really times out after 10s of minutes. */ private final AtomicLong lastCommandSentAt = new AtomicLong(); + private final AtomicLong lastCommandReceivedAt = new AtomicLong(); /** @@ -296,7 +301,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable { /** * Property bag that contains application-specific stuff. */ - private final ConcurrentHashMap properties = new ConcurrentHashMap<>(); + private final ConcurrentHashMap properties = new ConcurrentHashMap<>(); /** * Proxy to the remote {@link Channel} object. @@ -361,16 +366,19 @@ public enum Mode { /** * Send binary data over the stream. Most efficient. */ - BINARY(new byte[]{0,0,0,0}), + BINARY(new byte[] {0, 0, 0, 0}), /** * Send ASCII over the stream. Uses base64, so the efficiency goes down by 33%, * but this is useful where stream is binary-unsafe, such as telnet. */ TEXT("<===[HUDSON TRANSMISSION BEGINS]===>") { - @Override protected OutputStream wrap(OutputStream os) { + @Override + protected OutputStream wrap(OutputStream os) { return BinarySafeStream.wrap(os); } - @Override protected InputStream wrap(InputStream is) { + + @Override + protected InputStream wrap(InputStream is) { return BinarySafeStream.wrap(is); } }, @@ -397,8 +405,13 @@ public enum Mode { this.preamble = preamble; } - protected OutputStream wrap(OutputStream os) { return os; } - protected InputStream wrap(InputStream is) { return is; } + protected OutputStream wrap(OutputStream os) { + return os; + } + + protected InputStream wrap(InputStream is) { + return is; + } } /** @@ -410,7 +423,7 @@ public enum Mode { */ @Deprecated public Channel(String name, ExecutorService exec, InputStream is, OutputStream os) throws IOException { - this(name,exec,Mode.BINARY,is,os,null); + this(name, exec, Mode.BINARY, is, os, null); } /** @@ -422,7 +435,7 @@ public Channel(String name, ExecutorService exec, InputStream is, OutputStream o */ @Deprecated public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os) throws IOException { - this(name,exec,mode,is,os,null); + this(name, exec, mode, is, os, null); } /** @@ -434,8 +447,9 @@ public Channel(String name, ExecutorService exec, Mode mode, InputStream is, Out * .build(is, os) */ @Deprecated - public Channel(String name, ExecutorService exec, InputStream is, OutputStream os, OutputStream header) throws IOException { - this(name,exec,Mode.BINARY,is,os,header); + public Channel(String name, ExecutorService exec, InputStream is, OutputStream os, OutputStream header) + throws IOException { + this(name, exec, Mode.BINARY, is, os, header); } /** @@ -449,8 +463,9 @@ public Channel(String name, ExecutorService exec, InputStream is, OutputStream o * .build(is, os) */ @Deprecated - public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header) throws IOException { - this(name,exec,mode,is,os,header,false); + public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header) + throws IOException { + this(name, exec, mode, is, os, header, false); } /** @@ -465,8 +480,16 @@ public Channel(String name, ExecutorService exec, Mode mode, InputStream is, Out * .build(is, os) */ @Deprecated - public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted) throws IOException { - this(name,exec,mode,is,os,header,restricted,null); + public Channel( + String name, + ExecutorService exec, + Mode mode, + InputStream is, + OutputStream os, + OutputStream header, + boolean restricted) + throws IOException { + this(name, exec, mode, is, os, header, restricted, null); } /** @@ -485,19 +508,40 @@ public Channel(String name, ExecutorService exec, Mode mode, InputStream is, Out * .build(is, os) */ @Deprecated - public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted, ClassLoader base) throws IOException { - this(name,exec,mode,is,os,header,restricted,base,new Capability()); - } - - /*package*/ Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted, ClassLoader base, Capability capability) throws IOException { - this(new ChannelBuilder(name,exec) - .withMode(mode) - .withBaseLoader(base) - .withCapability(capability) - .withHeaderStream(header) - .withArbitraryCallableAllowed(!restricted) - .withRemoteClassLoadingAllowed(!restricted) - , is, os); + public Channel( + String name, + ExecutorService exec, + Mode mode, + InputStream is, + OutputStream os, + OutputStream header, + boolean restricted, + ClassLoader base) + throws IOException { + this(name, exec, mode, is, os, header, restricted, base, new Capability()); + } + + /*package*/ Channel( + String name, + ExecutorService exec, + Mode mode, + InputStream is, + OutputStream os, + OutputStream header, + boolean restricted, + ClassLoader base, + Capability capability) + throws IOException { + this( + new ChannelBuilder(name, exec) + .withMode(mode) + .withBaseLoader(base) + .withCapability(capability) + .withHeaderStream(header) + .withArbitraryCallableAllowed(!restricted) + .withRemoteClassLoadingAllowed(!restricted), + is, + os); } /** @@ -511,17 +555,18 @@ public Channel(String name, ExecutorService exec, Mode mode, InputStream is, Out * @since 2.13 */ @Deprecated - public Channel(String name, ExecutorService exec, CommandTransport transport, boolean restricted, ClassLoader base) throws IOException { - this(new ChannelBuilder(name,exec) - .withBaseLoader(base) - .withArbitraryCallableAllowed(!restricted) - .withRemoteClassLoadingAllowed(!restricted) - , transport); - + public Channel(String name, ExecutorService exec, CommandTransport transport, boolean restricted, ClassLoader base) + throws IOException { + this( + new ChannelBuilder(name, exec) + .withBaseLoader(base) + .withArbitraryCallableAllowed(!restricted) + .withRemoteClassLoadingAllowed(!restricted), + transport); } /*package*/ Channel(ChannelBuilder settings, InputStream is, OutputStream os) throws IOException { - this(settings, settings.negotiate(is,os)); + this(settings, settings.negotiate(is, os)); } /** @@ -549,12 +594,20 @@ public Channel(String name, ExecutorService exec, CommandTransport transport, bo * .build(transport) */ @Deprecated - public Channel(String name, ExecutorService exec, CommandTransport transport, boolean restricted, ClassLoader base, JarCache jarCache) throws IOException { - this(new ChannelBuilder(name,exec) - .withBaseLoader(base) - .withRestricted(restricted) - .withJarCache(jarCache) - , transport); + public Channel( + String name, + ExecutorService exec, + CommandTransport transport, + boolean restricted, + ClassLoader base, + JarCache jarCache) + throws IOException { + this( + new ChannelBuilder(name, exec) + .withBaseLoader(base) + .withRestricted(restricted) + .withJarCache(jarCache), + transport); } /** @@ -563,7 +616,7 @@ public Channel(String name, ExecutorService exec, CommandTransport transport, bo protected Channel(@NonNull ChannelBuilder settings, @NonNull CommandTransport transport) throws IOException { this.name = settings.getName(); this.reference = new Ref(this); - this.executor = new InterceptingExecutorService(settings.getExecutors(),decorators); + this.executor = new InterceptingExecutorService(settings.getExecutors(), decorators); this.arbitraryCallableAllowed = settings.isArbitraryCallableAllowed(); this.remoteClassLoadingAllowed = settings.isRemoteClassLoadingAllowed(); this.underlyingOutput = transport.getUnderlyingStream(); @@ -577,8 +630,9 @@ protected Channel(@NonNull ChannelBuilder settings, @NonNull CommandTransport tr this.baseClassLoader = settings.getBaseLoader(); this.classFilter = settings.getClassFilter(); - if(internalExport(IChannel.class, this, false)!=1) + if (internalExport(IChannel.class, this, false) != 1) { throw new AssertionError(); // export number 1 is reserved for the channel itself + } remoteChannel = RemoteInvocationHandler.wrap(this, 1, IChannel.class, true, false, false, true); this.remoteCapability = transport.getRemoteCapability(); @@ -606,10 +660,15 @@ public void handle(Command cmd) { try { cmd.execute(Channel.this); if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Completed command {0}. It took {1}ms", new Object[] {cmd, System.currentTimeMillis() - receivedAt}); + logger.log(Level.FINE, "Completed command {0}. It took {1}ms", new Object[] { + cmd, System.currentTimeMillis() - receivedAt + }); } } catch (Throwable t) { - logger.log(Level.SEVERE, "Failed to execute command " + cmd + " (channel " + Channel.this.name + ")", t); + logger.log( + Level.SEVERE, + "Failed to execute command " + cmd + " (channel " + Channel.this.name + ")", + t); if (cmd.createdAt != null) { logger.log(Level.SEVERE, "This command is created here", cmd.createdAt); } @@ -621,7 +680,7 @@ public void terminate(IOException e) { Channel.this.terminate(e); } }); - ACTIVE_CHANNELS.put(this,ref()); + ACTIVE_CHANNELS.put(this, ref()); } /** @@ -640,7 +699,7 @@ public void terminate(IOException e) { * @see #addListener * @see LoggingChannelListener */ - public static abstract class Listener { + public abstract static class Listener { /** * When the channel was closed normally or abnormally due to an error. * @@ -688,14 +747,13 @@ public void onResponse(Channel channel, Request req, Response rsp, l * @since 3.17 */ public void onJar(Channel channel, File jar) {} - } /** * Is the sender side of the transport already closed? */ public boolean isOutClosed() { - return outClosed!=null; + return outClosed != null; } /** @@ -744,8 +802,9 @@ public Throwable getCloseRequestCause() { * which is the historical behaviour. */ private ExecutorService createPipeWriterExecutor() { - if (remoteCapability.supportsPipeThrottling()) + if (remoteCapability.supportsPipeThrottling()) { return new SingleLaneExecutorService(executor); + } return new SynchronousExecutorService(); } @@ -756,12 +815,17 @@ private ExecutorService createPipeWriterExecutor() { * This is the lowest layer of abstraction in {@link Channel}. * {@link Command}s are executed on a remote system in the order they are sent. */ - @SuppressFBWarnings(value = "VO_VOLATILE_INCREMENT", justification = "The method is synchronized, no other usages. See https://sourceforge.net/p/findbugs/bugs/1032/") + @SuppressFBWarnings( + value = "VO_VOLATILE_INCREMENT", + justification = + "The method is synchronized, no other usages. See https://sourceforge.net/p/findbugs/bugs/1032/") /*package*/ synchronized void send(Command cmd) throws IOException { - if(outClosed!=null) + if (outClosed != null) { throw new ChannelClosedException(this, outClosed); - if(logger.isLoggable(Level.FINE)) - logger.fine("Send "+cmd); + } + if (logger.isLoggable(Level.FINE)) { + logger.fine("Send " + cmd); + } transport.write(cmd, cmd instanceof CloseCommand); commandsSent.incrementAndGet(); @@ -791,26 +855,29 @@ public T export(Class type, T instance) { * {@code null} if the input instance is {@code null}. */ @Nullable - /*package*/ T export(Class type, @CheckForNull T instance, boolean userProxy, boolean userScope, boolean recordCreatedAt) { - if(instance==null) { + /*package*/ T export( + Class type, @CheckForNull T instance, boolean userProxy, boolean userScope, boolean recordCreatedAt) { + if (instance == null) { return null; } // every so often perform GC on the remote system so that // unused RemoteInvocationHandler get released, which triggers // unexport operation. - if((++gcCounter)%10000==0) + if ((++gcCounter) % 10000 == 0) { try { send(new GCCommand()); } catch (IOException e) { // for compatibility reason we can't change the export method signature - logger.log(Level.WARNING, "Unable to send GC command",e); + logger.log(Level.WARNING, "Unable to send GC command", e); } + } // either local side will auto-unexport, or the remote side will unexport when it's GC-ed boolean autoUnexportByCaller = exportedObjects.isRecording(); final int id = internalExport(type, instance, autoUnexportByCaller); - return RemoteInvocationHandler.wrap(null, id, type, userProxy, autoUnexportByCaller, userScope, recordCreatedAt); + return RemoteInvocationHandler.wrap( + null, id, type, userProxy, autoUnexportByCaller, userScope, recordCreatedAt); } /*package*/ int internalExport(Class clazz, T instance) { @@ -821,16 +888,18 @@ public T export(Class type, T instance) { return exportedObjects.export(clazz, instance, automaticUnexport); } - /*package*/ @NonNull Object getExportedObject(int oid) throws ExecutionException { + /*package*/ @NonNull + Object getExportedObject(int oid) throws ExecutionException { return exportedObjects.get(oid); } @CheckForNull - /*package*/ Object getExportedObjectOrNull(int oid) { + /*package*/ Object getExportedObjectOrNull(int oid) { return exportedObjects.getOrNull(oid); } - /*package*/ @NonNull Class[] getExportedTypes(int oid) throws ExecutionException { + /*package*/ @NonNull + Class[] getExportedTypes(int oid) throws ExecutionException { return exportedObjects.type(oid); } @@ -860,7 +929,7 @@ public void pin(@NonNull Object instance) { * {@linkplain #pin(Object) Pin down} the exported classloader. */ public void pinClassLoader(ClassLoader cl) { - RemoteClassLoader.pin(cl,this); + RemoteClassLoader.pin(cl, this); } /** @@ -919,19 +988,21 @@ public void pinClassLoader(ClassLoader cl) { * @throws IOException * if the preloading fails. */ - public boolean preloadJar(Callable classLoaderRef, Class... classesInJar) throws IOException, InterruptedException { + public boolean preloadJar(Callable classLoaderRef, Class... classesInJar) + throws IOException, InterruptedException { return preloadJar(UserRequest.getClassLoader(classLoaderRef), classesInJar); } public boolean preloadJar(ClassLoader local, Class... classesInJar) throws IOException, InterruptedException { URL[] jars = new URL[classesInJar.length]; - for (int i = 0; i < classesInJar.length; i++) + for (int i = 0; i < classesInJar.length; i++) { jars[i] = Which.jarFile(classesInJar[i]).toURI().toURL(); + } return call(new PreloadJarTask(jars, local)); } public boolean preloadJar(ClassLoader local, URL... jars) throws IOException, InterruptedException { - return call(new PreloadJarTask(jars,local)); + return call(new PreloadJarTask(jars, local)); } /** @@ -965,42 +1036,44 @@ public void setJarCache(@NonNull JarCache jarCache) { synchronized (pipeWindows) { PipeWindow.Key k = new PipeWindow.Key(oid); WeakReference v = pipeWindows.get(k); - if (v!=null) { + if (v != null) { PipeWindow w = v.get(); - if (w!=null) + if (w != null) { return w; + } } PipeWindow w; - if (remoteCapability.supportsPipeThrottling()) + if (remoteCapability.supportsPipeThrottling()) { w = new PipeWindow.Real(k, PIPE_WINDOW_SIZE); - else + } else { w = new PipeWindow.Fake(); + } pipeWindows.put(k, new WeakReference<>(w)); return w; } } - /** * {@inheritDoc} */ @Override - public - V call(Callable callable) throws IOException, T, InterruptedException { + public V call(Callable callable) throws IOException, T, InterruptedException { if (isClosingOrClosed()) { // No reason to even try performing a user request - throw new ChannelClosedException(this, "Remote call on " + name + " failed. " - + "The channel is closing down or has closed down", getCloseRequestCause()); + throw new ChannelClosedException( + this, + "Remote call on " + name + " failed. " + "The channel is closing down or has closed down", + getCloseRequestCause()); } - UserRequest request=null; + UserRequest request = null; try { request = new UserRequest<>(this, callable); UserRequest.ResponseToUserRequest r = request.call(this); return r.retrieve(this, UserRequest.getClassLoader(callable)); - // re-wrap the exception so that we can capture the stack trace of the caller. + // re-wrap the exception so that we can capture the stack trace of the caller. } catch (ClassNotFoundException | Error e) { throw new IOException("Remote call on " + name + " failed", e); } catch (SecurityException e) { @@ -1010,8 +1083,9 @@ V call(Callable callable) throws IOException, T, InterruptedException { // we assume all the exported objects are out of scope. // (that is, the operation shouldn't spawn a new thread or altter // global state in the remote system. - if(request!=null) + if (request != null) { request.releaseExports(); + } } } @@ -1019,12 +1093,13 @@ V call(Callable callable) throws IOException, T, InterruptedException { * {@inheritDoc} */ @Override - public - Future callAsync(final Callable callable) throws IOException { + public Future callAsync(final Callable callable) throws IOException { if (isClosingOrClosed()) { // No reason to even try performing a user request - throw new ChannelClosedException(this, "Remote call on " + name + " failed. " - + "The channel is closing down or has closed down", getCloseRequestCause()); + throw new ChannelClosedException( + this, + "Remote call on " + name + " failed. " + "The channel is closing down or has closed down", + getCloseRequestCause()); } final Future> f = new UserRequest(this, callable).callAsync(this); @@ -1033,7 +1108,7 @@ Future callAsync(final Callable callable) throws IOException { protected V adapt(UserRequest.ResponseToUserRequest r) throws ExecutionException { try { return r.retrieve(Channel.this, UserRequest.getClassLoader(callable)); - } catch (Throwable t) {// really means catch(T t) + } catch (Throwable t) { // really means catch(T t) throw new ExecutionException(t); } } @@ -1052,7 +1127,9 @@ protected V adapt(UserRequest.ResponseToUserRequest r) throws ExecutionExc * @param e * The error that caused the connection to be aborted. Never null. */ - @SuppressFBWarnings(value = "ITA_INEFFICIENT_TO_ARRAY", justification = "intentionally; race condition on listeners otherwise") + @SuppressFBWarnings( + value = "ITA_INEFFICIENT_TO_ARRAY", + justification = "intentionally; race condition on listeners otherwise") public void terminate(@NonNull IOException e) { if (e == null) { @@ -1096,14 +1173,17 @@ public void terminate(@NonNull IOException e) { } } // JENKINS-14909: leave synch block } finally { - if (e instanceof OrderlyShutdown) e = null; + if (e instanceof OrderlyShutdown) { + e = null; + } for (Listener l : listeners) { try { l.onClosed(this, e); } catch (Throwable t) { - LogRecord lr = new LogRecord(Level.SEVERE, "Listener {0} propagated an exception for channel {1}'s close: {2}"); + LogRecord lr = new LogRecord( + Level.SEVERE, "Listener {0} propagated an exception for channel {1}'s close: {2}"); lr.setThrown(t); - lr.setParameters(new Object[]{l, this, t.getMessage()}); + lr.setParameters(new Object[] {l, this, t.getMessage()}); logger.log(lr); } } @@ -1175,12 +1255,13 @@ public void removeLocalExecutionInterceptor(CallableFilter filter) { */ @Override public synchronized void join() throws InterruptedException { - while(inClosed==null || outClosed==null) + while (inClosed == null || outClosed == null) { // not that I really encountered any situation where this happens, but // given tickets like JENKINS-20709 that talks about hangs, it seems // like a good defensive measure to periodically wake up to make sure // that the wait condition is still not met in case we don't call notifyAll correctly wait(TimeUnit.SECONDS.toMillis(30)); + } } /** @@ -1188,7 +1269,7 @@ public synchronized void join() throws InterruptedException { * this method returns true. */ public boolean isInClosed() { - return inClosed!=null; + return inClosed != null; } /** @@ -1258,22 +1339,27 @@ public void setArbitraryCallableAllowed(boolean b) { */ public void setMaximumBytecodeLevel(short level) throws IOException, InterruptedException { if (level < 5) { - throw new IllegalArgumentException("Does not make sense to specify JDK 1.4 or below since remoting itself requires JDK 5+"); + throw new IllegalArgumentException( + "Does not make sense to specify JDK 1.4 or below since remoting itself requires JDK 5+"); } call(new SetMaximumBytecodeLevel(level)); } - private static final class SetMaximumBytecodeLevel implements InternalCallable { + + private static final class SetMaximumBytecodeLevel implements InternalCallable { private static final long serialVersionUID = 1; private final short level; + SetMaximumBytecodeLevel(short level) { this.level = level; } + @Override public Void call() throws RuntimeException { Channel.currentOrFail().maximumBytecodeLevel = level; return null; } - // no specific role needed, which is somewhat dubious, but I can't think of any attack vector that involves this. + // no specific role needed, which is somewhat dubious, but I can't think of any attack vector that involves + // this. // it would have been simpler if the setMaximumBytecodeLevel only controlled the local setting, // not the remote setting } @@ -1313,8 +1399,8 @@ protected void execute(Channel channel) { channel.close(); channel.terminate(new OrderlyShutdown(createdAt)); } catch (IOException e) { - logger.log(Level.SEVERE,"close command failed on "+channel.name,e); - logger.log(Level.INFO,"close command created at",createdAt); + logger.log(Level.SEVERE, "close command failed on " + channel.name, e); + logger.log(Level.INFO, "close command created at", createdAt); } } @@ -1323,7 +1409,8 @@ public String toString() { return "Close"; } - // this value is compatible with remoting < 2.8. I made an incompatible change in 2.8 that got corrected in 2.11. + // this value is compatible with remoting < 2.8. I made an incompatible change in 2.8 that got corrected in + // 2.11. static final long serialVersionUID = 972857271608138115L; } @@ -1332,9 +1419,10 @@ public String toString() { * where the termination was initiated as a nested exception. */ private static final class OrderlyShutdown extends IOException { - private OrderlyShutdown(@CheckForNull Throwable cause) { + private OrderlyShutdown(@CheckForNull Throwable cause) { super(cause); } + private static final long serialVersionUID = 1L; } @@ -1359,13 +1447,13 @@ public void dumpPerformanceCounters(PrintWriter w) throws IOException { int l = classLoadingCount.get(); int p = classLoadingPrefetchCacheCount.get(); w.printf(Locale.ENGLISH, "Class loading count=%d%n", l); - w.printf(Locale.ENGLISH, "Class loading prefetch hit=%s (%d%%)%n", p, p*100/l); + w.printf(Locale.ENGLISH, "Class loading prefetch hit=%s (%d%%)%n", p, p * 100 / l); w.printf(Locale.ENGLISH, "Class loading time=%,dms%n", classLoadingTime.get() / (1000 * 1000)); w.printf(Locale.ENGLISH, "Resource loading count=%d%n", resourceLoadingCount.get()); w.printf(Locale.ENGLISH, "Resource loading time=%,dms%n", resourceLoadingTime.get() / (1000 * 1000)); } - //TODO: Make public after merge into the master branch + // TODO: Make public after merge into the master branch /** * Print the diagnostic information. * @@ -1428,7 +1516,7 @@ public void dumpPerformanceCounters(PrintWriter w) throws IOException { */ @Restricted(NoExternalUse.class) public void dumpDiagnostics(@NonNull PrintWriter w) throws IOException { - w.printf("Channel %s%n",name); + w.printf("Channel %s%n", name); w.printf(" Created=%s%n", new Date(createdAt)); w.printf(" Commands sent=%d%n", commandsSent.get()); w.printf(" Commands received=%d%n", commandsReceived.get()); @@ -1463,16 +1551,19 @@ public void close() throws IOException { * @since 2.8 */ public void close(@CheckForNull Throwable diagnosis) throws IOException { - if(outClosed!=null) return; // already closed + if (outClosed != null) { + return; // already closed + } closeRequested = true; if (closeRequestCause == null) { // Cache the cause value just in case it takes long to acquire the lock - // TODO: This IOException wrapper is copy-pasted from the original logic, but do we actually need it when diagnosis is non-null? + // TODO: This IOException wrapper is copy-pasted from the original logic, but do we actually need it when + // diagnosis is non-null? closeRequestCause = new IOException(diagnosis); } - synchronized(this) { - if(outClosed!=null) { + synchronized (this) { + if (outClosed != null) { // It has been closed while we were waiting for the lock return; } @@ -1489,7 +1580,9 @@ public void close(@CheckForNull Throwable diagnosis) throws IOException { terminate(e); return; } - outClosed = new IOException(diagnosis); // last command sent. no further command allowed. lock guarantees that no command will slip inbetween + outClosed = new IOException( + diagnosis); // last command sent. no further command allowed. lock guarantees that no command will + // slip inbetween notifyAll(); try { transport.closeWrite(); @@ -1506,7 +1599,7 @@ public void close(@CheckForNull Throwable diagnosis) throws IOException { // termination is done by CloseCommand when we received it. } - //TODO: ideally waitForProperty() methods should get rid of the notify-driven implementation + // TODO: ideally waitForProperty() methods should get rid of the notify-driven implementation /** * Gets the application specific property set by {@link #setProperty(Object, Object)}. * These properties are also accessible from the remote channel via {@link #getRemoteProperty(Object)}. @@ -1543,19 +1636,21 @@ public Object waitForProperty(@NonNull Object key) throws InterruptedException { // There is no need to acquire the channel lock if the property is already set Object prop = properties.get(key); - if(prop!=null) { + if (prop != null) { return prop; } // TODO: Does it make sense to execute this thing when the channel is closing? - if (isInClosed()) + if (isInClosed()) { throw new IllegalStateException("Channel was already closed", inClosed); - if (isOutClosed()) + } + if (isOutClosed()) { throw new IllegalStateException("Channel was already closed", outClosed); + } while (true) { // Now we wait till setProperty() notifies us (in a cycle) - synchronized(this) { + synchronized (this) { if (isInClosed()) { throw new IllegalStateException("Channel was already closed", inClosed); } else if (isOutClosed()) { @@ -1565,7 +1660,9 @@ public Object waitForProperty(@NonNull Object key) throws InterruptedException { } } Object v = properties.get(key); - if (v != null) return v; + if (v != null) { + return v; + } } } @@ -1601,7 +1698,6 @@ public T setProperty(ChannelProperty key, T value) { return key.type.cast(setProperty((Object) key, value)); } - /** * Gets the property set on the remote peer. * @@ -1671,9 +1767,10 @@ public OutputStream getUnderlyingOutput() { * @deprecated as of 3.39 */ @Deprecated - public ListeningPort createLocalToRemotePortForwarding(int recvPort, String forwardHost, int forwardPort) throws IOException, InterruptedException { - PortForwarder portForwarder = new PortForwarder(recvPort, - ForwarderFactory.create(this, forwardHost, forwardPort)); + public ListeningPort createLocalToRemotePortForwarding(int recvPort, String forwardHost, int forwardPort) + throws IOException, InterruptedException { + PortForwarder portForwarder = + new PortForwarder(recvPort, ForwarderFactory.create(this, forwardHost, forwardPort)); portForwarder.start(); return portForwarder; } @@ -1696,9 +1793,9 @@ public ListeningPort createLocalToRemotePortForwarding(int recvPort, String forw * @deprecated as of 3.39 */ @Deprecated - public ListeningPort createRemoteToLocalPortForwarding(int recvPort, String forwardHost, int forwardPort) throws IOException, InterruptedException { - return PortForwarder.create(this,recvPort, - ForwarderFactory.create(forwardHost, forwardPort)); + public ListeningPort createRemoteToLocalPortForwarding(int recvPort, String forwardHost, int forwardPort) + throws IOException, InterruptedException { + return PortForwarder.create(this, recvPort, ForwarderFactory.create(forwardHost, forwardPort)); } /** @@ -1733,29 +1830,32 @@ public void syncIO() throws IOException, InterruptedException { call(new IOSyncer()); } -// Barrier doesn't work because IOSyncer is a Callable and not Command -// (yet making it Command would break JENKINS-5977, which introduced this split in the first place!) -// /** -// * Non-blocking version of {@link #syncIO()} that has a weaker commitment. -// * -// * This method only guarantees that any later remote commands will happen after all the I/O packets sent before -// * this method call gets fully executed. This is faster in that it it doesn't wait for a response -// * from the other side, yet it normally achieves the desired semantics. -// */ -// public void barrierIO() throws IOException { -// callAsync(new IOSyncer()); -// } + // Barrier doesn't work because IOSyncer is a Callable and not Command + // (yet making it Command would break JENKINS-5977, which introduced this split in the first place!) + // /** + // * Non-blocking version of {@link #syncIO()} that has a weaker commitment. + // * + // * This method only guarantees that any later remote commands will happen after all the I/O packets sent + // before + // * this method call gets fully executed. This is faster in that it it doesn't wait for a response + // * from the other side, yet it normally achieves the desired semantics. + // */ + // public void barrierIO() throws IOException { + // callAsync(new IOSyncer()); + // } @Override public void syncLocalIO() throws InterruptedException { Thread t = Thread.currentThread(); String old = t.getName(); - t.setName("I/O sync: "+old); + t.setName("I/O sync: " + old); try { // no one waits for the completion of this Runnable, so not using I/O ID - pipeWriter.submit(0, () -> { - // noop - }).get(); + pipeWriter + .submit(0, () -> { + // noop + }) + .get(); } catch (ExecutionException e) { throw new AssertionError(e); // impossible } finally { @@ -1800,7 +1900,7 @@ public String getName() { @Override public String toString() { - return super.toString()+":"+name; + return super.toString() + ":" + name; } /** @@ -1882,11 +1982,12 @@ public static void dumpDiagnosticsForAll(@NonNull PrintWriter w) { for (Ref ref : channels) { // Check if we can still write the output if (w.checkError()) { - logger.log(Level.WARNING, - String.format("Cannot dump diagnostics for all channels, because output stream encountered an error. " - + "Processed %d of %d channels, first unprocessed channel reference is %s.", - processedCount, channels.length, ref - )); + logger.log( + Level.WARNING, + String.format( + "Cannot dump diagnostics for all channels, because output stream encountered an error. " + + "Processed %d of %d channels, first unprocessed channel reference is %s.", + processedCount, channels.length, ref)); break; } @@ -1897,12 +1998,15 @@ public static void dumpDiagnosticsForAll(@NonNull PrintWriter w) { ch.dumpDiagnostics(w); } catch (Throwable ex) { if (ex instanceof Error) { - throw (Error)ex; + throw (Error) ex; } - w.printf("Cannot dump diagnostics for the channel %s. %s. See Error stacktrace in system logs", + w.printf( + "Cannot dump diagnostics for the channel %s. %s. See Error stacktrace in system logs", ch.getName(), ex.getMessage()); - logger.log(Level.WARNING, - String.format("Cannot dump diagnostics for the channel %s", ch.getName()), ex); + logger.log( + Level.WARNING, + String.format("Cannot dump diagnostics for the channel %s", ch.getName()), + ex); } } processedCount++; @@ -1924,7 +2028,8 @@ public static boolean isClosedChannelException(@CheckForNull Throwable t) { } else if (t == null) { return false; } else { - return isClosedChannelException(t.getCause()) || Stream.of(t.getSuppressed()).anyMatch(Channel::isClosedChannelException); + return isClosedChannelException(t.getCause()) + || Stream.of(t.getSuppressed()).anyMatch(Channel::isClosedChannelException); } } @@ -1992,7 +2097,6 @@ void notifyJar(File jar) { } } - /** * Remembers the current "channel" associated for this thread. */ @@ -2015,12 +2119,13 @@ void notifyJar(File jar) { * * @see PipeWindow */ - public static final int PIPE_WINDOW_SIZE = Integer.getInteger(Channel.class.getName()+".pipeWindowSize",1024*1024); + public static final int PIPE_WINDOW_SIZE = + Integer.getInteger(Channel.class.getName() + ".pipeWindowSize", 1024 * 1024); /** * Keep track of active channels in the system for diagnostics purposes. */ - private static final Map ACTIVE_CHANNELS = Collections.synchronizedMap(new WeakHashMap<>()); + private static final Map ACTIVE_CHANNELS = Collections.synchronizedMap(new WeakHashMap<>()); static final Class jarLoaderProxy; @@ -2034,7 +2139,7 @@ void notifyJar(File jar) { // then thread A tries to touch JarLoader proxy (which blocks on thread B) // // to avoid situations like this, create proxy classes that we need during the classloading - jarLoaderProxy=RemoteInvocationHandler.getProxyClass(JarLoader.class); + jarLoaderProxy = RemoteInvocationHandler.getProxyClass(JarLoader.class); } /** @@ -2099,7 +2204,7 @@ public Channel channel() { */ @CheckForNull public Exception cause() { - return cause; + return cause; } /** diff --git a/src/main/java/hudson/remoting/ChannelBuilder.java b/src/main/java/hudson/remoting/ChannelBuilder.java index 5165dc47c..cbc861864 100644 --- a/src/main/java/hudson/remoting/ChannelBuilder.java +++ b/src/main/java/hudson/remoting/ChannelBuilder.java @@ -43,7 +43,9 @@ public class ChannelBuilder { * Our logger. */ private static final Logger LOGGER = Logger.getLogger(ChannelBuilder.class.getName()); - private static /* non-final for Groovy */ boolean CALLABLES_CAN_IGNORE_ROLECHECKER = Boolean.getBoolean(ChannelBuilder.class.getName() + ".allCallablesCanIgnoreRoleChecker"); + + private static /* non-final for Groovy */ boolean CALLABLES_CAN_IGNORE_ROLECHECKER = + Boolean.getBoolean(ChannelBuilder.class.getName() + ".allCallablesCanIgnoreRoleChecker"); private static final Set SPECIFIC_CALLABLES_CAN_IGNORE_ROLECHECKER = new HashSet<>(); @@ -51,26 +53,32 @@ public class ChannelBuilder { final String propertyName = ChannelBuilder.class.getName() + ".specificCallablesCanIgnoreRoleChecker"; final String property = System.getProperty(propertyName); if (property != null) { - final Set names = Arrays.stream(property.split(",")).map(String::trim).collect(Collectors.toSet()); - LOGGER.log(Level.INFO, () -> "Allowing the following callables to bypass role checker requirement: " + String.join(", ", names)); + final Set names = + Arrays.stream(property.split(",")).map(String::trim).collect(Collectors.toSet()); + LOGGER.log( + Level.INFO, + () -> "Allowing the following callables to bypass role checker requirement: " + + String.join(", ", names)); SPECIFIC_CALLABLES_CAN_IGNORE_ROLECHECKER.addAll(names); } } - private final String name; private final ExecutorService executors; private ClassLoader base = this.getClass().getClassLoader(); private Channel.Mode mode = Channel.Mode.NEGOTIATE; private Capability capability = new Capability(); + @CheckForNull private OutputStream header; + @CheckForNull private JarCache jarCache; + private final List decorators = new ArrayList<>(); private boolean arbitraryCallableAllowed = true; private boolean remoteClassLoadingAllowed = true; - private final Map properties = new HashMap<>(); + private final Map properties = new HashMap<>(); private ClassFilter filter = ClassFilter.DEFAULT; /** @@ -102,7 +110,9 @@ public ExecutorService getExecutors() { * so that those classes resolve. If null, {@code Channel.class.getClassLoader()} is used. */ public ChannelBuilder withBaseLoader(ClassLoader base) { - if (base==null) base = this.getClass().getClassLoader(); + if (base == null) { + base = this.getClass().getClassLoader(); + } this.base = base; return this; } @@ -158,7 +168,7 @@ public OutputStream getHeaderStream() { * Control individual features. */ @Deprecated - public ChannelBuilder withRestricted(boolean restricted) { + public ChannelBuilder withRestricted(boolean restricted) { withArbitraryCallableAllowed(!restricted); withRemoteClassLoadingAllowed(!restricted); return this; @@ -303,11 +313,13 @@ private static boolean isCallableProhibitedByRequiredRoleCheck(Callable ca } if (callable instanceof InternalCallable) { - LOGGER.fine(() -> "Callable " + callable.getClass().getName() + " is a remoting built-in callable allowed to bypass the role check"); + LOGGER.fine(() -> "Callable " + callable.getClass().getName() + + " is a remoting built-in callable allowed to bypass the role check"); return false; } - if (SPECIFIC_CALLABLES_CAN_IGNORE_ROLECHECKER.contains(callable.getClass().getName())) { + if (SPECIFIC_CALLABLES_CAN_IGNORE_ROLECHECKER.contains( + callable.getClass().getName())) { LOGGER.fine(() -> "Callable " + callable.getClass().getName() + " is allowed through override"); return false; } @@ -327,13 +339,20 @@ public Callable userRequest(Callable op, Ca RequiredRoleCheckerWrapper wrapped = new RequiredRoleCheckerWrapper(checker); stem.checkRoles(wrapped); if (wrapped.isChecked()) { - LOGGER.log(Level.FINER, () -> "Callable " + stem.getClass().getName() + " checked roles"); + LOGGER.log( + Level.FINER, () -> "Callable " + stem.getClass().getName() + " checked roles"); } else if (isCallableProhibitedByRequiredRoleCheck(stem)) { - LOGGER.log(Level.INFO, () -> "Rejecting callable " + stem.getClass().getName() + " for ignoring RoleChecker in #checkRoles, see https://www.jenkins.io/redirect/required-role-check"); - throw new SecurityException("Security hardening prohibits the Callable implementation " + stem.getClass().getName() + " from ignoring RoleChecker, see https://www.jenkins.io/redirect/required-role-check"); + LOGGER.log( + Level.INFO, + () -> "Rejecting callable " + stem.getClass().getName() + + " for ignoring RoleChecker in #checkRoles, see https://www.jenkins.io/redirect/required-role-check"); + throw new SecurityException( + "Security hardening prohibits the Callable implementation " + + stem.getClass().getName() + + " from ignoring RoleChecker, see https://www.jenkins.io/redirect/required-role-check"); } } catch (AbstractMethodError e) { - checker.check(stem, Role.UNKNOWN);// not implemented, assume 'unknown' + checker.check(stem, Role.UNKNOWN); // not implemented, assume 'unknown' } return stem; @@ -350,7 +369,7 @@ public Callable userRequest(Callable op, Ca * @since 2.47 */ public ChannelBuilder withProperty(Object key, Object value) { - properties.put(key,value); + properties.put(key, value); return this; } @@ -364,7 +383,7 @@ public ChannelBuilder withProperty(ChannelProperty key, T value) { /** * @since 2.47 */ - public Map getProperties() { + public Map getProperties() { return Collections.unmodifiableMap(properties); } @@ -375,7 +394,9 @@ public Map getProperties() { * @since 2.53 */ public ChannelBuilder withClassFilter(ClassFilter filter) { - if (filter==null) throw new IllegalArgumentException(); + if (filter == null) { + throw new IllegalArgumentException(); + } this.filter = filter; return this; } @@ -398,23 +419,22 @@ public ClassFilter getClassFilter() { * buffering on this stream, if that's necessary. */ public Channel build(InputStream is, OutputStream os) throws IOException { - return new Channel(this,negotiate(is,os)); + return new Channel(this, negotiate(is, os)); } public Channel build(Socket s) throws IOException { // support half-close properly - return build(new BufferedInputStream(SocketChannelStream.in(s)), - new BufferedOutputStream(SocketChannelStream.out(s))); + return build( + new BufferedInputStream(SocketChannelStream.in(s)), + new BufferedOutputStream(SocketChannelStream.out(s))); } public Channel build(SocketChannel s) throws IOException { - return build( - SocketChannelStream.in(s), - SocketChannelStream.out(s)); + return build(SocketChannelStream.in(s), SocketChannelStream.out(s)); } public Channel build(CommandTransport transport) throws IOException { - return new Channel(this,transport); + return new Channel(this, transport); } /** @@ -439,63 +459,71 @@ protected CommandTransport negotiate(final InputStream is, final OutputStream os if (mode != Channel.Mode.NEGOTIATE) { LOGGER.log(Level.FINER, "Sending mode preamble: {0}", mode); os.write(mode.preamble); - os.flush(); // make sure that stream preamble is sent to the other end. avoids dead-lock + os.flush(); // make sure that stream preamble is sent to the other end. avoids dead-lock } else { LOGGER.log(Level.FINER, "Awaiting mode preamble..."); } - {// read the input until we hit preamble + { // read the input until we hit preamble Channel.Mode[] modes = {Channel.Mode.BINARY, Channel.Mode.TEXT}; - byte[][] preambles = new byte[][]{Channel.Mode.BINARY.preamble, Channel.Mode.TEXT.preamble, Capability.PREAMBLE}; - int[] ptr=new int[3]; - Capability cap = new Capability(0); // remote capacity that we obtained. If we don't hear from remote, assume no capability + byte[][] preambles = + new byte[][] {Channel.Mode.BINARY.preamble, Channel.Mode.TEXT.preamble, Capability.PREAMBLE}; + int[] ptr = new int[3]; + Capability cap = new Capability( + 0); // remote capacity that we obtained. If we don't hear from remote, assume no capability - while(true) { + while (true) { int ch = is.read(); - if(ch==-1) + if (ch == -1) { throw new EOFException("unexpected stream termination"); + } - for(int i=0;i>8)); - header[1] = (byte)(length); + header[0] = (byte) ((hasMore ? 0x80 : 0) | (length >> 8)); + header[1] = (byte) (length); return header; } } diff --git a/src/main/java/hudson/remoting/ChunkedCommandTransport.java b/src/main/java/hudson/remoting/ChunkedCommandTransport.java index a9e56cd13..c42365a3c 100644 --- a/src/main/java/hudson/remoting/ChunkedCommandTransport.java +++ b/src/main/java/hudson/remoting/ChunkedCommandTransport.java @@ -21,10 +21,11 @@ class ChunkedCommandTransport extends AbstractSynchronousByteArrayCommandTranspo */ private final OutputStream rawOut; - /*package*/ ChunkedCommandTransport(Capability remoteCapability, InputStream in, OutputStream out, OutputStream rawOut) { + /*package*/ ChunkedCommandTransport( + Capability remoteCapability, InputStream in, OutputStream out, OutputStream rawOut) { this.remoteCapability = remoteCapability; this.in = new ChunkedInputStream(in); - this.out = new ChunkedOutputStream(8192,out); + this.out = new ChunkedOutputStream(8192, out); this.rawOut = rawOut; } diff --git a/src/main/java/hudson/remoting/ChunkedInputStream.java b/src/main/java/hudson/remoting/ChunkedInputStream.java index 9b9fd478a..49fa9324b 100644 --- a/src/main/java/hudson/remoting/ChunkedInputStream.java +++ b/src/main/java/hudson/remoting/ChunkedInputStream.java @@ -32,7 +32,9 @@ public ChunkedInputStream(InputStream base) { @Override public int read() throws IOException { - if (nextPayload()) return -1; + if (nextPayload()) { + return -1; + } int x = base.read(); remaining--; return x; @@ -40,12 +42,16 @@ public int read() throws IOException { @Override public int read(@NonNull byte[] b, int off, int len) throws IOException { - if (nextPayload()) return -1; + if (nextPayload()) { + return -1; + } - len = Math.min(remaining,len); + len = Math.min(remaining, len); - int x = base.read(b,off,len); - if (x<0) return x; + int x = base.read(b, off, len); + if (x < 0) { + return x; + } remaining -= x; return x; @@ -55,9 +61,10 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { * If we are supposed to read the length of the next chunk, do so. */ private boolean nextPayload() throws IOException { - while (remaining==0) { - if (readHeader()) + while (remaining == 0) { + if (readHeader()) { return true; + } } return false; } @@ -68,15 +75,20 @@ private boolean nextPayload() throws IOException { * true if the underlying stream hits EOF */ private boolean readHeader() throws IOException { - if (remaining>0) return false; + if (remaining > 0) { + return false; + } int b1 = base.read(); int b2 = base.read(); - if (b1<0 || b2<0) return true; // EOF + if (b1 < 0 || b2 < 0) { + return true; // EOF + } int header = ChunkHeader.parse(b1, b2); - if (isLast=ChunkHeader.isLast(header)) + if (isLast = ChunkHeader.isLast(header)) { onBreak(); + } remaining = ChunkHeader.length(header); return false; } @@ -84,8 +96,7 @@ private boolean readHeader() throws IOException { /** * Signifies the chunk boundary. */ - protected void onBreak() { - } + protected void onBreak() {} /** * Reads bytes until we hit the chunk boundary. Bytes read will be written to the sink. @@ -93,19 +104,22 @@ protected void onBreak() { public void readUntilBreak(OutputStream sink) throws IOException { byte[] buf = new byte[4096]; while (true) { - if (remaining>0) { + if (remaining > 0) { // more bytes to read in the current chunk - int read = read(buf, 0, Math.min(remaining,buf.length)); - if (read==-1) + int read = read(buf, 0, Math.min(remaining, buf.length)); + if (read == -1) { throw new IOException("Unexpected EOF"); - sink.write(buf,0,read); + } + sink.write(buf, 0, read); } else { // move on to the next chunk - if (readHeader()) - return; // stream has EOFed. No more bytes to read. + if (readHeader()) { + return; // stream has EOFed. No more bytes to read. + } } - if (isLast && remaining==0) + if (isLast && remaining == 0) { return; // we've read the all payload of the last chunk + } } } diff --git a/src/main/java/hudson/remoting/ChunkedOutputStream.java b/src/main/java/hudson/remoting/ChunkedOutputStream.java index 133da4452..8fcd8a9e4 100644 --- a/src/main/java/hudson/remoting/ChunkedOutputStream.java +++ b/src/main/java/hudson/remoting/ChunkedOutputStream.java @@ -37,23 +37,23 @@ public ChunkedOutputStream(int frameSize, OutputStream base) { * How many more bytes can our buffer take? */ private int capacity() { - return buf.length-size; + return buf.length - size; } @Override public void write(int b) throws IOException { - buf[size++] = (byte)b; + buf[size++] = (byte) b; drain(); } @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { - while (len>0) { - int s = Math.min(capacity(),len); - System.arraycopy(b,off,buf,size,s); - off+=s; - len-=s; - size+=s; + while (len > 0) { + int s = Math.min(capacity(), len); + System.arraycopy(b, off, buf, size, s); + off += s; + len -= s; + size += s; drain(); } } @@ -68,7 +68,7 @@ public void sendBreak() throws IOException { @Override public void flush() throws IOException { - if (size>0) { + if (size > 0) { sendFrame(true); base.flush(); } @@ -84,13 +84,14 @@ public void close() throws IOException { * If the buffer is filled up, send a frame. */ private void drain() throws IOException { - if (capacity()==0) + if (capacity() == 0) { sendFrame(true); + } } private void sendFrame(boolean hasMore) throws IOException { - base.write(ChunkHeader.pack(size,hasMore)); - base.write(buf,0,size); + base.write(ChunkHeader.pack(size, hasMore)); + base.write(buf, 0, size); size = 0; } } diff --git a/src/main/java/hudson/remoting/ClassFilter.java b/src/main/java/hudson/remoting/ClassFilter.java index 77b193aba..e3020f674 100644 --- a/src/main/java/hudson/remoting/ClassFilter.java +++ b/src/main/java/hudson/remoting/ClassFilter.java @@ -33,7 +33,8 @@ public abstract class ClassFilter { * @deprecated use {@link #setDefault} as needed */ @Deprecated - public static final String FILE_OVERRIDE_LOCATION_PROPERTY = "hudson.remoting.ClassFilter.DEFAULTS_OVERRIDE_LOCATION"; + public static final String FILE_OVERRIDE_LOCATION_PROPERTY = + "hudson.remoting.ClassFilter.DEFAULTS_OVERRIDE_LOCATION"; private static final Logger LOGGER = Logger.getLogger(ClassFilter.class.getName()); @@ -120,6 +121,7 @@ public final Class check(Class c) { public boolean isBlacklisted(@NonNull Class c) { return CURRENT_DEFAULT.isBlacklisted(c); } + @Override public boolean isBlacklisted(@NonNull String name) { return CURRENT_DEFAULT.isBlacklisted(name); @@ -173,8 +175,7 @@ public static void appendDefaultFilter(Pattern filter) throws ClassFilterExcepti /** * No filtering whatsoever. */ - public static final ClassFilter NONE = new ClassFilter() { - }; + public static final ClassFilter NONE = new ClassFilter() {}; /** * The default filtering rules to apply, unless the context guarantees the trust between two channels. The defaults @@ -190,8 +191,7 @@ public static void appendDefaultFilter(Pattern filter) throws ClassFilterExcepti LOGGER.log(Level.FINE, "Using default in built class blacklisting"); return new RegExpClassFilter(DEFAULT_PATTERNS); } - } - catch (Error e) { + } catch (Error e) { // when being used by something like XStream the actual cause gets swallowed LOGGER.log(Level.SEVERE, "Failed to initialize the default class filter", e); throw e; @@ -201,14 +201,15 @@ public static void appendDefaultFilter(Pattern filter) throws ClassFilterExcepti @CheckForNull private static List loadPatternOverride() { String prop = System.getProperty(FILE_OVERRIDE_LOCATION_PROPERTY); - if (prop==null) { + if (prop == null) { return null; } LOGGER.log(Level.FINE, "Attempting to load user provided overrides for ClassFiltering from ''{0}''.", prop); File f = new File(prop); if (!f.exists() || !f.canRead()) { - throw new Error("Could not load user provided overrides for ClassFiltering from as " + prop + " does not exist or is not readable."); + throw new Error("Could not load user provided overrides for ClassFiltering from as " + prop + + " does not exist or is not readable."); } BufferedReader br = null; @@ -220,12 +221,17 @@ private static List loadPatternOverride() { Pattern.compile(line); patterns.add(line); } catch (PatternSyntaxException pex) { - throw new Error("Error compiling blacklist expressions - '" + line + "' is not a valid regular expression.", pex); + throw new Error( + "Error compiling blacklist expressions - '" + line + "' is not a valid regular expression.", + pex); } } return patterns; } catch (IOException ex) { - throw new Error("Could not load user provided overrides for ClassFiltering from as "+prop+" does not exist or is not readable.",ex); + throw new Error( + "Could not load user provided overrides for ClassFiltering from as " + prop + + " does not exist or is not readable.", + ex); } finally { if (br != null) { try { @@ -240,7 +246,10 @@ private static List loadPatternOverride() { /** * A class that uses a given set of regular expression patterns to determine if the class is blacklisted. */ - @SuppressFBWarnings(value = "REDOS", justification = "In an odd usage, this pattern is used to determine if another pattern matches it and not to match a string to it. REDOS doesn't apply.") + @SuppressFBWarnings( + value = "REDOS", + justification = + "In an odd usage, this pattern is used to determine if another pattern matches it and not to match a string to it. REDOS doesn't apply.") private static final class RegExpClassFilter extends ClassFilter { /** @@ -248,8 +257,8 @@ private static final class RegExpClassFilter extends ClassFilter { * {@link String#startsWith(String)} test and we can reduce CPU usage by performing that test explicitly as * well as reduce GC pressure. */ - private static final Pattern OPTIMIZE1 = Pattern.compile( - "^\\^(([\\p{L}_$][\\p{L}\\p{N}_$]*(\\.|\\[\\.\\])?)+)\\.\\*$"); + private static final Pattern OPTIMIZE1 = + Pattern.compile("^\\^(([\\p{L}_$][\\p{L}\\p{N}_$]*(\\.|\\[\\.\\])?)+)\\.\\*$"); /** * Any regex that is {@code ^\Qsome.package.name\E.*} is really just a {@link String#startsWith(String)} @@ -288,9 +297,9 @@ void add(String pattern) throws ClassFilterException { @Override public boolean isBlacklisted(@NonNull String name) { for (Object p : blacklistPatterns) { - if (p instanceof Pattern && ((Pattern)p).matcher(name).matches()) { + if (p instanceof Pattern && ((Pattern) p).matcher(name).matches()) { return true; - } else if (p instanceof String && name.startsWith((String)p)) { + } else if (p instanceof String && name.startsWith((String) p)) { return true; } } diff --git a/src/main/java/hudson/remoting/ClassLoaderHolder.java b/src/main/java/hudson/remoting/ClassLoaderHolder.java index a2cf72b3d..0b584aebd 100644 --- a/src/main/java/hudson/remoting/ClassLoaderHolder.java +++ b/src/main/java/hudson/remoting/ClassLoaderHolder.java @@ -14,7 +14,7 @@ * @since 2.12 */ public class ClassLoaderHolder implements SerializableOnlyOverRemoting { - + @CheckForNull private transient ClassLoader classLoader; @@ -22,8 +22,7 @@ public ClassLoaderHolder(@CheckForNull ClassLoader classLoader) { this.classLoader = classLoader; } - public ClassLoaderHolder() { - } + public ClassLoaderHolder() {} @CheckForNull public ClassLoader get() { @@ -36,15 +35,18 @@ public void set(@CheckForNull ClassLoader classLoader) { private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { RemoteClassLoader.IClassLoader proxy = (RemoteClassLoader.IClassLoader) ois.readObject(); - classLoader = proxy==null ? null : getChannelForSerialization().importedClassLoaders.get(proxy); + classLoader = proxy == null + ? null + : getChannelForSerialization().importedClassLoaders.get(proxy); } - @SuppressFBWarnings(value = "DMI_NONSERIALIZABLE_OBJECT_WRITTEN", + @SuppressFBWarnings( + value = "DMI_NONSERIALIZABLE_OBJECT_WRITTEN", justification = "RemoteClassLoader.export() produces a serializable wrapper class") private void writeObject(ObjectOutputStream oos) throws IOException { - if (classLoader==null) + if (classLoader == null) { oos.writeObject(null); - else { + } else { RemoteClassLoader.IClassLoader proxy = RemoteClassLoader.export(classLoader, getChannelForSerialization()); oos.writeObject(proxy); } diff --git a/src/main/java/hudson/remoting/ClassicCommandTransport.java b/src/main/java/hudson/remoting/ClassicCommandTransport.java index 9d4d1b669..50948a9d6 100644 --- a/src/main/java/hudson/remoting/ClassicCommandTransport.java +++ b/src/main/java/hudson/remoting/ClassicCommandTransport.java @@ -11,11 +11,11 @@ /** * The default {@link CommandTransport} that has been used historically. - * + * *

    * This implementation builds a {@link SynchronousCommandTransport} on top of a plain bi-directional byte stream. * {@link Channel.Mode} support allows this to be built on 8-bit unsafe transport, such as telnet. - * + * * @author Kohsuke Kawaguchi * @since 2.13 */ @@ -27,17 +27,21 @@ * Transport level {@link InputStream} that we use only for diagnostics in case we detect stream * corruption. Can be null. */ - private final @Nullable - FlightRecorderInputStream rawIn; + private final @Nullable FlightRecorderInputStream rawIn; /** * See {@link CommandTransport#getUnderlyingStream()} */ private final OutputStream rawOut; - /*package*/ ClassicCommandTransport(ObjectInputStream ois, ObjectOutputStream oos, @CheckForNull FlightRecorderInputStream rawIn, OutputStream rawOut, Capability remoteCapability) { + /*package*/ ClassicCommandTransport( + ObjectInputStream ois, + ObjectOutputStream oos, + @CheckForNull FlightRecorderInputStream rawIn, + OutputStream rawOut, + Capability remoteCapability) { this.ois = ois; this.oos = oos; - this.rawIn= rawIn; + this.rawIn = rawIn; this.rawOut = rawOut; this.remoteCapability = remoteCapability; } @@ -49,9 +53,9 @@ public Capability getRemoteCapability() throws IOException { @Override public final void write(Command cmd, boolean last) throws IOException { - cmd.writeTo(channel,oos); + cmd.writeTo(channel, oos); // TODO notifyWrite using CountingOutputStream - oos.flush(); // make sure the command reaches the other end. + oos.flush(); // make sure the command reaches the other end. // unless this is the last command, have OOS and remote OIS forget all the objects we sent // in this command. Otherwise it'll keep objects in memory unnecessarily. @@ -59,8 +63,9 @@ public final void write(Command cmd, boolean last) throws IOException { // ever sent. It is possible for our ReaderThread to receive the reflecting close call from the other side // and close the output before the sending code gets to here. // See the comment from jglick on JENKINS-3077 about what happens if we do oos.reset(). - if(!last) + if (!last) { oos.reset(); + } } @Override @@ -73,10 +78,11 @@ public final Command read() throws IOException, ClassNotFoundException { try { Command cmd = Command.readFromObjectStream(channel, ois); // TODO notifyRead using CountingInputStream - if (rawIn!=null) + if (rawIn != null) { rawIn.clear(); + } return cmd; - } catch (RuntimeException | StreamCorruptedException e) {// see JENKINS-19046 + } catch (RuntimeException | StreamCorruptedException e) { // see JENKINS-19046 throw diagnoseStreamCorruption(e); } } @@ -86,14 +92,15 @@ public final Command read() throws IOException, ClassNotFoundException { * This operation can block, so we'll use another thread to do this. */ private StreamCorruptedException diagnoseStreamCorruption(Exception e) { - if (rawIn==null) {// no source of diagnostics information. can't diagnose. - if (e instanceof StreamCorruptedException) - return (StreamCorruptedException)e; - else - return (StreamCorruptedException)new StreamCorruptedException().initCause(e); + if (rawIn == null) { // no source of diagnostics information. can't diagnose. + if (e instanceof StreamCorruptedException) { + return (StreamCorruptedException) e; + } else { + return (StreamCorruptedException) new StreamCorruptedException().initCause(e); + } } - return rawIn.analyzeCrash(e,(channel!=null ? channel : this).toString()); + return rawIn.analyzeCrash(e, (channel != null ? channel : this).toString()); } @Override diff --git a/src/main/java/hudson/remoting/Command.java b/src/main/java/hudson/remoting/Command.java index 5004b1710..d7f1a1355 100644 --- a/src/main/java/hudson/remoting/Command.java +++ b/src/main/java/hudson/remoting/Command.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,7 +43,7 @@ *

    * At this level, remoting of class files are not provided, so both {@link Channel}s * need to have the definition of {@link Command}-implementation. - * + * * @author Kohsuke Kawaguchi * @see Channel.Listener#onRead * @see Channel.Listener#onWrite @@ -76,10 +76,11 @@ public abstract class Command implements Serializable { * transferred. */ Command(boolean recordCreatedAt) { - if(recordCreatedAt) + if (recordCreatedAt) { this.createdAt = new Source(); - else + } else { this.createdAt = null; + } } /** @@ -91,7 +92,6 @@ public abstract class Command implements Serializable { */ abstract void execute(Channel channel) throws ExecutionException; - /** * Chains the {@link #createdAt} cause. * It will happen if and only if cause recording is enabled. @@ -102,7 +102,7 @@ final void chainCause(@CheckForNull Throwable initCause) { createdAt.initCause(initCause); } } - + /** Consider calling {@link Channel#notifyWrite} afterwards. */ void writeTo(Channel channel, ObjectOutputStream oos) throws IOException { Channel old = Channel.setCurrent(channel); @@ -138,20 +138,22 @@ public static Command readFrom(@NonNull Channel channel, @NonNull byte[] payload */ /*package*/ static Command readFrom(@NonNull Channel channel, @NonNull InputStream istream, int payloadSize) throws IOException, ClassNotFoundException { - Command cmd = Command.readFromObjectStream(channel, new ObjectInputStreamEx( - istream, - channel.baseClassLoader,channel.classFilter)); + Command cmd = Command.readFromObjectStream( + channel, new ObjectInputStreamEx(istream, channel.baseClassLoader, channel.classFilter)); channel.notifyRead(cmd, payloadSize); return cmd; } - /** Consider calling {@link Channel#notifyRead} afterwards. */ - @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION", justification = "Used for sending commands between authorized agent and server. Class filtering is done through JEP-200.") - static Command readFromObjectStream(Channel channel, ObjectInputStream ois) throws IOException, ClassNotFoundException { + @SuppressFBWarnings( + value = "OBJECT_DESERIALIZATION", + justification = + "Used for sending commands between authorized agent and server. Class filtering is done through JEP-200.") + static Command readFromObjectStream(Channel channel, ObjectInputStream ois) + throws IOException, ClassNotFoundException { Channel old = Channel.setCurrent(channel); try { - return (Command)ois.readObject(); + return (Command) ois.readObject(); } finally { Channel.setCurrent(old); } @@ -177,8 +179,7 @@ static Command readFromObjectStream(Channel channel, ObjectInputStream ois) thro private static final long serialVersionUID = 1L; private final class Source extends Exception { - public Source() { - } + public Source() {} private Source(@CheckForNull Throwable cause) { super(cause); diff --git a/src/main/java/hudson/remoting/CommandTransport.java b/src/main/java/hudson/remoting/CommandTransport.java index 9116eb0b0..c38f126d0 100644 --- a/src/main/java/hudson/remoting/CommandTransport.java +++ b/src/main/java/hudson/remoting/CommandTransport.java @@ -8,11 +8,11 @@ /** * Lower level abstraction under {@link Channel} for sending and receiving commands - * + * *

    * {@link Channel} is internally implemented on top of a transport that satisfies * the following characteristics: - * + * *

    *
    Point-to-point
    *
    @@ -32,7 +32,7 @@ * or else both sides must raise an error, like TCP. *
    *
    - * + * *

    * {@linkplain ClassicCommandTransport the default traditional implementation} implements * this on top of a TCP-like bi-directional byte stream, but {@link Channel} can work with @@ -51,8 +51,7 @@ */ public abstract class CommandTransport { - protected CommandTransport() { - } + protected CommandTransport() {} /** * SPI implemented by {@link Channel} so that the transport can pass the received command @@ -61,20 +60,20 @@ protected CommandTransport() { protected interface CommandReceiver { /** * Notifies the channel that a new {@link Command} was received from the other side. - * + * *

    * {@link Channel} performs all the error recovery of the error resulting from the command invocation. * {@link Channel} implements this method in a non-reentrant fashion; a transport can invoke this method * from different threads, but as the class javadoc states, the transport must * guarantee in-order delivery of the commands, and that means you cannot call this method * concurrently. - * + * * @param cmd * The command received. This object must be read from the payload * using {@link Command#readFrom(Channel, byte[])}. */ void handle(Command cmd); - + /** * Indicates that the transport has encountered a problem. * This tells the channel that it shouldn't expect future invocation of {@link #handle(Command)}, @@ -93,26 +92,26 @@ protected interface CommandReceiver { /** * Starts the transport. - * + * * This method is called once and only once at the end of the initialization of {@link Channel}, * after the {@link #getRemoteCapability()} is invoked. - * + * * The first purpose of this method is to provide a reference back to {@link Channel}, and * the second purpose of this method is to allow {@link CommandTransport} to message pumping, * where it starts receiving commands from the other side and pass them onto {@link CommandReceiver}. - * + * * This abstraction enables asynchronous processing — for example you can have a single thread * serving a large number of {@link Channel}s via NIO. - * + * * For subtypes that prefer synchronous operation, extend from {@link SynchronousCommandTransport}. - * + * *

    * Closing the read pump: {@link Channel} implements * {@code Channel.CloseCommand} its own "end of command stream" marker, and * therefore under the orderly shutdown scenario, it doesn't rely on the transport to provide EOF-like * marker. Instead, {@link Channel} will call your {@link #closeRead()} (from the same thread * that invoked {@link CommandReceiver#handle(Command)}) to indicate that it is done with the reading. - * + * *

    * If the transport encounters any error from the lower layer (say, the underlying TCP/IP socket * encountered a REST), then call {@link CommandReceiver#terminate(IOException)} to initiate the abnormal @@ -122,7 +121,7 @@ protected interface CommandReceiver { /** * Called by {@link Channel} to send one command to the other side. - * + * * {@link Channel} serializes the invocation of this method for ordering. That is, * at any given point in time only one thread executes this method. * @@ -146,7 +145,7 @@ protected interface CommandReceiver { /** * Called to close the write side of the transport, allowing the underlying transport * to be shut down. - * + * *

    * If the {@link Channel} aborts the communication, this method may end up invoked * asynchronously, concurrently, and multiple times. The implementation must protect @@ -157,7 +156,7 @@ protected interface CommandReceiver { /** * Called to indicate that the no further input is expected and any resources * associated with reading commands should be freed. - * + * * {@link Channel#isInClosed()} can be also used to test if the command reading * should terminate. */ @@ -166,7 +165,7 @@ protected interface CommandReceiver { /** * Historical artifact left for backward compatibility, necessary only for retaining * {@link Channel#getUnderlyingOutput()}. - * + * *

    * Historically, {@link CommandTransport} abstraction is introduced much later than * {@link Channel}. The implementation of the historical {@link Channel} was mostly @@ -174,7 +173,7 @@ protected interface CommandReceiver { * there was one method in Channel that assumed that there's the underlying {@link OutputStream} * (that now belongs to the implementation details of {@link CommandTransport}), * hence this method. - * + * *

    * This method is package private, to prevent new {@link CommandTransport} from * providing this feature. diff --git a/src/main/java/hudson/remoting/DaemonThreadFactory.java b/src/main/java/hudson/remoting/DaemonThreadFactory.java index bc716597a..08d2d29bf 100644 --- a/src/main/java/hudson/remoting/DaemonThreadFactory.java +++ b/src/main/java/hudson/remoting/DaemonThreadFactory.java @@ -15,7 +15,8 @@ public class DaemonThreadFactory implements ThreadFactory { public Thread newThread(@NonNull Runnable r) { Thread thread = new Thread(r); thread.setDaemon(true); - thread.setUncaughtExceptionHandler((t, e) -> LOGGER.log(Level.SEVERE, e, () -> "Unhandled exception in thread " + t)); + thread.setUncaughtExceptionHandler( + (t, e) -> LOGGER.log(Level.SEVERE, e, () -> "Unhandled exception in thread " + t)); return thread; } } diff --git a/src/main/java/hudson/remoting/DelegatingCallable.java b/src/main/java/hudson/remoting/DelegatingCallable.java index 43619cd96..e178ca6b7 100644 --- a/src/main/java/hudson/remoting/DelegatingCallable.java +++ b/src/main/java/hudson/remoting/DelegatingCallable.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -39,18 +39,18 @@ * In such a case, implement this interface, instead of plain {@link Callable} and * return a classloader that can see all the classes. * - * In case of Jenkins, {@code PluginManager.uberClassLoader} is a good candidate. + * In case of Jenkins, {@code PluginManager.uberClassLoader} is a good candidate. * * @author Kohsuke Kawaguchi */ -public interface DelegatingCallable extends Callable { - +public interface DelegatingCallable extends Callable { + /** * Returns the class loader to be used for the callable. - * + * * @return {@link ClassLoader} to be used. * The value may be {@code null} if the classloader is not being propagated to the remote side. - * If all classes in the call are primitives or {@code Void}, the value may be also {@code null}. + * If all classes in the call are primitives or {@code Void}, the value may be also {@code null}. * In such cased the handling code should try other possible classloaders. */ @CheckForNull diff --git a/src/main/java/hudson/remoting/DelegatingExecutorService.java b/src/main/java/hudson/remoting/DelegatingExecutorService.java index 8f6188e8f..b256f229f 100644 --- a/src/main/java/hudson/remoting/DelegatingExecutorService.java +++ b/src/main/java/hudson/remoting/DelegatingExecutorService.java @@ -74,18 +74,22 @@ public List> invokeAll(@NonNull Collection> @Override @NonNull - public List> invokeAll(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException { + public List> invokeAll( + @NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) + throws InterruptedException { return base.invokeAll(tasks, timeout, unit); } @Override @NonNull - public T invokeAny(@NonNull Collection> tasks) throws InterruptedException, ExecutionException { + public T invokeAny(@NonNull Collection> tasks) + throws InterruptedException, ExecutionException { return base.invokeAny(tasks); } @Override - public T invokeAny(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public T invokeAny(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { return base.invokeAny(tasks, timeout, unit); } diff --git a/src/main/java/hudson/remoting/DiagnosedStreamCorruptionException.java b/src/main/java/hudson/remoting/DiagnosedStreamCorruptionException.java index eb174a12d..24156a854 100644 --- a/src/main/java/hudson/remoting/DiagnosedStreamCorruptionException.java +++ b/src/main/java/hudson/remoting/DiagnosedStreamCorruptionException.java @@ -20,8 +20,8 @@ public class DiagnosedStreamCorruptionException extends StreamCorruptedException @NonNull private final byte[] readAhead; - DiagnosedStreamCorruptionException(Exception cause, Exception diagnoseFailure, - @NonNull byte[] readBack, @NonNull byte[] readAhead) { + DiagnosedStreamCorruptionException( + Exception cause, Exception diagnoseFailure, @NonNull byte[] readBack, @NonNull byte[] readAhead) { initCause(cause); this.diagnoseFailure = diagnoseFailure; this.readBack = readBack; @@ -43,20 +43,22 @@ public byte[] getReadAhead() { } @Override - @SuppressFBWarnings(value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", justification = "Used for diagnosing stream corruption between agent and server.") + @SuppressFBWarnings( + value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", + justification = "Used for diagnosing stream corruption between agent and server.") public String toString() { StringBuilder buf = new StringBuilder(); buf.append(super.toString()).append("\n"); buf.append("Read back: ").append(HexDump.toHex(readBack)).append('\n'); buf.append("Read ahead: ").append(HexDump.toHex(readAhead)); - if (diagnoseFailure!=null) { + if (diagnoseFailure != null) { StringWriter w = new StringWriter(); PrintWriter p = new PrintWriter(w); diagnoseFailure.printStackTrace(p); p.flush(); buf.append("\nDiagnosis problem:\n "); - buf.append(w.toString().trim().replace("\n","\n ")); + buf.append(w.toString().trim().replace("\n", "\n ")); } return buf.toString(); } diff --git a/src/main/java/hudson/remoting/DumbClassLoaderBridge.java b/src/main/java/hudson/remoting/DumbClassLoaderBridge.java index 8ca68b77d..2e1944ab3 100644 --- a/src/main/java/hudson/remoting/DumbClassLoaderBridge.java +++ b/src/main/java/hudson/remoting/DumbClassLoaderBridge.java @@ -53,15 +53,20 @@ public byte[][] getResources(String name) throws IOException { @Override public Map fetch3(String className) throws ClassNotFoundException { RemoteClassLoader.ClassFile cf = fetch2(className); - return Map.of(className, - new RemoteClassLoader.ClassFile2(cf.classLoader, new ResourceImageDirect(cf.classImage), null, null, null)); + return Map.of( + className, + new RemoteClassLoader.ClassFile2( + cf.classLoader, new ResourceImageDirect(cf.classImage), null, null, null)); } @Override public RemoteClassLoader.ResourceFile getResource2(String name) throws IOException { byte[] img = base.getResource(name); - if (img==null) return null; - return new RemoteClassLoader.ResourceFile(new ResourceImageDirect(img), null); // we are on the receiving side, so null is ok + if (img == null) { + return null; + } + return new RemoteClassLoader.ResourceFile( + new ResourceImageDirect(img), null); // we are on the receiving side, so null is ok } @Override @@ -70,7 +75,8 @@ public RemoteClassLoader.ResourceFile[] getResources2(String name) throws IOExce byte[][] r = base.getResources(name); RemoteClassLoader.ResourceFile[] res = new RemoteClassLoader.ResourceFile[r.length]; for (int i = 0; i < res.length; i++) { - res[i] = new RemoteClassLoader.ResourceFile(new ResourceImageDirect(r[i]), null); // we are on the receiving side, so null is ok + res[i] = new RemoteClassLoader.ResourceFile( + new ResourceImageDirect(r[i]), null); // we are on the receiving side, so null is ok } return res; } @@ -79,5 +85,4 @@ public RemoteClassLoader.ResourceFile[] getResources2(String name) throws IOExce public String getName() throws IOException { return base.getName(); } - } diff --git a/src/main/java/hudson/remoting/Engine.java b/src/main/java/hudson/remoting/Engine.java index 4af2efda2..78620b73c 100644 --- a/src/main/java/hudson/remoting/Engine.java +++ b/src/main/java/hudson/remoting/Engine.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -132,6 +132,7 @@ public class Engine extends Thread { */ private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() { private final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); + @Override public Thread newThread(@NonNull final Runnable r) { Thread thread = defaultFactory.newThread(() -> { @@ -139,7 +140,8 @@ public Thread newThread(@NonNull final Runnable r) { r.run(); }); thread.setDaemon(true); - thread.setUncaughtExceptionHandler((t, e) -> LOGGER.log(Level.SEVERE, e, () -> "Uncaught exception in thread " + t)); + thread.setUncaughtExceptionHandler( + (t, e) -> LOGGER.log(Level.SEVERE, e, () -> "Uncaught exception in thread " + t)); return thread; } }); @@ -174,6 +176,7 @@ public Thread newThread(@NonNull final Runnable r) { */ @CheckForNull private URL hudsonUrl; + private final String secretKey; private final String agentName; private boolean webSocket; @@ -205,7 +208,7 @@ public Thread newThread(@NonNull final Runnable r) { * @since 2.62.1 */ private boolean keepAlive = true; - + @CheckForNull private JarCache jarCache = null; @@ -217,14 +220,14 @@ public Thread newThread(@NonNull final Runnable r) { */ @CheckForNull private Path agentLog; - + /** * Specified location of the property file with JUL settings. * @since 3.8 */ @CheckForNull private Path loggingConfigFilePath = null; - + /** * Specifies a default working directory of the remoting instance. * If specified, this directory will be used to store logs, JAR cache, etc. @@ -255,7 +258,8 @@ public Thread newThread(@NonNull final Runnable r) { */ public boolean failIfWorkDirIsMissing = WorkDirManager.DEFAULT_FAIL_IF_WORKDIR_IS_MISSING; - private final DelegatingX509ExtendedTrustManager agentTrustManager = new DelegatingX509ExtendedTrustManager(new BlindTrustX509ExtendedTrustManager()); + private final DelegatingX509ExtendedTrustManager agentTrustManager = + new DelegatingX509ExtendedTrustManager(new BlindTrustX509ExtendedTrustManager()); private final String directConnection; private final String instanceIdentity; @@ -265,17 +269,24 @@ public Engine(EngineListener listener, List hudsonUrls, String secretKey, S this(listener, hudsonUrls, secretKey, agentName, null, null, null); } - public Engine(EngineListener listener, List hudsonUrls, String secretKey, String agentName, String directConnection, String instanceIdentity, - Set protocols) { + public Engine( + EngineListener listener, + List hudsonUrls, + String secretKey, + String agentName, + String directConnection, + String instanceIdentity, + Set protocols) { this.listener = listener; this.directConnection = directConnection; this.events.add(listener); - this.candidateUrls = hudsonUrls.stream().map(Engine::ensureTrailingSlash).collect(Collectors.toList()); + this.candidateUrls = + hudsonUrls.stream().map(Engine::ensureTrailingSlash).collect(Collectors.toList()); this.secretKey = secretKey; this.agentName = agentName; this.instanceIdentity = instanceIdentity; this.protocols = protocols; - if(candidateUrls.isEmpty() && instanceIdentity == null) { + if (candidateUrls.isEmpty() && instanceIdentity == null) { throw new IllegalArgumentException("No URLs given"); } setUncaughtExceptionHandler((t, e) -> { @@ -305,7 +316,7 @@ private static URL ensureTrailingSlash(URL u) { public synchronized void startEngine() throws IOException { startEngine(false); } - + /** * Starts engine. * @param dryRun If {@code true}, do not actually start the engine. @@ -314,7 +325,7 @@ public synchronized void startEngine() throws IOException { /*package*/ void startEngine(boolean dryRun) throws IOException { LOGGER.log(Level.INFO, "Using Remoting version: {0}", Launcher.VERSION); @CheckForNull File jarCacheDirectory = null; - + // Prepare the working directory if required if (workDir != null) { final WorkDirManager workDirManager = WorkDirManager.getInstance(); @@ -322,20 +333,23 @@ public synchronized void startEngine() throws IOException { // Somebody has already specificed Jar Cache, hence we do not need it in the workspace. workDirManager.disable(WorkDirManager.DirType.JAR_CACHE_DIR); } - + if (loggingConfigFilePath != null) { workDirManager.setLoggingConfig(loggingConfigFilePath.toFile()); } - + final Path path = workDirManager.initializeWorkDir(workDir.toFile(), internalDir, failIfWorkDirIsMissing); jarCacheDirectory = workDirManager.getLocation(WorkDirManager.DirType.JAR_CACHE_DIR); workDirManager.setupLogging(path, agentLog); } else if (jarCache == null) { - LOGGER.log(Level.WARNING, "No Working Directory. Using the legacy JAR Cache location: {0}", JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION); + LOGGER.log( + Level.WARNING, + "No Working Directory. Using the legacy JAR Cache location: {0}", + JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION); jarCacheDirectory = JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION; } - - if (jarCache == null){ + + if (jarCache == null) { if (jarCacheDirectory == null) { // Should never happen in the current code throw new IOException("Cannot find the JAR Cache location"); @@ -349,7 +363,7 @@ public synchronized void startEngine() throws IOException { } else { LOGGER.log(Level.INFO, "Using custom JAR Cache: {0}", jarCache); } - + // Start the engine thread if (!dryRun) { this.start(); @@ -365,7 +379,7 @@ public synchronized void startEngine() throws IOException { public void setJarCache(@NonNull JarCache jarCache) { this.jarCache = jarCache; } - + /** * Sets path to the property file with JUL settings. * @param filePath JAR Cache to be used @@ -481,7 +495,9 @@ public void setInternalDir(@NonNull String internalDir) { * @param failIfWorkDirIsMissing Flag * @since 3.8 */ - public void setFailIfWorkDirIsMissing(boolean failIfWorkDirIsMissing) { this.failIfWorkDirIsMissing = failIfWorkDirIsMissing; } + public void setFailIfWorkDirIsMissing(boolean failIfWorkDirIsMissing) { + this.failIfWorkDirIsMissing = failIfWorkDirIsMissing; + } /** * Returns {@code true} if and only if the socket to the controller will have {@link Socket#setKeepAlive(boolean)} set. @@ -502,9 +518,7 @@ public void setKeepAlive(boolean keepAlive) { } public void setCandidateCertificates(List candidateCertificates) { - this.candidateCertificates = candidateCertificates == null - ? null - : new ArrayList<>(candidateCertificates); + this.candidateCertificates = candidateCertificates == null ? null : new ArrayList<>(candidateCertificates); } public void addCandidateCertificate(X509Certificate certificate) { @@ -557,7 +571,8 @@ public void run() { try { kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("Java runtime specification requires support for default key manager", e); + throw new IllegalStateException( + "Java runtime specification requires support for default key manager", e); } try { kmf.init(store, password); @@ -565,7 +580,7 @@ public void run() { throw new IllegalStateException(e); } try { - context.init(kmf.getKeyManagers(), new TrustManager[]{agentTrustManager}, null); + context.init(kmf.getKeyManagers(), new TrustManager[] {agentTrustManager}, null); } catch (KeyManagementException e) { events.error(e); return; @@ -577,7 +592,9 @@ public void run() { } } - @SuppressFBWarnings(value = {"REC_CATCH_EXCEPTION", "URLCONNECTION_SSRF_FD"}, justification = "checked exceptions were a mistake to begin with; connecting to Jenkins from agent") + @SuppressFBWarnings( + value = {"REC_CATCH_EXCEPTION", "URLCONNECTION_SSRF_FD"}, + justification = "checked exceptions were a mistake to begin with; connecting to Jenkins from agent") private void runWebSocket() { try { String localCap = new Capability().toASCII(); @@ -594,11 +611,13 @@ private void runWebSocket() { AtomicReference ch = new AtomicReference<>(); class HeaderHandler extends ClientEndpointConfig.Configurator { Capability remoteCapability = new Capability(); + @Override public void beforeRequest(Map> headers) { headers.putAll(addedHeaders); LOGGER.fine(() -> "Sending: " + headers); } + @Override public void afterResponse(HandshakeResponse hr) { LOGGER.fine(() -> "Receiving: " + hr.getHeaders()); @@ -607,7 +626,8 @@ public void afterResponse(HandshakeResponse hr) { VersionNumber minimumSupportedVersion = new VersionNumber(remotingMinimumVersion.get(0)); VersionNumber currentVersion = new VersionNumber(Launcher.VERSION); if (currentVersion.isOlderThan(minimumSupportedVersion)) { - events.error(new IOException("Agent version " + minimumSupportedVersion + " or newer is required.")); + events.error(new IOException( + "Agent version " + minimumSupportedVersion + " or newer is required.")); } } try { @@ -631,7 +651,9 @@ public void afterResponse(HandshakeResponse hr) { } HeaderHandler headerHandler = new HeaderHandler(); class AgentEndpoint extends Endpoint { - @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "just trust me here") + @SuppressFBWarnings( + value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", + justification = "just trust me here") AgentEndpoint.Transport transport; @Override @@ -640,13 +662,15 @@ public void onOpen(Session session, EndpointConfig config) { session.addMessageHandler(ByteBuffer.class, this::onMessage); try { transport = new Transport(session); - ch.set(new ChannelBuilder(agentName, executor). - withJarCacheOrDefault(jarCache). // unless EngineJnlpConnectionStateListener can be used for this purpose - build(transport)); + ch.set(new ChannelBuilder(agentName, executor) + .withJarCacheOrDefault(jarCache) + . // unless EngineJnlpConnectionStateListener can be used for this purpose + build(transport)); } catch (IOException x) { events.error(x); } } + private void onMessage(ByteBuffer message) { try { transport.receive(message); @@ -657,18 +681,24 @@ private void onMessage(ByteBuffer message) { Thread.currentThread().interrupt(); } } + @Override - @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", - justification = "We want the transport.terminate method to run asynchronously and don't want to wait for its status.") + @SuppressFBWarnings( + value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", + justification = + "We want the transport.terminate method to run asynchronously and don't want to wait for its status.") public void onClose(Session session, CloseReason closeReason) { LOGGER.fine(() -> "onClose: " + closeReason); // making this call async to avoid potential deadlocks when some thread is holding a lock on the // channel object while this thread is trying to acquire it to call Transport#terminate ch.get().executor.submit(() -> transport.terminate(new ChannelClosedException(ch.get(), null))); } + @Override - @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", - justification = "We want the transport.terminate method to run asynchronously and don't want to wait for its status.") + @SuppressFBWarnings( + value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", + justification = + "We want the transport.terminate method to run asynchronously and don't want to wait for its status.") public void onError(Session session, Throwable x) { // TODO or would events.error(x) be better? LOGGER.log(Level.FINE, null, x); @@ -678,15 +708,20 @@ public void onError(Session session, Throwable x) { class Transport extends AbstractByteBufferCommandTransport { final Session session; + Transport(Session session) { super(true); this.session = session; } + @Override protected void write(ByteBuffer headerAndData) throws IOException { - LOGGER.finest(() -> "sending message of length " + (headerAndData.remaining() - ChunkHeader.SIZE)); + LOGGER.finest(() -> + "sending message of length " + (headerAndData.remaining() - ChunkHeader.SIZE)); try { - session.getAsyncRemote().sendBinary(headerAndData).get(5, TimeUnit.MINUTES); + session.getAsyncRemote() + .sendBinary(headerAndData) + .get(5, TimeUnit.MINUTES); } catch (Exception x) { throw new IOException(x); } @@ -696,11 +731,13 @@ protected void write(ByteBuffer headerAndData) throws IOException { public Capability getRemoteCapability() { return headerHandler.remoteCapability; } + @Override public void closeWrite() throws IOException { events.status("Write side closed"); session.close(); } + @Override public void closeRead() throws IOException { events.status("Read side closed"); @@ -716,7 +753,9 @@ public void closeRead() throws IOException { String proxyHost = System.getProperty("http.proxyHost", System.getenv("proxy_host")); String proxyPort = System.getProperty("http.proxyPort"); - if (proxyHost != null && "http".equals(hudsonUrl.getProtocol()) && NoProxyEvaluator.shouldProxy(hudsonUrl.getHost())) { + if (proxyHost != null + && "http".equals(hudsonUrl.getProtocol()) + && NoProxyEvaluator.shouldProxy(hudsonUrl.getHost())) { URI proxyUri; if (proxyPort != null) { proxyUri = URI.create(String.format("http://%s:%s", proxyHost, proxyPort)); @@ -725,7 +764,15 @@ public void closeRead() throws IOException { } client.getProperties().put(ClientProperties.PROXY_URI, proxyUri); if (proxyCredentials != null) { - client.getProperties().put(ClientProperties.PROXY_HEADERS, Map.of("Proxy-Authorization", "Basic " + Base64.getEncoder().encodeToString(proxyCredentials.getBytes(StandardCharsets.UTF_8)))); + client.getProperties() + .put( + ClientProperties.PROXY_HEADERS, + Map.of( + "Proxy-Authorization", + "Basic " + + Base64.getEncoder() + .encodeToString(proxyCredentials.getBytes( + StandardCharsets.UTF_8)))); } } @@ -738,8 +785,12 @@ public void closeRead() throws IOException { client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator); } } - container.connectToServer(new AgentEndpoint(), - ClientEndpointConfig.Builder.create().configurator(headerHandler).build(), URI.create(wsUrl + "wsagents/")); + container.connectToServer( + new AgentEndpoint(), + ClientEndpointConfig.Builder.create() + .configurator(headerHandler) + .build(), + URI.create(wsUrl + "wsagents/")); while (ch.get() == null) { Thread.sleep(100); } @@ -759,7 +810,8 @@ public void closeRead() throws IOException { return; } TimeUnit.SECONDS.sleep(10); - // Unlike JnlpAgentEndpointResolver, we do not use $jenkins/tcpSlaveAgentListener/, as that will be a 404 if the TCP port is disabled. + // Unlike JnlpAgentEndpointResolver, we do not use $jenkins/tcpSlaveAgentListener/, as that will be + // a 404 if the TCP port is disabled. URL ping = new URL(hudsonUrl, "login"); try { HttpURLConnection conn = (HttpURLConnection) ping.openConnection(); @@ -799,11 +851,11 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { .withSSLContext(context) .withPreferNonBlockingIO(false) // we only have one connection, prefer blocking I/O .handlers(); - final Map headers = new HashMap<>(); + final Map headers = new HashMap<>(); headers.put(JnlpConnectionState.CLIENT_NAME_KEY, agentName); headers.put(JnlpConnectionState.SECRET_KEY, secretKey); List jenkinsUrls = new ArrayList<>(); - for (URL url: candidateUrls) { + for (URL url : candidateUrls) { jenkinsUrls.add(url.toExternalForm()); } JnlpEndpointResolver resolver = createEndpointResolver(jenkinsUrls, agentName); @@ -811,12 +863,13 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { try { boolean first = true; firstAttempt = Instant.now(); - while(true) { - if(first) { + while (true) { + if (first) { first = false; } else { - if(noReconnect) + if (noReconnect) { return; // exit + } } if (Util.shouldBailOut(firstAttempt, noReconnectAfter)) { events.status("Bailing out after " + DurationFormatter.format(noReconnectAfter)); @@ -828,12 +881,15 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { endpoint = resolver.resolve(); } catch (IOException e) { if (!noReconnect) { - events.status("Could not locate server among " + candidateUrls + "; waiting 10 seconds before retry", e); + events.status( + "Could not locate server among " + candidateUrls + "; waiting 10 seconds before retry", + e); // TODO refactor various sleep statements into a common method TimeUnit.SECONDS.sleep(10); continue; } else { - if (Boolean.getBoolean(Engine.class.getName() + ".nonFatalJnlpAgentEndpointResolutionExceptions")) { + if (Boolean.getBoolean( + Engine.class.getName() + ".nonFatalJnlpAgentEndpointResolutionExceptions")) { events.status("Could not resolve JNLP agent endpoint", e); } else { events.error(e); @@ -847,14 +903,12 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { } hudsonUrl = endpoint.getServiceUrl(); - events.status(String.format("Agent discovery successful%n" - + " Agent address: %s%n" - + " Agent port: %d%n" - + " Identity: %s", - endpoint.getHost(), - endpoint.getPort(), - KeyUtils.fingerprint(endpoint.getPublicKey())) - ); + events.status(String.format( + "Agent discovery successful%n" + + " Agent address: %s%n" + + " Agent port: %d%n" + + " Identity: %s", + endpoint.getHost(), endpoint.getPort(), KeyUtils.fingerprint(endpoint.getPublicKey()))); PublicKeyMatchingX509ExtendedTrustManager delegate = new PublicKeyMatchingX509ExtendedTrustManager(); RSAPublicKey publicKey = endpoint.getPublicKey(); if (publicKey != null) { @@ -886,14 +940,18 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { triedAtLeastOneProtocol = true; events.status("Trying protocol: " + protocol.getName()); try { - channel = protocol.connect(jnlpSocket, headers, new EngineJnlpConnectionStateListener(endpoint.getPublicKey(), headers)).get(); + channel = protocol.connect( + jnlpSocket, + headers, + new EngineJnlpConnectionStateListener(endpoint.getPublicKey(), headers)) + .get(); } catch (IOException ioe) { events.status("Protocol " + protocol.getName() + " failed to establish channel", ioe); } catch (RuntimeException e) { events.status("Protocol " + protocol.getName() + " encountered a runtime error", e); } catch (Error e) { - events.status("Protocol " + protocol.getName() + " could not be completed due to an error", - e); + events.status( + "Protocol " + protocol.getName() + " could not be completed due to an error", e); } catch (Throwable e) { events.status("Protocol " + protocol.getName() + " encountered an unexpected exception", e); } @@ -932,8 +990,9 @@ private void innerRun(IOHub hub, SSLContext context, ExecutorService service) { } } } - if(noReconnect) + if (noReconnect) { return; // exit + } firstAttempt = Instant.now(); events.onDisconnect(); @@ -956,16 +1015,25 @@ private JnlpEndpointResolver createEndpointResolver(List jenkinsUrls, St } catch (Exception e) { events.error(e); } - resolver = new JnlpAgentEndpointResolver(jenkinsUrls, agentName, credentials, proxyCredentials, tunnel, - sslSocketFactory, disableHttpsCertValidation, noReconnectAfter); + resolver = new JnlpAgentEndpointResolver( + jenkinsUrls, + agentName, + credentials, + proxyCredentials, + tunnel, + sslSocketFactory, + disableHttpsCertValidation, + noReconnectAfter); } else { - resolver = new JnlpAgentEndpointConfigurator(directConnection, instanceIdentity, protocols, proxyCredentials); + resolver = + new JnlpAgentEndpointConfigurator(directConnection, instanceIdentity, protocols, proxyCredentials); } return resolver; } private void onConnectionRejected(String greeting) throws InterruptedException { - events.status("reconnect rejected, sleeping 10s: ", new Exception("The server rejected the connection: " + greeting)); + events.status( + "reconnect rejected, sleeping 10s: ", new Exception("The server rejected the connection: " + greeting)); // TODO refactor various sleep statements into a common method TimeUnit.SECONDS.sleep(10); } @@ -980,18 +1048,19 @@ private Socket connectTcp(@NonNull JnlpAgentEndpoint endpoint) throws IOExceptio String msg = "Connecting to " + endpoint.getHost() + ':' + endpoint.getPort(); events.status(msg); int retry = 1; - while(true) { + while (true) { try { - final Socket s = endpoint.open(SOCKET_TIMEOUT); // default is 30 mins. See PingThread for the ping interval + final Socket s = + endpoint.open(SOCKET_TIMEOUT); // default is 30 mins. See PingThread for the ping interval s.setKeepAlive(keepAlive); return s; } catch (IOException e) { - if(retry++>10) { + if (retry++ > 10) { throw e; } // TODO refactor various sleep statements into a common method TimeUnit.SECONDS.sleep(10); - events.status(msg+" (retrying:"+retry+")",e); + events.status(msg + " (retrying:" + retry + ")", e); } } } @@ -1013,13 +1082,14 @@ public static Engine current() { @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "File path is loaded from system properties.") static KeyStore getCacertsKeyStore() throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException, - NoSuchAlgorithmException, IOException { - Map properties = AccessController.doPrivileged( - (PrivilegedExceptionAction>) () -> { + NoSuchAlgorithmException, IOException { + Map properties = + AccessController.doPrivileged((PrivilegedExceptionAction>) () -> { Map result = new HashMap<>(); result.put("trustStore", System.getProperty("javax.net.ssl.trustStore")); result.put("javaHome", System.getProperty("java.home")); - result.put("trustStoreType", + result.put( + "trustStoreType", System.getProperty("javax.net.ssl.trustStoreType", KeyStore.getDefaultType())); result.put("trustStoreProvider", System.getProperty("javax.net.ssl.trustStoreProvider", "")); result.put("trustStorePasswd", System.getProperty("javax.net.ssl.trustStorePassword", "")); @@ -1037,13 +1107,11 @@ static KeyStore getCacertsKeyStore() trustStoreStream = getFileInputStream(trustStoreFile); } else { String javaHome = properties.get("javaHome"); - trustStoreFile = new File( - javaHome + File.separator + "lib" + File.separator + "security" + File.separator - + "jssecacerts"); + trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + + File.separator + "jssecacerts"); if ((trustStoreStream = getFileInputStream(trustStoreFile)) == null) { - trustStoreFile = new File( - javaHome + File.separator + "lib" + File.separator + "security" + File.separator - + "cacerts"); + trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + + File.separator + "cacerts"); trustStoreStream = getFileInputStream(trustStoreFile); } } @@ -1104,11 +1172,11 @@ private static FileInputStream getFileInputStream(final File file) throws Privil @CheckForNull private static SSLContext getSSLContext(List x509Certificates, boolean noCertificateCheck) throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException, - NoSuchAlgorithmException, IOException, KeyManagementException { + NoSuchAlgorithmException, IOException, KeyManagementException { SSLContext sslContext = null; if (noCertificateCheck) { sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[]{new NoCheckTrustManager()}, new SecureRandom()); + sslContext.init(null, new TrustManager[] {new NoCheckTrustManager()}, new SecureRandom()); } else if (x509Certificates != null && !x509Certificates.isEmpty()) { KeyStore keyStore = getCacertsKeyStore(); // load the keystore @@ -1128,12 +1196,12 @@ private static SSLContext getSSLContext(List x509Certificates, } return sslContext; } - + @CheckForNull @Restricted(NoExternalUse.class) static SSLSocketFactory getSSLSocketFactory(List x509Certificates, boolean noCertificateCheck) throws PrivilegedActionException, KeyStoreException, NoSuchProviderException, CertificateException, - NoSuchAlgorithmException, IOException, KeyManagementException { + NoSuchAlgorithmException, IOException, KeyManagementException { SSLContext sslContext = getSSLContext(x509Certificates, noCertificateCheck); return sslContext != null ? sslContext.getSocketFactory() : null; } @@ -1143,7 +1211,7 @@ static SSLSocketFactory getSSLSocketFactory(List x509Certificat * A {@link SocketInputStream#read()} call associated with underlying Socket will block for only this amount of time * @since 2.4 */ - static final int SOCKET_TIMEOUT = Integer.getInteger(Engine.class.getName()+".socketTimeout",30*60*1000); + static final int SOCKET_TIMEOUT = Integer.getInteger(Engine.class.getName() + ".socketTimeout", 30 * 60 * 1000); /** * Get the agent name associated with this Engine instance. @@ -1183,11 +1251,9 @@ public void beforeProperties(@NonNull JnlpConnectionState event) { if (event instanceof Jnlp4ConnectionState) { X509Certificate certificate = ((Jnlp4ConnectionState) event).getCertificate(); if (certificate != null) { - String fingerprint = KeyUtils - .fingerprint(certificate.getPublicKey()); + String fingerprint = KeyUtils.fingerprint(certificate.getPublicKey()); if (!KeyUtils.equals(publicKey, certificate.getPublicKey())) { - event.reject(new ConnectionRefusalException( - "Expecting identity " + fingerprint)); + event.reject(new ConnectionRefusalException("Expecting identity " + fingerprint)); } events.status("Remote identity confirmed: " + fingerprint); } diff --git a/src/main/java/hudson/remoting/EngineListener.java b/src/main/java/hudson/remoting/EngineListener.java index 95da284cd..32fe34495 100644 --- a/src/main/java/hudson/remoting/EngineListener.java +++ b/src/main/java/hudson/remoting/EngineListener.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -50,7 +50,7 @@ public interface EngineListener { void status(String msg, Throwable t); /** - * Fatal error that's non recoverable. + * Fatal error that's non recoverable. */ void error(Throwable t); diff --git a/src/main/java/hudson/remoting/EngineListenerAdapter.java b/src/main/java/hudson/remoting/EngineListenerAdapter.java index 1a220ea67..5d2468345 100644 --- a/src/main/java/hudson/remoting/EngineListenerAdapter.java +++ b/src/main/java/hudson/remoting/EngineListenerAdapter.java @@ -8,22 +8,17 @@ */ public abstract class EngineListenerAdapter implements EngineListener { @Override - public void status(String msg) { - } + public void status(String msg) {} @Override - public void status(String msg, Throwable t) { - } + public void status(String msg, Throwable t) {} @Override - public void error(Throwable t) { - } + public void error(Throwable t) {} @Override - public void onDisconnect() { - } + public void onDisconnect() {} @Override - public void onReconnect() { - } + public void onReconnect() {} } diff --git a/src/main/java/hudson/remoting/EngineListenerSplitter.java b/src/main/java/hudson/remoting/EngineListenerSplitter.java index face303d3..7555cae90 100644 --- a/src/main/java/hudson/remoting/EngineListenerSplitter.java +++ b/src/main/java/hudson/remoting/EngineListenerSplitter.java @@ -30,7 +30,7 @@ public void status(String msg) { @Override public void status(String msg, Throwable t) { for (EngineListener l : listeners) { - l.status(msg,t); + l.status(msg, t); } } diff --git a/src/main/java/hudson/remoting/ExportTable.java b/src/main/java/hudson/remoting/ExportTable.java index afa9629ee..34a117e42 100644 --- a/src/main/java/hudson/remoting/ExportTable.java +++ b/src/main/java/hudson/remoting/ExportTable.java @@ -47,8 +47,8 @@ * @author Kohsuke Kawaguchi */ final class ExportTable { - private final Map> table = new HashMap<>(); - private final Map> reverse = new HashMap<>(); + private final Map> table = new HashMap<>(); + private final Map> reverse = new HashMap<>(); /** * {@link ExportList}s which are actively recording the current * export operation. @@ -100,8 +100,8 @@ private final class Entry { this.objectType = object.getClass().getName(); this.allocationTrace = EXPORT_TRACES ? new CreatedAt() : null; - table.put(id,this); - reverse.put(object,this); + table.put(id, this); + reverse.put(object, this); } void addRef() { @@ -126,8 +126,9 @@ void pin() { // addRef -> 0x80000000 => BOOM // By making the decision point half way, we give the maximum number of releases away from the pinned // magic value - if (referenceCount<0x20000000) + if (referenceCount < 0x20000000) { referenceCount += 0x40000000; + } } /** @@ -137,7 +138,7 @@ void pin() { * in case it was requested from the other side of the channel. */ void release(@CheckForNull Throwable callSite) { - if(--referenceCount==0) { + if (--referenceCount == 0) { table.remove(id); reverse.remove(object); @@ -146,15 +147,16 @@ void release(@CheckForNull Throwable callSite) { releaseTrace = new ReleasedAt(callSite); } unexportLog.add(this); - while (unexportLog.size() > UNEXPORT_LOG_SIZE) + while (unexportLog.size() > UNEXPORT_LOG_SIZE) { unexportLog.remove(0); + } } } private String interfaceNames() { StringBuilder buf = new StringBuilder(10 + getInterfaces().length * 128); String sep = "["; - for (Class clazz: getInterfaces()) { + for (Class clazz : getInterfaces()) { buf.append(sep).append(clazz.getName()); sep = ", "; } @@ -166,7 +168,9 @@ private String interfaceNames() { * Dumps the contents of the entry. */ void dump(PrintWriter w) throws IOException { - w.printf("#%d (ref.%d) : object=%s type=%s interfaces=%s%n", id, referenceCount, object, objectType, interfaceNames()); + w.printf( + "#%d (ref.%d) : object=%s type=%s interfaces=%s%n", + id, referenceCount, object, objectType, interfaceNames()); if (allocationTrace != null) { allocationTrace.printStackTrace(w); } @@ -180,7 +184,7 @@ String dump() { try (PrintWriter pw = new PrintWriter(sw)) { dump(pw); } catch (IOException e) { - throw new Error(e); // impossible + throw new Error(e); // impossible } return sw.toString(); } @@ -190,15 +194,16 @@ synchronized Class[] getInterfaces() { } synchronized void addInterface(Class clazz) { - for (Class c: interfaces) { - if (c.equals(clazz)) return; + for (Class c : interfaces) { + if (c.equals(clazz)) { + return; + } } - Class[] replacement = new Class[interfaces.length+1]; + Class[] replacement = new Class[interfaces.length + 1]; System.arraycopy(interfaces, 0, replacement, 0, interfaces.length); replacement[interfaces.length] = clazz; interfaces = replacement; } - } static class Source extends Exception { @@ -212,7 +217,6 @@ static class Source extends Exception { Source(@CheckForNull Throwable callSite) { super(callSite); } - } static class CreatedAt extends Source { @@ -222,7 +226,7 @@ static class CreatedAt extends Source { @Override public String toString() { - return " Created at "+new Date(timestamp); + return " Created at " + new Date(timestamp); } } @@ -233,7 +237,7 @@ static class ReleasedAt extends Source { @Override public String toString() { - return " Released at "+new Date(timestamp); + return " Released at " + new Date(timestamp); } } @@ -244,26 +248,32 @@ public String toString() { * The class is not serializable. */ @Restricted(NoExternalUse.class) - @SuppressFBWarnings(value = {"EQ_DOESNT_OVERRIDE_EQUALS", "SE_BAD_FIELD_INNER_CLASS"}, + @SuppressFBWarnings( + value = {"EQ_DOESNT_OVERRIDE_EQUALS", "SE_BAD_FIELD_INNER_CLASS"}, justification = "ExportList is supposed to be serializable as ArrayList, but it is not. " - + "The issue is ignored since the class does not belong to the public API") + + "The issue is ignored since the class does not belong to the public API") public final class ExportList extends ArrayList> { private final ExportList old; + private ExportList() { - old=lists.get(); + old = lists.get(); lists.set(this); } + void release(Throwable callSite) { - synchronized(ExportTable.this) { - for (Entry e : this) + synchronized (ExportTable.this) { + for (Entry e : this) { e.release(callSite); + } } } + void stopRecording() { lists.set(old); } - private static final long serialVersionUID = 1L; // we don't actually serialize this class but just to shutup FindBugs + private static final long serialVersionUID = + 1L; // we don't actually serialize this class but just to shutup FindBugs } /** @@ -284,7 +294,7 @@ ExportList startRecording() { } boolean isRecording() { - return lists.get()!=null; + return lists.get() != null; } /** @@ -302,7 +312,7 @@ boolean isRecording() { * @param t Class instance */ synchronized int export(@NonNull Class clazz, @CheckForNull T t) { - return export(clazz, t,true); + return export(clazz, t, true); } /** @@ -317,7 +327,9 @@ synchronized int export(@NonNull Class clazz, @CheckForNull T t) { * {@code 0} if the input parameter is {@code null}. */ synchronized int export(@NonNull Class clazz, @CheckForNull T t, boolean notifyListener) { - if(t==null) return 0; // bootstrap classloader + if (t == null) { + return 0; // bootstrap classloader + } Entry e = (Entry) reverse.get(t); if (e == null) { @@ -327,9 +339,11 @@ synchronized int export(@NonNull Class clazz, @CheckForNull T t, boolean } e.addRef(); - if(notifyListener) { + if (notifyListener) { ExportList l = lists.get(); - if(l!=null) l.add(e); + if (l != null) { + l.add(e); + } } return e.id; @@ -337,8 +351,9 @@ synchronized int export(@NonNull Class clazz, @CheckForNull T t, boolean /*package*/ synchronized void pin(@NonNull Object t) { Entry e = reverse.get(t); - if(e!=null) + if (e != null) { e.pin(); + } } /** @@ -351,7 +366,9 @@ synchronized int export(@NonNull Class clazz, @CheckForNull T t, boolean @NonNull synchronized Object get(int id) throws ExecutionException { Entry e = table.get(id); - if(e!=null) return e.object; + if (e != null) { + return e.object; + } throw diagnoseInvalidObjectId(id); } @@ -364,7 +381,9 @@ synchronized Object get(int id) throws ExecutionException { @CheckForNull synchronized Object getOrNull(int oid) { Entry e = table.get(oid); - if(e!=null) return e.object; + if (e != null) { + return e.object; + } return null; } @@ -372,7 +391,9 @@ synchronized Object getOrNull(int oid) { @NonNull synchronized Class[] type(int id) throws ExecutionException { Entry e = table.get(id); - if(e!=null) return e.getInterfaces(); + if (e != null) { + return e.getInterfaces(); + } throw diagnoseInvalidObjectId(id); } @@ -396,9 +417,9 @@ void abort(@CheckForNull Throwable e) { for (Entry v : values) { if (v.object instanceof ErrorPropagatingOutputStream) { try { - ((ErrorPropagatingOutputStream)v.object).error(e); + ((ErrorPropagatingOutputStream) v.object).error(e); } catch (Throwable x) { - LOGGER.log(Level.INFO, "Failed to propagate a channel termination error",x); + LOGGER.log(Level.INFO, "Failed to propagate a channel termination error", x); } } } @@ -419,24 +440,25 @@ void abort(@CheckForNull Throwable e) { */ @NonNull private synchronized ExecutionException diagnoseInvalidObjectId(int id) { - Exception cause=null; + Exception cause = null; if (!unexportLog.isEmpty()) { for (Entry e : unexportLog) { - if (e.id==id) { + if (e.id == id) { cause = new Exception("Object was recently deallocated\n" + Util.indent(e.dump()), e.releaseTrace); break; } } - if (cause==null) { - // If there is no cause available, create an artificial cause and use the last unexport entry as an estimated release time if possible + if (cause == null) { + // If there is no cause available, create an artificial cause and use the last unexport entry as an + // estimated release time if possible final ReleasedAt releasedAt = unexportLog.get(0).releaseTrace; final Date releasedBefore = releasedAt != null ? new Date(releasedAt.timestamp) : new Date(); - cause = new Exception("Object appears to be deallocated at lease before "+ releasedBefore); + cause = new Exception("Object appears to be deallocated at lease before " + releasedBefore); } } - return new ExecutionException("Invalid object ID "+id+" iota="+iota, cause); + return new ExecutionException("Invalid object ID " + id + " iota=" + iota, cause); } /** @@ -454,14 +476,21 @@ void unexportByOid(Integer oid) { * @param severeErrorIfMissing Consider missing object as {@link Level#SEVERE} error. {@link Level#FINE} otherwise * @since 2.62 */ - synchronized void unexportByOid(@CheckForNull Integer oid, @CheckForNull Throwable callSite, boolean severeErrorIfMissing) { - if(oid==null) return; + synchronized void unexportByOid( + @CheckForNull Integer oid, @CheckForNull Throwable callSite, boolean severeErrorIfMissing) { + if (oid == null) { + return; + } Entry e = table.get(oid); - if(e==null) { + if (e == null) { Level loggingLevel = severeErrorIfMissing ? Level.SEVERE : Level.FINE; - LOGGER.log(loggingLevel, "Trying to unexport an object that's already unexported", diagnoseInvalidObjectId(oid)); - if (callSite!=null) + LOGGER.log( + loggingLevel, + "Trying to unexport an object that's already unexported", + diagnoseInvalidObjectId(oid)); + if (callSite != null) { LOGGER.log(loggingLevel, "2nd unexport attempt is here", callSite); + } return; } e.release(callSite); @@ -477,7 +506,7 @@ synchronized void dump(@NonNull PrintWriter w) throws IOException { } } - /*package*/ synchronized boolean isExported(Object o) { + /*package*/ synchronized boolean isExported(Object o) { return reverse.containsKey(o); } @@ -485,7 +514,7 @@ synchronized void dump(@NonNull PrintWriter w) throws IOException { * Defines number of entries to be stored in the unexport history. * @since 2.40 */ - public static int UNEXPORT_LOG_SIZE = Integer.getInteger(ExportTable.class.getName()+".unexportLogSize",1024); + public static int UNEXPORT_LOG_SIZE = Integer.getInteger(ExportTable.class.getName() + ".unexportLogSize", 1024); static boolean EXPORT_TRACES = Boolean.getBoolean(ExportTable.class.getName() + ".exportTraces"); diff --git a/src/main/java/hudson/remoting/FastPipedInputStream.java b/src/main/java/hudson/remoting/FastPipedInputStream.java index d764104c7..d36de2b33 100644 --- a/src/main/java/hudson/remoting/FastPipedInputStream.java +++ b/src/main/java/hudson/remoting/FastPipedInputStream.java @@ -44,6 +44,7 @@ public class FastPipedInputStream extends InputStream { * Once closed, this is set to the stack trace of who closed it. */ ClosedBy closed = null; + int readLaps = 0; int readPosition = 0; WeakReference source; @@ -51,7 +52,7 @@ public class FastPipedInputStream extends InputStream { int writePosition = 0; private final Throwable allocatedAt = new Throwable(); - + /** * Creates an unconnected PipedInputStream with a default buffer size. */ @@ -74,7 +75,7 @@ public FastPipedInputStream(FastPipedOutputStream source) throws IOException { * @exception IOException It was already connected. */ public FastPipedInputStream(FastPipedOutputStream source, int bufferSize) throws IOException { - if(source != null) { + if (source != null) { connect(source); } this.buffer = new byte[bufferSize]; @@ -82,7 +83,9 @@ public FastPipedInputStream(FastPipedOutputStream source, int bufferSize) throws private void checkSource() throws IOException { FastPipedOutputStream s = source.get(); - if (s==null) throw new IOException("Writer side has already been abandoned", allocatedAt); + if (s == null) { + throw new IOException("Writer side has already been abandoned", allocatedAt); + } } @Override @@ -91,10 +94,10 @@ public int available() throws IOException { * are located. */ synchronized (buffer) { - return writePosition > readPosition /* The writer is in the same lap. */? writePosition - - readPosition - : (writePosition < readPosition /* The writer is in the next lap. */? buffer.length - - readPosition + 1 + writePosition + return writePosition > readPosition /* The writer is in the same lap. */ + ? writePosition - readPosition + : (writePosition < readPosition /* The writer is in the next lap. */ + ? buffer.length - readPosition + 1 + writePosition : /* The writer is at the same position or a complete lap ahead. */ (writeLaps > readLaps ? buffer.length : 0)); @@ -106,10 +109,10 @@ public int available() throws IOException { */ @Override public void close() throws IOException { - if(source == null) { + if (source == null) { throw new IOException("Unconnected pipe"); } - synchronized(buffer) { + synchronized (buffer) { closed = new ClosedBy(null); // Release any pending writers. buffer.notifyAll(); @@ -120,7 +123,7 @@ public void close() throws IOException { * @exception IOException The pipe is already connected. */ public void connect(FastPipedOutputStream source) throws IOException { - if(this.source != null) { + if (this.source != null) { throw new IOException("Pipe already connected"); } this.source = new WeakReference<>(source); @@ -134,8 +137,7 @@ protected void finalize() throws Throwable { } @Override - public void mark(int readLimit) { - } + public void mark(int readLimit) {} @Override public boolean markSupported() { @@ -158,16 +160,18 @@ public int read(@NonNull byte[] b) throws IOException { */ @Override public int read(@NonNull byte[] b, int off, int len) throws IOException { - if(source == null) { + if (source == null) { throw new IOException("Unconnected pipe"); } while (true) { - synchronized(buffer) { - if(writePosition == readPosition && writeLaps == readLaps) { - if(closed!=null) { + synchronized (buffer) { + if (writePosition == readPosition && writeLaps == readLaps) { + if (closed != null) { Throwable c = closed.getCause(); - if (c==null) return -1; // EOF + if (c == null) { + return -1; // EOF + } throw new IOException(c); } checkSource(); // make sure the sink is still trying to read, or else fail the write. @@ -185,13 +189,12 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { // Don't read more than the capacity indicated by len or what's available // in the circular buffer. - int amount = Math.min(len, (writePosition > readPosition ? writePosition - : buffer.length) - - readPosition); + int amount = + Math.min(len, (writePosition > readPosition ? writePosition : buffer.length) - readPosition); System.arraycopy(buffer, readPosition, b, off, amount); readPosition += amount; - if(readPosition == buffer.length) {// A lap was completed, so go back. + if (readPosition == buffer.length) { // A lap was completed, so go back. readPosition = 0; ++readLaps; } diff --git a/src/main/java/hudson/remoting/FastPipedOutputStream.java b/src/main/java/hudson/remoting/FastPipedOutputStream.java index 824e16405..9c9150182 100644 --- a/src/main/java/hudson/remoting/FastPipedOutputStream.java +++ b/src/main/java/hudson/remoting/FastPipedOutputStream.java @@ -74,7 +74,9 @@ public FastPipedOutputStream(FastPipedInputStream sink, int bufferSize) throws I private FastPipedInputStream sink() throws IOException { FastPipedInputStream s = sink.get(); - if (s==null) throw new IOException("Reader side has already been abandoned", allocatedAt); + if (s == null) { + throw new IOException("Reader side has already been abandoned", allocatedAt); + } return s; } @@ -88,12 +90,12 @@ public void close() throws IOException { @Override public void error(Throwable e) throws IOException { - if(sink == null) { + if (sink == null) { throw new IOException("Unconnected pipe"); } FastPipedInputStream s = sink(); - synchronized(s.buffer) { - if (s.closed==null) { + synchronized (s.buffer) { + if (s.closed == null) { s.closed = new FastPipedInputStream.ClosedBy(e); flush(); } @@ -104,7 +106,7 @@ public void error(Throwable e) throws IOException { * @exception IOException The pipe is already connected. */ public void connect(FastPipedInputStream sink) throws IOException { - if(this.sink != null) { + if (this.sink != null) { throw new IOException("Pipe already connected"); } this.sink = new WeakReference<>(sink); @@ -120,7 +122,7 @@ protected void finalize() throws Throwable { @Override public void flush() throws IOException { FastPipedInputStream s = sink(); - synchronized(s.buffer) { + synchronized (s.buffer) { // Release all readers. s.buffer.notifyAll(); } @@ -128,7 +130,7 @@ public void flush() throws IOException { @Override public void write(int b) throws IOException { - write(new byte[] { (byte) b }); + write(new byte[] {(byte) b}); } @Override @@ -141,19 +143,19 @@ public void write(@NonNull byte[] b) throws IOException { */ @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { - if(sink == null) { + if (sink == null) { throw new IOException("Unconnected pipe"); } - while (len>0) { + while (len > 0) { FastPipedInputStream s = sink(); // make sure the sink is still trying to read, or else fail the write. - if(s.closed!=null) { + if (s.closed != null) { throw new IOException("Pipe is already closed", s.closed); } - synchronized(s.buffer) { - if(s.writePosition == s.readPosition && s.writeLaps > s.readLaps) { + synchronized (s.buffer) { + if (s.writePosition == s.readPosition && s.writeLaps > s.readLaps) { // The circular buffer is full, so wait for some reader to consume // something. @@ -163,11 +165,11 @@ public void write(@NonNull byte[] b, int off, int len) throws IOException { Thread t = Thread.currentThread(); String oldName = t.getName(); - t.setName("Blocking to write "+HexDump.toHex(b,off,Math.min(len,256))+": "+oldName); + t.setName("Blocking to write " + HexDump.toHex(b, off, Math.min(len, 256)) + ": " + oldName); try { buf.wait(TIMEOUT); } catch (InterruptedException e) { - throw (InterruptedIOException)new InterruptedIOException(e.getMessage()).initCause(e); + throw (InterruptedIOException) new InterruptedIOException(e.getMessage()).initCause(e); } finally { t.setName(oldName); } @@ -177,13 +179,12 @@ public void write(@NonNull byte[] b, int off, int len) throws IOException { // Don't write more than the capacity indicated by len or the space // available in the circular buffer. - int amount = Math.min(len, (s.writePosition < s.readPosition ? s.readPosition - : s.buffer.length) - - s.writePosition); + int amount = Math.min( + len, (s.writePosition < s.readPosition ? s.readPosition : s.buffer.length) - s.writePosition); System.arraycopy(b, off, s.buffer, s.writePosition, amount); s.writePosition += amount; - if(s.writePosition == s.buffer.length) { + if (s.writePosition == s.buffer.length) { s.writePosition = 0; ++s.writeLaps; } @@ -196,5 +197,5 @@ public void write(@NonNull byte[] b, int off, int len) throws IOException { } } - static final int TIMEOUT = Integer.getInteger(FastPipedOutputStream.class.getName()+".timeout",10*1000); + static final int TIMEOUT = Integer.getInteger(FastPipedOutputStream.class.getName() + ".timeout", 10 * 1000); } diff --git a/src/main/java/hudson/remoting/FileSystemJarCache.java b/src/main/java/hudson/remoting/FileSystemJarCache.java index 3b28be306..2d733081f 100644 --- a/src/main/java/hudson/remoting/FileSystemJarCache.java +++ b/src/main/java/hudson/remoting/FileSystemJarCache.java @@ -40,9 +40,9 @@ public class FileSystemJarCache extends JarCacheSupport { @GuardedBy("itself") private final Map checksumsByPath = new HashMap<>(); - //TODO: Create new IOException constructor + // TODO: Create new IOException constructor /** - * @param rootDir + * @param rootDir * Root directory. * @param touch * True to touch the cached jar file that's used. This enables external LRU based cache @@ -53,8 +53,9 @@ public class FileSystemJarCache extends JarCacheSupport { public FileSystemJarCache(@NonNull File rootDir, boolean touch) { this.rootDir = rootDir; this.touch = touch; - if (rootDir==null) + if (rootDir == null) { throw new IllegalArgumentException("Root directory is null"); + } try { Files.createDirectories(rootDir.toPath()); @@ -67,17 +68,17 @@ public FileSystemJarCache(@NonNull File rootDir, boolean touch) { public String toString() { return String.format("FileSystem JAR Cache: path=%s, touch=%s", rootDir, touch); } - + @Override protected URL lookInCache(Channel channel, long sum1, long sum2) throws IOException, InterruptedException { File jar = map(sum1, sum2); if (jar.exists()) { - LOGGER.log(Level.FINER, () -> String.format("Jar file cache hit %16X%16X",sum1,sum2)); - if (touch) { + LOGGER.log(Level.FINER, () -> String.format("Jar file cache hit %16X%16X", sum1, sum2)); + if (touch) { Files.setLastModifiedTime(PathUtils.fileToPath(jar), FileTime.fromMillis(System.currentTimeMillis())); } - if (notified.add(new Checksum(sum1,sum2))) { - getJarLoader(channel).notifyJarPresence(sum1,sum2); + if (notified.add(new Checksum(sum1, sum2))) { + getJarLoader(channel).notifyJarPresence(sum1, sum2); } return jar.toURI().toURL(); } @@ -85,7 +86,9 @@ protected URL lookInCache(Channel channel, long sum1, long sum2) throws IOExcept } @Override - @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "The file path is a generated value based on server supplied data.") + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "The file path is a generated value based on server supplied data.") protected URL retrieve(Channel channel, long sum1, long sum2) throws IOException, InterruptedException { Checksum expected = new Checksum(sum1, sum2); File target = map(sum1, sum2); @@ -99,8 +102,7 @@ protected URL retrieve(Channel channel, long sum1, long sum2) throws IOException LOGGER.warning(String.format( "Cached file checksum mismatch: %s%nExpected: %s%n Actual: %s", - target.getAbsolutePath(), expected, actual - )); + target.getAbsolutePath(), expected, actual)); Files.delete(PathUtils.fileToPath(target)); synchronized (checksumsByPath) { checksumsByPath.remove(target.getCanonicalPath()); @@ -145,7 +147,7 @@ protected URL retrieve(Channel channel, long sum1, long sum2) throws IOException Files.deleteIfExists(PathUtils.fileToPath(tmp)); } } catch (IOException e) { - throw new IOException("Failed to write to "+target, e); + throw new IOException("Failed to write to " + target, e); } } @@ -160,7 +162,9 @@ private Checksum fileChecksum(File file) throws IOException { // until calculated to be picked up from cache right away. synchronized (checksumsByPath) { Checksum checksum = checksumsByPath.get(location); - if (checksum != null) return checksum; + if (checksum != null) { + return checksum; + } checksum = Checksum.forFile(file); checksumsByPath.put(location, checksum); @@ -168,7 +172,9 @@ private Checksum fileChecksum(File file) throws IOException { } } - @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "This path exists within a temp directory so the potential traversal is limited.") + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "This path exists within a temp directory so the potential traversal is limited.") /*package for testing*/ File createTempJar(@NonNull File target) throws IOException { File parent = target.getParentFile(); Files.createDirectories(parent.toPath()); @@ -179,9 +185,9 @@ private Checksum fileChecksum(File file) throws IOException { * Map to the cache jar file name. */ File map(long sum1, long sum2) { - return new File(rootDir,String.format("%02X/%014X%016X.jar", - (int)(sum1>>>(64-8)), - sum1&0x00FFFFFFFFFFFFFFL, sum2)); + return new File( + rootDir, + String.format("%02X/%014X%016X.jar", (int) (sum1 >>> (64 - 8)), sum1 & 0x00FFFFFFFFFFFFFFL, sum2)); } private static final Logger LOGGER = Logger.getLogger(FileSystemJarCache.class.getName()); diff --git a/src/main/java/hudson/remoting/FlightRecorderInputStream.java b/src/main/java/hudson/remoting/FlightRecorderInputStream.java index 845ae848b..9e2dcaa3f 100644 --- a/src/main/java/hudson/remoting/FlightRecorderInputStream.java +++ b/src/main/java/hudson/remoting/FlightRecorderInputStream.java @@ -22,7 +22,8 @@ class FlightRecorderInputStream extends InputStream { * Size (in bytes) of the flight recorder ring buffer used for debugging remoting issues. * @since 2.41 */ - static final int BUFFER_SIZE = Integer.getInteger("hudson.remoting.FlightRecorderInputStream.BUFFER_SIZE", 1024 * 1024); + static final int BUFFER_SIZE = + Integer.getInteger("hudson.remoting.FlightRecorderInputStream.BUFFER_SIZE", 1024 * 1024); private final InputStream source; private ByteArrayRingBuffer recorder = new ByteArrayRingBuffer(BUFFER_SIZE); @@ -53,13 +54,14 @@ public DiagnosedStreamCorruptionException analyzeCrash(Exception problem, String final ByteArrayOutputStream readAhead = new ByteArrayOutputStream(); final IOException[] error = new IOException[1]; - Thread diagnosisThread = new Thread(diagnosisName+" stream corruption diagnosis thread") { + Thread diagnosisThread = new Thread(diagnosisName + " stream corruption diagnosis thread") { @Override public void run() { int b; try { - // not all InputStream will look for the thread interrupt flag, so check that explicitly to be defensive - while (!Thread.interrupted() && (b=source.read())!=-1) { + // not all InputStream will look for the thread interrupt flag, so check that explicitly to be + // defensive + while (!Thread.interrupted() && (b = source.read()) != -1) { readAhead.write(b); } } catch (IOException e) { @@ -81,26 +83,28 @@ public void run() { } IOException diagnosisProblem = error[0]; // capture the error, if any, before we kill the thread - if (diagnosisThread.isAlive()) - diagnosisThread.interrupt(); // if it's not dead, kill - - return new DiagnosedStreamCorruptionException(problem,diagnosisProblem,getRecord(),readAhead.toByteArray()); + if (diagnosisThread.isAlive()) { + diagnosisThread.interrupt(); // if it's not dead, kill + } + return new DiagnosedStreamCorruptionException(problem, diagnosisProblem, getRecord(), readAhead.toByteArray()); } @Override public int read() throws IOException { int i = source.read(); - if (i>=0) + if (i >= 0) { recorder.write(i); + } return i; } @Override public int read(@NonNull byte[] b, int off, int len) throws IOException { len = source.read(b, off, len); - if (len>0) - recorder.write(b,off,len); + if (len > 0) { + recorder.write(b, off, len); + } return len; } @@ -109,8 +113,8 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { */ @Override public long skip(long n) throws IOException { - byte[] buf = new byte[(int)Math.min(n,64*1024)]; - return read(buf,0,buf.length); + byte[] buf = new byte[(int) Math.min(n, 64 * 1024)]; + return read(buf, 0, buf.length); } @Override @@ -160,9 +164,10 @@ public synchronized byte[] toByteArray() { System.arraycopy(data, 0, ret, capacity - pos, pos); return ret; } - + /** @author @roadrunner2 */ - @Override public synchronized void write(@NonNull byte[] buf, int off, int len) { + @Override + public synchronized void write(@NonNull byte[] buf, int off, int len) { // no point in trying to copy more than capacity; this also simplifies logic below if (len > capacity) { off += (len - capacity); @@ -190,7 +195,5 @@ public synchronized byte[] toByteArray() { pos += len; } } - } - } diff --git a/src/main/java/hudson/remoting/Future.java b/src/main/java/hudson/remoting/Future.java index bc535ad16..f59b3ae7a 100644 --- a/src/main/java/hudson/remoting/Future.java +++ b/src/main/java/hudson/remoting/Future.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,17 +25,17 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -//TODO: This Future should be actually deprecated, because it may confuse API users +// TODO: This Future should be actually deprecated, because it may confuse API users /** * Alias to {@link Future}. * *

    * This alias is defined so that retro-translation won't affect * the publicly committed signature of the API. - * + * * @author Kohsuke Kawaguchi */ -@SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_INTERFACE", +@SuppressFBWarnings( + value = "NM_SAME_SIMPLE_NAME_AS_INTERFACE", justification = "This class is just an alias, but this alias is a part of public API") -public interface Future extends java.util.concurrent.Future { -} +public interface Future extends java.util.concurrent.Future {} diff --git a/src/main/java/hudson/remoting/FutureAdapter.java b/src/main/java/hudson/remoting/FutureAdapter.java index 851c5f275..4c5a334dd 100644 --- a/src/main/java/hudson/remoting/FutureAdapter.java +++ b/src/main/java/hudson/remoting/FutureAdapter.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,7 +33,7 @@ * * @author Kohsuke Kawaguchi */ -abstract class FutureAdapter implements Future { +abstract class FutureAdapter implements Future { protected final Future core; protected FutureAdapter(Future core) { @@ -61,7 +61,8 @@ public X get() throws InterruptedException, ExecutionException { } @Override - public X get(long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public X get(long timeout, @NonNull TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { return adapt(core.get(timeout, unit)); } diff --git a/src/main/java/hudson/remoting/HexDump.java b/src/main/java/hudson/remoting/HexDump.java index bf5c9a3a3..2a30aa5a0 100644 --- a/src/main/java/hudson/remoting/HexDump.java +++ b/src/main/java/hudson/remoting/HexDump.java @@ -7,13 +7,14 @@ public class HexDump { private static final String CODE = "0123456789abcdef"; public static String toHex(byte[] buf) { - return toHex(buf,0,buf.length); + return toHex(buf, 0, buf.length); } + public static String toHex(byte[] buf, int start, int len) { - StringBuilder r = new StringBuilder(len*2); + StringBuilder r = new StringBuilder(len * 2); boolean inText = false; - for (int i=0; i= 0x20 && b <= 0x7e) { if (!inText) { inText = true; @@ -26,8 +27,8 @@ public static String toHex(byte[] buf, int start, int len) { inText = false; } r.append("0x"); - r.append(CODE.charAt((b>>4)&15)); - r.append(CODE.charAt(b&15)); + r.append(CODE.charAt((b >> 4) & 15)); + r.append(CODE.charAt(b & 15)); if (i < len - 1) { if (b == 10) { r.append('\n'); diff --git a/src/main/java/hudson/remoting/IChannel.java b/src/main/java/hudson/remoting/IChannel.java index 24d6291fc..0737ec21a 100644 --- a/src/main/java/hudson/remoting/IChannel.java +++ b/src/main/java/hudson/remoting/IChannel.java @@ -33,5 +33,6 @@ */ interface IChannel { Object getProperty(Object key); + Object waitForProperty(Object key) throws InterruptedException; } diff --git a/src/main/java/hudson/remoting/IReadResolve.java b/src/main/java/hudson/remoting/IReadResolve.java index c7d87696f..886f704b3 100644 --- a/src/main/java/hudson/remoting/IReadResolve.java +++ b/src/main/java/hudson/remoting/IReadResolve.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/hudson/remoting/ImportedClassLoaderTable.java b/src/main/java/hudson/remoting/ImportedClassLoaderTable.java index 18353a092..374b082d3 100644 --- a/src/main/java/hudson/remoting/ImportedClassLoaderTable.java +++ b/src/main/java/hudson/remoting/ImportedClassLoaderTable.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -49,7 +49,8 @@ final class ImportedClassLoaderTable { */ @NonNull public ClassLoader get(int oid) { - return get(RemoteInvocationHandler.wrap(channel, oid, RemoteClassLoader.IClassLoader.class, false, false, false, false)); + return get(RemoteInvocationHandler.wrap( + channel, oid, RemoteClassLoader.IClassLoader.class, false, false, false, false)); } /** @@ -61,6 +62,7 @@ public ClassLoader get(int oid) { @NonNull public ClassLoader get(@NonNull RemoteClassLoader.IClassLoader classLoaderProxy) { // we need to be able to use the same hudson.remoting classes, hence delegate to this class loader. - return classLoaders.computeIfAbsent(classLoaderProxy, proxy -> RemoteClassLoader.create(channel.baseClassLoader, proxy)); + return classLoaders.computeIfAbsent( + classLoaderProxy, proxy -> RemoteClassLoader.create(channel.baseClassLoader, proxy)); } } diff --git a/src/main/java/hudson/remoting/InitializeJarCacheMain.java b/src/main/java/hudson/remoting/InitializeJarCacheMain.java index f3283d71b..0393633aa 100644 --- a/src/main/java/hudson/remoting/InitializeJarCacheMain.java +++ b/src/main/java/hudson/remoting/InitializeJarCacheMain.java @@ -27,12 +27,14 @@ public class InitializeJarCacheMain { *

  • The jar cache directory. * */ - @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "These file values are provided by users with sufficient administrative permissions to run this utility program.") + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = + "These file values are provided by users with sufficient administrative permissions to run this utility program.") public static void main(String[] argv) throws Exception { if (argv.length != 2) { - throw new IllegalArgumentException( - "Usage: java -cp agent.jar hudson.remoting.InitializeJarCacheMain " + - " "); + throw new IllegalArgumentException("Usage: java -cp agent.jar hudson.remoting.InitializeJarCacheMain " + + " "); } File sourceJarDir = new File(argv[0]); diff --git a/src/main/java/hudson/remoting/InterceptingExecutorService.java b/src/main/java/hudson/remoting/InterceptingExecutorService.java index 415cfb9e5..fbb2292f6 100644 --- a/src/main/java/hudson/remoting/InterceptingExecutorService.java +++ b/src/main/java/hudson/remoting/InterceptingExecutorService.java @@ -46,7 +46,7 @@ public Future submit(@NonNull Runnable task) { @Override @NonNull public Future submit(@NonNull Runnable task, T result) { - return super.submit(wrap(task,result)); + return super.submit(wrap(task, result)); } @Override @@ -57,18 +57,22 @@ public List> invokeAll(@NonNull Collection> @Override @NonNull - public List> invokeAll(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException { + public List> invokeAll( + @NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) + throws InterruptedException { return super.invokeAll(wrap(tasks), timeout, unit); } @Override @NonNull - public T invokeAny(@NonNull Collection> tasks) throws InterruptedException, ExecutionException { + public T invokeAny(@NonNull Collection> tasks) + throws InterruptedException, ExecutionException { return super.invokeAny(wrap(tasks)); } @Override - public T invokeAny(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public T invokeAny(@NonNull Collection> tasks, long timeout, @NonNull TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { return super.invokeAny(wrap(tasks), timeout, unit); } diff --git a/src/main/java/hudson/remoting/JarCache.java b/src/main/java/hudson/remoting/JarCache.java index 8180da876..3ddd6ce42 100644 --- a/src/main/java/hudson/remoting/JarCache.java +++ b/src/main/java/hudson/remoting/JarCache.java @@ -25,9 +25,9 @@ public abstract class JarCache { * Default JAR cache location for disabled workspace Manager. */ public static final File DEFAULT_NOWS_JAR_CACHE_LOCATION = - new File(System.getProperty("user.home"),".jenkins/cache/jars"); + new File(System.getProperty("user.home"), ".jenkins/cache/jars"); - //TODO: replace by checked exception + // TODO: replace by checked exception /** * Gets a default value for {@link FileSystemJarCache} to be initialized on agents. * @return Created JAR Cache @@ -55,5 +55,6 @@ public abstract class JarCache { * URL of the jar file. */ @NonNull - public abstract CompletableFuture resolve(@NonNull Channel channel, long sum1, long sum2) throws IOException, InterruptedException; + public abstract CompletableFuture resolve(@NonNull Channel channel, long sum1, long sum2) + throws IOException, InterruptedException; } diff --git a/src/main/java/hudson/remoting/JarCacheSupport.java b/src/main/java/hudson/remoting/JarCacheSupport.java index 01685d071..479fed4c3 100644 --- a/src/main/java/hudson/remoting/JarCacheSupport.java +++ b/src/main/java/hudson/remoting/JarCacheSupport.java @@ -25,7 +25,7 @@ public abstract class JarCacheSupport extends JarCache { /** * Remember in-progress jar file resolution to avoid retrieving the same jar file twice. */ - private final ConcurrentMap> inprogress = new ConcurrentHashMap<>(); + private final ConcurrentMap> inprogress = new ConcurrentHashMap<>(); /** * Look up the local cache and return URL if found. @@ -44,8 +44,7 @@ public abstract class JarCacheSupport extends JarCache { * Throttle the jar downloading activity so that it won't eat up all the channel bandwidth. */ private final ExecutorService downloader = newCachingSingleThreadExecutor( - new NamingThreadFactory(new DaemonThreadFactory(), JarCacheSupport.class.getSimpleName()) - ); + new NamingThreadFactory(new DaemonThreadFactory(), JarCacheSupport.class.getSimpleName())); private static ExecutorService newCachingSingleThreadExecutor(ThreadFactory threadFactory) { ThreadPoolExecutor threadPoolExecutor = @@ -56,9 +55,10 @@ private static ExecutorService newCachingSingleThreadExecutor(ThreadFactory thre @Override @NonNull - public CompletableFuture resolve(@NonNull final Channel channel, final long sum1, final long sum2) throws IOException, InterruptedException { - URL jar = lookInCache(channel,sum1, sum2); - if (jar!=null) { + public CompletableFuture resolve(@NonNull final Channel channel, final long sum1, final long sum2) + throws IOException, InterruptedException { + URL jar = lookInCache(channel, sum1, sum2); + if (jar != null) { // already in the cache return CompletableFuture.completedFuture(jar); } @@ -74,9 +74,9 @@ private CompletableFuture submitDownload(Channel channel, long sum1, long s downloader.submit(new DownloadRunnable(channel, sum1, sum2, key, promise)); return promise; } - + private class DownloadRunnable implements Runnable { - + final Channel channel; final long sum1; final long sum2; @@ -90,7 +90,7 @@ public DownloadRunnable(Channel channel, long sum1, long sum2, Checksum key, Com this.key = key; this.promise = promise; } - + @Override public void run() { try { @@ -98,7 +98,8 @@ public void run() { if (inprogress.remove(key, promise)) { promise.complete(url); } else { - promise.completeExceptionally(new IllegalStateException("Download is (unexpectedly) no longer in progress")); + promise.completeExceptionally( + new IllegalStateException("Download is (unexpectedly) no longer in progress")); } } catch (ChannelClosedException | RequestAbortedException e) { // the connection was killed while we were still resolving the file @@ -125,19 +126,19 @@ public void run() { * Report a failure of the retrieval and allows another thread to retry. */ private void bailout(Throwable e) { - inprogress.remove(key, promise); // this lets another thread to retry later - promise.completeExceptionally(e); // then tell those who are waiting that we aborted + inprogress.remove(key, promise); // this lets another thread to retry later + promise.completeExceptionally(e); // then tell those who are waiting that we aborted } } protected JarLoader getJarLoader(Channel channel) throws InterruptedException { JarLoader jl = channel.getProperty(JarLoader.THEIRS); - if (jl==null) {// even if two threads run this simultaneously, it is harmless + if (jl == null) { // even if two threads run this simultaneously, it is harmless jl = (JarLoader) channel.waitForRemoteProperty(JarLoader.OURS); - channel.setProperty(JarLoader.THEIRS,jl); + channel.setProperty(JarLoader.THEIRS, jl); } return jl; } - + private static final Logger LOGGER = Logger.getLogger(JarCacheSupport.class.getName()); } diff --git a/src/main/java/hudson/remoting/JarLoader.java b/src/main/java/hudson/remoting/JarLoader.java index dcf42263d..15ad9a758 100644 --- a/src/main/java/hudson/remoting/JarLoader.java +++ b/src/main/java/hudson/remoting/JarLoader.java @@ -52,6 +52,6 @@ public interface JarLoader { */ boolean isPresentOnRemote(Checksum sum); - String OURS = JarLoader.class.getName()+".ours"; + String OURS = JarLoader.class.getName() + ".ours"; ChannelProperty THEIRS = new ChannelProperty<>(JarLoader.class, "their JarLoader"); } diff --git a/src/main/java/hudson/remoting/JarLoaderImpl.java b/src/main/java/hudson/remoting/JarLoaderImpl.java index 1ed8f3c8c..f1fc0c866 100644 --- a/src/main/java/hudson/remoting/JarLoaderImpl.java +++ b/src/main/java/hudson/remoting/JarLoaderImpl.java @@ -25,19 +25,22 @@ class JarLoaderImpl implements JarLoader, SerializableOnlyOverRemoting { private static final Logger LOGGER = Logger.getLogger(JarLoaderImpl.class.getName()); - private final ConcurrentMap knownJars = new ConcurrentHashMap<>(); + private final ConcurrentMap knownJars = new ConcurrentHashMap<>(); - private final ConcurrentMap checksums = new ConcurrentHashMap<>(); + private final ConcurrentMap checksums = new ConcurrentHashMap<>(); private final Set presentOnRemote = Collections.synchronizedSet(new HashSet<>()); @Override - @SuppressFBWarnings(value = {"URLCONNECTION_SSRF_FD", "PATH_TRAVERSAL_IN"}, justification = "This is only used for managing the jar cache as files, not URLs.") + @SuppressFBWarnings( + value = {"URLCONNECTION_SSRF_FD", "PATH_TRAVERSAL_IN"}, + justification = "This is only used for managing the jar cache as files, not URLs.") public void writeJarTo(long sum1, long sum2, OutputStream sink) throws IOException, InterruptedException { Checksum k = new Checksum(sum1, sum2); URL url = knownJars.get(k); - if (url==null) - throw new IOException("Unadvertised jar file "+k); + if (url == null) { + throw new IOException("Unadvertised jar file " + k); + } Channel channel = Channel.current(); if (channel != null) { @@ -68,14 +71,15 @@ public boolean isPresentOnRemote(Checksum sum) { @Override public void notifyJarPresence(long sum1, long sum2) { - presentOnRemote.add(new Checksum(sum1,sum2)); + presentOnRemote.add(new Checksum(sum1, sum2)); } @Override public void notifyJarPresence(long[] sums) { synchronized (presentOnRemote) { - for (int i=0; i candidateCertificates; private List x509Certificates; @@ -221,7 +242,11 @@ public void setAuth(String auth) { * Disables HTTPs Certificate validation of the server when using {@link JnlpAgentEndpointResolver}. * This option is managed by the {@code -noCertificateCheck} option. */ - @Option(name="-noCertificateCheck", aliases = "-disableHttpsCertValidation", forbids = "-cert", usage="Ignore SSL validation errors - use as a last resort only.") + @Option( + name = "-noCertificateCheck", + aliases = "-disableHttpsCertValidation", + forbids = "-cert", + usage = "Ignore SSL validation errors - use as a last resort only.") public boolean noCertificateCheck = false; private HostnameVerifier hostnameVerifier; @@ -236,26 +261,35 @@ public void setAuth(String auth) { * @deprecated removed without replacement */ @Deprecated - @Option(name="-connectTo",usage="(deprecated) make a TCP connection to the given host and port, then start communication.",metaVar="HOST:PORT") + @Option( + name = "-connectTo", + usage = "(deprecated) make a TCP connection to the given host and port, then start communication.", + metaVar = "HOST:PORT") public void setConnectTo(String target) { String[] tokens = target.split(":"); - if(tokens.length!=2) { - System.err.println("Illegal parameter: "+target); + if (tokens.length != 2) { + System.err.println("Illegal parameter: " + target); System.exit(1); } - connectionTarget = new InetSocketAddress(tokens[0],Integer.parseInt(tokens[1])); + connectionTarget = new InetSocketAddress(tokens[0], Integer.parseInt(tokens[1])); System.err.println( "WARNING: The \"-connectTo\" argument is deprecated and will be removed without replacement in a future release."); } - @Option(name="-noReconnect",aliases="-noreconnect",usage="Doesn't try to reconnect when a communication fail, and exit instead") + @Option( + name = "-noReconnect", + aliases = "-noreconnect", + usage = "Doesn't try to reconnect when a communication fail, and exit instead") public boolean noReconnect = false; - @Option(name="-noReconnectAfter",usage = "Bail out after the given time after the first attempt to reconnect", handler = DurationOptionHandler.class, forbids = "-noReconnect") + @Option( + name = "-noReconnectAfter", + usage = "Bail out after the given time after the first attempt to reconnect", + handler = DurationOptionHandler.class, + forbids = "-noReconnect") public Duration noReconnectAfter; - @Option(name = "-noKeepAlive", - usage = "Disable TCP socket keep alive on connection to the controller.") + @Option(name = "-noKeepAlive", usage = "Disable TCP socket keep alive on connection to the controller.") public boolean noKeepAlive = false; /** @@ -267,7 +301,8 @@ public void setConnectTo(String target) { * Jenkins specifics: This working directory is expected to be equal to the agent root specified in Jenkins configuration. * @since 3.8 */ - @Option(name = "-workDir", + @Option( + name = "-workDir", usage = "Declares the working directory of the remoting instance (stores cache and logs by default)") @CheckForNull public File workDir = null; @@ -279,7 +314,8 @@ public void setConnectTo(String target) { * storage directory if the default {@code remoting} directory is consumed by other stuff. * @since 3.8 */ - @Option(name = "-internalDir", + @Option( + name = "-internalDir", usage = "Specifies a name of the internal files within a working directory ('remoting' by default)", depends = "-workDir") @NonNull @@ -291,12 +327,14 @@ public void setConnectTo(String target) { * (e.g. if a filesystem mount gets disconnected). * @since 3.8 */ - @Option(name = "-failIfWorkDirIsMissing", + @Option( + name = "-failIfWorkDirIsMissing", usage = "Fails the initialization if the requested workDir or internalDir are missing ('false' by default)", depends = "-workDir") public boolean failIfWorkDirIsMissing = WorkDirManager.DEFAULT_FAIL_IF_WORKDIR_IS_MISSING; - - @Option(name = "-tunnel", + + @Option( + name = "-tunnel", metaVar = "HOST:PORT", usage = "Connect to the specified host and port, instead of connecting directly to Jenkins. " + "Useful when connection to Jenkins needs to be tunneled. Can be also HOST: or :PORT, " @@ -323,19 +361,17 @@ public void setHeadlessMode(boolean headlessMode) { @Option(name = "-url", usage = "Specify the Jenkins root URLs to connect to.") public List urls = new ArrayList<>(); - @Option(name = "-webSocket", + @Option( + name = "-webSocket", usage = "Make a WebSocket connection to Jenkins rather than using the TCP port.", depends = "-url", - forbids = { - "-direct", - "-tunnel", - "-credentials", - "-noKeepAlive" - }) + forbids = {"-direct", "-tunnel", "-credentials", "-noKeepAlive"}) public boolean webSocket; - @Option(name = "-webSocketHeader", - usage = "Additional WebSocket header to set, eg for authenticating with reverse proxies. To specify multiple headers, call this flag multiple times, one with each header", + @Option( + name = "-webSocketHeader", + usage = + "Additional WebSocket header to set, eg for authenticating with reverse proxies. To specify multiple headers, call this flag multiple times, one with each header", metaVar = "NAME=VALUE", depends = "-webSocket") public Map webSocketHeaders; @@ -344,12 +380,14 @@ public void setHeadlessMode(boolean headlessMode) { * Connect directly to the TCP port specified, skipping the HTTP(S) connection parameter download. * @since 3.34 */ - @Option(name = "-direct", + @Option( + name = "-direct", metaVar = "HOST:PORT", aliases = "-directConnection", depends = "-instanceIdentity", forbids = {"-jnlpUrl", "-url", "-tunnel"}, - usage = "Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download. For example, \"myjenkins:50000\".") + usage = + "Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download. For example, \"myjenkins:50000\".") public String directConnection; /** @@ -357,9 +395,11 @@ public void setHeadlessMode(boolean headlessMode) { * @see Instance Identity * @since 3.34 */ - @Option(name = "-instanceIdentity", + @Option( + name = "-instanceIdentity", depends = "-direct", - usage = "The base64 encoded InstanceIdentity byte array of the Jenkins controller. When this is set, the agent skips connecting to an HTTP(S) port for connection info.") + usage = + "The base64 encoded InstanceIdentity byte array of the Jenkins controller. When this is set, the agent skips connecting to an HTTP(S) port for connection info.") public String instanceIdentity; /** @@ -368,7 +408,8 @@ public void setHeadlessMode(boolean headlessMode) { * it knows. Use this to limit the protocol list. * @since 3.34 */ - @Option(name = "-protocols", + @Option( + name = "-protocols", depends = {"-direct"}, usage = "Specify the remoting protocols to attempt when instanceIdentity is provided.") public List protocols = new ArrayList<>(); @@ -377,14 +418,14 @@ public void setHeadlessMode(boolean headlessMode) { * Shows help message and then exits * @since 3.36 */ - @Option(name="-help",usage="Show this help message") + @Option(name = "-help", usage = "Show this help message") public boolean showHelp = false; /** * Shows version information and then exits * @since 3.36 */ - @Option(name="-version",usage="Shows the version of the remoting jar and then exits") + @Option(name = "-version", usage = "Shows the version of the remoting jar and then exits") public boolean showVersion = false; /** @@ -420,11 +461,13 @@ public static void main(String... args) throws IOException, InterruptedException } } - @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "log file, just like console output, should be in platform default encoding") + @SuppressFBWarnings( + value = "DM_DEFAULT_ENCODING", + justification = "log file, just like console output, should be in platform default encoding") public void run() throws CmdLineException, IOException, InterruptedException { if (showVersion) { String version = Util.getVersion(); - if(version != null) { + if (version != null) { System.out.println(version); } return; @@ -456,9 +499,11 @@ private synchronized void initialize() throws IOException { throw new IllegalStateException("double initialization"); } // Create and verify working directory and logging - // TODO: The pass-through for the JNLP mode has been added in JENKINS-39817. But we still need to keep this parameter in + // TODO: The pass-through for the JNLP mode has been added in JENKINS-39817. But we still need to keep this + // parameter in // consideration for other modes (TcpServer, TcpClient, etc.) to retain the legacy behavior. - // On the other hand, in such case there is no need to invoke WorkDirManager and handle the double initialization logic + // On the other hand, in such case there is no need to invoke WorkDirManager and handle the double + // initialization logic final WorkDirManager workDirManager = WorkDirManager.getInstance(); final Path internalDirPath = workDirManager.initializeWorkDir(workDir, internalDir, failIfWorkDirIsMissing); if (agentLog != null) { @@ -506,25 +551,30 @@ private void createX509Certificates() { // larger // than 64kb we can revisit the upper bound. cert = new byte[(int) length]; - int read = fis.read(cert); - if (cert.length != read) { - LOGGER.log(Level.WARNING, "Only read {0} bytes from {1}, expected to read {2}", - new Object[]{read, file, cert.length}); - // skip it - continue; - } + int read = fis.read(cert); + if (cert.length != read) { + LOGGER.log( + Level.WARNING, + "Only read {0} bytes from {1}, expected to read {2}", + new Object[] {read, file, cert.length}); + // skip it + continue; + } } catch (IOException e) { LOGGER.log(Level.WARNING, e, () -> "Could not read certificate from " + file); continue; } } else { if (file.isFile()) { - LOGGER.log(Level.WARNING, - "Could not read certificate from {0}. File size is not within " + - "the expected range for a PEM encoded X.509 certificate", + LOGGER.log( + Level.WARNING, + "Could not read certificate from {0}. File size is not within " + + "the expected range for a PEM encoded X.509 certificate", file.getAbsolutePath()); } else { - LOGGER.log(Level.WARNING, "Could not read certificate from {0}. File not found", + LOGGER.log( + Level.WARNING, + "Could not read certificate from {0}. File not found", file.getAbsolutePath()); } continue; @@ -678,8 +728,11 @@ private void runAsInboundAgent() throws CmdLineException, IOException, Interrupt /** * Parses the connection arguments from JNLP file given in the URL. */ - @SuppressFBWarnings(value = {"CIPHER_INTEGRITY", "STATIC_IV"}, justification = "Integrity not needed here. IV used for decryption only, loaded from encryptor.") - private List parseJnlpArguments() throws ParserConfigurationException, SAXException, IOException, InterruptedException { + @SuppressFBWarnings( + value = {"CIPHER_INTEGRITY", "STATIC_IV"}, + justification = "Integrity not needed here. IV used for decryption only, loaded from encryptor.") + private List parseJnlpArguments() + throws ParserConfigurationException, SAXException, IOException, InterruptedException { initialize(); if (secret != null) { agentJnlpURL = new URL(agentJnlpURL + "?encrypt=true"); @@ -691,21 +744,25 @@ private List parseJnlpArguments() throws ParserConfigurationException, S while (true) { URLConnection con = null; try { - con = JnlpAgentEndpointResolver.openURLConnection(agentJnlpURL, null, agentJnlpCredentials, proxyCredentials, sslSocketFactory, hostnameVerifier); + con = JnlpAgentEndpointResolver.openURLConnection( + agentJnlpURL, null, agentJnlpCredentials, proxyCredentials, sslSocketFactory, hostnameVerifier); con.connect(); if (con instanceof HttpURLConnection) { HttpURLConnection http = (HttpURLConnection) con; - if(http.getResponseCode()>=400) + if (http.getResponseCode() >= 400) { // got the error code. report that (such as 401) - throw new IOException("Failed to load "+ agentJnlpURL +": "+http.getResponseCode()+" "+http.getResponseMessage()); + throw new IOException("Failed to load " + agentJnlpURL + ": " + http.getResponseCode() + " " + + http.getResponseMessage()); + } } Document dom; // check if this URL points to a .jnlp file String contentType = con.getHeaderField("Content-Type"); - String expectedContentType = secret == null ? "application/x-java-jnlp-file" : "application/octet-stream"; + String expectedContentType = + secret == null ? "application/x-java-jnlp-file" : "application/octet-stream"; InputStream input = con.getInputStream(); if (secret != null) { byte[] payload = input.readAllBytes(); @@ -713,21 +770,25 @@ private List parseJnlpArguments() throws ParserConfigurationException, S try { Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, - new SecretKeySpec(fromHexString(secret.substring(0, Math.min(secret.length(), 32))), "AES"), - new IvParameterSpec(payload,0,16)); - byte[] decrypted = cipher.doFinal(payload,16,payload.length-16); + cipher.init( + Cipher.DECRYPT_MODE, + new SecretKeySpec( + fromHexString(secret.substring(0, Math.min(secret.length(), 32))), "AES"), + new IvParameterSpec(payload, 0, 16)); + byte[] decrypted = cipher.doFinal(payload, 16, payload.length - 16); input = new ByteArrayInputStream(decrypted); } catch (GeneralSecurityException x) { throw new IOException("Failed to decrypt the JNLP file. Invalid secret key?", x); } } - if(contentType==null || !contentType.startsWith(expectedContentType)) { - // load DOM anyway, but if it fails to parse, that's probably because this is not an XML file to begin with. + if (contentType == null || !contentType.startsWith(expectedContentType)) { + // load DOM anyway, but if it fails to parse, that's probably because this is not an XML file to + // begin with. try { dom = loadDom(input); } catch (SAXException | IOException e) { - throw new IOException(agentJnlpURL +" doesn't look like a JNLP file; content type was "+contentType); + throw new IOException( + agentJnlpURL + " doesn't look like a JNLP file; content type was " + contentType); } } else { dom = loadDom(input); @@ -736,22 +797,29 @@ private List parseJnlpArguments() throws ParserConfigurationException, S // exec into the JNLP launcher, to fetch the connection parameter through JNLP. NodeList argElements = dom.getElementsByTagName("argument"); List jnlpArgs = new ArrayList<>(); - for( int i=0; i parseJnlpArguments() throws ParserConfigurationException, S // from hudson.Util private static byte[] fromHexString(String data) { byte[] r = new byte[data.length() / 2]; - for (int i = 0; i < data.length(); i += 2) + for (int i = 0; i < data.length(); i += 2) { r[i / 2] = (byte) Integer.parseInt(data.substring(i, i + 2), 16); + } return r; } @@ -786,15 +855,18 @@ static Document loadDom(InputStream is) throws ParserConfigurationException, SAX * then accepts one TCP connection. */ @Deprecated - @SuppressFBWarnings(value = {"UNENCRYPTED_SERVER_SOCKET", "DM_DEFAULT_ENCODING", "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "This is an old, insecure mechanism that should be removed. port number file should be in platform default encoding. Laucher instance is created only once.") + @SuppressFBWarnings( + value = {"UNENCRYPTED_SERVER_SOCKET", "DM_DEFAULT_ENCODING", "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, + justification = + "This is an old, insecure mechanism that should be removed. port number file should be in platform default encoding. Laucher instance is created only once.") private void runAsTcpServer() throws IOException, InterruptedException { // accept just one connection and that's it. // when we are done, remove the port file to avoid stale port file Socket s; - try (ServerSocket ss = new ServerSocket(0,1)) { + try (ServerSocket ss = new ServerSocket(0, 1)) { // if no one connects for too long, assume something went wrong // and avoid hanging forever - ss.setSoTimeout(30*1000); + ss.setSoTimeout(30 * 1000); // write a port file to report the port number try (FileWriter w = new FileWriter(tcpPortFile)) { @@ -819,56 +891,64 @@ private void runOnSocket(Socket s) throws IOException, InterruptedException { s.setKeepAlive(true); // we take care of buffering on our own s.setTcpNoDelay(true); - main(new BufferedInputStream(SocketChannelStream.in(s)), - new BufferedOutputStream(SocketChannelStream.out(s)), mode,ping, - jarCache != null ? new FileSystemJarCache(jarCache,true) : null); + main( + new BufferedInputStream(SocketChannelStream.in(s)), + new BufferedOutputStream(SocketChannelStream.out(s)), + mode, + ping, + jarCache != null ? new FileSystemJarCache(jarCache, true) : null); } /** * Connects to the given TCP port and then start running */ - @SuppressFBWarnings(value = {"UNENCRYPTED_SOCKET", "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "This implements an old, insecure connection mechanism. Laucher instance is created only once.") + @SuppressFBWarnings( + value = {"UNENCRYPTED_SOCKET", "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, + justification = + "This implements an old, insecure connection mechanism. Laucher instance is created only once.") @Deprecated private void runAsTcpClient() throws IOException, InterruptedException { // if no one connects for too long, assume something went wrong // and avoid hanging forever - Socket s = new Socket(connectionTarget.getAddress(),connectionTarget.getPort()); + Socket s = new Socket(connectionTarget.getAddress(), connectionTarget.getPort()); Launcher.communicationProtocolName = "TCP (remote: client)"; runOnSocket(s); } - @SuppressFBWarnings(value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", "DMI_RANDOM_USED_ONLY_ONCE"}, justification = "Laucher instance is created only once.") + @SuppressFBWarnings( + value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", "DMI_RANDOM_USED_ONLY_ONCE"}, + justification = "Laucher instance is created only once.") private void runWithStdinStdout() throws IOException, InterruptedException { // use stdin/stdout for channel communication ttyCheck(); if (isWindows()) { /* - To prevent the dead lock between GetFileType from _ioinit in C runtime and blocking read that ChannelReaderThread - would do on stdin, load the crypto DLL first. - - This is a band-aid solution to the problem. Still searching for more fundamental fix. - - 02f1e750 7c90d99a ntdll!KiFastSystemCallRet - 02f1e754 7c810f63 ntdll!NtQueryVolumeInformationFile+0xc - 02f1e784 77c2c9f9 kernel32!GetFileType+0x7e - 02f1e7e8 77c1f01d msvcrt!_ioinit+0x19f - 02f1e88c 7c90118a msvcrt!__CRTDLL_INIT+0xac - 02f1e8ac 7c91c4fa ntdll!LdrpCallInitRoutine+0x14 - 02f1e9b4 7c916371 ntdll!LdrpRunInitializeRoutines+0x344 - 02f1ec60 7c9164d3 ntdll!LdrpLoadDll+0x3e5 - 02f1ef08 7c801bbd ntdll!LdrLoadDll+0x230 - 02f1ef70 7c801d72 kernel32!LoadLibraryExW+0x18e - 02f1ef84 7c801da8 kernel32!LoadLibraryExA+0x1f - 02f1efa0 77de8830 kernel32!LoadLibraryA+0x94 - 02f1f05c 6d3eb1be ADVAPI32!CryptAcquireContextA+0x512 - WARNING: Stack unwind information not available. Following frames may be wrong. - 02f1f13c 6d99c844 java_6d3e0000!Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed+0x6e - - see http://weblogs.java.net/blog/kohsuke/archive/2009/09/28/reading-stdin-may-cause-your-jvm-hang - for more details - */ + To prevent the dead lock between GetFileType from _ioinit in C runtime and blocking read that ChannelReaderThread + would do on stdin, load the crypto DLL first. + + This is a band-aid solution to the problem. Still searching for more fundamental fix. + + 02f1e750 7c90d99a ntdll!KiFastSystemCallRet + 02f1e754 7c810f63 ntdll!NtQueryVolumeInformationFile+0xc + 02f1e784 77c2c9f9 kernel32!GetFileType+0x7e + 02f1e7e8 77c1f01d msvcrt!_ioinit+0x19f + 02f1e88c 7c90118a msvcrt!__CRTDLL_INIT+0xac + 02f1e8ac 7c91c4fa ntdll!LdrpCallInitRoutine+0x14 + 02f1e9b4 7c916371 ntdll!LdrpRunInitializeRoutines+0x344 + 02f1ec60 7c9164d3 ntdll!LdrpLoadDll+0x3e5 + 02f1ef08 7c801bbd ntdll!LdrLoadDll+0x230 + 02f1ef70 7c801d72 kernel32!LoadLibraryExW+0x18e + 02f1ef84 7c801da8 kernel32!LoadLibraryExA+0x1f + 02f1efa0 77de8830 kernel32!LoadLibraryA+0x94 + 02f1f05c 6d3eb1be ADVAPI32!CryptAcquireContextA+0x512 + WARNING: Stack unwind information not available. Following frames may be wrong. + 02f1f13c 6d99c844 java_6d3e0000!Java_sun_security_provider_NativeSeedGenerator_nativeGenerateSeed+0x6e + + see http://weblogs.java.net/blog/kohsuke/archive/2009/09/28/reading-stdin-may-cause-your-jvm-hang + for more details + */ new SecureRandom().nextBoolean(); } @@ -880,7 +960,7 @@ private void runWithStdinStdout() throws IOException, InterruptedException { Launcher.communicationProtocolName = "Standard in/out"; // System.in/out appear to be already buffered (at least that was the case in Linux and Windows as of Java6) // so we are not going to double-buffer these. - main(System.in, os, mode, ping, jarCache != null ? new FileSystemJarCache(jarCache,true) : null); + main(System.in, os, mode, ping, jarCache != null ? new FileSystemJarCache(jarCache, true) : null); } /** @@ -889,13 +969,12 @@ private void runWithStdinStdout() throws IOException, InterruptedException { */ private static void ttyCheck() { final Console console = System.console(); - if(console != null) { + if (console != null) { // we seem to be running from interactive console. issue a warning. // but since this diagnosis could be wrong, go on and do what we normally do anyway. Don't exit. - System.out.println( - "WARNING: Are you running agent from an interactive console?\n" + - "If so, you are probably using it incorrectly.\n" + - "See https://wiki.jenkins.io/display/JENKINS/Launching+agent+from+console"); + System.out.println("WARNING: Are you running agent from an interactive console?\n" + + "If so, you are probably using it incorrectly.\n" + + "See https://wiki.jenkins.io/display/JENKINS/Launching+agent+from+console"); } } @@ -903,8 +982,9 @@ public static void main(InputStream is, OutputStream os) throws IOException, Int main(is, os, Channel.Mode.BINARY); } - public static void main(InputStream is, OutputStream os, Channel.Mode mode) throws IOException, InterruptedException { - main(is,os,mode,false); + public static void main(InputStream is, OutputStream os, Channel.Mode mode) + throws IOException, InterruptedException { + main(is, os, mode, false); } /** @@ -912,7 +992,8 @@ public static void main(InputStream is, OutputStream os, Channel.Mode mode) thro * Use {@link #main(InputStream, OutputStream, Channel.Mode, boolean, JarCache)} */ @Deprecated - public static void main(InputStream is, OutputStream os, Channel.Mode mode, boolean performPing) throws IOException, InterruptedException { + public static void main(InputStream is, OutputStream os, Channel.Mode mode, boolean performPing) + throws IOException, InterruptedException { main(is, os, mode, performPing, null); } /** @@ -921,26 +1002,33 @@ public static void main(InputStream is, OutputStream os, Channel.Mode mode, bool * If {@code null}, a default value will be used. * @since 2.24 */ - public static void main(InputStream is, OutputStream os, Channel.Mode mode, boolean performPing, @CheckForNull JarCache cache) throws IOException, InterruptedException { + public static void main( + InputStream is, OutputStream os, Channel.Mode mode, boolean performPing, @CheckForNull JarCache cache) + throws IOException, InterruptedException { ExecutorService executor = Executors.newCachedThreadPool(); - ChannelBuilder cb = new ChannelBuilder("channel", executor) - .withMode(mode) - .withJarCacheOrDefault(cache); + ChannelBuilder cb = + new ChannelBuilder("channel", executor).withMode(mode).withJarCacheOrDefault(cache); // expose StandardOutputStream as a channel property, which is a better way to make this available // to the user of Channel than Channel#getUnderlyingOutput() - if (os instanceof StandardOutputStream) - cb.withProperty(StandardOutputStream.class,os); + if (os instanceof StandardOutputStream) { + cb.withProperty(StandardOutputStream.class, os); + } Channel channel = cb.build(is, os); System.err.println("channel started"); // Both settings are available since remoting-2.0 - long timeout = 1000 * Long.parseLong( - System.getProperty("hudson.remoting.Launcher.pingTimeoutSec", "240")), - interval = 1000 * Long.parseLong( - System.getProperty("hudson.remoting.Launcher.pingIntervalSec", /* was "600" but this duplicates ChannelPinger */ "0")); - Logger.getLogger(PingThread.class.getName()).log(Level.FINE, "performPing={0} timeout={1} interval={2}", new Object[] {performPing, timeout, interval}); + long timeout = 1000 * Long.parseLong(System.getProperty("hudson.remoting.Launcher.pingTimeoutSec", "240")), + interval = + 1000 + * Long.parseLong(System.getProperty( + "hudson.remoting.Launcher.pingIntervalSec", /* was "600" but this duplicates ChannelPinger */ + "0")); + Logger.getLogger(PingThread.class.getName()) + .log(Level.FINE, "performPing={0} timeout={1} interval={2}", new Object[] { + performPing, timeout, interval + }); if (performPing && timeout > 0 && interval > 0) { new PingThread(channel, timeout, interval) { @Deprecated @@ -949,8 +1037,11 @@ protected void onDead() { System.err.println("Ping failed. Terminating"); System.exit(-1); } + @Override - @SuppressFBWarnings(value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", justification = "Prints the agent-side message to the agent log before exiting.") + @SuppressFBWarnings( + value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", + justification = "Prints the agent-side message to the agent log before exiting.") protected void onDead(Throwable cause) { System.err.println("Ping failed. Terminating"); cause.printStackTrace(); @@ -964,7 +1055,7 @@ protected void onDead(Throwable cause) { } public static boolean isWindows() { - return File.pathSeparatorChar==';'; + return File.pathSeparatorChar == ';'; } /** @@ -983,7 +1074,9 @@ private static String computeVersion() { Properties props = new Properties(); InputStream is = Launcher.class.getResourceAsStream(JENKINS_VERSION_PROP_FILE); if (is == null) { - LOGGER.log(Level.FINE, "Cannot locate the {0} resource file. Hudson/Jenkins version is unknown", + LOGGER.log( + Level.FINE, + "Cannot locate the {0} resource file. Hudson/Jenkins version is unknown", JENKINS_VERSION_PROP_FILE); return UNKNOWN_JENKINS_VERSION_STR; } @@ -1010,13 +1103,7 @@ private static void closeWithLogOnly(Closeable stream, String name) { private Engine createEngine() throws IOException { LOGGER.log(Level.INFO, "Setting up agent: {0}", name); Engine engine = new Engine( - new CuiListener(), - urls, - secret, - name, - directConnection, - instanceIdentity, - new HashSet<>(protocols)); + new CuiListener(), urls, secret, name, directConnection, instanceIdentity, new HashSet<>(protocols)); engine.setWebSocket(webSocket); if (webSocketHeaders != null) { engine.setWebSocketHeaders(webSocketHeaders); diff --git a/src/main/java/hudson/remoting/LocalChannel.java b/src/main/java/hudson/remoting/LocalChannel.java index 496368c10..263c86b03 100644 --- a/src/main/java/hudson/remoting/LocalChannel.java +++ b/src/main/java/hudson/remoting/LocalChannel.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -31,7 +31,7 @@ /** * {@link VirtualChannel} that performs computation on the local JVM. - * + * * @author Kohsuke Kawaguchi */ public class LocalChannel implements VirtualChannel { @@ -42,12 +42,12 @@ public LocalChannel(ExecutorService executor) { } @Override - public V call(Callable callable) throws T { + public V call(Callable callable) throws T { return callable.call(); } @Override - public Future callAsync(@NonNull final Callable callable) { + public Future callAsync(@NonNull final Callable callable) { final java.util.concurrent.Future f = executor.submit(() -> { try { return callable.call(); @@ -80,7 +80,8 @@ public V get() throws InterruptedException, ExecutionException { } @Override - public V get(long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public V get(long timeout, @NonNull TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { return f.get(timeout, unit); } }; diff --git a/src/main/java/hudson/remoting/MimicException.java b/src/main/java/hudson/remoting/MimicException.java index 07440b83a..5bdd92203 100644 --- a/src/main/java/hudson/remoting/MimicException.java +++ b/src/main/java/hudson/remoting/MimicException.java @@ -19,13 +19,15 @@ @Restricted(DoNotUse.class) class MimicException extends Exception { private final String className; + MimicException(Throwable cause) { super(cause.getMessage()); className = cause.getClass().getName(); setStackTrace(cause.getStackTrace()); - if (cause.getCause()!=null) + if (cause.getCause() != null) { initCause(new MimicException(cause.getCause())); + } } @Override @@ -37,13 +39,16 @@ public String toString() { @Nullable public static Throwable make(@NonNull Channel ch, @Nullable Throwable cause) { - if (cause == null) return null; + if (cause == null) { + return null; + } // make sure the remoting layer of the other end supports this - if (ch.remoteCapability.hasMimicException()) + if (ch.remoteCapability.hasMimicException()) { return new MimicException(cause); - else + } else { return cause; + } } private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/remoting/MultiClassLoaderSerializer.java b/src/main/java/hudson/remoting/MultiClassLoaderSerializer.java index 9ddea740d..fd609b7a4 100644 --- a/src/main/java/hudson/remoting/MultiClassLoaderSerializer.java +++ b/src/main/java/hudson/remoting/MultiClassLoaderSerializer.java @@ -34,7 +34,7 @@ static final class Output extends ObjectOutputStream { /** * Encountered Classloaders, to their indices. */ - private final Map classLoaders = new HashMap<>(); + private final Map classLoaders = new HashMap<>(); Output(Channel channel, OutputStream out) throws IOException { super(out); @@ -45,17 +45,17 @@ static final class Output extends ObjectOutputStream { protected void annotateClass(Class c) throws IOException { AnonymousClassWarnings.check(c); ClassLoader cl = c.getClassLoader(); - if (cl==null) {// bootstrap classloader. no need to export. + if (cl == null) { // bootstrap classloader. no need to export. writeInt(TAG_SYSTEMCLASSLOADER); return; } Integer idx = classLoaders.get(cl); - if (idx==null) { - classLoaders.put(cl,classLoaders.size()); + if (idx == null) { + classLoaders.put(cl, classLoaders.size()); if (cl instanceof RemoteClassLoader) { int oid = ((RemoteClassLoader) cl).getOid(channel); - if (oid>=0) { + if (oid >= 0) { // this classloader came from where we are sending this classloader to. writeInt(TAG_LOCAL_CLASSLOADER); writeInt(oid); @@ -64,10 +64,11 @@ protected void annotateClass(Class c) throws IOException { } // tell the receiving side that they need to import a new classloader - // this reference count is released when RemoteInvocationHandler backing RemoteClassLoader.IClassLoader is GCed on the remote node. + // this reference count is released when RemoteInvocationHandler backing RemoteClassLoader.IClassLoader + // is GCed on the remote node. writeInt(TAG_EXPORTED_CLASSLOADER); - writeInt(RemoteClassLoader.exportId(cl,channel)); - } else {// reference to a classloader that's already written + writeInt(RemoteClassLoader.exportId(cl, channel)); + } else { // reference to a classloader that's already written writeInt(idx); } } @@ -95,28 +96,30 @@ private ClassLoader readClassLoader() throws IOException, ClassNotFoundException ClassLoader cl; int code = readInt(); switch (code) { - case TAG_SYSTEMCLASSLOADER: - return null; - - case TAG_LOCAL_CLASSLOADER: - Object proxyObject; - int oid = readInt(); - try { - proxyObject = channel.getExportedObject(oid); - } catch (ExecutionException ex) { - throw new IOException("Cannot locate RemoteClassLoader.ClassLoaderProxy(" + - oid + ") in the channel exported table", ex); - } - cl = ((RemoteClassLoader.ClassLoaderProxy)proxyObject).cl; - classLoaders.add(cl); - return cl; - - case TAG_EXPORTED_CLASSLOADER: - cl = channel.importedClassLoaders.get(readInt()); - classLoaders.add(cl); - return cl; - default: - return classLoaders.get(code); + case TAG_SYSTEMCLASSLOADER: + return null; + + case TAG_LOCAL_CLASSLOADER: + Object proxyObject; + int oid = readInt(); + try { + proxyObject = channel.getExportedObject(oid); + } catch (ExecutionException ex) { + throw new IOException( + "Cannot locate RemoteClassLoader.ClassLoaderProxy(" + oid + + ") in the channel exported table", + ex); + } + cl = ((RemoteClassLoader.ClassLoaderProxy) proxyObject).cl; + classLoaders.add(cl); + return cl; + + case TAG_EXPORTED_CLASSLOADER: + cl = channel.importedClassLoaders.get(readInt()); + classLoaders.add(cl); + return cl; + default: + return classLoaders.get(code); } } @@ -140,9 +143,10 @@ protected Class resolveProxyClass(String[] interfaces) throws IOException, Cl ClassLoader cl = readClassLoader(); Class[] classes = new Class[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) + for (int i = 0; i < interfaces.length; i++) { // TODO: handle null classloader as a System one? classes[i] = Class.forName(interfaces[i], false, cl); + } /* dead lock prevention. @@ -162,15 +166,16 @@ protected Class resolveProxyClass(String[] interfaces) throws IOException, Cl So this is somewhat hack-ish, but in this change we look for a specific proxy type that we use and resolve them outside Proxy.getProxyClass. */ - if (classes.length==2 && classes[0]==JarLoader.class && classes[1]==IReadResolve.class) + if (classes.length == 2 && classes[0] == JarLoader.class && classes[1] == IReadResolve.class) { return Channel.jarLoaderProxy; + } return Proxy.getProxyClass(cl, classes); } @Override protected Object resolveObject(Object obj) throws IOException { - if(obj instanceof URL){ + if (obj instanceof URL) { // SECURITY-637, URL deserialization could lead to DNS query return URLDeserializationHelper.wrapIfRequired((URL) obj); } diff --git a/src/main/java/hudson/remoting/NoProxyEvaluator.java b/src/main/java/hudson/remoting/NoProxyEvaluator.java index 9d267d88c..5edd26f1d 100644 --- a/src/main/java/hudson/remoting/NoProxyEvaluator.java +++ b/src/main/java/hudson/remoting/NoProxyEvaluator.java @@ -92,16 +92,15 @@ private static String getEnvironmentValue() { } private boolean matchesIpAddress(InetAddress hostAddress) { - return noProxyIpAddresses.stream(). - anyMatch(inetAddress -> inetAddress.equals(hostAddress)); + return noProxyIpAddresses.stream().anyMatch(inetAddress -> inetAddress.equals(hostAddress)); } private void processSpecificationsIntoTypes(String noProxySpecification) { noProxySpecification = noProxySpecification.trim(); String[] noProxySpecifications = splitComponents(noProxySpecification); - for (String specification : noProxySpecifications){ + for (String specification : noProxySpecifications) { specification = stripLeadingStarDot(stripLeadingDot(specification.trim())); - if (specification.isEmpty() ) { + if (specification.isEmpty()) { continue; } if (isIpAddress(specification)) { @@ -149,12 +148,10 @@ private boolean matchesSubnet(String host) { } private boolean matchesDomainHost(String host) { - return noProxyDomainsHosts.stream(). - anyMatch(host::endsWith); + return noProxyDomainsHosts.stream().anyMatch(host::endsWith); } private boolean isIpAddress(String host) { return InetAddressValidator.getInstance().isValid(host); } - } diff --git a/src/main/java/hudson/remoting/ObjectInputStreamEx.java b/src/main/java/hudson/remoting/ObjectInputStreamEx.java index 4a0070cf6..e1d4ef482 100644 --- a/src/main/java/hudson/remoting/ObjectInputStreamEx.java +++ b/src/main/java/hudson/remoting/ObjectInputStreamEx.java @@ -43,7 +43,7 @@ public class ObjectInputStreamEx extends ObjectInputStream { */ @Deprecated public ObjectInputStreamEx(InputStream in, ClassLoader cl) throws IOException { - this(in,cl,ClassFilter.DEFAULT); + this(in, cl, ClassFilter.DEFAULT); } public ObjectInputStreamEx(InputStream in, ClassLoader cl, ClassFilter filter) throws IOException { @@ -78,8 +78,7 @@ protected Class resolveProxyClass(String[] interfaces) throws IOException, Cl if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { if (hasNonPublicInterface) { if (nonPublicLoader != cl.getClassLoader()) { - throw new IllegalAccessError( - "conflicting non-public interface class loaders"); + throw new IllegalAccessError("conflicting non-public interface class loaders"); } } else { nonPublicLoader = cl.getClassLoader(); @@ -89,9 +88,7 @@ protected Class resolveProxyClass(String[] interfaces) throws IOException, Cl classObjs[i] = cl; } try { - return Proxy.getProxyClass( - hasNonPublicInterface ? nonPublicLoader : latestLoader, - classObjs); + return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader : latestLoader, classObjs); } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } @@ -99,7 +96,7 @@ protected Class resolveProxyClass(String[] interfaces) throws IOException, Cl @Override protected Object resolveObject(Object obj) throws IOException { - if(obj instanceof URL){ + if (obj instanceof URL) { // SECURITY-637, URL deserialization could lead to DNS query return URLDeserializationHelper.wrapIfRequired((URL) obj); } diff --git a/src/main/java/hudson/remoting/PingThread.java b/src/main/java/hudson/remoting/PingThread.java index b5373694c..08008588a 100644 --- a/src/main/java/hudson/remoting/PingThread.java +++ b/src/main/java/hudson/remoting/PingThread.java @@ -59,7 +59,7 @@ public abstract class PingThread extends Thread { private final long interval; public PingThread(Channel channel, long timeout, long interval) { - super("Ping thread for channel "+channel); + super("Ping thread for channel " + channel); this.channel = channel; this.timeout = timeout; this.interval = interval; @@ -81,24 +81,24 @@ public PingThread(Channel channel) { @Override public void run() { try { - while(true) { + while (true) { long nextCheck = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(interval); ping(); // wait until the next check long diff; - while((diff = nextCheck - System.nanoTime()) > 0) { + while ((diff = nextCheck - System.nanoTime()) > 0) { TimeUnit.NANOSECONDS.sleep(diff); } } } catch (ChannelClosedException e) { - LOGGER.fine(getName()+" is closed. Terminating"); + LOGGER.fine(getName() + " is closed. Terminating"); } catch (IOException e) { onDead(e); } catch (InterruptedException e) { // use interruption as a way to terminate the ping thread. - LOGGER.fine(getName()+" is interrupted. Terminating"); + LOGGER.fine(getName() + " is interrupted. Terminating"); } } @@ -111,14 +111,17 @@ private void ping() throws IOException, InterruptedException { long remaining = end - System.nanoTime(); do { - LOGGER.log(Level.FINE, "waiting {0}s on {1}", new Object[] {TimeUnit.NANOSECONDS.toSeconds(remaining), channel.getName()}); + LOGGER.log(Level.FINE, "waiting {0}s on {1}", new Object[] { + TimeUnit.NANOSECONDS.toSeconds(remaining), channel.getName() + }); try { - f.get(Math.max(1,remaining),TimeUnit.NANOSECONDS); + f.get(Math.max(1, remaining), TimeUnit.NANOSECONDS); LOGGER.log(Level.FINE, "ping succeeded on {0}", channel.getName()); return; } catch (ExecutionException e) { - if (e.getCause() instanceof RequestAbortedException) + if (e.getCause() instanceof RequestAbortedException) { return; // connection has shut down orderly. + } onDead(e); return; } catch (TimeoutException e) { @@ -126,9 +129,10 @@ private void ping() throws IOException, InterruptedException { // so let's make sure that it really waited enough } remaining = end - System.nanoTime(); - } while(remaining>0); + } while (remaining > 0); - onDead(new TimeoutException("Ping started at "+start+" hasn't completed by "+System.currentTimeMillis()));//.initCause(e) + onDead(new TimeoutException( + "Ping started at " + start + " hasn't completed by " + System.currentTimeMillis())); // .initCause(e) } /** @@ -147,7 +151,7 @@ private void ping() throws IOException, InterruptedException { * @since 2.9 */ protected void onDead(Throwable diagnosis) { - onDead(); // fall back + onDead(); // fall back } private static final class Ping implements InternalCallable { diff --git a/src/main/java/hudson/remoting/Pipe.java b/src/main/java/hudson/remoting/Pipe.java index f327099b5..0e3f1420d 100644 --- a/src/main/java/hudson/remoting/Pipe.java +++ b/src/main/java/hudson/remoting/Pipe.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -140,14 +140,14 @@ public void error(Throwable t) throws IOException { */ public static Pipe createRemoteToLocal() { // OutputStream will be created on the target - return new Pipe(new FastPipedInputStream(),null); + return new Pipe(new FastPipedInputStream(), null); } /** * Creates a {@link Pipe} that allows local system to write and remote system to read. */ public static Pipe createLocalToRemote() { - return new Pipe(null,new ProxyOutputStream()); + return new Pipe(null, new ProxyOutputStream()); } private void writeObject(ObjectOutputStream oos) throws IOException { @@ -157,10 +157,11 @@ private void writeObject(ObjectOutputStream oos) throws IOException { // The former uses 1M, while the latter uses 64K, so if the sender is too fast, it'll cause // the pipe IO thread to block other IO activities. Fix this by first using adaptive growing buffer // in FastPipedInputStream, then make sure the maximum size is bigger than the pipe window size. - if(in!=null && out==null) { + if (in != null && out == null) { // remote will write to local - FastPipedOutputStream pos = new FastPipedOutputStream((FastPipedInputStream)in); - int oid = ch.internalExport(Object.class, pos, false); // this export is unexported in ProxyOutputStream.finalize() + FastPipedOutputStream pos = new FastPipedOutputStream((FastPipedInputStream) in); + int oid = ch.internalExport( + Object.class, pos, false); // this export is unexported in ProxyOutputStream.finalize() oos.writeBoolean(true); // marker oos.writeInt(oid); @@ -174,11 +175,13 @@ private void writeObject(ObjectOutputStream oos) throws IOException { } } - @SuppressFBWarnings(value = "DESERIALIZATION_GADGET", justification = "Serializable only over remoting. Class filtering is done through JEP-200.") + @SuppressFBWarnings( + value = "DESERIALIZATION_GADGET", + justification = "Serializable only over remoting. Class filtering is done through JEP-200.") private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { final Channel channel = getChannelForSerialization(); - if(ois.readBoolean()) { + if (ois.readBoolean()) { // local will write to remote in = null; out = new ProxyOutputStream(channel, ois.readInt()); @@ -192,7 +195,8 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound // we want 'oidRos' to send data to this PipedOutputStream FastPipedOutputStream pos = new FastPipedOutputStream(); FastPipedInputStream pis = new FastPipedInputStream(pos); - final int oidPos = channel.internalExport(Object.class, pos, false); // this gets unexported when the remote ProxyOutputStream closes. + final int oidPos = channel.internalExport( + Object.class, pos, false); // this gets unexported when the remote ProxyOutputStream closes. // tell 'ros' to connect to our 'pos'. channel.send(new ConnectCommand(oidRos, oidPos)); @@ -221,11 +225,11 @@ protected void execute(final Channel channel) throws ExecutionException { channel.pipeWriter.submit(0, () -> { try { final ProxyOutputStream ros = (ProxyOutputStream) channel.getExportedObject(oidRos); - channel.unexport(oidRos,createdAt); + channel.unexport(oidRos, createdAt); // the above unexport cancels out the export in writeObject above ros.connect(channel, oidPos); } catch (IOException e) { - logger.log(Level.SEVERE,"Failed to connect to pipe",e); + logger.log(Level.SEVERE, "Failed to connect to pipe", e); } catch (ExecutionException ex) { throw new IllegalStateException(ex); } diff --git a/src/main/java/hudson/remoting/PipeWindow.java b/src/main/java/hudson/remoting/PipeWindow.java index e00c8459c..891d19bce 100644 --- a/src/main/java/hudson/remoting/PipeWindow.java +++ b/src/main/java/hudson/remoting/PipeWindow.java @@ -105,7 +105,7 @@ abstract class PipeWindow { */ void dead(@CheckForNull Throwable cause) { // We need to record - this.dead = cause != null ? cause : new RemotingSystemException("Unknown cause", null) ; + this.dead = cause != null ? cause : new RemotingSystemException("Unknown cause", null); } /** @@ -120,7 +120,6 @@ protected void checkDeath() throws IOException { } } - /** * Fake implementation used when the receiver side doesn't support throttling. */ @@ -131,8 +130,7 @@ int max() { } @Override - void increase(int delta) { - } + void increase(int delta) {} @Override int peek() { @@ -146,8 +144,7 @@ int get(int min) throws InterruptedException, IOException { } @Override - void decrease(int delta) { - } + void decrease(int delta) {} } static final class Key { @@ -159,7 +156,9 @@ static final class Key { @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } return oid == ((Key) o).oid; } @@ -170,7 +169,7 @@ public int hashCode() { } } - //TODO: Consider rework and cleanup of the fields + // TODO: Consider rework and cleanup of the fields @SuppressFBWarnings(value = "URF_UNREAD_FIELD", justification = "Legacy implementation") static class Real extends PipeWindow { private final int initial; @@ -183,6 +182,7 @@ static class Real extends PipeWindow { * Total bytes that the remote side acked. */ private long acked; + private final int oid; /** * The only strong reference to the key, which in turn @@ -204,8 +204,9 @@ int max() { @Override public synchronized void increase(int delta) { - if (LOGGER.isLoggable(Level.FINER)) - LOGGER.finer(String.format("increase(%d,%d)->%d",oid,delta,delta+available)); + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer(String.format("increase(%d,%d)->%d", oid, delta, delta + available)); + } available += delta; acked += delta; notifyAll(); @@ -223,10 +224,11 @@ public synchronized int peek() { public int get(int min) throws InterruptedException, IOException { checkDeath(); synchronized (this) { - if (available>=min) + if (available >= min) { return available; + } - while (available%d",oid,delta,available-delta)); + if (LOGGER.isLoggable(Level.FINER)) { + LOGGER.finer(String.format("decrease(%d,%d)->%d", oid, delta, available - delta)); + } available -= delta; - written+= delta; + written += delta; /* HUDSON-7745 says the following assertion fails, which AFAICT is only possible if multiple threads write to OutputStream concurrently, but that doesn't happen in most of the situations, so @@ -248,8 +251,8 @@ public synchronized void decrease(int delta) { HUDSON-7581 appears to be related. */ -// if (available<0) -// throw new AssertionError(); + // if (available<0) + // throw new AssertionError(); } } diff --git a/src/main/java/hudson/remoting/PipeWriter.java b/src/main/java/hudson/remoting/PipeWriter.java index afb03d9e5..5d6cbbca5 100644 --- a/src/main/java/hudson/remoting/PipeWriter.java +++ b/src/main/java/hudson/remoting/PipeWriter.java @@ -105,13 +105,14 @@ public synchronized Future set(Future f) { } public synchronized Future get() throws InterruptedException { - while (f==null) + while (f == null) { wait(); + } return f; } } - private final Map pendingIO = Collections.synchronizedMap(new HashMap<>()); + private final Map pendingIO = Collections.synchronizedMap(new HashMap<>()); /** * Actually carries out the {@link Runnable}s. @@ -138,8 +139,9 @@ public void shutdown() { * Future object that can be used to wait for the completion of the submitted I/O task. */ public Future submit(final int id, final Runnable command) { - if (id==0) + if (id == 0) { return base.submit(command); + } // this indirection is needed to ensure that put happens before remove // if we store Future itself, then remove can happen before put, and @@ -147,7 +149,7 @@ public Future submit(final int id, final Runnable command) { FutureHolder fh = new FutureHolder(); FutureHolder old = pendingIO.put(id, fh); - assert old==null; + assert old == null; return fh.set(base.submit(new Runnable() { @Override @@ -155,11 +157,11 @@ public void run() { final Thread t = Thread.currentThread(); final String oldName = t.getName(); try { - t.setName(oldName+" : IO ID="+id+" : seq#="+iota.getAndIncrement()); + t.setName(oldName + " : IO ID=" + id + " : seq#=" + iota.getAndIncrement()); command.run(); } finally { FutureHolder old = pendingIO.remove(id); - assert old!=null; + assert old != null; t.setName(oldName); } } @@ -180,7 +182,9 @@ public void run() { */ public Future get(int id) throws InterruptedException { FutureHolder f = pendingIO.get(id); - if (f==null) return SIGNALED; // already completed + if (f == null) { + return SIGNALED; // already completed + } return f.get(); } diff --git a/src/main/java/hudson/remoting/PreloadJarTask.java b/src/main/java/hudson/remoting/PreloadJarTask.java index bfad994a2..3169973ae 100644 --- a/src/main/java/hudson/remoting/PreloadJarTask.java +++ b/src/main/java/hudson/remoting/PreloadJarTask.java @@ -34,13 +34,14 @@ * * @author Kohsuke Kawaguchi */ -final class PreloadJarTask implements DelegatingCallable { +final class PreloadJarTask implements DelegatingCallable { /** * Jar file to be preloaded. */ private final URL[] jars; - //TODO: This implementation exists starting from https://github.com/jenkinsci/remoting/commit/f3d0a81fdf46a10c3c6193faf252efaeaee98823 + // TODO: This implementation exists starting from + // https://github.com/jenkinsci/remoting/commit/f3d0a81fdf46a10c3c6193faf252efaeaee98823 // Since this time nothing has blown up, but it still seems to be suspicious. // The solution for null classloaders is available in RemoteDiagnostics.Script#call() in the Jenkins core codebase @CheckForNull @@ -59,13 +60,15 @@ public ClassLoader getClassLoader() { @Override public Boolean call() throws IOException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (!(cl instanceof RemoteClassLoader)) + if (!(cl instanceof RemoteClassLoader)) { return false; + } RemoteClassLoader rcl = (RemoteClassLoader) cl; boolean r = false; - for (URL jar : jars) + for (URL jar : jars) { r |= rcl.prefetch(jar); + } return r; } @@ -75,7 +78,7 @@ public Boolean call() throws IOException { */ @Override public void checkRoles(RoleChecker checker) throws SecurityException { - checker.check(this,Role.UNKNOWN); + checker.check(this, Role.UNKNOWN); } private static final long serialVersionUID = -773448303394727271L; diff --git a/src/main/java/hudson/remoting/ProxyException.java b/src/main/java/hudson/remoting/ProxyException.java index 6dd6b781d..38680a279 100644 --- a/src/main/java/hudson/remoting/ProxyException.java +++ b/src/main/java/hudson/remoting/ProxyException.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -65,6 +65,6 @@ private ProxyException(@NonNull Throwable cause, @NonNull Set visited */ @Override public ProxyException getCause() { - return (ProxyException)super.getCause(); + return (ProxyException) super.getCause(); } } diff --git a/src/main/java/hudson/remoting/ProxyInputStream.java b/src/main/java/hudson/remoting/ProxyInputStream.java index 005e9ce06..e9fc26f57 100644 --- a/src/main/java/hudson/remoting/ProxyInputStream.java +++ b/src/main/java/hudson/remoting/ProxyInputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,12 +43,12 @@ * @author Kohsuke Kawaguchi */ final class ProxyInputStream extends InputStream { - + private static final Logger LOGGER = Logger.getLogger(ProxyInputStream.class.getName()); - + private Channel channel; private int oid; - + /** * Creates an already connected {@link ProxyOutputStream}. * @@ -64,12 +64,13 @@ public ProxyInputStream(Channel channel, int oid) throws IOException { public int read() throws IOException { try { Buffer buf = _read(1); - if(buf.len==1) + if (buf.len == 1) { // byte->int expansion needs to be done carefully becaue byte in Java is signed // whose idea was it to make byte signed, anyway!? - return ((int)buf.buf[0])&0xFF; - else + return ((int) buf.buf[0]) & 0xFF; + } else { return -1; + } } catch (InterruptedException e) { // pretend EOF Thread.currentThread().interrupt(); // process interrupt later @@ -86,8 +87,10 @@ private synchronized Buffer _read(int len) throws IOException, InterruptedExcept public int read(@NonNull byte[] b, int off, int len) throws IOException { try { Buffer buf = _read(len); - if(buf.len==-1) return -1; - System.arraycopy(buf.buf,0,b,off,buf.len); + if (buf.len == -1) { + return -1; + } + System.arraycopy(buf.buf, 0, b, off, buf.len); return buf.len; } catch (InterruptedException e) { // pretend EOF @@ -99,7 +102,7 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { @Override public synchronized void close() throws IOException { - if(channel!=null) { + if (channel != null) { channel.send(new EOF(oid)); channel = null; oid = -1; @@ -115,7 +118,7 @@ public Buffer(int len) { } public void read(InputStream in) throws IOException { - len = in.read(buf,0,buf.length); + len = in.read(buf, 0, buf.length); } private static final long serialVersionUID = 1L; @@ -124,7 +127,7 @@ public void read(InputStream in) throws IOException { /** * Command to fetch bytes. */ - private static final class Chunk extends Request { + private static final class Chunk extends Request { private final int oid; private final int len; @@ -153,7 +156,6 @@ public String toString() { } private static final long serialVersionUID = 1L; - } /** @@ -169,19 +171,19 @@ public EOF(int oid) { @Override protected void execute(Channel channel) { final InputStream in = (InputStream) channel.getExportedObjectOrNull(oid); - // EOF may be late to the party if we interrupt request, hence we do not fail for this command + // EOF may be late to the party if we interrupt request, hence we do not fail for this command if (in == null) { // Input stream has not been closed yet LOGGER.log(Level.FINE, "InputStream with oid=%s has been already unexported", oid); return; } - - channel.unexport(oid,createdAt,false); + + channel.unexport(oid, createdAt, false); IOUtils.closeQuietly(in); } @Override public String toString() { - return "ProxyInputStream.EOF("+oid+")"; + return "ProxyInputStream.EOF(" + oid + ")"; } private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/remoting/ProxyOutputStream.java b/src/main/java/hudson/remoting/ProxyOutputStream.java index db0b70070..9e351ec55 100644 --- a/src/main/java/hudson/remoting/ProxyOutputStream.java +++ b/src/main/java/hudson/remoting/ProxyOutputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -58,8 +58,7 @@ final class ProxyOutputStream extends OutputStream implements ErrorPropagatingOu * when it's {@link #connect(Channel,int) connected} later, * the data will be sent at once to the remote stream. */ - public ProxyOutputStream() { - } + public ProxyOutputStream() {} /** * Creates an already connected {@link ProxyOutputStream}. @@ -68,87 +67,91 @@ public ProxyOutputStream() { * The object id of the exported {@link OutputStream}. */ public ProxyOutputStream(@NonNull Channel channel, int oid) throws IOException { - connect(channel,oid); + connect(channel, oid); } /** * Connects this stream to the specified remote object. */ synchronized void connect(@NonNull Channel channel, int oid) throws IOException { - if(this.channel!=null) + if (this.channel != null) { throw new IllegalStateException("Cannot connect twice"); - if(oid==0) + } + if (oid == 0) { throw new IllegalArgumentException("oid=0"); + } this.channel = channel; this.oid = oid; - window = channel.getPipeWindow(oid); + window = channel.getPipeWindow(oid); - if(closed) // already marked closed? + if (closed) { // already marked closed? doClose(error); + } notifyAll(); // release blocking writes } @Override public void write(int b) throws IOException { - write(new byte[]{(byte)b},0,1); + write(new byte[] {(byte) b}, 0, 1); } @Override public synchronized void write(@NonNull byte[] b, int off, int len) throws IOException { try { // block until stream gets connected - while (channel==null) { - if(closed) + while (channel == null) { + if (closed) { throw new IOException("stream is already closed"); + } wait(); } final int max = window.max(); - while (len>0) { + while (len > 0) { /* - To avoid fragmentation of the pipe window, at least demand that 10% of the pipe window - be reclaimed. + To avoid fragmentation of the pipe window, at least demand that 10% of the pipe window + be reclaimed. - Imagine a large latency network where we are always low on the window size, - and we are continuously sending data of irregular size. In such a circumstance, - a fragmentation will happen. We start sending out a small Chunk at a time (say 4 bytes), - and when its Ack comes back, it gets immediately consumed by another out-bound Chunk of 4 bytes. + Imagine a large latency network where we are always low on the window size, + and we are continuously sending data of irregular size. In such a circumstance, + a fragmentation will happen. We start sending out a small Chunk at a time (say 4 bytes), + and when its Ack comes back, it gets immediately consumed by another out-bound Chunk of 4 bytes. - Clearly, it's better to wait a bit until we have a sizable pipe window, then send out - a bigger Chunk, since Chunks have static overheads. This code does just that. + Clearly, it's better to wait a bit until we have a sizable pipe window, then send out + a bigger Chunk, since Chunks have static overheads. This code does just that. - (Except when what we are trying to send as a whole is smaller than the current available - window size, in which case there's no point in waiting.) - */ - int sendable = Math.min(window.get(Math.min(max/10,len)),len); + (Except when what we are trying to send as a whole is smaller than the current available + window size, in which case there's no point in waiting.) + */ + int sendable = Math.min(window.get(Math.min(max / 10, len)), len); /* - Imagine if we have a lot of data to send and the pipe window is fully available. - If we create one Chunk that fully uses the window size, we need to wait for the - whole Chunk to get to the other side, then the Ack to come back to this side, - before we can send a next Chunk. While the Ack is traveling back to us, we have - to sit idle. This fails to utilize available bandwidth. - - A better strategy is to create a smaller Chunk, say half the window size. - This allows the other side to send back the ack while we are sending the second - Chunk. In a network with a non-trivial latency, this allows Chunk and Ack - to overlap, and that improves the utilization. - - It's not clear what the best size of the chunk to send (there's a certain - overhead in our Command structure, around 100-200 bytes), so I'm just starting - with 2. Further analysis would be needed to determine the best value. - */ - sendable = Math.min(sendable, max /2); - - channel.send(new Chunk(channel.newIoId(),oid,b,off,sendable)); + Imagine if we have a lot of data to send and the pipe window is fully available. + If we create one Chunk that fully uses the window size, we need to wait for the + whole Chunk to get to the other side, then the Ack to come back to this side, + before we can send a next Chunk. While the Ack is traveling back to us, we have + to sit idle. This fails to utilize available bandwidth. + + A better strategy is to create a smaller Chunk, say half the window size. + This allows the other side to send back the ack while we are sending the second + Chunk. In a network with a non-trivial latency, this allows Chunk and Ack + to overlap, and that improves the utilization. + + It's not clear what the best size of the chunk to send (there's a certain + overhead in our Command structure, around 100-200 bytes), so I'm just starting + with 2. Further analysis would be needed to determine the best value. + */ + sendable = Math.min(sendable, max / 2); + + channel.send(new Chunk(channel.newIoId(), oid, b, off, sendable)); window.decrease(sendable); - off+=sendable; - len-=sendable; + off += sendable; + len -= sendable; } } catch (InterruptedException e) { - throw (IOException)new InterruptedIOException().initCause(e); + throw (IOException) new InterruptedIOException().initCause(e); } } @@ -170,13 +173,14 @@ public synchronized void error(Throwable e) throws IOException { closed = true; error = e; } - if(channel!=null) + if (channel != null) { doClose(e); - notifyAll(); // unblock any pending write + } + notifyAll(); // unblock any pending write } private void doClose(Throwable error) throws IOException { - channel.send(new EOF(channel.newIoId(),oid,error)); + channel.send(new EOF(channel.newIoId(), oid, error)); channel = null; oid = -1; } @@ -186,8 +190,8 @@ protected void finalize() throws Throwable { super.finalize(); // if we haven't done so, release the exported object on the remote side. // if the object is auto-unexported, the export entry could have already been removed. - if(channel != null && oid != -1) { - channel.send(new Unexport(channel.newIoId(),oid)); + if (channel != null && oid != -1) { + channel.send(new Unexport(channel.newIoId(), oid)); oid = -1; } } @@ -213,12 +217,13 @@ protected void finalize() throws Throwable { */ @Deprecated private static void markForIoSync(Channel channel, int requestId, java.util.concurrent.Future ioOp) { - Request call = channel.pendingCalls.get(requestId); + Request call = channel.pendingCalls.get(requestId); // call==null if: // 1) the remote peer uses old version that doesn't set the requestId field // 2) a bug in the code, but in that case we are being defensive - if (call!=null) + if (call != null) { call.lastIo = ioOp; + } } /** @@ -237,11 +242,11 @@ public Chunk(int ioId, int oid, byte[] buf, int start, int len) { super(false); this.ioId = ioId; this.oid = oid; - if (start==0 && len==buf.length) + if (start == 0 && len == buf.length) { this.buf = buf; - else { + } else { this.buf = new byte[len]; - System.arraycopy(buf,start,this.buf,0,len); + System.arraycopy(buf, start, this.buf, 0, len); } } @@ -251,33 +256,36 @@ protected void execute(final Channel channel) throws ExecutionException { try { os = (OutputStream) channel.getExportedObject(oid); } catch (ExecutionException ex) { - throw new ExecutionException(String.format("Channel %s: Output stream object has been released before sending last chunk for oid=%s", - channel.getName(), oid), ex); + throw new ExecutionException( + String.format( + "Channel %s: Output stream object has been released before sending last chunk for oid=%s", + channel.getName(), oid), + ex); } - markForIoSync(channel,requestId,channel.pipeWriter.submit(ioId, () -> { + markForIoSync(channel, requestId, channel.pipeWriter.submit(ioId, () -> { try { os.write(buf); } catch (IOException e) { try { - channel.send(new NotifyDeadWriter(channel,e,oid)); + channel.send(new NotifyDeadWriter(channel, e, oid)); } catch (ChannelClosedException x) { // the other direction can be already closed if the connection // shut down is initiated from this side. In that case, remain silent. } catch (IOException x) { // ignore errors - LOGGER.log(Level.WARNING, "Failed to notify the sender that the write end is dead",x); - LOGGER.log(Level.WARNING, "... the failed write was:",e); + LOGGER.log(Level.WARNING, "Failed to notify the sender that the write end is dead", x); + LOGGER.log(Level.WARNING, "... the failed write was:", e); } } finally { if (channel.remoteCapability.supportsPipeThrottling()) { try { - channel.send(new Ack(oid,buf.length)); + channel.send(new Ack(oid, buf.length)); } catch (ChannelClosedException x) { // the other direction can be already closed if the connection // shut down is initiated from this side. In that case, remain silent. } catch (IOException e) { // ignore errors - LOGGER.log(Level.WARNING, "Failed to ack the stream",e); + LOGGER.log(Level.WARNING, "Failed to ack the stream", e); } } } @@ -286,7 +294,7 @@ protected void execute(final Channel channel) throws ExecutionException { @Override public String toString() { - return "Pipe.Chunk("+oid+","+buf.length+")"; + return "Pipe.Chunk(" + oid + "," + buf.length + ")"; } private static final long serialVersionUID = 1L; @@ -309,7 +317,7 @@ public Flush(int ioId, int oid) { @Override protected void execute(Channel channel) throws ExecutionException { final OutputStream os = (OutputStream) channel.getExportedObject(oid); - markForIoSync(channel,requestId,channel.pipeWriter.submit(ioId, () -> { + markForIoSync(channel, requestId, channel.pipeWriter.submit(ioId, () -> { try { os.flush(); } catch (IOException e) { @@ -320,7 +328,7 @@ protected void execute(Channel channel) throws ExecutionException { @Override public String toString() { - return "Pipe.Flush("+oid+")"; + return "Pipe.Flush(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -343,12 +351,12 @@ public Unexport(int ioId, int oid) { @Override protected void execute(final Channel channel) { - channel.pipeWriter.submit(ioId, () -> channel.unexport(oid,createdAt,false)); + channel.pipeWriter.submit(ioId, () -> channel.unexport(oid, createdAt, false)); } @Override public String toString() { - return "ProxyOutputStream.Unexport("+oid+")"; + return "ProxyOutputStream.Unexport(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -369,7 +377,6 @@ public EOF(int ioId, int oid, Throwable error) { this.error = error; } - @Override protected void execute(final Channel channel) { final OutputStream os = (OutputStream) channel.getExportedObjectOrNull(oid); @@ -378,11 +385,12 @@ protected void execute(final Channel channel) { LOGGER.log(Level.FINE, "InputStream with oid=%s has been already unexported", oid); return; } - markForIoSync(channel,requestId,channel.pipeWriter.submit(ioId, () -> { - channel.unexport(oid,createdAt,false); + markForIoSync(channel, requestId, channel.pipeWriter.submit(ioId, () -> { + channel.unexport(oid, createdAt, false); try { - if (error!=null && os instanceof ErrorPropagatingOutputStream) + if (error != null && os instanceof ErrorPropagatingOutputStream) { ((ErrorPropagatingOutputStream) os).error(error); + } os.close(); } catch (IOException e) { // ignore errors @@ -392,7 +400,7 @@ protected void execute(final Channel channel) { @Override public String toString() { - return "ProxyOutputStream.EOF("+oid+")"; + return "ProxyOutputStream.EOF(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -425,7 +433,7 @@ protected void execute(Channel channel) { @Override public String toString() { - return "ProxyOutputStream.Ack("+oid+','+size+")"; + return "ProxyOutputStream.Ack(" + oid + ',' + size + ")"; } private static final long serialVersionUID = 1L; @@ -437,8 +445,8 @@ public String toString() { private static final class NotifyDeadWriter extends Command { private final int oid; - private NotifyDeadWriter(Channel channel,Throwable cause, int oid) { - super(channel,cause); + private NotifyDeadWriter(Channel channel, Throwable cause, int oid) { + super(channel, cause); this.oid = oid; } @@ -450,7 +458,7 @@ protected void execute(Channel channel) { @Override public String toString() { - return "ProxyOutputStream.Dead("+oid+")"; + return "ProxyOutputStream.Dead(" + oid + ")"; } private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/remoting/ProxyWriter.java b/src/main/java/hudson/remoting/ProxyWriter.java index e7d6c68f5..2da94fb51 100644 --- a/src/main/java/hudson/remoting/ProxyWriter.java +++ b/src/main/java/hudson/remoting/ProxyWriter.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -40,9 +40,10 @@ * {@link Writer} on a remote machine. */ final class ProxyWriter extends Writer { - + @GuardedBy("this") private Channel channel; + private int oid; private PipeWindow window; @@ -72,36 +73,38 @@ final class ProxyWriter extends Writer { * The object id of the exported {@link Writer}. */ public ProxyWriter(@NonNull Channel channel, int oid) throws IOException { - connect(channel,oid); + connect(channel, oid); } /** * Connects this stream to the specified remote object. */ synchronized void connect(@NonNull Channel channel, int oid) throws IOException { - if(this.channel!=null) + if (this.channel != null) { throw new IllegalStateException("Cannot connect twice"); - if(oid==0) + } + if (oid == 0) { throw new IllegalArgumentException("oid=0"); + } this.channel = channel; this.oid = oid; - window = channel.getPipeWindow(oid); + window = channel.getPipeWindow(oid); // if we already have bytes to write, do so now. - if(tmp!=null) { + if (tmp != null) { char[] b = tmp.toCharArray(); tmp = null; _write(b, 0, b.length); } - if(closeCause != null) { // already closed asynchronously? + if (closeCause != null) { // already closed asynchronously? close(); } } @Override public void write(int c) throws IOException { - write(new char[]{(char)c},0,1); + write(new char[] {(char) c}, 0, 1); } @Override @@ -116,65 +119,67 @@ public void write(@NonNull char[] cbuf, int off, int len) throws IOException { * {@link #write(char[])} without the close check. */ private synchronized void _write(char[] cbuf, int off, int len) throws IOException { - if(channel==null) { - if(tmp==null) + if (channel == null) { + if (tmp == null) { tmp = new CharArrayWriter(); + } tmp.write(cbuf); } else { final int max = window.max(); - while (len>0) { + while (len > 0) { int sendable; try { /* - To avoid fragmentation of the pipe window, at least demand that 10% of the pipe window - be reclaimed. + To avoid fragmentation of the pipe window, at least demand that 10% of the pipe window + be reclaimed. - Imagine a large latency network where we are always low on the window size, - and we are continuously sending data of irregular size. In such a circumstance, - a fragmentation will happen. We start sending out a small Chunk at a time (say 4 bytes), - and when its Ack comes back, it gets immediately consumed by another out-bound Chunk of 4 bytes. + Imagine a large latency network where we are always low on the window size, + and we are continuously sending data of irregular size. In such a circumstance, + a fragmentation will happen. We start sending out a small Chunk at a time (say 4 bytes), + and when its Ack comes back, it gets immediately consumed by another out-bound Chunk of 4 bytes. - Clearly, it's better to wait a bit until we have a sizable pipe window, then send out - a bigger Chunk, since Chunks have static overheads. This code does just that. + Clearly, it's better to wait a bit until we have a sizable pipe window, then send out + a bigger Chunk, since Chunks have static overheads. This code does just that. - (Except when what we are trying to send as a whole is smaller than the current available - window size, in which case there's no point in waiting.) - */ - sendable = Math.min(window.get(Math.min(max/10,len)),len); + (Except when what we are trying to send as a whole is smaller than the current available + window size, in which case there's no point in waiting.) + */ + sendable = Math.min(window.get(Math.min(max / 10, len)), len); /* - Imagine if we have a lot of data to send and the pipe window is fully available. - If we create one Chunk that fully uses the window size, we need to wait for the - whole Chunk to get to the other side, then the Ack to come back to this side, - before we can send a next Chunk. While the Ack is traveling back to us, we have - to sit idle. This fails to utilize available bandwidth. - - A better strategy is to create a smaller Chunk, say half the window size. - This allows the other side to send back the ack while we are sending the second - Chunk. In a network with a non-trivial latency, this allows Chunk and Ack - to overlap, and that improves the utilization. - - It's not clear what the best size of the chunk to send (there's a certain - overhead in our Command structure, around 100-200 bytes), so I'm just starting - with 2. Further analysis would be needed to determine the best value. - */ - sendable = Math.min(sendable, max /2); + Imagine if we have a lot of data to send and the pipe window is fully available. + If we create one Chunk that fully uses the window size, we need to wait for the + whole Chunk to get to the other side, then the Ack to come back to this side, + before we can send a next Chunk. While the Ack is traveling back to us, we have + to sit idle. This fails to utilize available bandwidth. + + A better strategy is to create a smaller Chunk, say half the window size. + This allows the other side to send back the ack while we are sending the second + Chunk. In a network with a non-trivial latency, this allows Chunk and Ack + to overlap, and that improves the utilization. + + It's not clear what the best size of the chunk to send (there's a certain + overhead in our Command structure, around 100-200 bytes), so I'm just starting + with 2. Further analysis would be needed to determine the best value. + */ + sendable = Math.min(sendable, max / 2); } catch (InterruptedException e) { - throw (IOException)new InterruptedIOException().initCause(e); + throw (IOException) new InterruptedIOException().initCause(e); } - channel.send(new Chunk(channel.newIoId(),oid,cbuf,off,sendable)); + channel.send(new Chunk(channel.newIoId(), oid, cbuf, off, sendable)); window.decrease(sendable); - off+=sendable; - len-=sendable; + off += sendable; + len -= sendable; } } } @Override public synchronized void flush() throws IOException { - if(channel!=null && channel.remoteCapability.supportsProxyWriter2_35()) - channel.send(new Flush(channel.newIoId(),oid)); + if (channel != null && channel.remoteCapability.supportsProxyWriter2_35()) { + channel.send(new Flush(channel.newIoId(), oid)); + } } @Override @@ -224,11 +229,13 @@ public void error(@CheckForNull Throwable cause) throws IOException { } synchronized (this) { - //TODO: Bug. If the channel cannot send the command, the channel object will be never released and garbage collected + // TODO: Bug. If the channel cannot send the command, the channel object will be never released and garbage + // collected if (channel != null) { - // Close the writer on the remote side. This call may be invoked multiple times until the channel is released - //TODO: send cause over the channel - channel.send(new EOF(channel.newIoId(), oid/*,error*/)); + // Close the writer on the remote side. This call may be invoked multiple times until the channel is + // released + // TODO: send cause over the channel + channel.send(new EOF(channel.newIoId(), oid /*,error*/)); channel = null; channelReleased = true; oid = -1; @@ -237,17 +244,18 @@ public void error(@CheckForNull Throwable cause) throws IOException { } @Override - //TODO: really? + // TODO: really? @SuppressFBWarnings(value = "FI_FINALIZER_NULLS_FIELDS", justification = "As designed") protected synchronized void finalize() throws Throwable { super.finalize(); // if we haven't done so, release the exported object on the remote side. // if the object is auto-unexported, the export entry could have already been removed. - if(channel!=null) { - if (channel.remoteCapability.supportsProxyWriter2_35()) - channel.send(new Unexport(channel.newIoId(),oid)); - else - channel.send(new EOF(channel.newIoId(),oid)); + if (channel != null) { + if (channel.remoteCapability.supportsProxyWriter2_35()) { + channel.send(new Unexport(channel.newIoId(), oid)); + } else { + channel.send(new EOF(channel.newIoId(), oid)); + } channel = null; oid = -1; } @@ -268,11 +276,11 @@ public Chunk(int ioId, int oid, char[] buf, int start, int len) { super(false); this.ioId = ioId; this.oid = oid; - if (start==0 && len==buf.length) + if (start == 0 && len == buf.length) { this.buf = buf; - else { + } else { this.buf = new char[len]; - System.arraycopy(buf,start,this.buf,0,len); + System.arraycopy(buf, start, this.buf, 0, len); } } @@ -284,8 +292,9 @@ protected void execute(final Channel channel) throws ExecutionException { os.write(buf); } catch (IOException e) { try { - if (channel.remoteCapability.supportsProxyWriter2_35()) + if (channel.remoteCapability.supportsProxyWriter2_35()) { channel.send(new NotifyDeadWriter(channel, e, oid)); + } } catch (ChannelClosedException x) { // the other direction can be already closed if the connection // shut down is initiated from this side. In that case, remain silent. @@ -312,7 +321,7 @@ protected void execute(final Channel channel) throws ExecutionException { @Override public String toString() { - return "ProxyWriter.Chunk("+oid+","+buf.length+")"; + return "ProxyWriter.Chunk(" + oid + "," + buf.length + ")"; } private static final long serialVersionUID = 1L; @@ -346,7 +355,7 @@ protected void execute(Channel channel) throws ExecutionException { @Override public String toString() { - return "ProxyWriter.Flush("+oid+")"; + return "ProxyWriter.Flush(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -370,12 +379,12 @@ public Unexport(int ioId, int oid) { @Override protected void execute(final Channel channel) { - channel.pipeWriter.submit(ioId, () -> channel.unexport(oid,createdAt,false)); + channel.pipeWriter.submit(ioId, () -> channel.unexport(oid, createdAt, false)); } @Override public String toString() { - return "ProxyWriter.Unexport("+oid+")"; + return "ProxyWriter.Unexport(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -388,7 +397,7 @@ private static final class EOF extends Command { private final int oid; private final int ioId; - public EOF(int ioId,int oid) { + public EOF(int ioId, int oid) { this.ioId = ioId; this.oid = oid; } @@ -402,7 +411,7 @@ protected void execute(final Channel channel) { return; } channel.pipeWriter.submit(ioId, () -> { - channel.unexport(oid,createdAt,false); + channel.unexport(oid, createdAt, false); try { os.close(); } catch (IOException e) { @@ -413,7 +422,7 @@ protected void execute(final Channel channel) { @Override public String toString() { - return "ProxyWriter.EOF("+oid+")"; + return "ProxyWriter.EOF(" + oid + ")"; } private static final long serialVersionUID = 1L; @@ -447,7 +456,7 @@ protected void execute(Channel channel) { @Override public String toString() { - return "ProxyWriter.Ack("+oid+','+size+")"; + return "ProxyWriter.Ack(" + oid + ',' + size + ")"; } private static final long serialVersionUID = 1L; @@ -460,8 +469,8 @@ public String toString() { private static final class NotifyDeadWriter extends Command { private final int oid; - private NotifyDeadWriter(Channel channel,Throwable cause, int oid) { - super(channel,cause); + private NotifyDeadWriter(Channel channel, Throwable cause, int oid) { + super(channel, cause); this.oid = oid; } @@ -473,7 +482,7 @@ protected void execute(Channel channel) { @Override public String toString() { - return "ProxyWriter.Dead("+oid+")"; + return "ProxyWriter.Dead(" + oid + ")"; } private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/remoting/RemoteClassLoader.java b/src/main/java/hudson/remoting/RemoteClassLoader.java index 5bbdfd6f0..34655c5b5 100644 --- a/src/main/java/hudson/remoting/RemoteClassLoader.java +++ b/src/main/java/hudson/remoting/RemoteClassLoader.java @@ -64,12 +64,9 @@ * @author Kohsuke Kawaguchi */ @SuppressFBWarnings( - value = { - "DMI_COLLECTION_OF_URLS", - "DMI_BLOCKING_METHODS_ON_URL", - "SIC_INNER_SHOULD_BE_STATIC_ANON" - }, - justification = "Since this is based on the URLClassLoader, it is difficult to switch to URIs. We have no indication this causes noticeable resource issues. The implementations here and in URL reduce the impact.") + value = {"DMI_COLLECTION_OF_URLS", "DMI_BLOCKING_METHODS_ON_URL", "SIC_INNER_SHOULD_BE_STATIC_ANON"}, + justification = + "Since this is based on the URLClassLoader, it is difficult to switch to URIs. We have no indication this causes noticeable resource issues. The implementations here and in URL reduce the impact.") final class RemoteClassLoader extends URLClassLoader { private static final Logger LOGGER = Logger.getLogger(RemoteClassLoader.class.getName()); @@ -100,7 +97,8 @@ interface Interruptible { * This sleep keeps it from hammering the channel if there is a failure. * The default value is 100 (ms). */ - static int RETRY_SLEEP_DURATION_MILLISECONDS = Integer.getInteger(RemoteClassLoader.class.getName() + "retrySleepDurationMilliseconds", 100); + static int RETRY_SLEEP_DURATION_MILLISECONDS = + Integer.getInteger(RemoteClassLoader.class.getName() + "retrySleepDurationMilliseconds", 100); /** * The total number of retries for an interrupted class load. * This makes the operation retry for an extended period of time but eventually timeout. @@ -167,13 +165,16 @@ public static ClassLoader create(@CheckForNull ClassLoader parent, @NonNull ICla String name; try { name = proxy.getName(); - } catch(IOException ignored) { + } catch (IOException ignored) { name = String.format(Locale.ROOT, "unknown-due-to-io-error %1$#x", System.identityHashCode(proxy)); } catch (IllegalStateException ignored) { // IllegalStateException is thrown if the method does not exist on the remote side. // TODO remove this at some point in the future when Jenkins sets the minimum remoting version to // 3244.vf7f977e04755 or higher - name = String.format(Locale.ROOT, "upgrade-remoting-to-3244.vf7f977e04755-or-higher %1$#x", System.identityHashCode(proxy)); + name = String.format( + Locale.ROOT, + "upgrade-remoting-to-3244.vf7f977e04755-or-higher %1$#x", + System.identityHashCode(proxy)); } return new RemoteClassLoader(name, parent, proxy); } @@ -248,17 +249,17 @@ private Class fetchFromProxy(String name, Channel channel) throws ClassNotFou } private Class loadWithMultiClassLoader(String name, Channel channel) throws ClassNotFoundException { - /* - In multi-classloader setup, RemoteClassLoaders do not retain the relationships among the original classloaders, - so each RemoteClassLoader ends up loading classes on its own without delegating to other RemoteClassLoaders. + /* + In multi-classloader setup, RemoteClassLoaders do not retain the relationships among the original classloaders, + so each RemoteClassLoader ends up loading classes on its own without delegating to other RemoteClassLoaders. - See the classloader X/Y examples in HUDSON-5048 for the depiction of the problem. + See the classloader X/Y examples in HUDSON-5048 for the depiction of the problem. - So instead, we find the right RemoteClassLoader to load the class on per class basis. - The communication is optimized for the single classloader use, by always returning the class file image - along with the reference to the initiating ClassLoader (if the initiating ClassLoader has already loaded this class, - then the class file image is wasted.) - */ + So instead, we find the right RemoteClassLoader to load the class on per class basis. + The communication is optimized for the single classloader use, by always returning the class file image + along with the reference to the initiating ClassLoader (if the initiating ClassLoader has already loaded this class, + then the class file image is wasted.) + */ long startTime = System.nanoTime(); ClassReference cr; if (channel.remoteCapability.supportsPrefetch()) { @@ -279,7 +280,8 @@ then the class file image is wasted.) } } - private Class loadRemoteClass(String name, Channel channel, ClassReference cr, RemoteClassLoader rcl) throws ClassNotFoundException { + private Class loadRemoteClass(String name, Channel channel, ClassReference cr, RemoteClassLoader rcl) + throws ClassNotFoundException { synchronized (rcl.getClassLoadingLock(name)) { Class c = rcl.findLoadedClass(name); @@ -314,7 +316,8 @@ private Class loadRemoteClass(String name, Channel channel, ClassReference cr // but we need to remember to set the interrupt flag back on // before we leave this call. sleepForRetry(); - LOGGER.finer("Handling interrupt while loading remote class. Current retry count = " + tries + ", maximum = " + MAX_RETRIES); + LOGGER.finer("Handling interrupt while loading remote class. Current retry count = " + tries + + ", maximum = " + MAX_RETRIES); continue; } break; @@ -342,8 +345,8 @@ private boolean hasMoreRetries(int tries) { private boolean isRetryException(Throwable e) { return e instanceof InterruptedException || (e instanceof RemotingSystemException - && (e.getCause() instanceof InterruptedException - || e.getCause() instanceof InterruptedIOException)); + && (e.getCause() instanceof InterruptedException + || e.getCause() instanceof InterruptedIOException)); } private ClassReference prefetchClassReference(String name, Channel channel) throws ClassNotFoundException { @@ -396,7 +399,7 @@ ClassReference toRef(ClassFile2 cf) { ref.rememberIn(cn, this); } - LOGGER.log(Level.FINER, "prefetch {0} -> {1}", new Object[]{name, cn}); + LOGGER.log(Level.FINER, "prefetch {0} -> {1}", new Object[] {name, cn}); } ref.rememberIn(cn, ref.classLoader); @@ -410,7 +413,8 @@ ClassReference toRef(ClassFile2 cf) { // but we need to remember to set the interrupt flag back on // before we leave this call. sleepForRetry(); - LOGGER.finer("Handling interrupt while fetching class reference. Current retry count = " + tries + ", maximum = " + MAX_RETRIES); + LOGGER.finer("Handling interrupt while fetching class reference. Current retry count = " + tries + + ", maximum = " + MAX_RETRIES); continue; } throw determineRemotingSystemException(x); @@ -451,7 +455,8 @@ private Class loadClassFile(String name, byte[] bytes) throws LinkageError { short bytecodeLevel = (short) ((bytes[6] << 8) + (bytes[7] & 0xFF) - 44); final Channel channel = channel(); if (channel != null && bytecodeLevel > channel.maximumBytecodeLevel) { - throw new UnsupportedClassVersionError("this channel is restricted to JDK 1." + channel.maximumBytecodeLevel + " compatibility but " + name + " was compiled for 1." + bytecodeLevel); + throw new UnsupportedClassVersionError("this channel is restricted to JDK 1." + channel.maximumBytecodeLevel + + " compatibility but " + name + " was compiled for 1." + bytecodeLevel); } // if someone else is forcing us to load a class by giving as bytecode, @@ -460,11 +465,12 @@ private Class loadClassFile(String name, byte[] bytes) throws LinkageError { definePackage(name); - //TODO: probably this wrapping is not required anymore + // TODO: probably this wrapping is not required anymore try { return defineClass(name, bytes, 0, bytes.length); } catch (UnsupportedClassVersionError e) { - throw (UnsupportedClassVersionError) new UnsupportedClassVersionError("Failed to load " + name).initCause(e); + throw (UnsupportedClassVersionError) + new UnsupportedClassVersionError("Failed to load " + name).initCause(e); } catch (ClassFormatError e) { throw (ClassFormatError) new ClassFormatError("Failed to load " + name).initCause(e); } catch (LinkageError e) { @@ -484,7 +490,7 @@ private void definePackage(String name) { } String packageName = name.substring(0, idx); - if (getPackage(packageName) != null) { // already defined + if (getPackage(packageName) != null) { // already defined return; } @@ -507,7 +513,7 @@ public URL findResource(String name) { if (resourceMap.containsKey(name)) { URLish f = resourceMap.get(name); if (f == null) { - return null; // no such resource + return null; // no such resource } URL u = f.toURL(); if (u != null) { @@ -544,7 +550,8 @@ public URL findResource(String name) { // but we need to remember to set the interrupt flag back on // before we leave this call. sleepForRetry(); - LOGGER.finer("Handling interrupt while finding resource. Current retry count = " + tries + ", maximum = " + MAX_RETRIES); + LOGGER.finer("Handling interrupt while finding resource. Current retry count = " + tries + + ", maximum = " + MAX_RETRIES); continue; } throw determineRemotingSystemException(x); @@ -575,7 +582,7 @@ private static Vector toURLs(Vector src) throws MalformedURLExcepti for (URLish s : src) { URL u = s.toURL(); if (u == null) { - return null; // abort + return null; // abort } r.add(u); } @@ -639,7 +646,8 @@ public Enumeration findResources(String name) throws IOException { // but we need to remember to set the interrupt flag back on // before we leave this call. sleepForRetry(); - LOGGER.finer("Handling interrupt while finding resource. Current retry count = " + tries + ", maximum = " + MAX_RETRIES); + LOGGER.finer("Handling interrupt while finding resource. Current retry count = " + tries + + ", maximum = " + MAX_RETRIES); continue; } throw determineRemotingSystemException(x); @@ -667,7 +675,6 @@ public static void deleteDirectoryOnExit(File dir) { Util.deleteDirectoryOnExit(dir); } - /** * Prefetches the jar into this class loader. * @@ -717,7 +724,6 @@ void rememberIn(String className, ClassLoader cl) { rcl.prefetchedClasses.put(className, this); } } - } /** @@ -730,6 +736,7 @@ public static class ClassFile implements Serializable { * oid of the classloader that should load this class. */ final int classLoader; + final byte[] classImage; ClassFile(int classLoader, byte[] classImage) { @@ -762,8 +769,10 @@ public static class ResourceFile implements Serializable { * this points to the location of the resource. Used by * the sender side to retrieve the resource when necessary. */ - @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "We're fine with the default null on the recipient side") - transient final URL local; + @SuppressFBWarnings( + value = "SE_TRANSIENT_FIELD_NOT_RESTORED", + justification = "We're fine with the default null on the recipient side") + final transient URL local; /** * Fall back for creating a direct resource @@ -816,8 +825,10 @@ public static class ClassFile2 extends ResourceFile { * While this object is still on the sender side, used to remember the actual * class that this {@link ClassFile2} represents. */ - @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "We're fine with the default null on the recipient side") - transient final Class clazz; + @SuppressFBWarnings( + value = "SE_TRANSIENT_FIELD_NOT_RESTORED", + justification = "We're fine with the default null on the recipient side") + final transient Class clazz; ClassFile2(int classLoader, ResourceImageRef image, ClassFile2 referer, Class clazz, URL local) { super(image, local); @@ -930,7 +941,9 @@ public static void pin(ClassLoader cl, Channel local) { // check if this is a remote classloader from the channel final RemoteClassLoader rcl = (RemoteClassLoader) cl; int oid = RemoteInvocationHandler.unwrap(rcl.proxy, local); - if (oid != -1) return; + if (oid != -1) { + return; + } } local.pin(new ClassLoaderProxy(cl, local)); } @@ -956,7 +969,9 @@ public ClassLoaderProxy(@NonNull ClassLoader cl, Channel channel) { } @Override - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "This is only used for managing the jar cache as files.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "This is only used for managing the jar cache as files.") public byte[] fetchJar(URL url) throws IOException { return Util.readFully(url.openStream()); } @@ -995,9 +1010,7 @@ public ClassFile fetch2(String className) throws ClassNotFoundException { if (in == null) { throw new ClassNotFoundException(className + " (" + ecl + " did not find class file)"); } - return new ClassFile( - exportId(ecl, channel), - Util.readFully(in)); + return new ClassFile(exportId(ecl, channel), Util.readFully(in)); } catch (IOException e) { throw new ClassNotFoundException(); } @@ -1019,7 +1032,8 @@ public ClassFile2 fetch4(String className, @CheckForNull ClassFile2 referer) thr if (USE_BOOTSTRAP_CLASSLOADER) { ecl = PSEUDO_BOOTSTRAP; } else { - throw new ClassNotFoundException("Bootstrap pseudo-classloader disabled: " + className + " via " + referrerClass); + throw new ClassNotFoundException( + "Bootstrap pseudo-classloader disabled: " + className + " via " + referrerClass); } } @@ -1028,7 +1042,7 @@ public ClassFile2 fetch4(String className, @CheckForNull ClassFile2 referer) thr try { File jar = Which.jarFile(c); - if (jar.isFile()) {// for historical reasons the jarFile method can return a directory + if (jar.isFile()) { // for historical reasons the jarFile method can return a directory Checksum sum = channel.jarLoader.calcChecksum(jar); ResourceImageRef imageRef; @@ -1037,7 +1051,9 @@ public ClassFile2 fetch4(String className, @CheckForNull ClassFile2 referer) thr // send the image as well, so as not to require another call to get this class loaded imageRef = new ResourceImageBoth(urlOfClassFile, sum); } else { // otherwise just send the checksum and save space - imageRef = new ResourceImageInJar(sum, null /* TODO: we need to check if the URL of c points to the expected location of the file */); + imageRef = new ResourceImageInJar( + sum, + null /* TODO: we need to check if the URL of c points to the expected location of the file */); } return new ClassFile2(exportId(ecl, channel), imageRef, referer, c, urlOfClassFile); @@ -1053,7 +1069,9 @@ public ClassFile2 fetch4(String className, @CheckForNull ClassFile2 referer) thr } @Override - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "This is only used for managing the jar cache as files.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "This is only used for managing the jar cache as files.") public Map fetch3(String className) throws ClassNotFoundException { ClassFile2 cf = fetch4(className, null); Map all = new HashMap<>(); @@ -1116,11 +1134,11 @@ public ResourceFile getResource2(String name) throws IOException { private ResourceFile makeResource(String name, URL resource) throws IOException { try { File jar = Which.jarFile(resource, name); - if (jar.isFile()) {// for historical reasons the jarFile method can return a directory + if (jar.isFile()) { // for historical reasons the jarFile method can return a directory Checksum sum = channel.jarLoader.calcChecksum(jar); ResourceImageRef ir; if (!channel.jarLoader.isPresentOnRemote(sum)) { - ir = new ResourceImageBoth(resource, sum); // remote probably doesn't have + ir = new ResourceImageBoth(resource, sum); // remote probably doesn't have } else { ir = new ResourceImageInJar(sum, null); } @@ -1133,7 +1151,8 @@ private ResourceFile makeResource(String name, URL resource) throws IOException } @Override - @SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", + @SuppressFBWarnings( + value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", justification = "Null return value is a part of the public interface") @CheckForNull public byte[] getResource(String name) throws IOException { @@ -1242,7 +1261,7 @@ public String toString() { * resolve back to the instance on the server. */ private static class RemoteIClassLoader implements IClassLoader, SerializableOnlyOverRemoting { - private transient final IClassLoader proxy; + private final transient IClassLoader proxy; private final int oid; private RemoteIClassLoader(int oid, IClassLoader proxy) { @@ -1361,7 +1380,6 @@ public ResourceFile[] getResources2(String name) throws IOException { public String getName() throws IOException { throw new IOException("Cannot getName", cause); } - } private static Iterable analyze(InputStream bytecode) { @@ -1379,7 +1397,8 @@ private static Iterable analyze(InputStream bytecode) { * By default, classes that belong to the bootstrap classloader will NOT be remoted, as each JVM gets its own JRE * and their versions can be potentially different. */ - public static boolean USE_BOOTSTRAP_CLASSLOADER = Boolean.getBoolean(RemoteClassLoader.class.getName() + ".useBootstrapClassLoader"); + public static boolean USE_BOOTSTRAP_CLASSLOADER = + Boolean.getBoolean(RemoteClassLoader.class.getName() + ".useBootstrapClassLoader"); private static final Enumeration EMPTY_ENUMERATION = new Vector().elements(); } diff --git a/src/main/java/hudson/remoting/RemoteInputStream.java b/src/main/java/hudson/remoting/RemoteInputStream.java index 2c29fca49..1a981e65f 100644 --- a/src/main/java/hudson/remoting/RemoteInputStream.java +++ b/src/main/java/hudson/remoting/RemoteInputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -78,21 +78,24 @@ public RemoteInputStream(InputStream core) { */ @Deprecated public RemoteInputStream(InputStream core, boolean autoUnexport) { - this(core, RemoteInputStream.Flag.NOT_GREEDY, autoUnexport ? RemoteInputStream.Flag.NOT_GREEDY : RemoteInputStream.Flag.MANUAL_UNEXPORT); + this( + core, + RemoteInputStream.Flag.NOT_GREEDY, + autoUnexport ? RemoteInputStream.Flag.NOT_GREEDY : RemoteInputStream.Flag.MANUAL_UNEXPORT); } /** * @since 2.35 */ public RemoteInputStream(InputStream core, Flag f) { - this(core,EnumSet.of(f)); + this(core, EnumSet.of(f)); } /** * @since 2.35 */ public RemoteInputStream(InputStream core, Flag f1, Flag f2) { - this(core,EnumSet.of(f1,f2)); + this(core, EnumSet.of(f1, f2)); } /** @@ -101,8 +104,9 @@ public RemoteInputStream(InputStream core, Flag f1, Flag f2) { public RemoteInputStream(InputStream core, Set flags) { this.core = core; greedy = flags.contains(RemoteInputStream.Flag.GREEDY); - if (greedy) + if (greedy) { greedyAt = new Greedy(); + } autoUnexport = !flags.contains(RemoteInputStream.Flag.MANUAL_UNEXPORT); } @@ -118,8 +122,8 @@ private void writeObject(ObjectOutputStream oos) throws IOException { new Thread("RemoteInputStream greedy pump thread: " + greedyAt.print()) { { - setUncaughtExceptionHandler( - (t, e) -> LOGGER.log(Level.SEVERE, "Uncaught exception in RemoteInputStream pump thread " + t, e)); + setUncaughtExceptionHandler((t, e) -> LOGGER.log( + Level.SEVERE, "Uncaught exception in RemoteInputStream pump thread " + t, e)); setDaemon(true); } @@ -131,7 +135,9 @@ public void run() { while (true) { try { len = i.read(buf); - if (len < 0) break; + if (len < 0) { + break; + } } catch (IOException e) { // if we can propagate the error, do so. In any case, give up if (o instanceof ErrorPropagatingOutputStream) { @@ -175,13 +181,15 @@ public void run() { oos.writeInt(id); } - @SuppressFBWarnings(value = "DESERIALIZATION_GADGET", justification = "Serializable only over remoting. Class filtering is done through JEP-200.") + @SuppressFBWarnings( + value = "DESERIALIZATION_GADGET", + justification = "Serializable only over remoting. Class filtering is done through JEP-200.") private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { final Channel channel = getChannelForSerialization(); if (channel.remoteCapability.supportsGreedyRemoteInputStream()) { boolean greedy = ois.readBoolean(); if (greedy) { - Pipe p = (Pipe)ois.readObject(); + Pipe p = (Pipe) ois.readObject(); this.core = p.getIn(); return; } @@ -258,11 +266,11 @@ public String print() { } } -// -// -// delegation to core -// -// + // + // + // delegation to core + // + // @Override public int read() throws IOException { diff --git a/src/main/java/hudson/remoting/RemoteInvocationHandler.java b/src/main/java/hudson/remoting/RemoteInvocationHandler.java index d37ae062a..802e41a6a 100644 --- a/src/main/java/hudson/remoting/RemoteInvocationHandler.java +++ b/src/main/java/hudson/remoting/RemoteInvocationHandler.java @@ -58,7 +58,7 @@ * * @author Kohsuke Kawaguchi */ -//TODO: Likely should be serializable over Remoting logic, but this class has protection logic +// TODO: Likely should be serializable over Remoting logic, but this class has protection logic // Use-cases need to be investigated @SuppressFBWarnings(value = "DESERIALIZATION_GADGET", justification = "This class has protection logic.") final class RemoteInvocationHandler implements InvocationHandler, Serializable { @@ -132,9 +132,14 @@ final class RemoteInvocationHandler implements InvocationHandler, Serializable { /** * Creates a proxy that wraps an existing OID on the remote. */ - private RemoteInvocationHandler(Channel channel, int id, boolean userProxy, - boolean autoUnexportByCaller, boolean userSpace, - Class proxyType, boolean recordCreatedAt) { + private RemoteInvocationHandler( + Channel channel, + int id, + boolean userProxy, + boolean autoUnexportByCaller, + boolean userSpace, + Class proxyType, + boolean recordCreatedAt) { this.channel = channel == null ? null : channel.ref(); this.oid = id; this.userProxy = userProxy; @@ -152,18 +157,27 @@ private RemoteInvocationHandler(Channel channel, int id, boolean userProxy, * @param recordCreatedAt as in {@link Command#Command(boolean)} */ @NonNull - static T wrap(Channel channel, int id, Class type, boolean userProxy, boolean autoUnexportByCaller, boolean userSpace, boolean recordCreatedAt) { + static T wrap( + Channel channel, + int id, + Class type, + boolean userProxy, + boolean autoUnexportByCaller, + boolean userSpace, + boolean recordCreatedAt) { ClassLoader cl = type.getClassLoader(); // if the type is a JDK-defined type, classloader should be for IReadResolve - if(cl==null || cl==ClassLoader.getSystemClassLoader()) + if (cl == null || cl == ClassLoader.getSystemClassLoader()) { cl = IReadResolve.class.getClassLoader(); - RemoteInvocationHandler handler = new RemoteInvocationHandler(channel, id, userProxy, autoUnexportByCaller, userSpace, type, recordCreatedAt); + } + RemoteInvocationHandler handler = new RemoteInvocationHandler( + channel, id, userProxy, autoUnexportByCaller, userSpace, type, recordCreatedAt); if (channel != null) { if (!autoUnexportByCaller) { UNEXPORTER.watch(handler); } } - return type.cast(Proxy.newProxyInstance(cl, new Class[]{type, IReadResolve.class}, handler)); + return type.cast(Proxy.newProxyInstance(cl, new Class[] {type, IReadResolve.class}, handler)); } /** @@ -210,7 +224,7 @@ private Channel channelOrFail() throws IOException { } Channel c = ch.channel(); if (c == null) { - throw new IOException("Backing channel '"+ch.name()+"' is disconnected.",ch.cause()); + throw new IOException("Backing channel '" + ch.name() + "' is disconnected.", ch.cause()); } return c; } @@ -226,8 +240,9 @@ public static int unwrap(Object proxy, Channel src) { InvocationHandler h = Proxy.getInvocationHandler(proxy); if (h instanceof RemoteInvocationHandler) { RemoteInvocationHandler rih = (RemoteInvocationHandler) h; - if(rih.channel()==src) + if (rih.channel() == src) { return rih.oid; + } } return -1; } @@ -249,23 +264,29 @@ public static Channel unwrap(Object proxy) { @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if(method.getDeclaringClass()==IReadResolve.class) { + if (method.getDeclaringClass() == IReadResolve.class) { // readResolve on the proxy. // if we are going back to where we came from, replace the proxy by the real object - if(goingHome) return Channel.currentOrFail().getExportedObject(oid); - else return proxy; + if (goingHome) { + return Channel.currentOrFail().getExportedObject(oid); + } else { + return proxy; + } } - if(channel==null) + if (channel == null) { throw new IllegalStateException("proxy is not connected to a channel"); + } - if(args==null) args = EMPTY_ARRAY; + if (args == null) { + args = EMPTY_ARRAY; + } Class dc = method.getDeclaringClass(); - if(dc ==Object.class) { + if (dc == Object.class) { // handle equals and hashCode by ourselves try { - return method.invoke(this,args); + return method.invoke(this, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } @@ -278,21 +299,29 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl ? new UserRPCRequest(oid, method, args, userProxy ? dc.getClassLoader() : null, recordCreatedAt) : new RPCRequest(oid, method, args, userProxy ? dc.getClassLoader() : null, recordCreatedAt); try { - if(userProxy) { - if (async) channelOrFail().callAsync(req); - else return channelOrFail().call(req); + if (userProxy) { + if (async) { + channelOrFail().callAsync(req); + } else { + return channelOrFail().call(req); + } } else { - if (async) req.callAsync(channelOrFail()); - else return req.call(channelOrFail()); + if (async) { + req.callAsync(channelOrFail()); + } else { + return req.call(channelOrFail()); + } } return null; } catch (Throwable e) { for (Class exc : method.getExceptionTypes()) { - if (exc.isInstance(e)) - throw e; // signature explicitly lists this exception + if (exc.isInstance(e)) { + throw e; // signature explicitly lists this exception + } + } + if (e instanceof RuntimeException || e instanceof Error) { + throw e; // these can be thrown from any methods } - if (e instanceof RuntimeException || e instanceof Error) - throw e; // these can be thrown from any methods // if the thrown exception type isn't compatible with the method signature // wrap it to RuntimeException to avoid UndeclaredThrowableException @@ -319,7 +348,7 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound } private void writeObject(ObjectOutputStream oos) throws IOException { - goingHome = channel!=null; + goingHome = channel != null; oos.defaultWriteObject(); } @@ -328,16 +357,20 @@ private void writeObject(ObjectOutputStream oos) throws IOException { */ @Override public boolean equals(Object o) { - if(o!=null && Proxy.isProxyClass(o.getClass())) + if (o != null && Proxy.isProxyClass(o.getClass())) { o = Proxy.getInvocationHandler(o); + } - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } RemoteInvocationHandler that = (RemoteInvocationHandler) o; - return this.oid==that.oid && this.channel==that.channel; - + return this.oid == that.oid && this.channel == that.channel; } @Override @@ -373,8 +406,8 @@ private static class PhantomReferenceImpl extends PhantomReference referenceQueue) { + private PhantomReferenceImpl( + RemoteInvocationHandler referent, ReferenceQueue referenceQueue) { super(referent, referenceQueue); this.oid = referent.oid; this.origin = Unexporter.retainOrigin ? referent.origin : null; @@ -450,29 +483,28 @@ private static class Unexporter implements Runnable { * even if this means that the sweep gets delayed. This constant allows for tuning of the batch size, * if the current recommendation proves insufficient in real world scenarios. */ - private static final int batchSize = Math.max(10, Math.min(10000, Integer.getInteger( - Unexporter.class.getName() + ".batchSize", 256))); + private static final int batchSize = + Math.max(10, Math.min(10000, Integer.getInteger(Unexporter.class.getName() + ".batchSize", 256))); /** * The decay factor for a rolling average that expects to be updated every {@link #measureInterval} and * should have a lifetime of approx 1 minute. */ - private static final double m1Alpha = 1.0 - Math.exp( -measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(1)); + private static final double m1Alpha = 1.0 - Math.exp(-measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(1)); /** * The decay factor for a rolling average that expects to be updated every {@link #measureInterval} and * should have a lifetime of approx 5 minutes. */ - private static final double m5Alpha = 1.0 - Math.exp( -measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(5)); + private static final double m5Alpha = 1.0 - Math.exp(-measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(5)); /** * The decay factor for a rolling average that expects to be updated every {@link #measureInterval} and * should have a lifetime of approx 15 minutes. */ - private static final double m15Alpha = 1.0 - Math.exp( -measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(15)); + private static final double m15Alpha = 1.0 - Math.exp(-measureInterval * 1.0 / TimeUnit.MINUTES.toNanos(15)); /** * Our executor service, we use at most one thread for all {@link Channel} instances in the current classloader. */ private final ExecutorService svc = new AtmostOneThreadExecutor( - new NamingThreadFactory(new DaemonThreadFactory(), RemoteInvocationHandler.class.getSimpleName()) - ); + new NamingThreadFactory(new DaemonThreadFactory(), RemoteInvocationHandler.class.getSimpleName())); /** * Flag to track that {@link #UNEXPORTER} has been queued for execution. */ @@ -489,8 +521,7 @@ private static class Unexporter implements Runnable { /** * The "live" {@link PhantomReferenceImpl} instances for each active {@link Channel}. */ - private final ConcurrentMap> referenceLists - = new ConcurrentHashMap<>(); + private final ConcurrentMap> referenceLists = new ConcurrentHashMap<>(); /** * The 1 minute rolling average. */ @@ -562,10 +593,10 @@ private static long secSysPropAsNanos(String name, double min, double def, doubl try { seconds = value == null || value.isEmpty() ? def : Double.parseDouble(value); } catch (NumberFormatException e) { - logger.log(Level.WARNING, + logger.log( + Level.WARNING, String.format("The system property '%s'='%s' could not be parsed", name, value), - e - ); + e); seconds = def; } return (long) (1.0e9 * Math.max(min, Math.min(max, seconds))); @@ -596,7 +627,8 @@ public void run() { int batchIndex = 0; while (nextSweep - System.nanoTime() > 0) { while (batchIndex < batch.length - && (remaining = (nextSweep - System.nanoTime())/ NANOSECONDS_PER_MILLISECOND) > 0) { + && (remaining = (nextSweep - System.nanoTime()) / NANOSECONDS_PER_MILLISECOND) + > 0) { Reference ref = queue.remove(remaining); if (ref == null) { break; @@ -613,12 +645,20 @@ public void run() { } catch (ChannelClosedException e) { // ignore, the cleanup is a no-op } catch (Error e) { - logger.log(Level.SEVERE, String.format("Couldn't clean up oid=%d from %s", - batch[index].oid, batch[index].origin), e); + logger.log( + Level.SEVERE, + String.format( + "Couldn't clean up oid=%d from %s", + batch[index].oid, batch[index].origin), + e); throw e; // pass on as there is nothing we can do with an error } catch (Throwable e) { - logger.log(Level.WARNING, String.format("Couldn't clean up oid=%d from %s", - batch[index].oid, batch[index].origin), e); + logger.log( + Level.WARNING, + String.format( + "Couldn't clean up oid=%d from %s", + batch[index].oid, batch[index].origin), + e); } finally { if (channelRef != null) { final List referenceList = referenceLists.get(channelRef); @@ -641,9 +681,9 @@ public void run() { nextSweep = System.nanoTime() + sweepInterval; // purge any dead channels, it does not matter if we spend a long time here as we are // removing future potential work for us from ever entering the queue and freeing garbage - for (Iterator>> - iterator = referenceLists.entrySet().iterator(); - iterator.hasNext(); ) { + for (Iterator>> iterator = + referenceLists.entrySet().iterator(); + iterator.hasNext(); ) { final Map.Entry> entry = iterator.next(); final Channel.Ref r = entry.getKey(); if (r == null || r.channel() == null) { @@ -697,12 +737,14 @@ private void reportStats() { double tStd = tCount <= 0 || tVarTimesCount < 0 ? 0 : Math.sqrt(tVarTimesCount / tCount); Level targetLevel = m15Avg > 100 ? Level.INFO : m15Avg > 50 ? Level.FINE : Level.FINER; if (logger.isLoggable(targetLevel)) { - logger.log(targetLevel, () -> String.format("rate(1min) = %.1f±%.1f/sec; " - + "rate(5min) = %.1f±%.1f/sec; " - + "rate(15min) = %.1f±%.1f/sec; " - + "rate(total) = %.1f±%.1f/sec; N = %d", - m1Avg, m1Std, m5Avg, m5Std, m15Avg, m15Std, tAvg, tStd, tCount - )); + logger.log( + targetLevel, + () -> String.format( + "rate(1min) = %.1f±%.1f/sec; " + + "rate(5min) = %.1f±%.1f/sec; " + + "rate(15min) = %.1f±%.1f/sec; " + + "rate(total) = %.1f±%.1f/sec; N = %d", + m1Avg, m1Std, m5Avg, m5Std, m15Avg, m15Std, tAvg, tStd, tCount)); } if (tCount < 10L) { // less than 10 reports is too soon to start alerting the user @@ -711,64 +753,78 @@ private void reportStats() { // now test if the average is above 100/sec if (m15Std > 1 && 100 < m15Avg - 2 * m15Std) { if (tStd > 1 && 100 < tAvg - 2 * tStd) { - logger.log(Level.SEVERE, - String.format(retainOrigin ? - "The all time average rate is %.1f±%.1f/sec. " - + "The 15 minute average rate is %.1f±%.1f/sec. " - + "At the 95% confidence level both are above 100.0/sec. " - + "If this message is repeated often in the logs then PLEASE " - + "seriously consider setting system property 'hudson.remoting" - + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " - + "'false' to trade debug diagnostics for reduced memory " - + "pressure." - : "The all time average rate is %.1f±%.1f/sec. " + logger.log( + Level.SEVERE, + String.format( + retainOrigin + ? "The all time average rate is %.1f±%.1f/sec. " + + "The 15 minute average rate is %.1f±%.1f/sec. " + + "At the 95% confidence level both are above 100.0/sec. " + + "If this message is repeated often in the logs then PLEASE " + + "seriously consider setting system property 'hudson.remoting" + + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " + + "'false' to trade debug diagnostics for reduced memory " + + "pressure." + : "The all time average rate is %.1f±%.1f/sec. " + "The 15 minute average rate is %.1f±%.1f/sec. " + "At the 95%% confidence level both are above 100.0/sec. ", - tAvg, tStd, m15Avg, m15Std)); + tAvg, + tStd, + m15Avg, + m15Std)); return; } - logger.log(Level.WARNING, - String.format(retainOrigin ? - "The 15 minute average rate is %.1f±%.1f/sec. " - + "At the 95% confidence level this is above 100.0/sec. " - + "If this message is repeated often in the logs then very " - + "seriously consider setting system property 'hudson.remoting" - + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " - + "'false' to trade debug diagnostics for reduced memory " - + "pressure." - : "The 15 minute average rate is %.1f±%.1f/sec. " - + "At the 95%% confidence level this is above 100.0/sec. ", - m15Avg, m15Std)); + logger.log( + Level.WARNING, + String.format( + retainOrigin + ? "The 15 minute average rate is %.1f±%.1f/sec. " + + "At the 95% confidence level this is above 100.0/sec. " + + "If this message is repeated often in the logs then very " + + "seriously consider setting system property 'hudson.remoting" + + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " + + "'false' to trade debug diagnostics for reduced memory " + + "pressure." + : "The 15 minute average rate is %.1f±%.1f/sec. " + + "At the 95%% confidence level this is above 100.0/sec. ", + m15Avg, + m15Std)); return; } if (m5Std > 1 && 100 < m5Avg - 2 * m5Std) { - logger.log(Level.WARNING, - String.format(retainOrigin ? - "The 5 minute average rate is %.1f±%.1f/sec. " - + "At the 95% confidence level this is above 100.0/sec. " - + "If this message is repeated often in the logs then " - + "seriously consider setting system property 'hudson.remoting" - + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " - + "'false' to trade debug diagnostics for reduced memory " - + "pressure." - : "The 5 minute average rate is %.1f±%.1f/sec. " - + "At the 95%% confidence level this is above 100.0/sec. ", - m5Avg, m5Std)); + logger.log( + Level.WARNING, + String.format( + retainOrigin + ? "The 5 minute average rate is %.1f±%.1f/sec. " + + "At the 95% confidence level this is above 100.0/sec. " + + "If this message is repeated often in the logs then " + + "seriously consider setting system property 'hudson.remoting" + + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " + + "'false' to trade debug diagnostics for reduced memory " + + "pressure." + : "The 5 minute average rate is %.1f±%.1f/sec. " + + "At the 95%% confidence level this is above 100.0/sec. ", + m5Avg, + m5Std)); return; } if (m1Std > 1 && 100 < m1Avg - 2 * m1Std) { - logger.log(Level.INFO, - String.format(retainOrigin ? - "The 1 minute average rate is %.1f±%.1f/sec. " - + "At the 95% confidence level this is above 100.0/sec. " - + "If this message is repeated often in the logs then " - + "consider setting system property 'hudson.remoting" - + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " - + "'false' to trade debug diagnostics for reduced memory " - + "pressure." - : "The 1 minute average rate is %.1f±%.1f/sec. " - + "At the 95%% confidence level this is above 100.0/sec. ", - m1Avg, m1Std)); + logger.log( + Level.INFO, + String.format( + retainOrigin + ? "The 1 minute average rate is %.1f±%.1f/sec. " + + "At the 95% confidence level this is above 100.0/sec. " + + "If this message is repeated often in the logs then " + + "consider setting system property 'hudson.remoting" + + ".RemoteInvocationHandler.Unexporter.retainOrigin' to " + + "'false' to trade debug diagnostics for reduced memory " + + "pressure." + : "The 1 minute average rate is %.1f±%.1f/sec. " + + "At the 95%% confidence level this is above 100.0/sec. ", + m1Avg, + m1Std)); } } @@ -848,7 +904,8 @@ private void onChannelTermination(Channel channel) { * * @see UserRPCRequest */ - static class RPCRequest extends Request implements DelegatingCallable, InternalCallable { + static class RPCRequest extends Request + implements DelegatingCallable, InternalCallable { // this callable only executes public methods exported by this side, so these methods are assumed to be safe /** * Target object id to invoke. @@ -878,10 +935,13 @@ static class RPCRequest extends Request implements Deleg * to be used to serialize the request and the response. */ @CheckForNull - @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "We're fine with the default null on the recipient side") + @SuppressFBWarnings( + value = "SE_TRANSIENT_FIELD_NOT_RESTORED", + justification = "We're fine with the default null on the recipient side") private final transient ClassLoader classLoader; - private RPCRequest(int oid, Method m, Object[] arguments, @CheckForNull ClassLoader cl, boolean recordCreatedAt) { + private RPCRequest( + int oid, Method m, Object[] arguments, @CheckForNull ClassLoader cl, boolean recordCreatedAt) { super(recordCreatedAt); this.oid = oid; this.arguments = arguments; @@ -891,8 +951,9 @@ private RPCRequest(int oid, Method m, Object[] arguments, @CheckForNull ClassLoa this.types = new String[arguments.length]; Class[] params = m.getParameterTypes(); - for( int i=0; i[] clazz = channel.getExportedTypes(oid); try { Method m = choose(clazz); - if(m==null) - throw new IllegalStateException("Unable to call " + methodName + ". No matching method found in " + Arrays.toString(clazz) + " for " + o); - m.setAccessible(true); // in case the class is not public + if (m == null) { + throw new IllegalStateException("Unable to call " + methodName + ". No matching method found in " + + Arrays.toString(clazz) + " for " + o); + } + m.setAccessible(true); // in case the class is not public Object r; try { r = m.invoke(o, arguments); } catch (IllegalArgumentException x) { - throw new RemotingSystemException("failed to invoke " + m + " on " + o + Arrays.toString(arguments), x); + throw new RemotingSystemException( + "failed to invoke " + m + " on " + o + Arrays.toString(arguments), x); } - if (r==null || r instanceof Serializable) + if (r == null || r instanceof Serializable) { return (Serializable) r; - else - throw new RemotingSystemException(new ClassCastException(r.getClass()+" is returned from "+m+" on "+o.getClass()+" but it's not serializable")); + } else { + throw new RemotingSystemException(new ClassCastException(r.getClass() + " is returned from " + m + + " on " + o.getClass() + " but it's not serializable")); + } } catch (InvocationTargetException e) { throw e.getTargetException(); } @@ -936,17 +1003,20 @@ protected Serializable perform(@NonNull Channel channel) throws Throwable { * Chooses the method to invoke. */ private Method choose(Class[] interfaces) { - for(Class clazz: interfaces) { + for (Class clazz : interfaces) { OUTER: for (Method m : clazz.getMethods()) { - if (!m.getName().equals(methodName)) + if (!m.getName().equals(methodName)) { continue; + } Class[] paramTypes = m.getParameterTypes(); - if (paramTypes.length != arguments.length) + if (paramTypes.length != arguments.length) { continue; + } for (int i = 0; i < types.length; i++) { - if (!types[i].equals(paramTypes[i].getName())) + if (!types[i].equals(paramTypes[i].getName())) { continue OUTER; + } } return m; } @@ -960,7 +1030,12 @@ Object[] getArguments() { // for debugging @Override public String toString() { - StringBuilder b = new StringBuilder(getClass().getSimpleName()).append(':').append(declaringClassName).append('.').append(methodName).append('['); + StringBuilder b = new StringBuilder(getClass().getSimpleName()) + .append(':') + .append(declaringClassName) + .append('.') + .append(methodName) + .append('['); for (int i = 0; i < types.length; i++) { if (i > 0) { b.append(','); @@ -1000,8 +1075,11 @@ public void checkIfCanBeExecutedOnChannel(@NonNull Channel channel) throws IOExc // We also do not want to run UserRequests when the channel is being closed if (channel.isClosingOrClosed()) { - throw new ChannelClosedException(channel, "The request cannot be executed on channel " + channel + ". " - + "The channel is closing down or has closed down", channel.getCloseRequestCause()); + throw new ChannelClosedException( + channel, + "The request cannot be executed on channel " + channel + ". " + + "The channel is closing down or has closed down", + channel.getCloseRequestCause()); } } } diff --git a/src/main/java/hudson/remoting/RemoteOutputStream.java b/src/main/java/hudson/remoting/RemoteOutputStream.java index 6d4cd175f..5dd2cdae7 100644 --- a/src/main/java/hudson/remoting/RemoteOutputStream.java +++ b/src/main/java/hudson/remoting/RemoteOutputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -74,13 +74,16 @@ public final class RemoteOutputStream extends OutputStream implements Serializab private transient OutputStream core; public RemoteOutputStream(OutputStream core) { - if(core==null) + if (core == null) { throw new IllegalArgumentException(); + } this.core = core; } private void writeObject(ObjectOutputStream oos) throws IOException { - int id = getChannelForSerialization().internalExport(OutputStream.class, core, false); // this export is unexported in ProxyOutputStream.finalize() + int id = getChannelForSerialization() + .internalExport( + OutputStream.class, core, false); // this export is unexported in ProxyOutputStream.finalize() oos.writeInt(id); } @@ -90,12 +93,11 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound private static final long serialVersionUID = 1L; - -// -// -// delegation to core -// -// + // + // + // delegation to core + // + // @Override public void write(int b) throws IOException { core.write(b); diff --git a/src/main/java/hudson/remoting/RemoteWriter.java b/src/main/java/hudson/remoting/RemoteWriter.java index 49fd5b7b6..840a804a4 100644 --- a/src/main/java/hudson/remoting/RemoteWriter.java +++ b/src/main/java/hudson/remoting/RemoteWriter.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -64,7 +64,8 @@ public RemoteWriter(Writer core) { } private void writeObject(ObjectOutputStream oos) throws IOException { - int id = getChannelForSerialization().internalExport(Writer.class, core, false); // this export is unexported in ProxyWriter.finalize() + int id = getChannelForSerialization() + .internalExport(Writer.class, core, false); // this export is unexported in ProxyWriter.finalize() oos.writeInt(id); } @@ -75,12 +76,11 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound private static final long serialVersionUID = 1L; - -// -// -// delegation to core -// -// + // + // + // delegation to core + // + // @Override public void write(int c) throws IOException { core.write(c); diff --git a/src/main/java/hudson/remoting/Request.java b/src/main/java/hudson/remoting/Request.java index 6a44339e7..06076ea8a 100644 --- a/src/main/java/hudson/remoting/Request.java +++ b/src/main/java/hudson/remoting/Request.java @@ -47,7 +47,7 @@ * @see Response * @since 3.17 */ -public abstract class Request extends Command { +public abstract class Request extends Command { /** * Executed on a remote system to perform the task. * @@ -79,20 +79,20 @@ public abstract class Request ex */ private int lastIoId; - private volatile Response response; + private volatile Response response; transient long startTime; /** * While executing the call this is set to the handle of the execution. */ - volatile transient Future future; + transient volatile Future future; /** * Set by {@link Response} to point to the I/O ID issued from the other side that this request needs to * synchronize with, before declaring the call to be complete. */ - /*package*/ volatile transient int responseIoId; + /*package*/ transient volatile int responseIoId; /** * @@ -101,16 +101,18 @@ public abstract class Request ex * with earlier version of remoting without losing the original fix to JENKINS-9189 completely. */ @Deprecated - /*package*/ volatile transient Future lastIo; + /*package*/ transient volatile Future lastIo; Request() { this(true); } - @SuppressFBWarnings(value="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification="That is why we synchronize on the class.") + @SuppressFBWarnings( + value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", + justification = "That is why we synchronize on the class.") Request(boolean recordCreatedAt) { super(recordCreatedAt); - synchronized(Request.class) { + synchronized (Request.class) { id = nextId++; } } @@ -151,65 +153,74 @@ final RSP call(Channel channel) throws EXC, InterruptedException, IOException { String name = t.getName(); try { t.setName(name + " / waiting for " + channel.getName() + " id=" + id); - checkIfCanBeExecutedOnChannel(channel); - lastIoId = channel.lastIoId(); - - // Channel.send() locks channel, and there are other call sequences - // ( like Channel.terminate()->Request.abort()->Request.onCompleted() ) - // that locks channel -> request, so lock objects in the same order - synchronized(channel) { - synchronized(this) { - response=null; - - channel.pendingCalls.put(id,this); - startTime = System.nanoTime(); - channel.send(this); + checkIfCanBeExecutedOnChannel(channel); + lastIoId = channel.lastIoId(); + + // Channel.send() locks channel, and there are other call sequences + // ( like Channel.terminate()->Request.abort()->Request.onCompleted() ) + // that locks channel -> request, so lock objects in the same order + synchronized (channel) { + synchronized (this) { + response = null; + + channel.pendingCalls.put(id, this); + startTime = System.nanoTime(); + channel.send(this); + } } - } - try { - synchronized(this) { - while(response==null && !channel.isInClosed()) + try { + synchronized (this) { + while (response == null && !channel.isInClosed()) { // I don't know exactly when this can happen, as pendingCalls are cleaned up by Channel, - // but in production I've observed that in rare occasion it can block forever, even after a channel + // but in production I've observed that in rare occasion it can block forever, even after a + // channel // is gone. So be defensive against that. - wait(30*1000); + wait(30 * 1000); + } - if (response==null) + if (response == null) { // channel is closed and we still don't have a response throw new RequestAbortedException(null); + } + + if (lastIo != null) { + try { + lastIo.get(); + } catch (ExecutionException e) { + // ignore the I/O error + } + } - if (lastIo != null) try { - lastIo.get(); + channel.pipeWriter.get(responseIoId).get(); } catch (ExecutionException e) { // ignore the I/O error } - try { - channel.pipeWriter.get(responseIoId).get(); - } catch (ExecutionException e) { - // ignore the I/O error - } + Throwable exc = response.exception; - Throwable exc = response.exception; + if (exc != null) { + channel.attachCallSiteStackTrace(exc); + throw (EXC) exc; // some versions of JDK fails to compile this line. If so, upgrade your JDK. + } - if (exc!=null) { - channel.attachCallSiteStackTrace(exc); - throw (EXC)exc; // some versions of JDK fails to compile this line. If so, upgrade your JDK. + return response.returnValue; } - - return response.returnValue; - } - } catch (InterruptedException e) { - // if we are cancelled, abort the remote computation, too. - // do this outside the "synchronized(this)" block to prevent locking Request and Channel in a wrong order. - synchronized (channel) { // ... so that the close check and send won't be interrupted in the middle by a close - if (!channel.isOutClosed()) - channel.send(new Cancel(id)); // only send a cancel if we can, or else ChannelClosedException will mask the original cause + } catch (InterruptedException e) { + // if we are cancelled, abort the remote computation, too. + // do this outside the "synchronized(this)" block to prevent locking Request and Channel in a wrong + // order. + synchronized ( + channel) { // ... so that the close check and send won't be interrupted in the middle by a close + if (!channel.isOutClosed()) { + channel.send(new Cancel( + id)); // only send a cancel if we can, or else ChannelClosedException will mask the + // original cause + } + } + throw e; } - throw e; - } } finally { t.setName(name); } @@ -229,10 +240,10 @@ final RSP call(Channel channel) throws EXC, InterruptedException, IOException { final hudson.remoting.Future callAsync(final Channel channel) throws IOException { checkIfCanBeExecutedOnChannel(channel); - response=null; + response = null; lastIoId = channel.lastIoId(); - channel.pendingCalls.put(id,this); + channel.pendingCalls.put(id, this); startTime = System.nanoTime(); channel.send(this); @@ -301,7 +312,8 @@ public RSP get() throws InterruptedException, ExecutionException { } @Override - public RSP get(long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + public RSP get(long timeout, @NonNull TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { synchronized (Request.this) { // wait until the response arrives // Note that the wait method can wake up for no reasons at all (AKA spurious wakeup), @@ -317,11 +329,13 @@ public RSP get(long timeout, @NonNull TimeUnit unit) throws InterruptedException Request.this.wait(Math.min(30 * 1000, Math.max(1, TimeUnit.NANOSECONDS.toMillis(end - now)))); now = System.nanoTime(); } - if (response == null) + if (response == null) { throw new TimeoutException(); + } - if (response.exception != null) + if (response.exception != null) { throw new ExecutionException(response.exception); + } return response.returnValue; } @@ -329,11 +343,10 @@ public RSP get(long timeout, @NonNull TimeUnit unit) throws InterruptedException }; } - /** * Called by the {@link Response} when we received it. */ - /*package*/ synchronized void onCompleted(Response response) { + /*package*/ synchronized void onCompleted(Response response) { this.response = response; notifyAll(); } @@ -350,21 +363,23 @@ public RSP get(long timeout, @NonNull TimeUnit unit) throws InterruptedException */ @Override final void execute(final Channel channel) { - channel.executingCalls.put(id,this); + channel.executingCalls.put(id, this); future = channel.executor.submit(new Runnable() { private int startIoId; private int calcLastIoId() { int endIoId = channel.lastIoId(); - if (startIoId==endIoId) return 0; + if (startIoId == endIoId) { + return 0; + } return endIoId; } @Override public void run() { String oldThreadName = Thread.currentThread().getName(); - Thread.currentThread().setName(oldThreadName+" for "+channel.getName()+" id="+id); + Thread.currentThread().setName(oldThreadName + " for " + channel.getName() + " id=" + id); try { Command rsp; CURRENT.set(Request.this); @@ -382,7 +397,7 @@ public void run() { } finally { CURRENT.remove(); } - if(chainCause) { + if (chainCause) { rsp.chainCause(createdAt); } @@ -394,7 +409,8 @@ public void run() { // TODO if this is from CloseCommand reduce level to FINE logger.info(() -> "Failed to send back a reply to the request " + Request.this + ": " + e); } else { - logger.log(Level.WARNING, e, () -> "Failed to send back a reply to the request " + Request.this); + logger.log( + Level.WARNING, e, () -> "Failed to send back a reply to the request " + Request.this); } } finally { channel.executingCalls.remove(id); @@ -407,7 +423,7 @@ public void run() { /** * Next request ID. */ - private static int nextId=0; + private static int nextId = 0; private static final long serialVersionUID = 1L; @@ -417,7 +433,7 @@ public void run() { * Set to true to chain {@link Command#createdAt} to track request/response relationship. * This will substantially increase the network traffic, but useful for debugging. */ - static boolean chainCause = Boolean.getBoolean(Request.class.getName()+".chainCause"); + static boolean chainCause = Boolean.getBoolean(Request.class.getName() + ".chainCause"); /** * Set to the {@link Request} object during {@linkplain #perform(Channel) the execution of the call}. @@ -431,7 +447,7 @@ public void run() { /*package*/ static int getCurrentRequestId() { Request r = CURRENT.get(); - return r!=null ? r.id : 0; + return r != null ? r.id : 0; } /** @@ -446,10 +462,14 @@ private static final class Cancel extends Command { @Override protected void execute(Channel channel) { - Request r = channel.executingCalls.get(id); - if(r==null) return; // already completed + Request r = channel.executingCalls.get(id); + if (r == null) { + return; // already completed + } Future f = r.future; - if(f!=null) f.cancel(true); + if (f != null) { + f.cancel(true); + } } @Override diff --git a/src/main/java/hudson/remoting/RequestAbortedException.java b/src/main/java/hudson/remoting/RequestAbortedException.java index dc491bb78..fb689f4af 100644 --- a/src/main/java/hudson/remoting/RequestAbortedException.java +++ b/src/main/java/hudson/remoting/RequestAbortedException.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/hudson/remoting/ResourceImageBoth.java b/src/main/java/hudson/remoting/ResourceImageBoth.java index f5982b618..9fac08a9c 100644 --- a/src/main/java/hudson/remoting/ResourceImageBoth.java +++ b/src/main/java/hudson/remoting/ResourceImageBoth.java @@ -11,7 +11,7 @@ * @author Kohsuke Kawaguchi */ class ResourceImageBoth extends ResourceImageDirect { - final long sum1,sum2; + final long sum1, sum2; public ResourceImageBoth(URL resource, Checksum sum) throws IOException { super(resource); @@ -28,15 +28,16 @@ Future resolve(Channel channel, String resourcePath) throws IOException, @Override Future resolveURL(Channel channel, String resourcePath) throws IOException, InterruptedException { Future f = initiateJarRetrieval(channel); - if (f.isDone()) // prefer using the jar URL if the stuff is already available - return new ResourceImageInJar(sum1,sum2,null).resolveURL(channel,resourcePath); - else + if (f.isDone()) { // prefer using the jar URL if the stuff is already available + return new ResourceImageInJar(sum1, sum2, null).resolveURL(channel, resourcePath); + } else { // prefer using the jar URL if the stuff is already available return super.resolveURL(channel, resourcePath); + } } /** * Starts JAR retrieval over the channel. - * + * * @param channel Channel instance * @return Future object. In the case of error the diagnostics info will be sent to {@link #LOGGER}. */ @@ -44,7 +45,8 @@ Future resolveURL(Channel channel, String resourcePath) throws IOExcepti private Future initiateJarRetrieval(@NonNull Channel channel) throws IOException, InterruptedException { JarCache c = channel.getJarCache(); if (c == null) { - throw new IOException("Failed to initiate retrieval. JAR Cache is disabled for the channel " + channel.getName()); + throw new IOException( + "Failed to initiate retrieval. JAR Cache is disabled for the channel " + channel.getName()); } try { diff --git a/src/main/java/hudson/remoting/ResourceImageDirect.java b/src/main/java/hudson/remoting/ResourceImageDirect.java index b9e2a7daf..2be4593d7 100644 --- a/src/main/java/hudson/remoting/ResourceImageDirect.java +++ b/src/main/java/hudson/remoting/ResourceImageDirect.java @@ -1,6 +1,5 @@ package hudson.remoting; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; @@ -17,7 +16,9 @@ * * @author Kohsuke Kawaguchi */ -@SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Used by the agent as part of jar cache management.") +@SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "Used by the agent as part of jar cache management.") class ResourceImageDirect extends ResourceImageRef { /** * The actual resource. @@ -34,7 +35,7 @@ class ResourceImageDirect extends ResourceImageRef { @Override Future resolve(Channel channel, String resourcePath) throws IOException, InterruptedException { - LOGGER.log(Level.FINE, resourcePath+" image is direct"); + LOGGER.log(Level.FINE, resourcePath + " image is direct"); return CompletableFuture.completedFuture(payload); } diff --git a/src/main/java/hudson/remoting/ResourceImageInJar.java b/src/main/java/hudson/remoting/ResourceImageInJar.java index ec9f1fc8a..9b32f071a 100644 --- a/src/main/java/hudson/remoting/ResourceImageInJar.java +++ b/src/main/java/hudson/remoting/ResourceImageInJar.java @@ -23,7 +23,7 @@ class ResourceImageInJar extends ResourceImageRef { /** * Check sum of the jar file that contains the resource. */ - final long sum1,sum2; + final long sum1, sum2; /** * This field is null if the resource being requested is in the 'sane' location inside the jar file @@ -39,7 +39,7 @@ class ResourceImageInJar extends ResourceImageRef { } ResourceImageInJar(Checksum sum, String path) { - this(sum.sum1,sum.sum2,path); + this(sum.sum1, sum.sum2, path); } @Override @@ -47,7 +47,9 @@ Future resolve(Channel channel, final String resourcePath) throws IOExce return _resolveJarURL(channel).thenApply(jar -> readContents(jar, resourcePath)); } - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "This is only used for managing the jar cache as files.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "This is only used for managing the jar cache as files.") private byte[] readContents(URL jar, String resourcePath) { try (InputStream in = toResourceURL(jar, resourcePath).openStream()) { return Util.readFully(in); @@ -71,27 +73,30 @@ private URLish getUrlish(URL jar, String resourcePath) { @NonNull private URL toResourceURL(URL jar, String resourcePath) throws IOException { - if (path!=null) + if (path != null) { resourcePath = path; + } /* - James Nord & Kohsuke: - Note that when we open a stream from this jar:// URL, it internally caches - open jar file (see sun.net.www.protocol.jar.JarURLConnection.JarURLInputStream.close()) - and leave it open. During unit test, this pins the file, and it prevents the test tear down code - from deleting the file. - */ - return new URL("jar:"+ jar +"!/"+resourcePath); + James Nord & Kohsuke: + Note that when we open a stream from this jar:// URL, it internally caches + open jar file (see sun.net.www.protocol.jar.JarURLConnection.JarURLInputStream.close()) + and leave it open. During unit test, this pins the file, and it prevents the test tear down code + from deleting the file. + */ + return new URL("jar:" + jar + "!/" + resourcePath); } CompletableFuture _resolveJarURL(Channel channel) throws IOException, InterruptedException { JarCache c = channel.getJarCache(); if (c == null) { - throw new IOException(String.format("Failed to resolve a jar %016x%016x. JAR Cache is disabled for the channel %s", + throw new IOException(String.format( + "Failed to resolve a jar %016x%016x. JAR Cache is disabled for the channel %s", sum1, sum2, channel.getName())); } return c.resolve(channel, sum1, sum2); -// throw (IOException)new IOException(String.format("Failed to resolve a jar %016x%016x",sum1,sum2)).initCause(e); + // throw (IOException)new IOException(String.format("Failed to resolve a jar + // %016x%016x",sum1,sum2)).initCause(e); } private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/remoting/ResourceImageRef.java b/src/main/java/hudson/remoting/ResourceImageRef.java index f7625134a..6b453bc88 100644 --- a/src/main/java/hudson/remoting/ResourceImageRef.java +++ b/src/main/java/hudson/remoting/ResourceImageRef.java @@ -34,14 +34,16 @@ * the amount of state {@link ResourceImageRef}s need to carry around, which helps reduce * the bandwidth consumption. */ - /*package*/ abstract Future resolve(Channel channel, String resourcePath) throws IOException, InterruptedException; + /*package*/ abstract Future resolve(Channel channel, String resourcePath) + throws IOException, InterruptedException; /** * Returns an URL that points to this resource. * * This may require creating a temporary file. */ - /*package*/ abstract Future resolveURL(Channel channel, String resourcePath) throws IOException, InterruptedException; + /*package*/ abstract Future resolveURL(Channel channel, String resourcePath) + throws IOException, InterruptedException; private static final long serialVersionUID = 1L; } diff --git a/src/main/java/hudson/remoting/Response.java b/src/main/java/hudson/remoting/Response.java index 12fd4de30..5a197f56f 100644 --- a/src/main/java/hudson/remoting/Response.java +++ b/src/main/java/hudson/remoting/Response.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -37,7 +37,7 @@ * @see Request * @since 3.17 */ -public final class Response extends Command { +public final class Response extends Command { /** * ID of the {@link Request} for which */ @@ -57,9 +57,14 @@ public final class Response exte final RSP returnValue; final EXC exception; - @SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Only supposed to be defined on one side.") + @SuppressFBWarnings( + value = "SE_TRANSIENT_FIELD_NOT_RESTORED", + justification = "Only supposed to be defined on one side.") private transient long totalTime; - @SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Bound after deserialization, in execute.") + + @SuppressFBWarnings( + value = "SE_TRANSIENT_FIELD_NOT_RESTORED", + justification = "Bound after deserialization, in execute.") private transient Request request; Response(Request request, int id, int lastIoId, RSP returnValue) { @@ -84,8 +89,9 @@ public final class Response exte @Override void execute(Channel channel) { Request req = (Request) channel.pendingCalls.get(id); - if(req==null) + if (req == null) { return; // maybe aborted + } req.responseIoId = lastIoId; req.onCompleted(this); @@ -101,15 +107,18 @@ void execute(Channel channel) { @Override public String toString() { - return "Response" + (request != null ? ":" + request : "") + "(" + (returnValue != null ? returnValue.getClass().getName() : exception != null ? exception.getClass().getName() : null) + ")"; + return "Response" + (request != null ? ":" + request : "") + "(" + + (returnValue != null + ? returnValue.getClass().getName() + : exception != null ? exception.getClass().getName() : null) + + ")"; } /** * Obtains the matching request. * @return null if this response has not been processed successfully */ - public @CheckForNull - Request getRequest() { + public @CheckForNull Request getRequest() { return request; } diff --git a/src/main/java/hudson/remoting/SingleLaneExecutorService.java b/src/main/java/hudson/remoting/SingleLaneExecutorService.java index 5a0a5483b..98f1d8a33 100644 --- a/src/main/java/hudson/remoting/SingleLaneExecutorService.java +++ b/src/main/java/hudson/remoting/SingleLaneExecutorService.java @@ -47,7 +47,7 @@ public class SingleLaneExecutorService extends AbstractExecutorService { * We have finished shut down. Every tasks are full executed. */ private boolean shutDown; - + private static final Logger LOGGER = Logger.getLogger(SingleLaneExecutorService.class.getName()); /** @@ -67,8 +67,9 @@ public SingleLaneExecutorService(ExecutorService base) { @Override public synchronized void shutdown() { shuttingDown = true; - if (tasks.isEmpty()) + if (tasks.isEmpty()) { shutDown = true; + } } /** @@ -111,12 +112,12 @@ public synchronized boolean awaitTermination(long timeout, TimeUnit unit) throws @Override public synchronized void execute(@NonNull Runnable command) { if (shuttingDown) { - throw new ExecutorServiceUtils.FatalRejectedExecutionException("Cannot execute the command " + command + - ". The executor service is shutting down"); + throw new ExecutorServiceUtils.FatalRejectedExecutionException( + "Cannot execute the command " + command + ". The executor service is shutting down"); } - + this.tasks.add(command); - + // If we haven't been scheduled yet, do so now if (!scheduled) { scheduled = true; @@ -125,7 +126,8 @@ public synchronized void execute(@NonNull Runnable command) { ExecutorServiceUtils.submitAsync(base, runner); } catch (ExecutorServiceUtils.ExecutionRejectedException ex) { // Wrap by the runtime exception since there is no other solution here - throw new RejectedExecutionException("Base executor service " + base + " has rejected the task " + command, ex); + throw new RejectedExecutionException( + "Base executor service " + base + " has rejected the task " + command, ex); } } } @@ -137,7 +139,7 @@ public void run() { tasks.peek().run(); } finally { synchronized (SingleLaneExecutorService.this) { - tasks.remove();// completed. this is needed because shutdown() looks at tasks.isEmpty() + tasks.remove(); // completed. this is needed because shutdown() looks at tasks.isEmpty() assert scheduled; if (!tasks.isEmpty()) { @@ -149,10 +151,14 @@ public void run() { // So the code just logs the error and then throws RuntimeException as it // used to do before the code migration to ExecutorServiceUtils. // TODO: so this behavior still implies the BOOM risk, but there wil be a log entry at least - LOGGER.log(Level.SEVERE, String.format( - "Base executor service %s has rejected the queue task %s. Propagating the RuntimeException to the caller.", - ex.getExecutorServiceDisplayName(), ex.getRunnableDisplayName()), ex); - throw ExecutorServiceUtils.createRuntimeException("Base executor service has rejected the task from the queue", ex); + LOGGER.log( + Level.SEVERE, + String.format( + "Base executor service %s has rejected the queue task %s. Propagating the RuntimeException to the caller.", + ex.getExecutorServiceDisplayName(), ex.getRunnableDisplayName()), + ex); + throw ExecutorServiceUtils.createRuntimeException( + "Base executor service has rejected the task from the queue", ex); } } else { scheduled = false; diff --git a/src/main/java/hudson/remoting/SocketChannelStream.java b/src/main/java/hudson/remoting/SocketChannelStream.java index ce6ed29a4..7597cd102 100644 --- a/src/main/java/hudson/remoting/SocketChannelStream.java +++ b/src/main/java/hudson/remoting/SocketChannelStream.java @@ -21,10 +21,11 @@ */ public class SocketChannelStream { public static InputStream in(Socket s) throws IOException { - if (s.getChannel()!=null) + if (s.getChannel() != null) { return in(s.getChannel()); - else + } else { return new SocketInputStream(s); + } } public static InputStream in(final SocketChannel ch) throws IOException { @@ -59,10 +60,11 @@ public boolean isOpen() { } public static OutputStream out(Socket s) throws IOException { - if (s.getChannel()!=null) + if (s.getChannel() != null) { return out(s.getChannel()); - else + } else { return new SocketOutputStream(s); + } } public static OutputStream out(final SocketChannel ch) throws IOException { diff --git a/src/main/java/hudson/remoting/SocketInputStream.java b/src/main/java/hudson/remoting/SocketInputStream.java index 35e76afbb..84983461c 100644 --- a/src/main/java/hudson/remoting/SocketInputStream.java +++ b/src/main/java/hudson/remoting/SocketInputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/hudson/remoting/SocketOutputStream.java b/src/main/java/hudson/remoting/SocketOutputStream.java index 587c535f6..b20445a0a 100644 --- a/src/main/java/hudson/remoting/SocketOutputStream.java +++ b/src/main/java/hudson/remoting/SocketOutputStream.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/hudson/remoting/StandardOutputStream.java b/src/main/java/hudson/remoting/StandardOutputStream.java index 2b61a9251..7d72cf2a9 100644 --- a/src/main/java/hudson/remoting/StandardOutputStream.java +++ b/src/main/java/hudson/remoting/StandardOutputStream.java @@ -62,8 +62,9 @@ public StandardOutputStream() { public synchronized OutputStream swap(OutputStream another) { // if the stream is already swapped, the caller's implicit assumption that this represents stdout // is wrong, so we raise an error. - if (swapped) + if (swapped) { throw new IllegalStateException(); + } OutputStream old = out; out = another; swapped = true; diff --git a/src/main/java/hudson/remoting/SynchronousCommandTransport.java b/src/main/java/hudson/remoting/SynchronousCommandTransport.java index 6154d8028..ea861df7d 100644 --- a/src/main/java/hudson/remoting/SynchronousCommandTransport.java +++ b/src/main/java/hudson/remoting/SynchronousCommandTransport.java @@ -9,25 +9,25 @@ /** * {@link CommandTransport} that implements the read operation in a synchronous fashion. - * + * *

    * This class uses a thread to pump commands and pass them to {@link CommandReceiver}. - * + * * @author Kohsuke Kawaguchi */ public abstract class SynchronousCommandTransport extends CommandTransport { protected Channel channel; - private static final String RDR_SOCKET_TIMEOUT_PROPERTY_NAME = + private static final String RDR_SOCKET_TIMEOUT_PROPERTY_NAME = SynchronousCommandTransport.class.getName() + ".failOnSocketTimeoutInReader"; - + /** - * Enables the original aggressive behavior, when the channel reader gets + * Enables the original aggressive behavior, when the channel reader gets * interrupted on any {@link SocketTimeoutException}. * @since 2.60 */ private static boolean RDR_FAIL_ON_SOCKET_TIMEOUT = Boolean.getBoolean(RDR_SOCKET_TIMEOUT_PROPERTY_NAME); - + /** * Called by {@link Channel} to read the next command to arrive from the stream. */ @@ -43,17 +43,18 @@ private final class ReaderThread extends Thread { private final CommandReceiver receiver; public ReaderThread(CommandReceiver receiver) { - super("Channel reader thread: "+channel.getName()); + super("Channel reader thread: " + channel.getName()); this.receiver = receiver; setUncaughtExceptionHandler((t, e) -> { - LOGGER.log(Level.SEVERE, e, () -> "Uncaught exception in SynchronousCommandTransport.ReaderThread " + t); + LOGGER.log( + Level.SEVERE, e, () -> "Uncaught exception in SynchronousCommandTransport.ReaderThread " + t); channel.terminate(new IOException("Unexpected reader termination", e)); }); } @Override public void run() { - final String name =channel.getName(); + final String name = channel.getName(); try { while (!channel.isInClosed()) { Command cmd; @@ -61,9 +62,13 @@ public void run() { cmd = read(); } catch (SocketTimeoutException ex) { if (RDR_FAIL_ON_SOCKET_TIMEOUT) { - LOGGER.log(Level.SEVERE, ex, () -> "Socket timeout in the Synchronous channel reader." - + " The channel will be interrupted, because " + RDR_SOCKET_TIMEOUT_PROPERTY_NAME - + " is set"); + LOGGER.log( + Level.SEVERE, + ex, + () -> "Socket timeout in the Synchronous channel reader." + + " The channel will be interrupted, because " + + RDR_SOCKET_TIMEOUT_PROPERTY_NAME + + " is set"); throw ex; } // Timeout happened during the read operation. @@ -82,14 +87,14 @@ public void run() { } closeRead(); } catch (InterruptedException e) { - LOGGER.log(Level.SEVERE, e, () -> "I/O error in channel "+name); + LOGGER.log(Level.SEVERE, e, () -> "I/O error in channel " + name); Thread.currentThread().interrupt(); channel.terminate((InterruptedIOException) new InterruptedIOException().initCause(e)); } catch (IOException e) { - LOGGER.log(Level.INFO, e, () -> "I/O error in channel "+name); + LOGGER.log(Level.INFO, e, () -> "I/O error in channel " + name); channel.terminate(e); } catch (RuntimeException | Error e) { - LOGGER.log(Level.SEVERE, e, () -> "Unexpected error in channel "+name); + LOGGER.log(Level.SEVERE, e, () -> "Unexpected error in channel " + name); channel.terminate(new IOException("Unexpected reader termination", e)); throw e; } finally { diff --git a/src/main/java/hudson/remoting/SynchronousExecutorService.java b/src/main/java/hudson/remoting/SynchronousExecutorService.java index b7f52bad8..0f25a8fa0 100644 --- a/src/main/java/hudson/remoting/SynchronousExecutorService.java +++ b/src/main/java/hudson/remoting/SynchronousExecutorService.java @@ -35,7 +35,7 @@ public boolean isShutdown() { @Override public synchronized boolean isTerminated() { - return shutdown && count==0; + return shutdown && count == 0; } @Override @@ -43,9 +43,9 @@ public synchronized boolean awaitTermination(long timeout, TimeUnit unit) throws long now = System.nanoTime(); long end = now + unit.toNanos(timeout); - while (count!=0) { + while (count != 0) { long d = end - now; - if (d<=0) { + if (d <= 0) { return false; } wait(TimeUnit.NANOSECONDS.toMillis(d)); @@ -56,8 +56,9 @@ public synchronized boolean awaitTermination(long timeout, TimeUnit unit) throws @Override public void execute(@NonNull Runnable command) { - if (shutdown) + if (shutdown) { throw new IllegalStateException("Already shut down"); + } touchCount(1); try { command.run(); @@ -68,7 +69,8 @@ public void execute(@NonNull Runnable command) { private synchronized void touchCount(int diff) { count += diff; - if (count==0) + if (count == 0) { notifyAll(); + } } } diff --git a/src/main/java/hudson/remoting/TeeOutputStream.java b/src/main/java/hudson/remoting/TeeOutputStream.java index 8986d5596..574895409 100644 --- a/src/main/java/hudson/remoting/TeeOutputStream.java +++ b/src/main/java/hudson/remoting/TeeOutputStream.java @@ -118,5 +118,4 @@ public void close() throws IOException { this.branch.close(); } } - } diff --git a/src/main/java/hudson/remoting/URLDeserializationHelper.java b/src/main/java/hudson/remoting/URLDeserializationHelper.java index 3ac0e2494..34c2b1c6f 100644 --- a/src/main/java/hudson/remoting/URLDeserializationHelper.java +++ b/src/main/java/hudson/remoting/URLDeserializationHelper.java @@ -32,62 +32,65 @@ import java.net.URLStreamHandler; /** - * SECURITY-637, this helper wraps the URL into a "safe" version if the url has a non-empty host + * SECURITY-637, this helper wraps the URL into a "safe" version if the url has a non-empty host * and the JVM configuration is standard. * * Essentially the wrap does not provide the same logic for {@link URLStreamHandler#hashCode(URL)} * and {@link URLStreamHandler#equals(URL, URL)} but a version that use directly the {@code String} representation * instead of requesting the DNS to have name equivalence. - * + * * @since 3.25 */ public class URLDeserializationHelper { // escape hatch for SECURITY-637 to keep legacy behavior @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "Accessible via System Groovy Scripts") - private static boolean AVOID_URL_WRAPPING = Boolean.getBoolean(URLDeserializationHelper.class + ".avoidUrlWrapping"); - + private static boolean AVOID_URL_WRAPPING = + Boolean.getBoolean(URLDeserializationHelper.class + ".avoidUrlWrapping"); + private static final SafeURLStreamHandler SAFE_HANDLER = new SafeURLStreamHandler(); - + /** - * Wraps the given URL into a "safe" version against deserialization attack if the url has a non-empty host + * Wraps the given URL into a "safe" version against deserialization attack if the url has a non-empty host * and the JVM configuration is standard. */ - public static @NonNull - URL wrapIfRequired(@NonNull URL url) throws IOException { - if(AVOID_URL_WRAPPING){ + public static @NonNull URL wrapIfRequired(@NonNull URL url) throws IOException { + if (AVOID_URL_WRAPPING) { // legacy behavior return url; } - + if (url.getHost() == null || url.getHost().isEmpty()) { // default equals/hashcode are not vulnerable in case the host is null or empty return url; } - + return new URL(null, url.toString(), SAFE_HANDLER); } - + private static class SafeURLStreamHandler extends URLStreamHandler { @Override - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Used for safely handling URLs, not for opening a connection.") - protected URLConnection openConnection(URL u, Proxy p) throws IOException - { + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "Used for safely handling URLs, not for opening a connection.") + protected URLConnection openConnection(URL u, Proxy p) throws IOException { return new URL(u.toString()).openConnection(p); } @Override - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Used for safely handling URLs, not for opening a connection.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "Used for safely handling URLs, not for opening a connection.") protected URLConnection openConnection(URL u) throws IOException { return new URL(u.toString()).openConnection(); } - + // actual correction is here (hashCode + equals), we avoid requesting the DNS for the hostname - + @Override protected int hashCode(URL u) { return u.toExternalForm().hashCode(); } - + @Override protected boolean equals(URL u1, URL u2) { return u1.toExternalForm().equals(u2.toExternalForm()); diff --git a/src/main/java/hudson/remoting/URLish.java b/src/main/java/hudson/remoting/URLish.java index 44783a74d..4a611d970 100644 --- a/src/main/java/hudson/remoting/URLish.java +++ b/src/main/java/hudson/remoting/URLish.java @@ -28,7 +28,7 @@ private URLish() {} @NonNull static URLish from(@NonNull final URL url) { - + return new URLish() { @Override @NonNull @@ -45,8 +45,9 @@ static URLish from(@NonNull final File f) { URL toURL() throws MalformedURLException { // be defensive against external factors that might have deleted this file, since we use /tmp // see http://www.nabble.com/Surefire-reports-tt17554215.html - if (f.exists()) + if (f.exists()) { return f.toURI().toURL(); + } return null; } }; diff --git a/src/main/java/hudson/remoting/UnexportCommand.java b/src/main/java/hudson/remoting/UnexportCommand.java index 2fa64f8be..d9e5c65cf 100644 --- a/src/main/java/hudson/remoting/UnexportCommand.java +++ b/src/main/java/hudson/remoting/UnexportCommand.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -42,12 +42,12 @@ public class UnexportCommand extends Command { */ @Deprecated public UnexportCommand(int oid) { - this(oid,null); + this(oid, null); } @Override protected void execute(Channel channel) { - channel.unexport(oid,createdAt); + channel.unexport(oid, createdAt); } @Override diff --git a/src/main/java/hudson/remoting/UserRequest.java b/src/main/java/hudson/remoting/UserRequest.java index 9c8d6312d..421329d77 100644 --- a/src/main/java/hudson/remoting/UserRequest.java +++ b/src/main/java/hudson/remoting/UserRequest.java @@ -47,22 +47,26 @@ * * @author Kohsuke Kawaguchi */ -final class UserRequest extends Request,EXC> { +final class UserRequest extends Request, EXC> { private static final Logger LOGGER = Logger.getLogger(UserRequest.class.getName()); private final byte[] request; @NonNull - @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "RemoteClassLoader.export() always returns a serializable instance, but we cannot check it statically due to the java.lang.reflect.Proxy") + @SuppressFBWarnings( + value = "SE_BAD_FIELD", + justification = + "RemoteClassLoader.export() always returns a serializable instance, but we cannot check it statically due to the java.lang.reflect.Proxy") private final RemoteClassLoader.IClassLoader classLoaderProxy; + private final String toString; /** * Objects exported by the request. This value will remain local * and won't be sent over to the remote side. */ @SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "We're fine with default null") - private transient final ExportTable.ExportList exports; + private final transient ExportTable.ExportList exports; /** * Creates a user request to be executed on the remote side. @@ -70,7 +74,7 @@ final class UserRequest extends Request c) throws IOException { + public UserRequest(Channel local, Callable c) throws IOException { this.toString = c.toString(); if (local.isClosingOrClosed()) { Throwable createdAtValue = createdAt; @@ -78,15 +82,17 @@ public UserRequest(Channel local, Callable c) throws IOException { // If Command API changes, the cause may be null here (e.g. if it stops recording cause by default) createdAtValue = new IllegalStateException("Command is created for the channel being interrupted"); } - throw new ChannelClosedException(local, "Cannot create UserRequest for channel " + local + - ". The channel is closed or being closed.", createdAtValue); + throw new ChannelClosedException( + local, + "Cannot create UserRequest for channel " + local + ". The channel is closed or being closed.", + createdAtValue); } - // Before serializing anything, check that we actually have a classloader for it final ClassLoader cl = getClassLoader(c); if (cl == null) { - // If we cannot determine classloader on the local side, there is no sense to continue the request, because the proxy object won't be created + // If we cannot determine classloader on the local side, there is no sense to continue the request, because + // the proxy object won't be created // It will cause failure in UserRequest#perform() throw new IOException("Cannot determine classloader for the command " + toString); } @@ -94,12 +100,13 @@ public UserRequest(Channel local, Callable c) throws IOException { // Serialize the command to the channel exports = local.startExportRecording(); try { - request = serialize(c,local); + request = serialize(c, local); } finally { exports.stopRecording(); } - // TODO: We know that the classloader is always serializable, but there is no way to express it here in a compatible way \ + // TODO: We know that the classloader is always serializable, but there is no way to express it here in a + // compatible way \ // (as well as to call instance off or whatever) this.classLoaderProxy = RemoteClassLoader.export(cl, local); } @@ -111,8 +118,11 @@ public void checkIfCanBeExecutedOnChannel(Channel channel) throws IOException { // We also do not want to run UserRequests when the channel is being closed if (channel.isClosingOrClosed()) { - throw new ChannelClosedException(channel, "The request cannot be executed on channel " + channel + ". " - + "The channel is closing down or has closed down", channel.getCloseRequestCause()); + throw new ChannelClosedException( + channel, + "The request cannot be executed on channel " + channel + ". " + + "The channel is closing down or has closed down", + channel.getCloseRequestCause()); } } @@ -125,10 +135,10 @@ public void checkIfCanBeExecutedOnChannel(Channel channel) throws IOException { * @return Classloader from the callable. May be {@code null} if all attempts to retrieve the classloader return {@code null}. */ @CheckForNull - /*package*/ static ClassLoader getClassLoader(@NonNull Callable c) { + /*package*/ static ClassLoader getClassLoader(@NonNull Callable c) { ClassLoader result = null; - if(c instanceof DelegatingCallable) { - result =((DelegatingCallable)c).getClassLoader(); + if (c instanceof DelegatingCallable) { + result = ((DelegatingCallable) c).getClassLoader(); } if (result == null) { result = c.getClass().getClassLoader(); @@ -142,8 +152,9 @@ public void checkIfCanBeExecutedOnChannel(Channel channel) throws IOException { } private static boolean workaroundDone = false; + @Override - protected ResponseToUserRequest perform(Channel channel) throws EXC { + protected ResponseToUserRequest perform(Channel channel) throws EXC { try { ClassLoader cl = channel.importedClassLoaders.get(classLoaderProxy); @@ -152,15 +163,14 @@ protected ResponseToUserRequest perform(Channel channel) throws EXC { // @Related https://issues.tmatesoft.com/issue/SGT-451 // @Since 2.4 final String clazz = System.getProperty(RemoteClassLoader.class.getName() + ".force", null); - if ( clazz != null && !workaroundDone) { + if (clazz != null && !workaroundDone) { // Optimistic logging set. String eventMsg = "Loaded"; Level logLevel = Level.INFO; // java.lang classes can only be instantiated by the bootstrap Classloader. // Guarantees that *all* threads with whatever Classloader in use, have the // same mutex instance: an intance of java.lang.Class - synchronized(Object.class) - { + synchronized (Object.class) { workaroundDone = true; try { Class.forName(clazz, true, cl); @@ -171,9 +181,10 @@ protected ResponseToUserRequest perform(Channel channel) throws EXC { } } final Logger logger = Logger.getLogger(RemoteClassLoader.class.getName()); - if( logger.isLoggable(logLevel) ) - { - logger.log(logLevel, "{0} class ''{1}'' using classloader: {2}", new Object[]{ eventMsg, clazz, cl.toString()} ); + if (logger.isLoggable(logLevel)) { + logger.log(logLevel, "{0} class ''{1}'' using classloader: {2}", new Object[] { + eventMsg, clazz, cl.toString() + }); } } @@ -182,21 +193,28 @@ protected ResponseToUserRequest perform(Channel channel) throws EXC { try { Object o; try { - o = deserialize(channel,request,cl); + o = deserialize(channel, request, cl); } catch (ClassNotFoundException e) { - throw new ClassNotFoundException("Failed to deserialize the Callable object. Perhaps you needed to implement DelegatingCallable?", e); + throw new ClassNotFoundException( + "Failed to deserialize the Callable object. Perhaps you needed to implement DelegatingCallable?", + e); } catch (RuntimeException e) { // if the error is during deserialization, throw it in one of the types Channel.call will // capture its call site stack trace. See - throw new Error("Failed to deserialize the Callable object.",e); + throw new Error("Failed to deserialize the Callable object.", e); } - Callable callable = (Callable)o; - if(!channel.isArbitraryCallableAllowed() && !(callable instanceof RemoteInvocationHandler.RPCRequest)) - // if we allow restricted channel to execute arbitrary Callable, the remote JVM can pick up many existing - // Callable implementations (such as ones in Hudson's FilePath) and do quite a lot. So restrict that. + Callable callable = (Callable) o; + if (!channel.isArbitraryCallableAllowed() + && !(callable instanceof RemoteInvocationHandler.RPCRequest)) { + // if we allow restricted channel to execute arbitrary Callable, the remote JVM can pick up many + // existing + // Callable implementations (such as ones in Hudson's FilePath) and do quite a lot. So restrict + // that. // OTOH, we need to allow RPCRequest so that method invocations on exported objects will go through. - throw new SecurityException("Execution of "+callable.toString()+" is prohibited because the channel is restricted"); + throw new SecurityException( + "Execution of " + callable.toString() + " is prohibited because the channel is restricted"); + } callable = channel.decorators.wrapUserRequest(callable); @@ -209,14 +227,19 @@ protected ResponseToUserRequest perform(Channel channel) throws EXC { Thread.currentThread().setContextClassLoader(old); } } catch (LinkageError e) { - LOGGER.log(channel.isClosingOrClosed() ? Level.FINE : Level.WARNING, "LinkageError while performing " + this, e); + LOGGER.log( + channel.isClosingOrClosed() ? Level.FINE : Level.WARNING, + "LinkageError while performing " + this, + e); throw e; } finally { Channel.setCurrent(oldc); } - byte[] response = serialize(r,channel); - return channel.remoteCapability.supportsProxyExceptionFallback() ? new NormalResponse<>(response) : new UserResponse<>(response,false); + byte[] response = serialize(r, channel); + return channel.remoteCapability.supportsProxyExceptionFallback() + ? new NormalResponse<>(response) + : new UserResponse<>(response, false); } catch (Throwable e) { // propagate this to the calling process try { @@ -241,7 +264,7 @@ protected ResponseToUserRequest perform(Channel channel) throws EXC { return new UserResponse<>(response, true); } catch (IOException x) { // throw it as a lower-level exception - throw (EXC)x; + throw (EXC) x; } } } @@ -251,10 +274,11 @@ private byte[] _serialize(Object o, final Channel channel) throws IOException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos; - if (channel.remoteCapability.supportsMultiClassLoaderRPC()) - oos = new MultiClassLoaderSerializer.Output(channel,baos); - else + if (channel.remoteCapability.supportsMultiClassLoaderRPC()) { + oos = new MultiClassLoaderSerializer.Output(channel, baos); + } else { oos = AnonymousClassWarnings.checkingObjectOutputStream(baos); + } oos.writeObject(o); return baos.toByteArray(); @@ -265,14 +289,17 @@ private byte[] _serialize(Object o, final Channel channel) throws IOException { private byte[] serialize(Object o, Channel localChannel) throws IOException { try { - return _serialize(o,localChannel); - } catch( NotSerializableException e ) { + return _serialize(o, localChannel); + } catch (NotSerializableException e) { throw new IOException("Unable to serialize " + o, e); } } - @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION", justification = "Used for sending user requests between authorized agent and server.") - /*package*/ static Object deserialize(final Channel channel, byte[] data, ClassLoader defaultClassLoader) throws IOException, ClassNotFoundException { + @SuppressFBWarnings( + value = "OBJECT_DESERIALIZATION", + justification = "Used for sending user requests between authorized agent and server.") + /*package*/ static Object deserialize(final Channel channel, byte[] data, ClassLoader defaultClassLoader) + throws IOException, ClassNotFoundException { ByteArrayInputStream in = new ByteArrayInputStream(data); ObjectInputStream ois; @@ -295,12 +322,12 @@ public void releaseExports() { @Override public String toString() { - return "UserRequest:"+toString; + return "UserRequest:" + toString; } private static final long serialVersionUID = 1L; - interface ResponseToUserRequest extends Serializable { + interface ResponseToUserRequest extends Serializable { /** * Deserializes the response byte stream into an object. */ @@ -310,9 +337,11 @@ interface ResponseToUserRequest extends Serializable private static final class NormalResponse implements ResponseToUserRequest { private static final long serialVersionUID = 1L; private final byte[] response; + NormalResponse(byte[] response) { this.response = response; } + @SuppressWarnings("unchecked") @Override public RSP retrieve(Channel channel, ClassLoader cl) throws IOException, ClassNotFoundException { @@ -325,14 +354,17 @@ public RSP retrieve(Channel channel, ClassLoader cl) throws IOException, ClassNo } } - private static final class ExceptionResponse implements ResponseToUserRequest { + private static final class ExceptionResponse + implements ResponseToUserRequest { private static final long serialVersionUID = 1L; private @CheckForNull final byte[] rawResponse; private final byte[] proxyResponse; + ExceptionResponse(@CheckForNull byte[] rawResponse, byte[] proxyResponse) { this.rawResponse = rawResponse; this.proxyResponse = proxyResponse; } + @SuppressWarnings("unchecked") @Override public RSP retrieve(Channel channel, ClassLoader cl) throws IOException, ClassNotFoundException, EXC { @@ -356,14 +388,13 @@ public RSP retrieve(Channel channel, ClassLoader cl) throws IOException, ClassNo } } } - } /** * @deprecated Used only when we lack {@link Capability#supportsProxyExceptionFallback}. */ @Deprecated -final class UserResponse implements UserRequest.ResponseToUserRequest { +final class UserResponse implements UserRequest.ResponseToUserRequest { private final byte[] response; private final boolean isException; @@ -379,13 +410,14 @@ public UserResponse(byte[] response, boolean isException) { public RSP retrieve(Channel channel, ClassLoader cl) throws IOException, ClassNotFoundException, EXC { Channel old = Channel.setCurrent(channel); try { - Object o = UserRequest.deserialize(channel,response,cl); + Object o = UserRequest.deserialize(channel, response, cl); - if(isException) { - channel.attachCallSiteStackTrace((Throwable)o); + if (isException) { + channel.attachCallSiteStackTrace((Throwable) o); throw (EXC) o; - } else + } else { return (RSP) o; + } } finally { Channel.setCurrent(old); } diff --git a/src/main/java/hudson/remoting/Util.java b/src/main/java/hudson/remoting/Util.java index ecd26e62a..d90e6c50a 100644 --- a/src/main/java/hudson/remoting/Util.java +++ b/src/main/java/hudson/remoting/Util.java @@ -34,13 +34,13 @@ public class Util { * Acts like basename(1) */ static String getBaseName(String path) { - return path.substring(path.lastIndexOf('/')+1); + return path.substring(path.lastIndexOf('/') + 1); } static byte[] readFully(InputStream in) throws IOException { // TODO perhaps replace by in.readAllBytes() after checking close behavior ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy(in,baos); + copy(in, baos); return baos.toByteArray(); } @@ -55,14 +55,16 @@ public static void copy(InputStream in, OutputStream out) throws IOException { } @NonNull - @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "This path exists within a temp directory so the potential traversal is limited.") + @SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "This path exists within a temp directory so the potential traversal is limited.") static File makeResource(String name, byte[] image) throws IOException { Path tmpDir = Files.createTempDirectory("resource-"); File resource = new File(tmpDir.toFile(), name); Files.createDirectories(PathUtils.fileToPath(resource.getParentFile())); Files.createFile(PathUtils.fileToPath(resource)); - try(FileOutputStream fos = new FileOutputStream(resource)) { + try (FileOutputStream fos = new FileOutputStream(resource)) { fos.write(image); } @@ -85,7 +87,9 @@ static void deleteDirectoryOnExit(final File dir) { if (dir.isDirectory()) { File[] childFiles = dir.listFiles(); if (childFiles != null) { // listFiles may return null if there's an IO error - for (File f: childFiles) { deleteDirectoryOnExit(f); } + for (File f : childFiles) { + deleteDirectoryOnExit(f); + } } } } @@ -94,17 +98,18 @@ static String indent(String s) { return " " + s.trim().replace("\n", "\n "); } - static public String getVersion() { + public static String getVersion() { String version = "unknown"; try { - Enumeration resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME); + Enumeration resEnum = + Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME); while (resEnum.hasMoreElements()) { URL url = resEnum.nextElement(); - try(InputStream is = url.openStream()) { + try (InputStream is = url.openStream()) { if (is != null) { Manifest manifest = new Manifest(is); version = manifest.getMainAttributes().getValue("Version"); - if(version != null) { + if (version != null) { break; } } @@ -123,7 +128,5 @@ public static boolean shouldBailOut(@NonNull Instant firstAttempt, @CheckForNull return Duration.between(firstAttempt, Instant.now()).compareTo(noReconnectAfter) > 0; } - private Util() { - } - + private Util() {} } diff --git a/src/main/java/hudson/remoting/VirtualChannel.java b/src/main/java/hudson/remoting/VirtualChannel.java index 8c5b8d031..fcfc41a24 100644 --- a/src/main/java/hudson/remoting/VirtualChannel.java +++ b/src/main/java/hudson/remoting/VirtualChannel.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -29,7 +29,7 @@ /** * Virtualized {@link Channel} that allows different implementations. - * + * * @author Kohsuke Kawaguchi */ public interface VirtualChannel { @@ -41,7 +41,7 @@ public interface VirtualChannel { * Such calls will be considered as user-space requests. * If the channel cannot execute the requests (e.g. when it is being closed), * the operations may be rejected even if the channel is still active. - * + * * @param callable Callable to be executed * @throws InterruptedException * If the current thread is interrupted while waiting for the completion. @@ -49,8 +49,7 @@ public interface VirtualChannel { * If there's any error in the communication between {@link Channel}s. * @throws T User exception defined by the callable */ - - V call(Callable callable) throws IOException, T, InterruptedException; + V call(Callable callable) throws IOException, T, InterruptedException; /** * Makes an asynchronous remote procedure call. @@ -67,8 +66,7 @@ public interface VirtualChannel { * @throws IOException * If there's an error during the communication. */ - - Future callAsync(final Callable callable) throws IOException; + Future callAsync(final Callable callable) throws IOException; /** * Performs an orderly shut down of this channel (and the remote peer.) @@ -105,13 +103,13 @@ public interface VirtualChannel { * Once it is released, the exported object will be deallocated as well. * Please keep in mind that the object may be also released earlier than expected by JVM * (e.g. see JENKINS-23271). - * - * @param instance + * + * @param instance * Instance to be exported. * {@code null} instances won't be exported to the remote instance. *

    * All the parameters and return values must be serializable. - * @param + * @param * Type * @param type * Interface to be remoted. @@ -119,7 +117,7 @@ public interface VirtualChannel { * the proxy object that implements {@code T}. This object can be transferred * to the other {@link Channel}, and calling methods on it from the remote side * will invoke the same method on the given local {@code instance} object. - * {@code null} if the input instance is {@code null}. + * {@code null} if the input instance is {@code null}. */ @Nullable T export(Class type, @CheckForNull T instance); @@ -131,4 +129,3 @@ public interface VirtualChannel { */ void syncLocalIO() throws InterruptedException; } - diff --git a/src/main/java/hudson/remoting/Which.java b/src/main/java/hudson/remoting/Which.java index 769533c5b..5596bbc48 100644 --- a/src/main/java/hudson/remoting/Which.java +++ b/src/main/java/hudson/remoting/Which.java @@ -46,7 +46,9 @@ * * @author Kohsuke Kawaguchi */ -@SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "Managed by the jar cache mechanism, using server data.") +@SuppressFBWarnings( + value = "PATH_TRAVERSAL_IN", + justification = "Managed by the jar cache mechanism, using server data.") public class Which { /** * Returns the URL of the class file where the given class has been loaded from. @@ -60,11 +62,13 @@ public class Which { @NonNull public static URL classFileUrl(Class clazz) throws IOException { ClassLoader cl = clazz.getClassLoader(); - if(cl==null) + if (cl == null) { cl = ClassLoader.getSystemClassLoader(); + } URL res = cl.getResource(clazz.getName().replace('.', '/') + ".class"); - if(res==null) - throw new IllegalArgumentException("Unable to locate class file for "+clazz); + if (res == null) { + throw new IllegalArgumentException("Unable to locate class file for " + clazz); + } return res; } @@ -91,10 +95,10 @@ public static URL jarURL(Class clazz) throws IOException { */ @NonNull public static File jarFile(Class clazz) throws IOException { - return jarFile(classFileUrl(clazz),clazz.getName().replace('.','/')+".class"); + return jarFile(classFileUrl(clazz), clazz.getName().replace('.', '/') + ".class"); } - //TODO: This method will likely start blowing up in Java 9. Needs some testing. + // TODO: This method will likely start blowing up in Java 9. Needs some testing. /** * Locates the jar file that contains the given resource * @@ -111,33 +115,40 @@ public static File jarFile(Class clazz) throws IOException { * JAR File, which contains the URL */ @NonNull - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Used by the agent as part of jar cache management.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "Used by the agent as part of jar cache management.") /*package*/ static File jarFile(URL res, String qualifiedName) throws IOException { String resURL = res.toExternalForm(); String originalURL = resURL; - if(resURL.startsWith("jar:file:") || resURL.startsWith("wsjar:file:")) + if (resURL.startsWith("jar:file:") || resURL.startsWith("wsjar:file:")) { return fromJarUrlToFile(resURL); + } - if(resURL.startsWith("code-source:/")) { + if (resURL.startsWith("code-source:/")) { // OC4J apparently uses this. See http://www.nabble.com/Hudson-on-OC4J-tt16702113.html - resURL = resURL.substring("code-source:/".length(), resURL.lastIndexOf('!')); // cut off jar: and the file name portion - return new File(decode(new URL("file:/"+resURL).getPath())); + resURL = resURL.substring( + "code-source:/".length(), resURL.lastIndexOf('!')); // cut off jar: and the file name portion + return new File(decode(new URL("file:/" + resURL).getPath())); } - if(resURL.startsWith("zip:")){ + if (resURL.startsWith("zip:")) { // weblogic uses this. See http://www.nabble.com/patch-to-get-Hudson-working-on-weblogic-td23997258.html // also see http://www.nabble.com/Re%3A-Hudson-on-Weblogic-10.3-td25038378.html#a25043415 - resURL = resURL.substring("zip:".length(), resURL.lastIndexOf('!')); // cut off zip: and the file name portion - return new File(decode(new URL("file:"+resURL).getPath())); + resURL = resURL.substring( + "zip:".length(), resURL.lastIndexOf('!')); // cut off zip: and the file name portion + return new File(decode(new URL("file:" + resURL).getPath())); } - if(resURL.startsWith("file:")) { + if (resURL.startsWith("file:")) { // unpackaged classes int n = qualifiedName.split("/").length; // how many slashes do wo need to cut? - for( ; n>0; n-- ) { + for (; n > 0; n--) { int idx = Math.max(resURL.lastIndexOf('/'), resURL.lastIndexOf('\\')); - if(idx<0) throw new IllegalArgumentException(originalURL + " - " + resURL); - resURL = resURL.substring(0,idx); + if (idx < 0) { + throw new IllegalArgumentException(originalURL + " - " + resURL); + } + resURL = resURL.substring(0, idx); } // won't work if res URL contains ' ' @@ -148,17 +159,17 @@ public static File jarFile(Class clazz) throws IOException { return new File(decode(new URL(resURL).getPath())); } - if(resURL.startsWith("vfszip:")) { + if (resURL.startsWith("vfszip:")) { // JBoss5 - try(InputStream is = res.openStream()) { + try (InputStream is = res.openStream()) { Object delegate = is; - while (delegate.getClass().getEnclosingClass()!=ZipFile.class) { + while (delegate.getClass().getEnclosingClass() != ZipFile.class) { Field f = delegate.getClass().getDeclaredField("delegate"); f.setAccessible(true); delegate = f.get(delegate); - //JENKINS-5922 - workaround for CertificateReaderInputStream; JBoss 5.0.0, EAP 5.0 and EAP 5.1 + // JENKINS-5922 - workaround for CertificateReaderInputStream; JBoss 5.0.0, EAP 5.0 and EAP 5.1 // java.util.jar.JarVerifier is not public in Java, so we have to use reflection - if(delegate.getClass().getName().equals("java.util.jar.JarVerifier$VerifierStream")){ + if (delegate.getClass().getName().equals("java.util.jar.JarVerifier$VerifierStream")) { f = delegate.getClass().getDeclaredField("is"); f.setAccessible(true); delegate = f.get(delegate); @@ -166,32 +177,40 @@ public static File jarFile(Class clazz) throws IOException { } Field f = delegate.getClass().getDeclaredField("this$0"); f.setAccessible(true); - ZipFile zipFile = (ZipFile)f.get(delegate); + ZipFile zipFile = (ZipFile) f.get(delegate); return new File(zipFile.getName()); } catch (NoSuchFieldException | IllegalAccessException e) { // something must have changed in JBoss5. fall through - LOGGER.log(Level.FINE, "Failed to resolve vfszip into a jar location",e); + LOGGER.log(Level.FINE, "Failed to resolve vfszip into a jar location", e); } } - if(resURL.startsWith("vfs:")) { + if (resURL.startsWith("vfs:")) { // JBoss6 String dotdot = "../".repeat(Math.max(0, qualifiedName.split("/").length - 1)); try { - URL jar = new URL(res,dotdot); + URL jar = new URL(res, dotdot); String path = jar.getPath(); - if (path.endsWith("/")) path=path.substring(0,path.length()-1); + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } // obtain the file name portion - String fileName = path.substring(path.lastIndexOf('/')+1); + String fileName = path.substring(path.lastIndexOf('/') + 1); - Object vfs = new URL(jar,"..").getContent(); // a VirtualFile object pointing to the parent of the jar - File dir = (File)vfs.getClass().getMethod("getPhysicalFile").invoke(vfs); + Object vfs = new URL(jar, "..").getContent(); // a VirtualFile object pointing to the parent of the jar + File dir = (File) vfs.getClass().getMethod("getPhysicalFile").invoke(vfs); - File jarFile = new File(dir,fileName); - if (jarFile.exists()) return jarFile; - } catch (RuntimeException | NoSuchMethodException | IllegalAccessException | IOException | InvocationTargetException e) { - LOGGER.log(Level.FINE, "Failed to resolve vfs file into a location",e); + File jarFile = new File(dir, fileName); + if (jarFile.exists()) { + return jarFile; + } + } catch (RuntimeException + | NoSuchMethodException + | IllegalAccessException + | IOException + | InvocationTargetException e) { + LOGGER.log(Level.FINE, "Failed to resolve vfs file into a location", e); } } @@ -199,9 +218,9 @@ public static File jarFile(Class clazz) throws IOException { if (con instanceof JarURLConnection) { JarURLConnection jcon = (JarURLConnection) con; JarFile jarFile = jcon.getJarFile(); - if (jarFile!=null) { + if (jarFile != null) { String n = jarFile.getName(); - if(n.length()>0) {// JDK6u10 needs this + if (n.length() > 0) { // JDK6u10 needs this return new File(n); } else { // JDK6u10 apparently starts hiding the real jar file name, @@ -213,7 +232,7 @@ public static File jarFile(Class clazz) throws IOException { f.setAccessible(true); return new File((String) f.get(jarFile)); } catch (NoSuchFieldException | IllegalAccessException e) { - LOGGER.log(Level.INFO, "Failed to obtain the local cache file name of "+resURL, e); + LOGGER.log(Level.INFO, "Failed to obtain the local cache file name of " + resURL, e); } } } @@ -227,7 +246,8 @@ public static File jarFile(URL resource) throws IOException { } private static File fromJarUrlToFile(String resURL) throws MalformedURLException { - resURL = resURL.substring(resURL.indexOf(':')+1, resURL.lastIndexOf('!')); // cut off "scheme:" and the file name portion + resURL = resURL.substring( + resURL.indexOf(':') + 1, resURL.lastIndexOf('!')); // cut off "scheme:" and the file name portion return new File(decode(new URL(resURL).getPath())); } @@ -236,11 +256,11 @@ private static File fromJarUrlToFile(String resURL) throws MalformedURLException */ private static String decode(String s) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - for( int i=0; i "Uncaught exception in CopyThread " + t + ", retrying copy"); new CopyThread(threadName, in, out, termination, remainingTries - 1).start(); } else { - LOGGER.log(Level.SEVERE, e, () -> "Uncaught exception in CopyThread " + t + ", out of retries"); + LOGGER.log(Level.SEVERE, e, () -> "Uncaught exception in CopyThread " + t + ", out of retries"); termination.run(); } }); @@ -43,8 +43,9 @@ public void run() { try { byte[] buf = new byte[8192]; int len; - while ((len = in.read(buf)) > 0) + while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); + } } catch (IOException e) { LOGGER.log(Level.WARNING, e, () -> "Exception while copying in thread: " + getName()); } diff --git a/src/main/java/hudson/remoting/forward/Forwarder.java b/src/main/java/hudson/remoting/forward/Forwarder.java index fd84e64bf..cf2d45979 100644 --- a/src/main/java/hudson/remoting/forward/Forwarder.java +++ b/src/main/java/hudson/remoting/forward/Forwarder.java @@ -31,7 +31,7 @@ * Abstracts away how the forwarding is set up. * * @author Kohsuke Kawaguchi -*/ + */ public interface Forwarder extends Serializable { /** * Establishes a port forwarding connection and returns diff --git a/src/main/java/hudson/remoting/forward/ForwarderFactory.java b/src/main/java/hudson/remoting/forward/ForwarderFactory.java index 988e63be6..863ab4b6a 100644 --- a/src/main/java/hudson/remoting/forward/ForwarderFactory.java +++ b/src/main/java/hudson/remoting/forward/ForwarderFactory.java @@ -52,12 +52,13 @@ public class ForwarderFactory { /** * Creates a connector on the remote side that connects to the speicied host and port. */ - public static Forwarder create(VirtualChannel channel, final String remoteHost, final int remotePort) throws IOException, InterruptedException { + public static Forwarder create(VirtualChannel channel, final String remoteHost, final int remotePort) + throws IOException, InterruptedException { return channel.call(new ForwarderCallable(remoteHost, remotePort)); } public static Forwarder create(String remoteHost, int remotePort) { - return new ForwarderImpl(remoteHost,remotePort); + return new ForwarderImpl(remoteHost, remotePort); } private static class ForwarderImpl implements Forwarder, SerializableOnlyOverRemoting { @@ -74,17 +75,14 @@ private ForwarderImpl(String remoteHost, int remotePort) { public OutputStream connect(OutputStream out) throws IOException { Socket s = new Socket(remoteHost, remotePort); try (InputStream in = SocketChannelStream.in(s)) { - new CopyThread( - String.format("Copier to %s:%d", remoteHost, remotePort), - in, - out, - () -> { + new CopyThread(String.format("Copier to %s:%d", remoteHost, remotePort), in, out, () -> { try { s.close(); } catch (IOException e) { LOGGER.log(Level.WARNING, "Problem closing socket for ForwardingFactory", e); } - }).start(); + }) + .start(); } return new RemoteOutputStream(SocketChannelStream.out(s)); } @@ -104,7 +102,7 @@ private Object writeReplace() throws ObjectStreamException { */ public static final Role ROLE = new Role(ForwarderFactory.class); - private static class ForwarderCallable implements Callable { + private static class ForwarderCallable implements Callable { private static final long serialVersionUID = 1L; private final String remoteHost; diff --git a/src/main/java/hudson/remoting/forward/PortForwarder.java b/src/main/java/hudson/remoting/forward/PortForwarder.java index 313dd586e..704d0f46c 100644 --- a/src/main/java/hudson/remoting/forward/PortForwarder.java +++ b/src/main/java/hudson/remoting/forward/PortForwarder.java @@ -53,7 +53,7 @@ public class PortForwarder extends Thread implements Closeable, ListeningPort { @SuppressFBWarnings(value = "UNENCRYPTED_SERVER_SOCKET", justification = "Unused") public PortForwarder(int localPort, Forwarder forwarder) throws IOException { - super(String.format("Port forwarder %d",localPort)); + super(String.format("Port forwarder %d", localPort)); this.forwarder = forwarder; this.socket = new ServerSocket(localPort); // mark as a daemon thread by default. @@ -78,28 +78,27 @@ public int getPort() { public void run() { try { try { - while(true) { + while (true) { final Socket s = socket.accept(); - new Thread("Port forwarding session from "+s.getRemoteSocketAddress()) { + new Thread("Port forwarding session from " + s.getRemoteSocketAddress()) { { - setUncaughtExceptionHandler( - (t, e) -> LOGGER.log(Level.SEVERE, e, () -> "Unhandled exception in port forwarding session " + t)); + setUncaughtExceptionHandler((t, e) -> LOGGER.log( + Level.SEVERE, e, () -> "Unhandled exception in port forwarding session " + t)); } + @Override public void run() { try (InputStream in = SocketChannelStream.in(s); - OutputStream out = forwarder.connect(new RemoteOutputStream(SocketChannelStream.out(s)))) { - new CopyThread( - "Copier for " + s.getRemoteSocketAddress(), - in, - out, - () -> { + OutputStream out = + forwarder.connect(new RemoteOutputStream(SocketChannelStream.out(s)))) { + new CopyThread("Copier for " + s.getRemoteSocketAddress(), in, out, () -> { try { s.close(); } catch (IOException e) { LOGGER.log(Level.WARNING, "Failed to close socket", e); } - }).start(); + }) + .start(); } catch (IOException e) { // this happens if the socket connection is terminated abruptly. LOGGER.log(Level.FINE, "Port forwarding session was shut down abnormally", e); @@ -131,7 +130,8 @@ public void close() throws IOException { * @return * A {@link Closeable} that can be used to shut the port forwarding down. */ - public static ListeningPort create(VirtualChannel ch, final int acceptingPort, Forwarder forwarder) throws IOException, InterruptedException { + public static ListeningPort create(VirtualChannel ch, final int acceptingPort, Forwarder forwarder) + throws IOException, InterruptedException { // need a remotable reference final Forwarder proxy = ch.export(Forwarder.class, forwarder); @@ -145,7 +145,7 @@ public static ListeningPort create(VirtualChannel ch, final int acceptingPort, F */ public static final Role ROLE = new Role(PortForwarder.class); - private static class ListeningPortCallable implements Callable { + private static class ListeningPortCallable implements Callable { private static final long serialVersionUID = 1L; private final int acceptingPort; private final Forwarder proxy; @@ -157,10 +157,12 @@ public ListeningPortCallable(int acceptingPort, Forwarder proxy) { @Override public ListeningPort call() throws IOException { - final Channel channel = getOpenChannelOrFail(); // We initialize it early, so the forwarder won's start its daemon if the channel is shutting down + final Channel channel = + getOpenChannelOrFail(); // We initialize it early, so the forwarder won's start its daemon if the + // channel is shutting down PortForwarder t = new PortForwarder(acceptingPort, proxy); t.start(); - return channel.export(ListeningPort.class,t); + return channel.export(ListeningPort.class, t); } @Override diff --git a/src/main/java/hudson/remoting/jnlp/package-info.java b/src/main/java/hudson/remoting/jnlp/package-info.java index e1fe32745..11f04d6b6 100644 --- a/src/main/java/hudson/remoting/jnlp/package-info.java +++ b/src/main/java/hudson/remoting/jnlp/package-info.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/hudson/remoting/package-info.java b/src/main/java/hudson/remoting/package-info.java index 27b29ff71..287a879b1 100644 --- a/src/main/java/hudson/remoting/package-info.java +++ b/src/main/java/hudson/remoting/package-info.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/main/java/org/jenkinsci/remoting/CallableDecorator.java b/src/main/java/org/jenkinsci/remoting/CallableDecorator.java index 589f67a6b..d8d9b5b5b 100644 --- a/src/main/java/org/jenkinsci/remoting/CallableDecorator.java +++ b/src/main/java/org/jenkinsci/remoting/CallableDecorator.java @@ -40,7 +40,7 @@ public V call(java.util.concurrent.Callable callable) throws Exception { * Any exception thrown from this method will be propagated to the other side as if the execution of * the callable had failed with this exception. */ - public Callable userRequest(Callable op, Callable stem) { + public Callable userRequest(Callable op, Callable stem) { return stem; } } diff --git a/src/main/java/org/jenkinsci/remoting/ChannelStateException.java b/src/main/java/org/jenkinsci/remoting/ChannelStateException.java index 828457be3..74d68d767 100644 --- a/src/main/java/org/jenkinsci/remoting/ChannelStateException.java +++ b/src/main/java/org/jenkinsci/remoting/ChannelStateException.java @@ -52,13 +52,13 @@ public class ChannelStateException extends IOException { public ChannelStateException(@CheckForNull Channel channel, @NonNull String message) { super(message); - channelRef = channel != null ? new WeakReference<>(channel) : null; + channelRef = channel != null ? new WeakReference<>(channel) : null; channelName = channel != null ? channel.getName() : "unknown"; } public ChannelStateException(@CheckForNull Channel channel, String message, @CheckForNull Throwable cause) { super(message, cause); - channelRef = channel != null ? new WeakReference<>(channel) : null; + channelRef = channel != null ? new WeakReference<>(channel) : null; channelName = channel != null ? channel.getName() : "unknown"; } diff --git a/src/main/java/org/jenkinsci/remoting/DurationOptionHandler.java b/src/main/java/org/jenkinsci/remoting/DurationOptionHandler.java index baf0a2ab2..48499589a 100644 --- a/src/main/java/org/jenkinsci/remoting/DurationOptionHandler.java +++ b/src/main/java/org/jenkinsci/remoting/DurationOptionHandler.java @@ -59,5 +59,4 @@ public String getDefaultMetaVariable() { protected String print(Duration v) { return DurationFormatter.format(v); } - } diff --git a/src/main/java/org/jenkinsci/remoting/Role.java b/src/main/java/org/jenkinsci/remoting/Role.java index a26a955c5..0ee1229ed 100644 --- a/src/main/java/org/jenkinsci/remoting/Role.java +++ b/src/main/java/org/jenkinsci/remoting/Role.java @@ -69,14 +69,16 @@ public String getName() { @Override public String toString() { - return super.toString()+"["+name+"]"; + return super.toString() + "[" + name + "]"; } - @Override public boolean equals(Object obj) { + @Override + public boolean equals(Object obj) { return obj instanceof Role && ((Role) obj).name.equals(name); } - @Override public int hashCode() { + @Override + public int hashCode() { return name.hashCode(); } diff --git a/src/main/java/org/jenkinsci/remoting/RoleChecker.java b/src/main/java/org/jenkinsci/remoting/RoleChecker.java index 23e428215..8f5b816e2 100644 --- a/src/main/java/org/jenkinsci/remoting/RoleChecker.java +++ b/src/main/java/org/jenkinsci/remoting/RoleChecker.java @@ -32,7 +32,8 @@ public abstract class RoleChecker { * Any exception thrown will prevent the callable from getting executed, but we recommend * {@link SecurityException} */ - public abstract void check(@NonNull RoleSensitive subject, @NonNull Collection expected) throws SecurityException; + public abstract void check(@NonNull RoleSensitive subject, @NonNull Collection expected) + throws SecurityException; public void check(@NonNull RoleSensitive subject, @NonNull Role expected) throws SecurityException { check(subject, Set.of(expected)); diff --git a/src/main/java/org/jenkinsci/remoting/SerializableOnlyOverRemoting.java b/src/main/java/org/jenkinsci/remoting/SerializableOnlyOverRemoting.java index 578038c81..bf178dadc 100644 --- a/src/main/java/org/jenkinsci/remoting/SerializableOnlyOverRemoting.java +++ b/src/main/java/org/jenkinsci/remoting/SerializableOnlyOverRemoting.java @@ -61,11 +61,11 @@ default Channel getChannelForSerialization() throws NotSerializableException { // This logic does not prevent from improperly serializing objects within Remoting calls. // If it happens in API calls in external usages, we wish good luck with diagnosing Remoting issues // and leaks in ExportTable. - //TODO: maybe there is a way to actually diagnose this case? + // TODO: maybe there is a way to actually diagnose this case? final Thread t = Thread.currentThread(); throw new NotSerializableException("The calling thread " + t + " has no associated channel. " - + "The current object " + this + " is " + SerializableOnlyOverRemoting.class + - ", but it is likely being serialized/deserialized without the channel"); + + "The current object " + this + " is " + SerializableOnlyOverRemoting.class + + ", but it is likely being serialized/deserialized without the channel"); } return ch; } diff --git a/src/main/java/org/jenkinsci/remoting/engine/HostPort.java b/src/main/java/org/jenkinsci/remoting/engine/HostPort.java index ba763c091..5a6555bbe 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/HostPort.java +++ b/src/main/java/org/jenkinsci/remoting/engine/HostPort.java @@ -32,7 +32,8 @@ private void splitHostPort(String value, String defaultHost, int defaultPort) { if (portString.length() > 0) { port = Integer.parseInt(portString); if (port <= PORT_MIN || port > PORT_MAX) { - throw new IllegalArgumentException("Port " + value + " out of valid range [" + PORT_MIN + ", " + PORT_MAX + ")"); + throw new IllegalArgumentException( + "Port " + value + " out of valid range [" + PORT_MIN + ", " + PORT_MAX + ")"); } } else { port = defaultPort; @@ -59,5 +60,4 @@ public String getHost() { public int getPort() { return port; } - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/Jnlp4ConnectionState.java b/src/main/java/org/jenkinsci/remoting/engine/Jnlp4ConnectionState.java index 009070827..2168f3c63 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/Jnlp4ConnectionState.java +++ b/src/main/java/org/jenkinsci/remoting/engine/Jnlp4ConnectionState.java @@ -49,8 +49,7 @@ public class Jnlp4ConnectionState extends JnlpConnectionState { * @param socket the {@link Socket}. * @param listeners the {@link JnlpConnectionStateListener} instances. */ - protected Jnlp4ConnectionState(@NonNull Socket socket, - List listeners) { + protected Jnlp4ConnectionState(@NonNull Socket socket, List listeners) { super(socket, listeners); } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpoint.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpoint.java index 51d1368ab..58001338c 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpoint.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpoint.java @@ -56,6 +56,7 @@ public class JnlpAgentEndpoint { */ @NonNull private final String host; + private final int port; /** * The {@code InstanceIdentity.getPublic()} of the instance or {@code null} if the instance identity was not @@ -83,8 +84,8 @@ public class JnlpAgentEndpoint { * @deprecated Use {@link #JnlpAgentEndpoint(String, int, RSAPublicKey, Set, URL, String)} */ @Deprecated - public JnlpAgentEndpoint(@NonNull String host, int port, @CheckForNull RSAPublicKey publicKey, - @CheckForNull Set protocols) { + public JnlpAgentEndpoint( + @NonNull String host, int port, @CheckForNull RSAPublicKey publicKey, @CheckForNull Set protocols) { this(host, port, publicKey, protocols, null, null); } @@ -92,8 +93,12 @@ public JnlpAgentEndpoint(@NonNull String host, int port, @CheckForNull RSAPublic * @deprecated Use {@link #JnlpAgentEndpoint(String, int, RSAPublicKey, Set, URL, String)} */ @Deprecated - public JnlpAgentEndpoint(@NonNull String host, int port, @CheckForNull RSAPublicKey publicKey, - @CheckForNull Set protocols, @CheckForNull URL serviceURL) { + public JnlpAgentEndpoint( + @NonNull String host, + int port, + @CheckForNull RSAPublicKey publicKey, + @CheckForNull Set protocols, + @CheckForNull URL serviceURL) { this(host, port, publicKey, protocols, serviceURL, null); } @@ -108,15 +113,22 @@ public JnlpAgentEndpoint(@NonNull String host, int port, @CheckForNull RSAPublic * Use {@code null} if it is not a web service or if the URL cannot be determined * @since 3.0 */ - public JnlpAgentEndpoint(@NonNull String host, int port, @CheckForNull RSAPublicKey publicKey, - @CheckForNull Set protocols, @CheckForNull URL serviceURL, @CheckForNull String proxyCredentials) { + public JnlpAgentEndpoint( + @NonNull String host, + int port, + @CheckForNull RSAPublicKey publicKey, + @CheckForNull Set protocols, + @CheckForNull URL serviceURL, + @CheckForNull String proxyCredentials) { if (port <= 0 || 65536 <= port) { throw new IllegalArgumentException("Port " + port + " is not in the range 1-65535"); } this.host = host; this.port = port; this.publicKey = publicKey; - this.protocols = protocols == null || protocols.isEmpty() ? null : Collections.unmodifiableSet(new LinkedHashSet<>(protocols)); + this.protocols = protocols == null || protocols.isEmpty() + ? null + : Collections.unmodifiableSet(new LinkedHashSet<>(protocols)); this.serviceUrl = serviceURL; this.proxyCredentials = proxyCredentials; } @@ -197,9 +209,9 @@ public boolean isProtocolSupported(@NonNull String name) { * @return the socket. * @throws IOException if things go wrong. */ - @SuppressFBWarnings(value = "VA_FORMAT_STRING_USES_NEWLINE", - justification = "Unsafe endline symbol is a pert of the protocol. Unsafe to fix it. See TODO " - + "below") + @SuppressFBWarnings( + value = "VA_FORMAT_STRING_USES_NEWLINE", + justification = "Unsafe endline symbol is a pert of the protocol. Unsafe to fix it. See TODO " + "below") public Socket open(int socketTimeout) throws IOException { boolean isHttpProxy = false; InetSocketAddress targetAddress = null; @@ -230,7 +242,8 @@ public Socket open(int socketTimeout) throws IOException { if (isHttpProxy) { String connectCommand = String.format("CONNECT %s:%s HTTP/1.1\r\nHost: %s\r\n", host, port, host); if (proxyCredentials != null) { - String encoding = Base64.getEncoder().encodeToString(proxyCredentials.getBytes(StandardCharsets.UTF_8)); + String encoding = + Base64.getEncoder().encodeToString(proxyCredentials.getBytes(StandardCharsets.UTF_8)); connectCommand += "Proxy-Authorization: Basic " + encoding + "\r\n"; } connectCommand += "\r\n"; @@ -240,8 +253,9 @@ public Socket open(int socketTimeout) throws IOException { BufferedInputStream is = new BufferedInputStream(socket.getInputStream()); BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); String line = reader.readLine(); - if (line == null) + if (line == null) { throw new IOException("Proxy socket closed"); + } String[] responseLineParts = line.trim().split(" "); if (responseLineParts.length < 2 || !responseLineParts[1].equals("200")) { throw new IOException("Got a bad response from proxy: " + line); @@ -322,10 +336,9 @@ public boolean equals(Object o) { */ @Override public String toString() { - return "JnlpAgentEndpoint{" + "host=" + host + - ", port=" + port + - ", publicKey=" + KeyUtils.fingerprint(publicKey) + - ", protocols=" + protocols + - '}'; + return "JnlpAgentEndpoint{" + "host=" + host + ", port=" + + port + ", publicKey=" + + KeyUtils.fingerprint(publicKey) + ", protocols=" + + protocols + '}'; } } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointConfigurator.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointConfigurator.java index f924ae1ed..9055a843b 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointConfigurator.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointConfigurator.java @@ -39,7 +39,8 @@ public class JnlpAgentEndpointConfigurator extends JnlpEndpointResolver { private final String directionConnection; private final String proxyCredentials; - public JnlpAgentEndpointConfigurator(String directConnection, String instanceIdentity, Set protocols, String proxyCredentials) { + public JnlpAgentEndpointConfigurator( + String directConnection, String instanceIdentity, Set protocols, String proxyCredentials) { this.directionConnection = directConnection; this.instanceIdentity = instanceIdentity; this.protocols = protocols; @@ -59,12 +60,12 @@ public JnlpAgentEndpoint resolve() throws IOException { } HostPort hostPort = new HostPort(directionConnection); - return new JnlpAgentEndpoint(hostPort.getHost(), hostPort.getPort(), identity, protocols, null, proxyCredentials); + return new JnlpAgentEndpoint( + hostPort.getHost(), hostPort.getPort(), identity, protocols, null, proxyCredentials); } @Override public void waitForReady() { LOGGER.log(Level.INFO, "Sleeping 10s before reconnect."); } - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointResolver.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointResolver.java index 9b4db2297..2c5be60a7 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointResolver.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpAgentEndpointResolver.java @@ -111,8 +111,15 @@ public class JnlpAgentEndpointResolver extends JnlpEndpointResolver { private static String PROTOCOL_NAMES_TO_TRY = System.getProperty(JnlpAgentEndpointResolver.class.getName() + ".protocolNamesToTry"); - public JnlpAgentEndpointResolver(@NonNull List jenkinsUrls, String agentName, String credentials, String proxyCredentials, - String tunnel, SSLSocketFactory sslSocketFactory, boolean disableHttpsCertValidation, Duration noReconnectAfter) { + public JnlpAgentEndpointResolver( + @NonNull List jenkinsUrls, + String agentName, + String credentials, + String proxyCredentials, + String tunnel, + SSLSocketFactory sslSocketFactory, + boolean disableHttpsCertValidation, + Duration noReconnectAfter) { this.jenkinsUrls = new ArrayList<>(jenkinsUrls); this.agentName = agentName; this.credentials = credentials; @@ -169,7 +176,6 @@ public void setTunnel(@CheckForNull String tunnel) { * * @return {@code true} if the HTTPs certificate is disabled, endpoint check is ignored */ - public boolean isDisableHttpsCertValidation() { return disableHttpsCertValidation; } @@ -203,26 +209,31 @@ public JnlpAgentEndpoint resolve() throws IOException { selectedJenkinsURL = new URL(jenkinsUrl); salURL = toAgentListenerURL(jenkinsUrl); } catch (MalformedURLException ex) { - LOGGER.log(Level.WARNING, String.format("Cannot parse agent endpoint URL %s. Skipping it", jenkinsUrl), ex); + LOGGER.log( + Level.WARNING, + String.format("Cannot parse agent endpoint URL %s. Skipping it", jenkinsUrl), + ex); continue; } // find out the TCP port - HttpURLConnection con = - (HttpURLConnection) openURLConnection(salURL, agentName, credentials, proxyCredentials, sslSocketFactory, hostnameVerifier); + HttpURLConnection con = (HttpURLConnection) openURLConnection( + salURL, agentName, credentials, proxyCredentials, sslSocketFactory, hostnameVerifier); try { try { con.setConnectTimeout(30000); con.setReadTimeout(60000); con.connect(); } catch (IOException x) { - firstError = ThrowableUtils.chain(firstError, - new IOException("Failed to connect to " + salURL + ": " + x.getMessage(), x)); + firstError = ThrowableUtils.chain( + firstError, new IOException("Failed to connect to " + salURL + ": " + x.getMessage(), x)); continue; } if (con.getResponseCode() != 200) { - firstError = ThrowableUtils.chain(firstError, new IOException( - salURL + " is invalid: " + con.getResponseCode() + " " + con.getResponseMessage())); + firstError = ThrowableUtils.chain( + firstError, + new IOException( + salURL + " is invalid: " + con.getResponseCode() + " " + con.getResponseMessage())); continue; } @@ -232,17 +243,19 @@ public JnlpAgentEndpoint resolve() throws IOException { VersionNumber minimumSupportedVersion = new VersionNumber(minimumSupportedVersionHeader); VersionNumber currentVersion = new VersionNumber(Launcher.VERSION); if (currentVersion.isOlderThan(minimumSupportedVersion)) { - firstError = ThrowableUtils.chain(firstError, new IOException( - "Agent version " + minimumSupportedVersion + " or newer is required." - )); + firstError = ThrowableUtils.chain( + firstError, + new IOException("Agent version " + minimumSupportedVersion + " or newer is required.")); continue; } } Set agentProtocolNames = null; - String portStr = Optional.ofNullable(con.getHeaderField("X-Jenkins-JNLP-Port")).orElse(con.getHeaderField("X-Hudson-JNLP-Port")); - String host = Optional.ofNullable(con.getHeaderField("X-Jenkins-JNLP-Host")).orElse(salURL.getHost()); + String portStr = Optional.ofNullable(con.getHeaderField("X-Jenkins-JNLP-Port")) + .orElse(con.getHeaderField("X-Hudson-JNLP-Port")); + String host = Optional.ofNullable(con.getHeaderField("X-Jenkins-JNLP-Host")) + .orElse(salURL.getHost()); String protocols = con.getHeaderField("X-Jenkins-Agent-Protocols"); if (protocols != null) { // Take the list of protocols to try from the headers @@ -252,20 +265,26 @@ public JnlpAgentEndpoint resolve() throws IOException { .collect(Collectors.toSet()); if (agentProtocolNames.isEmpty()) { - LOGGER.log(Level.WARNING, "Received the empty list of supported protocols from the server. " + - "All protocols are disabled on the controller side OR the 'X-Jenkins-Agent-Protocols' header is corrupted (JENKINS-41730). " + - "In the case of the header corruption as a workaround you can use the " + - "'org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.protocolNamesToTry' system property " + - "to define the supported protocols."); + LOGGER.log( + Level.WARNING, + "Received the empty list of supported protocols from the server. " + + "All protocols are disabled on the controller side OR the 'X-Jenkins-Agent-Protocols' header is corrupted (JENKINS-41730). " + + "In the case of the header corruption as a workaround you can use the " + + "'org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.protocolNamesToTry' system property " + + "to define the supported protocols."); } else { - LOGGER.log(Level.INFO, "Remoting server accepts the following protocols: {0}", agentProtocolNames); + LOGGER.log( + Level.INFO, "Remoting server accepts the following protocols: {0}", agentProtocolNames); } } if (PROTOCOL_NAMES_TO_TRY != null) { // Take a list of protocols to try from the system property - LOGGER.log(Level.INFO, "Ignoring the list of supported remoting protocols provided by the server, because the " + - "'org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.protocolNamesToTry' property is defined. Will try {0}", PROTOCOL_NAMES_TO_TRY); + LOGGER.log( + Level.INFO, + "Ignoring the list of supported remoting protocols provided by the server, because the " + + "'org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.protocolNamesToTry' property is defined. Will try {0}", + PROTOCOL_NAMES_TO_TRY); agentProtocolNames = Stream.of(PROTOCOL_NAMES_TO_TRY.split(",")) .map(String::trim) .filter(Predicate.not(String::isEmpty)) @@ -277,13 +296,15 @@ public JnlpAgentEndpoint resolve() throws IOException { try { identity = getIdentity(idHeader); if (identity == null) { - firstError = ThrowableUtils.chain(firstError, new IOException( - salURL + " appears to be publishing an invalid X-Instance-Identity.")); + firstError = ThrowableUtils.chain( + firstError, + new IOException(salURL + " appears to be publishing an invalid X-Instance-Identity.")); continue; } } catch (InvalidKeySpecException e) { - firstError = ThrowableUtils.chain(firstError, new IOException( - salURL + " appears to be publishing an invalid X-Instance-Identity.")); + firstError = ThrowableUtils.chain( + firstError, + new IOException(salURL + " appears to be publishing an invalid X-Instance-Identity.")); continue; } @@ -295,24 +316,30 @@ public JnlpAgentEndpoint resolve() throws IOException { try { port = Integer.parseInt(portStr); } catch (NumberFormatException e) { - firstError = ThrowableUtils.chain(firstError, new IOException(jenkinsUrl + " is publishing an invalid port", e)); + firstError = ThrowableUtils.chain( + firstError, new IOException(jenkinsUrl + " is publishing an invalid port", e)); continue; } if (port <= 0 || 65536 <= port) { - firstError = ThrowableUtils.chain(firstError, new IOException(jenkinsUrl + " is publishing an invalid port")); + firstError = ThrowableUtils.chain( + firstError, new IOException(jenkinsUrl + " is publishing an invalid port")); continue; } if (tunnel == null) { if (!isPortVisible(host, port)) { - firstError = ThrowableUtils.chain(firstError, new IOException(jenkinsUrl + " provided port:" + port - + " is not reachable on host " + host)); + firstError = ThrowableUtils.chain( + firstError, + new IOException( + jenkinsUrl + " provided port:" + port + " is not reachable on host " + host)); continue; } else { LOGGER.log(Level.FINE, "TCP Agent Listener Port availability check passed"); } } else { - LOGGER.log(Level.INFO, "Remoting TCP connection tunneling is enabled. " + - "Skipping the TCP Agent Listener Port availability check"); + LOGGER.log( + Level.INFO, + "Remoting TCP connection tunneling is enabled. " + + "Skipping the TCP Agent Listener Port availability check"); } // sort the URLs so that the winner is the one we try first next time final String winningJenkinsUrl = jenkinsUrl; @@ -331,8 +358,9 @@ public JnlpAgentEndpoint resolve() throws IOException { port = hostPort.getPort(); } - //TODO: all the checks above do not make much sense if tunneling is enabled (JENKINS-52246) - return new JnlpAgentEndpoint(host, port, identity, agentProtocolNames, selectedJenkinsURL, proxyCredentials); + // TODO: all the checks above do not make much sense if tunneling is enabled (JENKINS-52246) + return new JnlpAgentEndpoint( + host, port, identity, agentProtocolNames, selectedJenkinsURL, proxyCredentials); } finally { con.disconnect(); } @@ -343,7 +371,9 @@ public JnlpAgentEndpoint resolve() throws IOException { return null; } - @SuppressFBWarnings(value = "UNENCRYPTED_SOCKET", justification = "This just verifies connection to the port. No data is transmitted.") + @SuppressFBWarnings( + value = "UNENCRYPTED_SOCKET", + justification = "This just verifies connection to the port. No data is transmitted.") private synchronized boolean isPortVisible(String hostname, int port) { boolean exitStatus = false; Socket s = null; @@ -362,13 +392,15 @@ private synchronized boolean isPortVisible(String hostname, int port) { @Override protected PasswordAuthentication getPasswordAuthentication() { if (getRequestorType().equals(RequestorType.PROXY)) { - return new PasswordAuthentication(proxyCredentials.substring(0, index), proxyCredentials.substring(index + 1).toCharArray()); + return new PasswordAuthentication( + proxyCredentials.substring(0, index), + proxyCredentials.substring(index + 1).toCharArray()); } return super.getPasswordAuthentication(); } }); } - InetSocketAddress proxyToUse = getResolvedHttpProxyAddress(hostname,port); + InetSocketAddress proxyToUse = getResolvedHttpProxyAddress(hostname, port); s = proxyToUse == null ? new Socket() : new Socket(new Proxy(Proxy.Type.HTTP, proxyToUse)); s.setReuseAddress(true); SocketAddress sa = new InetSocketAddress(hostname, port); @@ -425,20 +457,22 @@ public void waitForReady() throws InterruptedException { retries++; t.setName(oldName + ": trying " + url + " for " + retries + " times"); - HttpURLConnection con = - (HttpURLConnection) openURLConnection(url, agentName, credentials, proxyCredentials, sslSocketFactory, hostnameVerifier); + HttpURLConnection con = (HttpURLConnection) openURLConnection( + url, agentName, credentials, proxyCredentials, sslSocketFactory, hostnameVerifier); con.setConnectTimeout(5000); con.setReadTimeout(5000); con.connect(); if (con.getResponseCode() == 200) { return; } - LOGGER.log(Level.INFO, + LOGGER.log( + Level.INFO, "Controller isn''t ready to talk to us on {0}. Will try again: response code={1}", - new Object[]{url, con.getResponseCode()}); + new Object[] {url, con.getResponseCode()}); } catch (SocketTimeoutException | ConnectException | NoRouteToHostException e) { - LOGGER.log(Level.INFO, "Failed to connect to {0}. Will try again: {1} {2}", - new String[] {firstUrl, e.getClass().getName(), e.getMessage()}); + LOGGER.log(Level.INFO, "Failed to connect to {0}. Will try again: {1} {2}", new String[] { + firstUrl, e.getClass().getName(), e.getMessage() + }); } catch (IOException e) { // report the failure LOGGER.log(Level.INFO, e, () -> "Failed to connect to " + firstUrl + ". Will try again"); @@ -452,45 +486,57 @@ public void waitForReady() throws InterruptedException { @CheckForNull static InetSocketAddress getResolvedHttpProxyAddress(@NonNull String host, int port) throws IOException { InetSocketAddress targetAddress = null; - Iterator - proxies = - ProxySelector.getDefault().select(URI.create(String.format("http://%s:%d", host, port))).iterator(); + Iterator proxies = ProxySelector.getDefault() + .select(URI.create(String.format("http://%s:%d", host, port))) + .iterator(); while (targetAddress == null && proxies.hasNext()) { Proxy proxy = proxies.next(); if (proxy.type() == Proxy.Type.DIRECT) { // Proxy.NO_PROXY with a DIRECT type is returned in two cases: - // - when no proxy (none) has been configured in the JVM (either with system properties or by the operating system) + // - when no proxy (none) has been configured in the JVM (either with system properties or by the + // operating system) // - when the host URI is part of the exclusion list defined by system property -Dhttp.nonProxyHosts // // Unfortunately, the Proxy class does not provide a way to differentiate both cases to fallback to - // environment variables only when no proxy has been configured. Therefore, we have to recheck if the URI + // environment variables only when no proxy has been configured. Therefore, we have to recheck if the + // URI // host is in the exclusion list. // // Warning: - // This code only supports Java 9+ implementation where nonProxyHosts entries are not interpreted as regex expressions anymore. - // Wildcard at the beginning or the end of an expression are the only remaining supported behaviours (e.g. *.jenkins.io or 127.*) + // This code only supports Java 9+ implementation where nonProxyHosts entries are not interpreted + // as regex expressions anymore. + // Wildcard at the beginning or the end of an expression are the only remaining supported + // behaviours (e.g. *.jenkins.io or 127.*) // https://bugs.java.com/view_bug.do?bug_id=8035158 // http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/50a749f2cade String nonProxyHosts = System.getProperty("http.nonProxyHosts"); - if(nonProxyHosts != null && nonProxyHosts.length() != 0) { + if (nonProxyHosts != null && nonProxyHosts.length() != 0) { // Build a list of regexps matching all nonProxyHosts entries StringJoiner sj = new StringJoiner("|"); nonProxyHosts = nonProxyHosts.toLowerCase(Locale.ENGLISH); - for(String entry : nonProxyHosts.split("\\|")) { - if(entry.isEmpty()) + for (String entry : nonProxyHosts.split("\\|")) { + if (entry.isEmpty()) { continue; - else if(entry.startsWith("*")) + } else if (entry.startsWith("*")) { sj.add(".*" + Pattern.quote(entry.substring(1))); - else if(entry.endsWith("*")) + } else if (entry.endsWith("*")) { sj.add(Pattern.quote(entry.substring(0, entry.length() - 1)) + ".*"); - else + } else { sj.add(Pattern.quote(entry)); - // Detect when the pattern contains multiple wildcard, which used to work previous to Java 9 (e.g. 127.*.*.*) - if(entry.split("\\*").length > 2) - LOGGER.log(Level.WARNING, "Using more than one wildcard is not supported in nonProxyHosts entries: {0}", entry); + } + // Detect when the pattern contains multiple wildcard, which used to work previous to Java 9 + // (e.g. 127.*.*.*) + if (entry.split("\\*").length > 2) { + LOGGER.log( + Level.WARNING, + "Using more than one wildcard is not supported in nonProxyHosts entries: {0}", + entry); + } } Pattern nonProxyRegexps = Pattern.compile(sj.toString()); - if(nonProxyRegexps.matcher(host.toLowerCase(Locale.ENGLISH)).matches()) { + if (nonProxyRegexps + .matcher(host.toLowerCase(Locale.ENGLISH)) + .matches()) { return null; } else { break; @@ -500,12 +546,16 @@ else if(entry.endsWith("*")) if (proxy.type() == Proxy.Type.HTTP) { final SocketAddress address = proxy.address(); if (!(address instanceof InetSocketAddress)) { - LOGGER.log(Level.WARNING, "Unsupported proxy address type {0}", (address != null ? address.getClass() : "null")); + LOGGER.log( + Level.WARNING, + "Unsupported proxy address type {0}", + (address != null ? address.getClass() : "null")); continue; } InetSocketAddress proxyAddress = (InetSocketAddress) address; - if (proxyAddress.isUnresolved()) + if (proxyAddress.isUnresolved()) { proxyAddress = new InetSocketAddress(proxyAddress.getHostName(), proxyAddress.getPort()); + } targetAddress = proxyAddress; } } @@ -530,7 +580,9 @@ else if(entry.endsWith("*")) * FIXME: similar to hudson.remoting.Util.openURLConnection which is still used in hudson.remoting.Launcher */ @Restricted(NoExternalUse.class) - @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Used by the agent for retrieving connection info from the server.") + @SuppressFBWarnings( + value = "URLCONNECTION_SSRF_FD", + justification = "Used by the agent for retrieving connection info from the server.") public static URLConnection openURLConnection( URL url, @CheckForNull String agentName, @@ -580,5 +632,4 @@ public static URLConnection openURLConnection( } return con; } - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionState.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionState.java index 7683e20a9..46bd36ac7 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionState.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionState.java @@ -52,8 +52,7 @@ public class JnlpConnectionState { /** * The current iterator being used to process the listener notifications. */ - private static final ThreadLocal> fireIterator - = new ThreadLocal<>(); + private static final ThreadLocal> fireIterator = new ThreadLocal<>(); /** * The property name for the secret key. @@ -520,7 +519,5 @@ private enum State { * @see JnlpConnectionState#setStash(ListenerState) * @see JnlpConnectionState#getStash(Class) */ - public interface ListenerState { - - } + public interface ListenerState {} } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionStateListener.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionStateListener.java index ec629c9c0..6118be89a 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionStateListener.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpConnectionStateListener.java @@ -58,9 +58,7 @@ public abstract class JnlpConnectionStateListener { * * @param event the event. */ - public void beforeProperties(@NonNull JnlpConnectionState event) { - - } + public void beforeProperties(@NonNull JnlpConnectionState event) {} /** * Notification that properties have been exchanged. @@ -78,8 +76,7 @@ public void beforeProperties(@NonNull JnlpConnectionState event) { * * @param event the event. */ - public void beforeChannel(@NonNull JnlpConnectionState event) { - } + public void beforeChannel(@NonNull JnlpConnectionState event) {} /** * Callback to notify the {@link JnlpConnectionState#approve()} listener that the {@link Channel} has been @@ -95,9 +92,7 @@ public void beforeChannel(@NonNull JnlpConnectionState event) { * * @param event the event. */ - public void channelClosed(@NonNull JnlpConnectionState event) { - - } + public void channelClosed(@NonNull JnlpConnectionState event) {} /** * Callback to notify the {@link JnlpConnectionState#approve()} listener that the {@link Socket} has been @@ -105,7 +100,5 @@ public void channelClosed(@NonNull JnlpConnectionState event) { * * @param event the event. */ - public void afterDisconnect(@NonNull JnlpConnectionState event) { - - } + public void afterDisconnect(@NonNull JnlpConnectionState event) {} } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpEndpointResolver.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpEndpointResolver.java index 4acb23954..c29d5a6f5 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpEndpointResolver.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpEndpointResolver.java @@ -38,16 +38,20 @@ public abstract class JnlpEndpointResolver { public abstract void waitForReady() throws InterruptedException; protected RSAPublicKey getIdentity(String base64EncodedIdentity) throws InvalidKeySpecException { - if (base64EncodedIdentity == null) return null; + if (base64EncodedIdentity == null) { + return null; + } try { byte[] encodedKey = Base64.getDecoder().decode(base64EncodedIdentity); - if (encodedKey == null) return null; + if (encodedKey == null) { + return null; + } X509EncodedKeySpec spec = new X509EncodedKeySpec(encodedKey); KeyFactory kf = KeyFactory.getInstance("RSA"); return (RSAPublicKey) kf.generatePublic(spec); } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("The Java Language Specification mandates RSA as a supported algorithm.", e); + throw new IllegalStateException( + "The Java Language Specification mandates RSA as a supported algorithm.", e); } } - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4Handler.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4Handler.java index 801427f74..aba5a1523 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4Handler.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4Handler.java @@ -104,9 +104,13 @@ public class JnlpProtocol4Handler extends JnlpProtocolHandler listeners) { + public Jnlp4ConnectionState createConnectionState( + @NonNull Socket socket, @NonNull List listeners) { return new Jnlp4ConnectionState(socket, listeners); } @@ -138,8 +142,10 @@ public Jnlp4ConnectionState createConnectionState(@NonNull Socket socket, */ @NonNull @Override - public Future handle(@NonNull Socket socket, @NonNull Map headers, - @NonNull List listeners) + public Future handle( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) throws IOException { NetworkLayer networkLayer = createNetworkLayer(socket); SSLEngine engine = createSSLEngine(socket); @@ -166,8 +172,11 @@ public Future handle(@NonNull Socket socket, @NonNull Map connect(@NonNull Socket socket, @NonNull Map headers, - @NonNull List listeners) throws IOException { + public Future connect( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) + throws IOException { NetworkLayer networkLayer = createNetworkLayer(socket); SSLEngine sslEngine = createSSLEngine(socket); sslEngine.setUseClientMode(true); @@ -195,7 +204,9 @@ private NetworkLayer createNetworkLayer(Socket socket) throws IOException { SocketChannel socketChannel = isPreferNio() ? socket.getChannel() : null; LOGGER.fine(() -> "prefer NIO? " + isPreferNio() + " actually using NIO? " + (socketChannel != null)); if (socketChannel == null) { - networkLayer = new BIONetworkLayer(ioHub, Channels.newChannel(SocketChannelStream.in(socket)), + networkLayer = new BIONetworkLayer( + ioHub, + Channels.newChannel(SocketChannelStream.in(socket)), Channels.newChannel(SocketChannelStream.out(socket))); } else { networkLayer = new NIONetworkLayer(ioHub, socketChannel, socketChannel); @@ -223,9 +234,12 @@ private SSLEngine createSSLEngine(Socket socket) { /** * Handles the state transitions for a connection. */ - private class Handler extends Channel.Listener implements SSLEngineFilterLayer.Listener, - ConnectionHeadersFilterLayer.Listener, ChannelApplicationLayer.Listener, ProtocolStack.Listener, - ChannelApplicationLayer.ChannelDecorator { + private class Handler extends Channel.Listener + implements SSLEngineFilterLayer.Listener, + ConnectionHeadersFilterLayer.Listener, + ChannelApplicationLayer.Listener, + ProtocolStack.Listener, + ChannelApplicationLayer.ChannelDecorator { /** * The event. */ @@ -303,9 +317,10 @@ public void onReceiveHeaders(Map headers) throws ConnectionRefus // no-op, we trust the certificate as being from the client break; case INVALID: - LOGGER.log(Level.WARNING, + LOGGER.log( + Level.WARNING, "An attempt was made to connect as {0} from {1} with an invalid client certificate", - new Object[]{clientName, event.getRemoteEndpointDescription()}); + new Object[] {clientName, event.getRemoteEndpointDescription()}); throw new ConnectionRefusalException("Authentication failure"); default: String secretKey = clientDatabase.getSecretOf(clientName); @@ -313,10 +328,13 @@ public void onReceiveHeaders(Map headers) throws ConnectionRefus // should never get hear unless there is a race condition in removing an entry from the DB throw new ConnectionRefusalException("Unknown client name: " + clientName); } - if (!MessageDigest.isEqual(secretKey.getBytes(StandardCharsets.UTF_8), headers.get(JnlpConnectionState.SECRET_KEY).getBytes(StandardCharsets.UTF_8))) { - LOGGER.log(Level.WARNING, + if (!MessageDigest.isEqual( + secretKey.getBytes(StandardCharsets.UTF_8), + headers.get(JnlpConnectionState.SECRET_KEY).getBytes(StandardCharsets.UTF_8))) { + LOGGER.log( + Level.WARNING, "An attempt was made to connect as {0} from {1} with an incorrect secret", - new Object[]{clientName, event.getRemoteEndpointDescription()}); + new Object[] {clientName, event.getRemoteEndpointDescription()}); throw new ConnectionRefusalException("Authorization failure"); } break; @@ -377,6 +395,4 @@ public void onClosed(ProtocolStack stack, IOException cause) { } } } - - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4ProxyHandler.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4ProxyHandler.java index d2850d67e..13274164d 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4ProxyHandler.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocol4ProxyHandler.java @@ -59,7 +59,11 @@ public String getName() { @Override @NonNull - public Future connect(@NonNull Socket socket, @NonNull Map headers, @NonNull List listeners) throws IOException { + public Future connect( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) + throws IOException { LOGGER.fine("sending my name"); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeUTF("Protocol:" + NAME); @@ -78,14 +82,18 @@ public Future connect(@NonNull Socket socket, @NonNull Map handle(@NonNull Socket socket, @NonNull Map headers, @NonNull List listeners) throws IOException { + public Future handle( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) + throws IOException { throw new UnsupportedOperationException("unused, API design mistake"); } @Override @NonNull - protected JnlpConnectionState createConnectionState(@NonNull Socket socket, @NonNull List listeners) throws IOException { + protected JnlpConnectionState createConnectionState( + @NonNull Socket socket, @NonNull List listeners) throws IOException { throw new UnsupportedOperationException("unused, API design mistake"); } - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandler.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandler.java index 9ef49b2fd..a004b4e17 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandler.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandler.java @@ -36,7 +36,7 @@ /** * Consolidates the protocol handling for both the server and the client ends of the connection. - * + * * @param State class for connection events * @since 3.0 */ @@ -108,9 +108,8 @@ public boolean isEnabled() { * @throws IOException if something goes wrong. */ @NonNull - protected abstract STATE createConnectionState(@NonNull Socket socket, - @NonNull List listeners) - throws IOException; + protected abstract STATE createConnectionState( + @NonNull Socket socket, @NonNull List listeners) throws IOException; /** * Handles an incoming client connection on the supplied socket. @@ -122,8 +121,10 @@ protected abstract STATE createConnectionState(@NonNull Socket socket, * @throws IOException if the protocol cannot be initiated. */ @NonNull - public final Future handle(@NonNull Socket socket, @NonNull Map headers, - @NonNull JnlpConnectionStateListener... listeners) + public final Future handle( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull JnlpConnectionStateListener... listeners) throws IOException { return handle(socket, headers, Arrays.asList(listeners)); } @@ -138,8 +139,10 @@ public final Future handle(@NonNull Socket socket, @NonNull Map handle(@NonNull Socket socket, @NonNull Map headers, - @NonNull List listeners) + public abstract Future handle( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) throws IOException; /** @@ -152,8 +155,11 @@ public abstract Future handle(@NonNull Socket socket, @NonNull Map connect(@NonNull Socket socket, @NonNull Map headers, - @NonNull JnlpConnectionStateListener... listeners) throws IOException { + public final Future connect( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull JnlpConnectionStateListener... listeners) + throws IOException { return connect(socket, headers, Arrays.asList(listeners)); } @@ -167,8 +173,9 @@ public final Future connect(@NonNull Socket socket, @NonNull Map connect(@NonNull Socket socket, @NonNull Map headers, - @NonNull List listeners) + public abstract Future connect( + @NonNull Socket socket, + @NonNull Map headers, + @NonNull List listeners) throws IOException; - } diff --git a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerFactory.java b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerFactory.java index b404f1f05..0d1122686 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerFactory.java +++ b/src/main/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerFactory.java @@ -160,7 +160,8 @@ public JnlpProtocolHandlerFactory withClientDatabase(@CheckForNull JnlpClientDat public List> handlers() { List> result = new ArrayList<>(); if (ioHub != null && context != null) { - JnlpProtocol4Handler jnlpProtocol4Handler = new JnlpProtocol4Handler(clientDatabase, threadPool, ioHub, context, needClientAuth, preferNio); + JnlpProtocol4Handler jnlpProtocol4Handler = + new JnlpProtocol4Handler(clientDatabase, threadPool, ioHub, context, needClientAuth, preferNio); result.add(new JnlpProtocol4ProxyHandler(jnlpProtocol4Handler)); result.add(jnlpProtocol4Handler); } diff --git a/src/main/java/org/jenkinsci/remoting/engine/WorkDirManager.java b/src/main/java/org/jenkinsci/remoting/engine/WorkDirManager.java index e0ac83b4b..dbe68ea98 100644 --- a/src/main/java/org/jenkinsci/remoting/engine/WorkDirManager.java +++ b/src/main/java/org/jenkinsci/remoting/engine/WorkDirManager.java @@ -97,7 +97,6 @@ public class WorkDirManager { */ private final Map directories = new HashMap<>(); - private WorkDirManager() { // Cannot be instantiated outside } @@ -168,7 +167,7 @@ public File getLoggingConfigFile() { return null; } - //TODO: New interfaces should ideally use Path instead of File + // TODO: New interfaces should ideally use Path instead of File /** * Initializes the working directory for the agent. * Within the working directory the method also initializes a working directory for internal needs (like logging) @@ -184,16 +183,20 @@ public File getLoggingConfigFile() { */ @CheckForNull @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "Parameter supplied by user / administrator.") - public Path initializeWorkDir(final @CheckForNull File workDir, final @NonNull String internalDir, final boolean failIfMissing) throws IOException { + public Path initializeWorkDir( + final @CheckForNull File workDir, final @NonNull String internalDir, final boolean failIfMissing) + throws IOException { if (!internalDir.matches(SUPPORTED_INTERNAL_DIR_NAME_MASK)) { - throw new IOException(String.format("Name of %s ('%s') is not compliant with the required format: %s", + throw new IOException(String.format( + "Name of %s ('%s') is not compliant with the required format: %s", DirType.INTERNAL_DIR, internalDir, SUPPORTED_INTERNAL_DIR_NAME_MASK)); } if (workDir == null) { // TODO: this message likely suppresses the connection setup on CI - // LOGGER.log(Level.WARNING, "Agent working directory is not specified. Some functionality introduced in Remoting 3 may be disabled"); + // LOGGER.log(Level.WARNING, "Agent working directory is not specified. Some functionality introduced in + // Remoting 3 may be disabled"); return null; } else { // Verify working directory @@ -219,8 +222,7 @@ public Path initializeWorkDir(final @CheckForNull File workDir, final @NonNull S } @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "Value supplied by user / administrator.") - private void createInternalDirIfRequired(File internalDir, DirType type) - throws IOException { + private void createInternalDirIfRequired(File internalDir, DirType type) throws IOException { if (!disabledDirectories.contains(type)) { final File directory = new File(internalDir, type.getDefaultLocation()); verifyDirectory(directory, type, false); @@ -239,13 +241,16 @@ private void createInternalDirIfRequired(File internalDir, DirType type) * @param failIfMissing Fail if the directory is missing * @throws IOException Verification failure */ - private static void verifyDirectory(@NonNull File dir, @NonNull DirType type, boolean failIfMissing) throws IOException { + private static void verifyDirectory(@NonNull File dir, @NonNull DirType type, boolean failIfMissing) + throws IOException { if (dir.exists()) { if (!dir.isDirectory()) { - throw new IOException("The specified " + type + " path points to a non-directory file: " + dir.getPath()); + throw new IOException( + "The specified " + type + " path points to a non-directory file: " + dir.getPath()); } if (!dir.canWrite() || !dir.canRead() || !dir.canExecute()) { - throw new IOException("The specified " + type + " should be fully accessible to the remoting executable (RWX): " + dir.getPath()); + throw new IOException("The specified " + type + + " should be fully accessible to the remoting executable (RWX): " + dir.getPath()); } } else if (failIfMissing) { throw new IOException("The " + type + " is missing, but it is expected to exist: " + dir.getPath()); @@ -263,7 +268,8 @@ private static void verifyDirectory(@NonNull File dir, @NonNull DirType type, bo * If {@code null}, the behavior is defined by {@code internalDirPath}. * @throws IOException Initialization error */ - public void setupLogging(@CheckForNull Path internalDirPath, @CheckForNull Path overrideLogPath) throws IOException { + public void setupLogging(@CheckForNull Path internalDirPath, @CheckForNull Path overrideLogPath) + throws IOException { if (loggingInitialized) { // Do nothing, in Remoting initialization there may be two calls due to the // legacy -agentLog behavior implementation. @@ -273,15 +279,19 @@ public void setupLogging(@CheckForNull Path internalDirPath, @CheckForNull Path final File configFile = getLoggingConfigFile(); if (configFile != null) { - // TODO: There is a risk of second configuration call in the case of java.util.logging.config.file, but it's safe + // TODO: There is a risk of second configuration call in the case of java.util.logging.config.file, but it's + // safe LOGGER.log(Level.FINE, "Reading Logging configuration from file: {0}", configFile); - try(FileInputStream fis = new FileInputStream(configFile)) { + try (FileInputStream fis = new FileInputStream(configFile)) { LogManager.getLogManager().readConfiguration(fis); } } if (overrideLogPath != null) { // Legacy behavior - LOGGER.log(Level.INFO, "Using {0} as an agent error log destination; output log will not be generated", overrideLogPath); + LOGGER.log( + Level.INFO, + "Using {0} as an agent error log destination; output log will not be generated", + overrideLogPath); System.out.flush(); // Just in case the channel System.err.flush(); System.setErr(legacyCreateTeeStream(System.err, overrideLogPath)); @@ -299,8 +309,7 @@ public void setupLogging(@CheckForNull Path internalDirPath, @CheckForNull Path if (configFile == null) { final Logger rootLogger = Logger.getLogger(""); final File julLog = new File(logsDir, "remoting.log"); - final FileHandler logHandler = new FileHandler(julLog.getAbsolutePath(), - 10*1024*1024, 5, false); + final FileHandler logHandler = new FileHandler(julLog.getAbsolutePath(), 10 * 1024 * 1024, 5, false); logHandler.setFormatter(new SimpleFormatter()); logHandler.setLevel(Level.INFO); rootLogger.addHandler(logHandler); @@ -310,7 +319,10 @@ public void setupLogging(@CheckForNull Path internalDirPath, @CheckForNull Path } } - @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "It is a legacy logging mode. Relying on the default is not fine, but it just behaves as it used to behave for years") + @SuppressFBWarnings( + value = "DM_DEFAULT_ENCODING", + justification = + "It is a legacy logging mode. Relying on the default is not fine, but it just behaves as it used to behave for years") private PrintStream legacyCreateTeeStream(OutputStream ostream, Path destination) throws FileNotFoundException { return new PrintStream(new TeeOutputStream(ostream, new FileOutputStream(destination.toFile()))); } @@ -370,6 +382,5 @@ public String getDefaultLocation() { public String getName() { return name; } - } } diff --git a/src/main/java/org/jenkinsci/remoting/nio/Closeables.java b/src/main/java/org/jenkinsci/remoting/nio/Closeables.java index 009c1e191..abba4e39d 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/Closeables.java +++ b/src/main/java/org/jenkinsci/remoting/nio/Closeables.java @@ -24,12 +24,13 @@ public static Closeable input(SelectableChannel ch) { // at least as of Java7u55, shutdownInput fails if the socket // is already closed or half-closed, as opposed to be a no-op. // so let's just ignore close error altogether - LOGGER.log(Level.FINE, "Failed to close "+s,e); + LOGGER.log(Level.FINE, "Failed to close " + s, e); } maybeClose(s); }; - } else + } else { return ch; + } } public static Closeable output(SelectableChannel ch) { @@ -40,12 +41,13 @@ public static Closeable output(SelectableChannel ch) { s.socket().shutdownOutput(); } catch (IOException e) { // see the discussion in try/catch block around shutdownInput above - LOGGER.log(Level.FINE, "Failed to close "+s,e); + LOGGER.log(Level.FINE, "Failed to close " + s, e); } maybeClose(s); }; - } else + } else { return ch; + } } /** diff --git a/src/main/java/org/jenkinsci/remoting/nio/FifoBuffer.java b/src/main/java/org/jenkinsci/remoting/nio/FifoBuffer.java index 3a6cceebb..02be3fa5d 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/FifoBuffer.java +++ b/src/main/java/org/jenkinsci/remoting/nio/FifoBuffer.java @@ -56,13 +56,13 @@ class Pointer { } Pointer copy() { - return new Pointer(p,off); + return new Pointer(p, off); } void forward(int offset) { - while (offset>0) { - int ch = Math.min(offset,chunk()); - assert 0 0) { + int ch = Math.min(offset, chunk()); + assert 0 < ch && ch <= offset; offset -= ch; off += ch; } @@ -72,53 +72,56 @@ void forward(int offset) { * Figure out the number of bytes that can be read/written in one array copy. */ private int chunk() { - int sz = pageSize-off; - assert sz>=0; + int sz = pageSize - off; + assert sz >= 0; - if (sz>0) return sz; + if (sz > 0) { + return sz; + } Page q = p.next; - if (q==null) + if (q == null) { q = p.next = newPage(); + } p = q; off = 0; return pageSize; } public void write(ByteBuffer buf, int len) { - while (len>0) { - int chunk = Math.min(len,chunk()); + while (len > 0) { + int chunk = Math.min(len, chunk()); buf.get(p.buf, off, chunk); - off+=chunk; - len-=chunk; + off += chunk; + len -= chunk; } } public void write(byte[] buf, int start, int len) { - while (len>0) { - int chunk = Math.min(len,chunk()); - System.arraycopy(buf,start,p.buf,off,chunk); + while (len > 0) { + int chunk = Math.min(len, chunk()); + System.arraycopy(buf, start, p.buf, off, chunk); - off+=chunk; - len-=chunk; - start+=chunk; + off += chunk; + len -= chunk; + start += chunk; } } public void read(byte[] buf, int start, int len) { - while (len>0) { - int chunk = Math.min(len,chunk()); - assert off+chunk <= p.buf.length; - assert start+chunk <= buf.length; - assert off>=0; - assert start>=0; - assert chunk>=0; - System.arraycopy(p.buf,off,buf,start,chunk); - - off+=chunk; - len-=chunk; - start+=chunk; + while (len > 0) { + int chunk = Math.min(len, chunk()); + assert off + chunk <= p.buf.length; + assert start + chunk <= buf.length; + assert off >= 0; + assert start >= 0; + assert chunk >= 0; + System.arraycopy(p.buf, off, buf, start, chunk); + + off += chunk; + len -= chunk; + start += chunk; } } @@ -126,19 +129,21 @@ public void read(byte[] buf, int start, int len) { * Returns the current page as a {@link ByteBuffer}. */ private ByteBuffer asBuffer(int max) { - int ch = chunk(); // this needs to be done first - return ByteBuffer.wrap(p.buf,off,Math.min(ch,max)); + int ch = chunk(); // this needs to be done first + return ByteBuffer.wrap(p.buf, off, Math.min(ch, max)); } public int send(WritableByteChannel ch, int max) throws IOException { int n = ch.write(asBuffer(max)); - off+=n; + off += n; return n; } public int receive(ReadableByteChannel ch, int max) throws IOException { int n = ch.read(asBuffer(max)); - if (n>=0) off+=n; + if (n >= 0) { + off += n; + } return n; } } @@ -154,12 +159,13 @@ public int receive(ReadableByteChannel ch, int max) throws IOException { */ @GuardedBy("lock") private int limit; + private final int pageSize; /** * The position at which the next read/write will happen. */ - private Pointer r,w; + private Pointer r, w; /** * Set to true when the writer closes the write end. @@ -179,21 +185,21 @@ public int receive(ReadableByteChannel ch, int max) throws IOException { private boolean closeRequested = false; public FifoBuffer(int pageSize, int limit) { - this(null,pageSize,limit); + this(null, pageSize, limit); } public FifoBuffer(int limit) { - this(Math.max(limit/256,1024),limit); + this(Math.max(limit / 256, 1024), limit); } public FifoBuffer(Object lock, int pageSize, int limit) { - this.lock = lock==null ? this : lock; + this.lock = lock == null ? this : lock; this.limit = limit; this.pageSize = pageSize; Page p = newPage(); - r = new Pointer(p,0); - w = new Pointer(p,0); + r = new Pointer(p, 0); + w = new Pointer(p, 0); } /** @@ -222,21 +228,25 @@ private Page newPage() { */ public int readable() { synchronized (lock) { - if (sz>0) return sz; - if (closed) return -1; + if (sz > 0) { + return sz; + } + if (closed) { + return -1; + } return 0; } } - //TODO: Value beyond the limit is actually a bug (JENKINS-37514) + // TODO: Value beyond the limit is actually a bug (JENKINS-37514) /** * Number of bytes writable. * @return Number of bytes we can write to the buffer. * If the buffer is closed, may return the value beyond the limit (JENKINS-37514) */ public int writable() { - synchronized(lock) { - return Math.max(0,limit-readable()); + synchronized (lock) { + return Math.max(0, limit - readable()); } } @@ -270,32 +280,35 @@ public CloseCause getCloseCause() { * any more data to write. */ public int send(WritableByteChannel ch) throws IOException { - int read = 0; // total # of bytes read + int read = 0; // total # of bytes read while (true) { synchronized (lock) { int chunk = readable(); - if (chunk<=0) { + if (chunk <= 0) { // there's nothing we can immediately read - if (read>0) return read; // we've already read some + if (read > 0) { + return read; // we've already read some + } if (closeRequested) { // Somebody requested the close operation in parallel thread handleCloseRequest(); - return -1; // no more data + return -1; // no more data } - return 0; // no data to read + return 0; // no data to read } try { - int sent = r.send(ch, chunk); // bytes actually written + int sent = r.send(ch, chunk); // bytes actually written read += sent; sz -= sent; lock.notifyAll(); - if (sent == 0) // channel filled up + if (sent == 0) { // channel filled up return read; + } } catch (ClosedChannelException e) { // If the underlying channel is closed, we should close the buffer as well close(); @@ -305,7 +318,6 @@ public int send(WritableByteChannel ch) throws IOException { } } - /** * Non-blocking write. * @@ -314,10 +326,12 @@ public int send(WritableByteChannel ch) throws IOException { */ public int writeNonBlock(ByteBuffer buf) { synchronized (lock) { - int chunk = Math.min(buf.remaining(),writable()); - if (chunk==0) return 0; + int chunk = Math.min(buf.remaining(), writable()); + if (chunk == 0) { + return 0; + } - w.write(buf,chunk); + w.write(buf, chunk); sz += chunk; @@ -336,15 +350,17 @@ public int writeNonBlock(ByteBuffer buf) { * receive error */ public int receive(ReadableByteChannel ch) throws IOException { - if (closed) + if (closed) { throw new IOException("already closed"); + } int written = 0; while (true) { synchronized (lock) { int chunk = writable(); - if (chunk==0) + if (chunk == 0) { return written; // no more space to write + } // If the buffer gets closed before we acquire lock, we are at risk of null "w" and NPE. // So in such case we just interrupt the receive process @@ -354,10 +370,13 @@ public int receive(ReadableByteChannel ch) throws IOException { try { int received = w.receive(ch, chunk); - if (received==0) + if (received == 0) { return written; // channel is fully drained - if (received==-1) { - if (written==0) return -1; // propagate EOF + } + if (received == -1) { + if (written == 0) { + return -1; // propagate EOF + } return written; } @@ -366,29 +385,31 @@ public int receive(ReadableByteChannel ch) throws IOException { } catch (ClosedChannelException e) { // If the underlying channel is closed, we should close the buffer as well close(); - if (written == 0) return -1; // propagate EOF + if (written == 0) { + return -1; // propagate EOF + } return written; } lock.notifyAll(); - } } } public void write(byte[] buf) throws InterruptedException, IOException { - write(buf,0,buf.length); + write(buf, 0, buf.length); } public void write(byte[] buf, int start, int len) throws InterruptedException, IOException { - if (closed) + if (closed) { throw new IOException("already closed"); + } - while (len>0) { + while (len > 0) { int chunk; synchronized (lock) { - while ((chunk = Math.min(len,writable()))==0) { + while ((chunk = Math.min(len, writable())) == 0) { if (closeRequested) { handleCloseRequest(); throw new IOException("closed during write() operation"); @@ -448,8 +469,9 @@ private void handleCloseRequest() { * If the ring is no longer needed, release the buffer. */ private void releaseRing() { - if (readable()<0) + if (readable() < 0) { r = w = null; + } } /** @@ -462,22 +484,24 @@ private void releaseRing() { */ public int peek(int offset, byte[] data, int start, int len) { synchronized (lock) { - len = Math.min(len, readable()-offset); // can't read beyond the end of the readable buffer - if (len<=0) return 0; + len = Math.min(len, readable() - offset); // can't read beyond the end of the readable buffer + if (len <= 0) { + return 0; + } Pointer v = this.r.copy(); v.forward(offset); - v.read(data,start,len); + v.read(data, start, len); return len; } } public int peek(int offset, byte[] data) { - return peek(offset,data,0,data.length); + return peek(offset, data, 0, data.length); } public int read(byte[] buf) throws InterruptedException { - return read(buf,0,buf.length); + return read(buf, 0, buf.length); } /** @@ -485,12 +509,16 @@ public int read(byte[] buf) throws InterruptedException { * @see InputStream#read(byte[],int,int) */ public int read(byte[] buf, int start, int len) throws InterruptedException { - if (len==0) return 0; // the only case where we can legally return 0 + if (len == 0) { + return 0; // the only case where we can legally return 0 + } synchronized (lock) { while (true) { - int r = readNonBlocking(buf,start,len); - if (r!=0) return r; - lock.wait(); // wait until the writer gives us something + int r = readNonBlocking(buf, start, len); + if (r != 0) { + return r; + } + lock.wait(); // wait until the writer gives us something } } } @@ -504,31 +532,37 @@ public int readNonBlocking(byte[] buf) { * @see InputStream#read(byte[],int,int) */ public int readNonBlocking(byte[] buf, int start, int len) { - if (len==0) return 0; + if (len == 0) { + return 0; + } - int read = 0; // total # of bytes read + int read = 0; // total # of bytes read while (true) { int chunk; synchronized (lock) { while (true) { - chunk = Math.min(len,readable()); - if (chunk>0) break; + chunk = Math.min(len, readable()); + if (chunk > 0) { + break; + } // there's nothing we can immediately read - if (read>0) return read; // we've already read some + if (read > 0) { + return read; // we've already read some + } if (closeRequested) { handleCloseRequest(); - return -1; // no more data + return -1; // no more data } return 0; // nothing to read } - r.read(buf,start,chunk); + r.read(buf, start, chunk); start += chunk; len -= chunk; @@ -548,21 +582,21 @@ public OutputStream getOutputStream() { @Override public void write(int b) throws IOException { try { - byte[] buf = new byte[]{(byte)b}; + byte[] buf = new byte[] {(byte) b}; FifoBuffer.this.write(buf); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw (InterruptedIOException)new InterruptedIOException().initCause(e); + throw (InterruptedIOException) new InterruptedIOException().initCause(e); } } @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { try { - FifoBuffer.this.write(b,off,len); + FifoBuffer.this.write(b, off, len); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw (InterruptedIOException)new InterruptedIOException().initCause(e); + throw (InterruptedIOException) new InterruptedIOException().initCause(e); } } @@ -583,12 +617,16 @@ public int read() throws IOException { try { byte[] b = new byte[1]; int n = FifoBuffer.this.read(b); - if (n<0) return -1; - if (n==0) throw new AssertionError(); - return ((int)b[0])&0xFF; + if (n < 0) { + return -1; + } + if (n == 0) { + throw new AssertionError(); + } + return ((int) b[0]) & 0xFF; } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw (InterruptedIOException)new InterruptedIOException().initCause(e); + throw (InterruptedIOException) new InterruptedIOException().initCause(e); } } @@ -598,7 +636,7 @@ public int read(@NonNull byte[] b, int off, int len) throws IOException { return FifoBuffer.this.read(b, off, len); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw (InterruptedIOException)new InterruptedIOException().initCause(e); + throw (InterruptedIOException) new InterruptedIOException().initCause(e); } } }; diff --git a/src/main/java/org/jenkinsci/remoting/nio/NioChannelBuilder.java b/src/main/java/org/jenkinsci/remoting/nio/NioChannelBuilder.java index d1ee37a34..0ba2099f3 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/NioChannelBuilder.java +++ b/src/main/java/org/jenkinsci/remoting/nio/NioChannelBuilder.java @@ -23,7 +23,7 @@ * @see NioChannelHub#newChannelBuilder(String, ExecutorService) */ public abstract class NioChannelBuilder extends ChannelBuilder { - /*package*/ SelectableChannel/* & ReadableByteChannel&WritableByteChannel */ r,w; + /*package*/ SelectableChannel /* & ReadableByteChannel&WritableByteChannel */ r, w; NioChannelBuilder(String name, ExecutorService executors) { super(name, executors); @@ -40,27 +40,26 @@ public Channel build(SelectableChannel r, SelectableChannel w) throws IOExceptio this.r = r; this.w = w; return super.build( - Channels.newInputStream((ReadableByteChannel)r), - Channels.newOutputStream((WritableByteChannel)w)); + Channels.newInputStream((ReadableByteChannel) r), Channels.newOutputStream((WritableByteChannel) w)); } @Override public Channel build(Socket s) throws IOException { SocketChannel ch = s.getChannel(); - if (ch==null) - throw new IllegalArgumentException(s+" doesn't have a channel"); + if (ch == null) { + throw new IllegalArgumentException(s + " doesn't have a channel"); + } return build(ch); } - @Override public NioChannelBuilder withBaseLoader(ClassLoader base) { - return (NioChannelBuilder)super.withBaseLoader(base); + return (NioChannelBuilder) super.withBaseLoader(base); } @Override public NioChannelBuilder withMode(Channel.Mode mode) { - return (NioChannelBuilder)super.withMode(mode); + return (NioChannelBuilder) super.withMode(mode); } @Override @@ -90,6 +89,6 @@ public NioChannelBuilder withoutJarCache() { @Override public NioChannelBuilder withClassFilter(ClassFilter filter) { - return (NioChannelBuilder)super.withClassFilter(filter); + return (NioChannelBuilder) super.withClassFilter(filter); } } diff --git a/src/main/java/org/jenkinsci/remoting/nio/NioChannelHub.java b/src/main/java/org/jenkinsci/remoting/nio/NioChannelHub.java index b7ed997e3..4a5ce9ca8 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/NioChannelHub.java +++ b/src/main/java/org/jenkinsci/remoting/nio/NioChannelHub.java @@ -54,13 +54,13 @@ public class NioChannelHub implements Runnable, Closeable { * Maximum size of the chunk. */ private int transportFrameSize = 8192; + private final SelectableFileChannelFactory factory = new SelectableFileChannelFactory(); /** * Used to schedule work that can be only done synchronously with the {@link Selector#select()} call. */ - private final Queue> selectorTasks - = new ConcurrentLinkedQueue<>(); + private final Queue> selectorTasks = new ConcurrentLinkedQueue<>(); /** * {@link ExecutorService} that processes command parsing and executions. @@ -77,13 +77,13 @@ public class NioChannelHub implements Runnable, Closeable { * Sets to the thread that's in the {@link #run()} method. */ private volatile Thread selectorThread; + private volatile Throwable whatKilledSelectorThread; // used to ensure that NioChannelHub.run() has started before creating new channels private boolean started = false; private final Object startedLock = new Object(); - /** * Bi-directional NIO channel used as the transport of a {@link Channel}. * @@ -105,11 +105,11 @@ abstract class NioTransport extends AbstractByteArrayCommandTransport { * The receiver buffer has to be big enough to accommodate a single command in its entirety. * There's no size restriction in a command, so we'll just buffer as much as we can. */ - final FifoBuffer rb = new FifoBuffer(16*1024, Integer.MAX_VALUE); + final FifoBuffer rb = new FifoBuffer(16 * 1024, Integer.MAX_VALUE); /** * Where we pools bytes to be send to {@link #ww()} but not yet done. */ - final FifoBuffer wb = new FifoBuffer(16*1024,256*1024); + final FifoBuffer wb = new FifoBuffer(16 * 1024, 256 * 1024); @CheckForNull private AbstractByteArrayCommandTransport.ByteArrayReceiver receiver = null; @@ -147,7 +147,7 @@ abstract class NioTransport extends AbstractByteArrayCommandTransport { * when we have more space in {@link #rb}. */ boolean wantsToRead() { - return receiver!=null && rb.writable()!=0; + return receiver != null && rb.writable() != 0; } /** @@ -155,7 +155,7 @@ boolean wantsToRead() { * when we have some data in {@link #wb}. */ boolean wantsToWrite() { - return wb.readable()!=0; + return wb.readable() != 0; } /** @@ -185,15 +185,16 @@ boolean wantsToWrite() { @SelectorThreadOnly protected final void cancelKey(SelectionKey key) { - if (key!=null) + if (key != null) { key.cancel(); + } } protected Channel getChannel() { return channel; } - //TODO: do not just ignore the exceptions below + // TODO: do not just ignore the exceptions below @SelectorThreadOnly public void abort(Throwable e) { try { @@ -209,7 +210,7 @@ public void abort(Throwable e) { if (receiver == null) { throw new IllegalStateException("Aborting connection before it has been actually set up"); } - receiver.terminate(new IOException("Connection aborted: "+this, e)); + receiver.terminate(new IOException("Connection aborted: " + this, e)); } @Override @@ -221,20 +222,20 @@ public void writeBlock(Channel channel, byte[] bytes) throws IOException { int frame = Math.min(transportFrameSize, bytes.length - pos); // # of bytes we send in this chunk hasMore = frame + pos < bytes.length; wb.write(ChunkHeader.pack(frame, hasMore)); - wb.write(bytes,pos,frame); + wb.write(bytes, pos, frame); scheduleReregister(); - pos+=frame; - } while(hasMore); + pos += frame; + } while (hasMore); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw (InterruptedIOException)new InterruptedIOException().initCause(e); + throw (InterruptedIOException) new InterruptedIOException().initCause(e); } } @Override public void setup(AbstractByteArrayCommandTransport.ByteArrayReceiver receiver) { this.receiver = receiver; - scheduleReregister(); // ready to read bytes now + scheduleReregister(); // ready to read bytes now } @Override @@ -268,7 +269,7 @@ private void scheduleReregister() { @Override public String toString() { - return super.toString()+"[name="+name+"]"; + return super.toString() + "[name=" + name + "]"; } } @@ -282,10 +283,10 @@ class MonoNioTransport extends NioTransport { * the contract of {@link SelectableChannel}. These objects represent the strategy to close them, * and when it's closed, set to null. */ - Closeable rc,wc; + Closeable rc, wc; MonoNioTransport(String name, SelectableChannel ch, Capability remoteCapability) { - super(name,remoteCapability); + super(name, remoteCapability); this.ch = ch; this.rc = Closeables.input(ch); @@ -294,22 +295,22 @@ class MonoNioTransport extends NioTransport { @Override ReadableByteChannel rr() { - return (ReadableByteChannel)ch; + return (ReadableByteChannel) ch; } @Override WritableByteChannel ww() { - return (WritableByteChannel)ch; + return (WritableByteChannel) ch; } @Override boolean isWopen() { - return wc!=null; + return wc != null; } @Override boolean isRopen() { - return rc!=null; + return rc != null; } @Override @@ -326,7 +327,7 @@ void closeR() throws IOException { @Override @SelectorThreadOnly void closeW() throws IOException { - if (wc!=null) { + if (wc != null) { wc.close(); wc = null; wb.close(); // wb will not accept incoming data any more @@ -337,7 +338,8 @@ void closeW() throws IOException { @Override @SelectorThreadOnly public void reregister() throws IOException { - int flag = (wantsToWrite() && isWopen() ? SelectionKey.OP_WRITE : 0) + (wantsToRead() && isRopen() ? SelectionKey.OP_READ : 0); + int flag = (wantsToWrite() && isWopen() ? SelectionKey.OP_WRITE : 0) + + (wantsToRead() && isRopen() ? SelectionKey.OP_READ : 0); if (ch.isOpen()) { ch.configureBlocking(false); ch.register(selector, flag).attach(this); @@ -350,24 +352,23 @@ public void reregister() throws IOException { @SelectorThreadOnly private void maybeCancelKey() throws IOException { SelectionKey key = ch.keyFor(selector); - if (rc==null && wc==null) { + if (rc == null && wc == null) { // both ends are closed cancelKey(key); } else { - reregister(); + reregister(); } } - } /** * NioTransport that uses two {@link SelectableChannel}s to do read and write each. */ class DualNioTransport extends NioTransport { - private final SelectableChannel r,w; + private final SelectableChannel r, w; DualNioTransport(String name, SelectableChannel r, SelectableChannel w, Capability remoteCapability) { - super(name,remoteCapability); + super(name, remoteCapability); assert r instanceof ReadableByteChannel && w instanceof WritableByteChannel; this.r = r; @@ -426,12 +427,11 @@ public void reregister() throws IOException { @SelectorThreadOnly private void cancelKey(SelectableChannel c) { - assert c==r || c==w; + assert c == r || c == w; cancelKey(c.keyFor(selector)); } } - /** * * @param commandProcessor @@ -444,7 +444,7 @@ public NioChannelHub(ExecutorService commandProcessor) throws IOException { } public void setFrameSize(int sz) { - assert 0 t = selectorTasks.poll(); - if (t==null) break; + if (t == null) { + break; + } try { t.call(); } catch (IOException e) { @@ -577,7 +589,8 @@ public void run() { } } - selectorThread.setName("NioChannelHub keys=" + selector.keys().size() + " gen=" + (gen++) + ": " + oldName); + selectorThread.setName( + "NioChannelHub keys=" + selector.keys().size() + " gen=" + (gen++) + ": " + oldName); selector.select(); } catch (IOException e) { whatKilledSelectorThread = e; @@ -602,64 +615,72 @@ public void run() { } final byte[] buf = new byte[ChunkHeader.SIZE]; - int pos=0; - int packetSize=0; + int pos = 0; + int packetSize = 0; while (true) { - if (t.rb.peek(pos,buf) 0) { ExecutorServiceUtils.submitAsync(t.swimLane, () -> { - final AbstractByteArrayCommandTransport.ByteArrayReceiver receiver = t.receiver; + final AbstractByteArrayCommandTransport.ByteArrayReceiver receiver = + t.receiver; if (receiver == null) { - throw new IllegalStateException("NIO transport layer has not been set up yet"); + throw new IllegalStateException( + "NIO transport layer has not been set up yet"); } receiver.handle(packet); }); } - pos=0; + pos = 0; } } - if (t.rb.writable()==0 && t.rb.readable()>0) { - String msg = "Command buffer overflow. Read " + t.rb.readable() + " bytes but still too small for a single command"; + if (t.rb.writable() == 0 && t.rb.readable() > 0) { + String msg = "Command buffer overflow. Read " + t.rb.readable() + + " bytes but still too small for a single command"; LOGGER.log(Level.WARNING, msg); // to avoid infinite hang, abort this connection t.abort(new IOException(msg)); } if (t.rb.isClosed()) { - // EOF. process this synchronously with respect to packets waiting for handling in the queue + // EOF. process this synchronously with respect to packets waiting for handling in + // the queue ExecutorServiceUtils.submitAsync(t.swimLane, () -> { // if this EOF is unexpected, report an error. if (!t.getChannel().isInClosed()) { - t.getChannel().terminate(new IOException("Unexpected EOF while receiving the data from the channel. " - + "FIFO buffer has been already closed", t.rb.getCloseCause())); + t.getChannel() + .terminate(new IOException( + "Unexpected EOF while receiving the data from the channel. " + + "FIFO buffer has been already closed", + t.rb.getCloseCause())); } }); } } if (key.isValid() && key.isWritable()) { t.wb.send(t.ww()); - if (t.wb.readable()<0) { + if (t.wb.readable() < 0) { // done with sending all the data t.closeW(); } @@ -667,18 +688,28 @@ public void run() { t.reregister(); } catch (IOException e) { // It causes the channel failure, hence it is severe - LOGGER.log(Level.SEVERE, "Communication problem in " + t + ". NIO Transport will be aborted.", e); + LOGGER.log( + Level.SEVERE, + "Communication problem in " + t + ". NIO Transport will be aborted.", + e); t.abort(e); } catch (ExecutorServiceUtils.ExecutionRejectedException e) { // TODO: should we try to reschedule the task if the issue is not fatal? // The swimlane has rejected the execution, e.g. due to the "shutting down" state. - LOGGER.log(Level.SEVERE, "The underlying executor service rejected the task in " + t + ". NIO Transport will be aborted.", e); + LOGGER.log( + Level.SEVERE, + "The underlying executor service rejected the task in " + t + + ". NIO Transport will be aborted.", + e); t.abort(e); } catch (CancelledKeyException e) { // see JENKINS-24050. I don't understand how this can happen, given that the selector // thread is the only thread that cancels keys. So to better understand what's going on, // report the problem. - LOGGER.log(Level.SEVERE, "Unexpected key cancellation for " + t + ". NIO Transport will be aborted.", e); + LOGGER.log( + Level.SEVERE, + "Unexpected key cancellation for " + t + ". NIO Transport will be aborted.", + e); // to be on the safe side, abort the communication. if we don't do this, it's possible // that the key never gets re-registered to the selector, and the traffic will hang // on this channel. @@ -701,25 +732,26 @@ public void run() { } finally { selectorThread.setName(oldName); selectorThread = null; - if (whatKilledSelectorThread==null) + if (whatKilledSelectorThread == null) { whatKilledSelectorThread = new AssertionError("NioChannelHub shouldn't exit normally"); + } } } /** * Called when the unknown key registered to the selector is selected. */ - protected void onSelected(SelectionKey key) { - - } + protected void onSelected(SelectionKey key) {} @SelectorThreadOnly private void abortAll(Throwable e) { Set pairs = new HashSet<>(); - for (SelectionKey k : selector.keys()) - pairs.add((NioTransport)k.attachment()); - for (NioTransport p : pairs) + for (SelectionKey k : selector.keys()) { + pairs.add((NioTransport) k.attachment()); + } + for (NioTransport p : pairs) { p.abort(e); + } } public Selector getSelector() { @@ -736,8 +768,9 @@ public Selector getSelector() { * This check makes it easier to find this problem and report why the selector thread has died. */ public void ensureValid() throws IOException { - if (selectorThread==null) - throw new IOException("NIO selector thread is not running",whatKilledSelectorThread); + if (selectorThread == null) { + throw new IOException("NIO selector thread is not running", whatKilledSelectorThread); + } } private static final Logger LOGGER = Logger.getLogger(NioChannelHub.class.getName()); diff --git a/src/main/java/org/jenkinsci/remoting/nio/SelectableFileChannelFactory.java b/src/main/java/org/jenkinsci/remoting/nio/SelectableFileChannelFactory.java index e5e262478..6b0430dea 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/SelectableFileChannelFactory.java +++ b/src/main/java/org/jenkinsci/remoting/nio/SelectableFileChannelFactory.java @@ -44,14 +44,14 @@ * @since 2.38 */ public class SelectableFileChannelFactory { - + @CheckForNull protected FileInputStream unwrap(InputStream i) { if (i instanceof BufferedInputStream) { try { Field $in = FilterInputStream.class.getDeclaredField("in"); $in.setAccessible(true); - return unwrap((InputStream)$in.get(i)); + return unwrap((InputStream) $in.get(i)); } catch (NoSuchFieldException | IllegalAccessException e) { warn(e); return null; @@ -60,7 +60,7 @@ protected FileInputStream unwrap(InputStream i) { if (i instanceof FileInputStream) { return (FileInputStream) i; } - return null; // unknown type + return null; // unknown type } @CheckForNull @@ -69,7 +69,7 @@ protected FileOutputStream unwrap(OutputStream i) { try { Field $in = FilterOutputStream.class.getDeclaredField("out"); $in.setAccessible(true); - return unwrap((OutputStream)$in.get(i)); + return unwrap((OutputStream) $in.get(i)); } catch (NoSuchFieldException | IllegalAccessException e) { warn(e); return null; @@ -78,7 +78,7 @@ protected FileOutputStream unwrap(OutputStream i) { if (i instanceof FileOutputStream) { return (FileOutputStream) i; } - return null; // unknown type + return null; // unknown type } @CheckForNull @@ -93,34 +93,36 @@ public SocketChannel create(OutputStream out) throws IOException { @CheckForNull public SocketChannel create(FileInputStream in) throws IOException { - if (in==null) return null; + if (in == null) { + return null; + } return create(in.getFD()); } @CheckForNull public SocketChannel create(FileOutputStream out) throws IOException { - if (out==null) return null; + if (out == null) { + return null; + } return create(out.getFD()); } /** * Create channel using the specified file descriptor. - * + * * @param fd File Descriptor * @return {@code null} if the platform does not support it (e.g. Windows) OR the socket channel cannot be created. * In the latter case the error message will be printed to {@link #LOGGER} then. */ @CheckForNull public SocketChannel create(FileDescriptor fd) { - if (File.pathSeparatorChar==';') + if (File.pathSeparatorChar == ';') { return null; // not selectable on Windows + } try { - Constructor $c = Class.forName("sun.nio.ch.SocketChannelImpl").getDeclaredConstructor( - SelectorProvider.class, - FileDescriptor.class, - InetSocketAddress.class - ); + Constructor $c = Class.forName("sun.nio.ch.SocketChannelImpl") + .getDeclaredConstructor(SelectorProvider.class, FileDescriptor.class, InetSocketAddress.class); $c.setAccessible(true); // increment the FileDescriptor use count since we are giving it to SocketChannel @@ -128,8 +130,13 @@ public SocketChannel create(FileDescriptor fd) { $m.setAccessible(true); $m.invoke(fd); - return (SocketChannel)$c.newInstance(SelectorProvider.provider(), fd, null); - } catch (NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | InstantiationException e) { + return (SocketChannel) $c.newInstance(SelectorProvider.provider(), fd, null); + } catch (NoSuchMethodException + | SecurityException + | ClassNotFoundException + | IllegalAccessException + | InvocationTargetException + | InstantiationException e) { warn(e); return null; } @@ -138,7 +145,7 @@ public SocketChannel create(FileDescriptor fd) { private void warn(Exception e) { if (!warned) { warned = true; - LOGGER.log(Level.WARNING, "Failed to wrap aFileDescriptor into SocketChannel",e); + LOGGER.log(Level.WARNING, "Failed to wrap aFileDescriptor into SocketChannel", e); } } diff --git a/src/main/java/org/jenkinsci/remoting/nio/SelectorThreadOnly.java b/src/main/java/org/jenkinsci/remoting/nio/SelectorThreadOnly.java index 7ad680d5d..e069da148 100644 --- a/src/main/java/org/jenkinsci/remoting/nio/SelectorThreadOnly.java +++ b/src/main/java/org/jenkinsci/remoting/nio/SelectorThreadOnly.java @@ -18,5 +18,4 @@ */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) -@interface SelectorThreadOnly { -} +@interface SelectorThreadOnly {} diff --git a/src/main/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtils.java b/src/main/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtils.java index 9a75c59e6..81cbc76f9 100644 --- a/src/main/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtils.java +++ b/src/main/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtils.java @@ -27,7 +27,7 @@ * @see "http://www.faqs.org/rfcs/rfc1519.html" * @since 2.0 */ -//[PATCH] +// [PATCH] @Restricted(NoExternalUse.class) // end of [PATCH] public class SubnetUtils { @@ -40,8 +40,7 @@ public final class SubnetInfo { /** Mask to convert unsigned int to a long (i.e. keep 32 bits). */ private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; - private SubnetInfo() { - } + private SubnetInfo() {} public int asInteger(final String address) { return toInteger(address); @@ -57,7 +56,7 @@ private long broadcastLong() { private String format(final int[] octets) { final int last = octets.length - 1; final StringBuilder builder = new StringBuilder(); - for (int i = 0;; i++) { + for (int i = 0; ; i++) { builder.append(octets[i]); if (i == last) { return builder.toString(); @@ -214,13 +213,13 @@ private int[] toArray(final int val) { */ @Override public String toString() { - return "CIDR Signature:\t[" + getCidrSignature() + "]\n" + - " Netmask: [" + getNetmask() + "]\n" + - " Network: [" + getNetworkAddress() + "]\n" + - " Broadcast: [" + getBroadcastAddress() + "]\n" + - " First address: [" + getLowAddress() + "]\n" + - " Last address: [" + getHighAddress() + "]\n" + - " Address Count: [" + getAddressCountLong() + "]\n"; + return "CIDR Signature:\t[" + getCidrSignature() + "]\n" + " Netmask: [" + + getNetmask() + "]\n" + " Network: [" + + getNetworkAddress() + "]\n" + " Broadcast: [" + + getBroadcastAddress() + "]\n" + " First address: [" + + getLowAddress() + "]\n" + " Last address: [" + + getHighAddress() + "]\n" + " Address Count: [" + + getAddressCountLong() + "]\n"; } } @@ -372,5 +371,4 @@ public boolean isInclusiveHostCount() { public void setInclusiveHostCount(final boolean inclusiveHostCount) { this.inclusiveHostCount = inclusiveHostCount; } - } diff --git a/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidator.java b/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidator.java index a3029865e..1edde5bb7 100644 --- a/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidator.java +++ b/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidator.java @@ -37,7 +37,7 @@ * @version $Revision$ * @since Validator 1.4 */ -//[PATCH] +// [PATCH] @Restricted(NoExternalUse.class) // end of [PATCH] public class InetAddressValidator implements Serializable { @@ -50,8 +50,7 @@ public class InetAddressValidator implements Serializable { private static final long serialVersionUID = -919201640201914789L; - private static final String IPV4_REGEX = - "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; + private static final String IPV4_REGEX = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; // Max number of hex groups (separated by :) in an IPV6 address private static final int IPV6_MAX_HEX_GROUPS = 8; @@ -118,7 +117,6 @@ public boolean isValidInet4Address(String inet4Address) { if (ipSegment.length() > 1 && ipSegment.startsWith("0")) { return false; } - } return true; diff --git a/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidator.java b/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidator.java index 1b3291cc3..52fde8593 100644 --- a/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidator.java +++ b/src/main/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidator.java @@ -70,7 +70,7 @@ * @version $Revision$ * @since Validator 1.4 */ -//[PATCH] +// [PATCH] @Restricted(NoExternalUse.class) // end of [PATCH] public class RegexValidator implements Serializable { @@ -133,7 +133,7 @@ public RegexValidator(String[] regexs, boolean caseSensitive) { if (regexs[i] == null || regexs[i].isEmpty()) { throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); } - patterns[i] = Pattern.compile(regexs[i], flags); + patterns[i] = Pattern.compile(regexs[i], flags); } } @@ -182,7 +182,6 @@ public String[] match(String value) { return null; } - /** * Validate a value against the set of regular expressions * returning a String value of the aggregated groups. @@ -232,5 +231,4 @@ public String toString() { buffer.append("}"); return buffer.toString(); } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/ApplicationLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/ApplicationLayer.java index b6fe7f98d..930092931 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/ApplicationLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/ApplicationLayer.java @@ -254,5 +254,4 @@ public final boolean isRecvOpen() { return false; } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/FilterLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/FilterLayer.java index 68eddf5ea..de808d951 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/FilterLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/FilterLayer.java @@ -149,7 +149,7 @@ final void onRecvRemoved() { protected final void abort(@NonNull IOException cause) { if (LOGGER.isLoggable(Level.FINEST)) { LogRecord record = new LogRecord(Level.FINEST, "[{0}] Aborted"); - record.setParameters(new Object[]{stack().name()}); + record.setParameters(new Object[] {stack().name()}); record.setThrown(cause); LOGGER.log(record); } @@ -166,7 +166,7 @@ protected final void abort(@NonNull IOException cause) { } catch (IOException e) { if (LOGGER.isLoggable(Level.FINE)) { LogRecord record = new LogRecord(Level.FINE, "[{0}] Close notification only partially completed"); - record.setParameters(new Object[]{stack().name()}); + record.setParameters(new Object[] {stack().name()}); record.setThrown(e); LOGGER.log(record); } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/IOHub.java b/src/main/java/org/jenkinsci/remoting/protocol/IOHub.java index 3dd37060b..fb0a7a69c 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/IOHub.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/IOHub.java @@ -76,7 +76,8 @@ public class IOHub implements Executor, Closeable, Runnable, ByteBufferPool { * Defines the Selector wakeup timeout via a system property. Defaults to {@code 1000ms}. * @since 3.15 */ - private static final long SELECTOR_WAKEUP_TIMEOUT_MS = Long.getLong(IOHub.class.getName() + ".selectorWakeupTimeout", 1000); + private static final long SELECTOR_WAKEUP_TIMEOUT_MS = + Long.getLong(IOHub.class.getName() + ".selectorWakeupTimeout", 1000); /** * The next ID to use. @@ -90,6 +91,7 @@ public class IOHub implements Executor, Closeable, Runnable, ByteBufferPool { * Our selector. */ private final Selector selector; + private volatile boolean ioHubRunning = false; private final Object selectorLockObject = new Object(); @@ -151,7 +153,8 @@ private IOHub(Executor executor) throws IOException { public static IOHub create(Executor executor) throws IOException { IOHub result = new IOHub(executor); executor.execute(result); - LOGGER.log(Level.FINE, "Starting an additional Selector wakeup thread. See JENKINS-47965 for more information."); + LOGGER.log( + Level.FINE, "Starting an additional Selector wakeup thread. See JENKINS-47965 for more information."); executor.execute(new IOHubSelectorWatcher(result)); return result; } @@ -368,9 +371,14 @@ public final void removeInterestWrite(SelectionKey key) { * @param write {@code true} to initially register for writing data. * @param callback the {@link IOHubRegistrationCallback} to notify on registration. */ - public final void register(SelectableChannel channel, IOHubReadyListener listener, boolean accept, boolean connect, - boolean read, boolean write, - IOHubRegistrationCallback callback) { + public final void register( + SelectableChannel channel, + IOHubReadyListener listener, + boolean accept, + boolean connect, + boolean read, + boolean write, + IOHubRegistrationCallback callback) { int ops = 0; if (accept) { ops |= SelectionKey.OP_ACCEPT; @@ -400,8 +408,13 @@ public final void register(SelectableChannel channel, IOHubReadyListener listene * @param write {@code true} to initially register for writing data. * @return the {@link Future} for the {@link SelectionKey}. */ - public final Future register(SelectableChannel channel, IOHubReadyListener listener, boolean accept, - boolean connect, boolean read, boolean write) { + public final Future register( + SelectableChannel channel, + IOHubReadyListener listener, + boolean accept, + boolean connect, + boolean read, + boolean write) { IOHubRegistrationFutureAdapterImpl callback = new IOHubRegistrationFutureAdapterImpl(); register(channel, listener, accept, connect, read, write, callback); return callback.getFuture(); @@ -456,7 +469,8 @@ public final void run() { } else { // On Windows the select(timeout) operation ALWAYS waits for the timeout, // so we workaround it by IOHubSelectorWatcher - // "Ubuntu on Windows also qualifies as Windows, so we just rely on the wakeup thread ad use infinite timeout" + // "Ubuntu on Windows also qualifies as Windows, so we just rely on the wakeup thread ad use + // infinite timeout" selected = selector.select(); } @@ -490,7 +504,8 @@ public final void run() { long sleepNanos = System.nanoTime() - cpuOverheatProtection; if (sleepNanos > 0) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, + LOGGER.log( + Level.FINEST, "Sleeping for {0,number}ns to prevent selector thread CPU monopolization!", sleepNanos); } @@ -659,7 +674,6 @@ public boolean equals(Object o) { IOHub ioHub = (IOHub) o; return _id == ioHub._id; - } /** @@ -719,8 +733,8 @@ private static final class Registration { * @param listener the listener to set as the {@link SelectionKey#attachment()}. * @param callback the callback to notify on registration. */ - Registration(int ops, SelectableChannel channel, IOHubReadyListener listener, - IOHubRegistrationCallback callback) { + Registration( + int ops, SelectableChannel channel, IOHubReadyListener listener, IOHubRegistrationCallback callback) { this.ops = ops; this.channel = channel; this.listener = listener; @@ -732,13 +746,11 @@ private static final class Registration { */ @Override public String toString() { - return "Registration{" + "ops=" + ops + - ", channel=" + channel + - ", listener=" + listener + - ", callback=" + callback + - '}'; + return "Registration{" + "ops=" + ops + ", channel=" + + channel + ", listener=" + + listener + ", callback=" + + callback + '}'; } - } /** @@ -780,13 +792,17 @@ public void run() { workerThread.setName("IOHub#" + _id + ": Worker[channel:" + key.channel() + "] / " + oldName); if (LOGGER.isLoggable(Level.FINEST)) { // TODO probably want some more info about the key here... - LOGGER.log(Level.FINEST, "Calling listener.ready({0}, {1}, {2}, {3}) for channel {4}", - new Object[] { (ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT, - (ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT, - (ops & SelectionKey.OP_READ) == SelectionKey.OP_READ, - (ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE, key.channel() }); + LOGGER.log( + Level.FINEST, "Calling listener.ready({0}, {1}, {2}, {3}) for channel {4}", new Object[] { + (ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT, + (ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT, + (ops & SelectionKey.OP_READ) == SelectionKey.OP_READ, + (ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE, + key.channel() + }); } - listener.ready((ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT, + listener.ready( + (ops & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT, (ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT, (ops & SelectionKey.OP_READ) == SelectionKey.OP_READ, (ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE); @@ -794,11 +810,13 @@ public void run() { if (LOGGER.isLoggable(Level.SEVERE)) { LogRecord record = new LogRecord(Level.SEVERE, "[{0}] Listener {1} propagated an uncaught {2}"); record.setThrown(e); - record.setParameters(new Object[]{workerThread.getName(), listener, e.getClass().getSimpleName()}); + record.setParameters(new Object[] { + workerThread.getName(), listener, e.getClass().getSimpleName() + }); LOGGER.log(record); } if (e instanceof Error) { - throw (Error)e; + throw (Error) e; } } finally { workerThread.setName(oldName); @@ -846,8 +864,10 @@ private InterestOps(SelectionKey key, int add, int remove) { private boolean interestOps() { if (LOGGER.isLoggable(Level.FINEST)) { // TODO probably want some more info about the key here... - LOGGER.log(Level.FINEST, "updating interest ops &={0} |={1} on {2} with existing ops {3} on key {4}", - new Object[] { opsAnd, opsOr, key.channel(), key.interestOps(), key }); + LOGGER.log( + Level.FINEST, + "updating interest ops &={0} |={1} on {2} with existing ops {3} on key {4}", + new Object[] {opsAnd, opsOr, key.channel(), key.interestOps(), key}); } if (key.isValid()) { key.interestOps((key.interestOps() & opsAnd) | opsOr); @@ -949,12 +969,7 @@ public void run() { final Thread workerThread = Thread.currentThread(); final String oldName = workerThread.getName(); try { - workerThread.setName( - String.format("IOHub#%d: Timeout[%s] / %s", - _id, - task, - oldName) - ); + workerThread.setName(String.format("IOHub#%d: Timeout[%s] / %s", _id, task, oldName)); task.run(); synchronized (this) { done = true; @@ -1056,5 +1071,4 @@ public synchronized Void get(long timeout, TimeUnit unit) return null; } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/NetworkLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/NetworkLayer.java index d40dee487..1e57c36a0 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/NetworkLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/NetworkLayer.java @@ -253,7 +253,7 @@ public void start() throws IOException { } catch (IOException e) { if (LOGGER.isLoggable(Level.FINEST)) { LogRecord record = new LogRecord(Level.FINEST, "[{0}] Could not complete start"); - record.setParameters(new Object[]{ptr.stack().name()}); + record.setParameters(new Object[] {ptr.stack().name()}); record.setThrown(e); LOGGER.log(record); } @@ -306,5 +306,4 @@ protected ByteBufferQueue newByteBufferQueue() { protected ProtocolStack stack() { return ptr == null ? null : ptr.stack(); } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/ProtocolStack.java b/src/main/java/org/jenkinsci/remoting/protocol/ProtocolStack.java index ebdebe116..4e472ef89 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/ProtocolStack.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/ProtocolStack.java @@ -158,10 +158,12 @@ public class ProtocolStack implements Closeable, ByteBufferPool { * @param filters the filters. * @param application the application layer. */ - private ProtocolStack(String name, NetworkLayer network, - List filters, - ApplicationLayer application, - List listeners) { + private ProtocolStack( + String name, + NetworkLayer network, + List filters, + ApplicationLayer application, + List listeners) { this.name = name; this.network = network; this.application = application; @@ -210,7 +212,7 @@ private void init() throws IOException { } catch (IOException e) { if (LOGGER.isLoggable(Level.FINEST)) { LogRecord record = new LogRecord(Level.FINEST, "[{0}] Start failure"); - record.setParameters(new Object[]{name()}); + record.setParameters(new Object[] {name()}); record.setThrown(e); LOGGER.log(record); } @@ -254,7 +256,7 @@ public String name() { public void name(String name) { if (!(Objects.equals(this.name, name))) { if (LOGGER.isLoggable(Level.FINER)) { - LOGGER.log(Level.FINER, "[{0}] is now known as [{1}]", new Object[]{this.name, name}); + LOGGER.log(Level.FINER, "[{0}] is now known as [{1}]", new Object[] {this.name, name}); } this.name = name != null && !name.isEmpty() ? name : this.name; } @@ -273,7 +275,7 @@ public void close() throws IOException { } catch (IOException e) { if (LOGGER.isLoggable(Level.FINEST)) { LogRecord record = new LogRecord(Level.FINEST, "[{0}] Abnormal close"); - record.setParameters(new Object[]{name()}); + record.setParameters(new Object[] {name()}); record.setThrown(e); LOGGER.log(record); } @@ -380,7 +382,6 @@ public String toString() { for (Listener listener : listeners) { listener.onClosed(this, cause); } - } /** @@ -553,13 +554,12 @@ public ProtocolStack build(ApplicationLayer application) throws IOExce } checkNotBuilt(); built = true; - ProtocolStack stack = - new ProtocolStack<>( - name == null || name.isEmpty() ? String.format("Stack-%d", id.incrementAndGet()) : name, - network, - filters, - application, - listeners); + ProtocolStack stack = new ProtocolStack<>( + name == null || name.isEmpty() ? String.format("Stack-%d", id.incrementAndGet()) : name, + network, + filters, + application, + listeners); stack.init(); return stack; } @@ -572,7 +572,6 @@ private void checkNotBuilt() { throw new IllegalStateException("Builder is single-shot as Network layers cannot be reused"); } } - } /** @@ -865,7 +864,7 @@ private Ptr getNextSend() { while (this.nextSend != nextSend && this.nextSend != null && this.nextSend.removed) { assert this.nextSend.layer instanceof FilterLayer : "this is the layer before and there is a layer after nextSend thus nextSend " - + "*must* be a FilterLayer"; + + "*must* be a FilterLayer"; ((FilterLayer) this.nextSend.layer).onSendRemoved(); // remove this.nextSend from the stack as it has set it's removed flag Ptr tmp = this.nextSend.nextSend; @@ -918,7 +917,7 @@ private Ptr getNextRecv() { while (this.nextRecv != nextRecv && this.nextRecv != null && this.nextRecv.removed) { assert this.nextRecv.layer instanceof FilterLayer : "this is the layer before and there is a layer after nextRecv thus nextRecv " - + "*must* be a FilterLayer"; + + "*must* be a FilterLayer"; ((FilterLayer) this.nextRecv.layer).onRecvRemoved(); // remove this.nextRecv from the stack as it has set it's removed flag Ptr tmp = this.nextRecv.nextRecv; @@ -931,7 +930,6 @@ private Ptr getNextRecv() { } return nextRecv; } - } /** @@ -948,5 +946,4 @@ public interface Listener { */ void onClosed(ProtocolStack stack, IOException cause); } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/cert/DelegatingX509ExtendedTrustManager.java b/src/main/java/org/jenkinsci/remoting/protocol/cert/DelegatingX509ExtendedTrustManager.java index 50660baab..9bc83a06e 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/cert/DelegatingX509ExtendedTrustManager.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/cert/DelegatingX509ExtendedTrustManager.java @@ -150,8 +150,7 @@ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngi * {@inheritDoc} */ @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { validateAuthType(authType); validateChain(chain); delegate.checkClientTrusted(chain, authType); @@ -161,8 +160,7 @@ public void checkClientTrusted(X509Certificate[] chain, String authType) * {@inheritDoc} */ @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { validateAuthType(authType); validateChain(chain); delegate.checkServerTrusted(chain, authType); diff --git a/src/main/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManager.java b/src/main/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManager.java index dc5055408..46bcc713c 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManager.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManager.java @@ -92,8 +92,8 @@ public PublicKeyMatchingX509ExtendedTrustManager(PublicKey... publicKeys) { * have trusted any public keys. * @param publicKeys the initial list of trusted public keys. */ - public PublicKeyMatchingX509ExtendedTrustManager(boolean strictClient, boolean strictServer, - PublicKey... publicKeys) { + public PublicKeyMatchingX509ExtendedTrustManager( + boolean strictClient, boolean strictServer, PublicKey... publicKeys) { this.publicKeys = new ArrayList<>(Arrays.asList(publicKeys)); this.strictClient = strictClient; this.strictServer = strictServer; @@ -202,20 +202,19 @@ private void checkPublicKey(boolean client, X509Certificate[] chain) throws Cert PublicKey chainKey = chain[0].getPublicKey(); byte[] chainKeyEncoded = chainKey.getEncoded(); if (chainKeyEncoded == null) { - throw new CertificateException( - String.format("Public key of the first certificate in chain (subject: '%s') " - + "(algorithm: '%s'; format: '%s') does not support binary encoding", - chain[0].getSubjectDN(), chainKey.getAlgorithm(), chainKey.getFormat())); + throw new CertificateException(String.format( + "Public key of the first certificate in chain (subject: '%s') " + + "(algorithm: '%s'; format: '%s') does not support binary encoding", + chain[0].getSubjectDN(), chainKey.getAlgorithm(), chainKey.getFormat())); } synchronized (publicKeys) { if (publicKeys.isEmpty() ? (client ? !strictClient : !strictServer) : isTrusted(chainKey)) { return; } } - throw new CertificateException( - String.format("Public key of the first certificate in chain (subject: %s) " - + "is not in the list of trusted keys", - chain[0].getSubjectDN())); + throw new CertificateException(String.format( + "Public key of the first certificate in chain (subject: %s) " + "is not in the list of trusted keys", + chain[0].getSubjectDN())); } /** diff --git a/src/main/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManager.java b/src/main/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManager.java index f4635d725..9e9aecc08 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManager.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManager.java @@ -152,8 +152,7 @@ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngi * {@inheritDoc} */ @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { validateAuthType(authType); validateChain(chain); checkValidity(chain); @@ -164,8 +163,7 @@ public void checkClientTrusted(X509Certificate[] chain, String authType) * {@inheritDoc} */ @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { validateAuthType(authType); validateChain(chain); checkValidity(chain); diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayer.java index f40d1c709..f89486d22 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayer.java @@ -119,17 +119,20 @@ private static String toHexString(ByteBuffer buffer) { return expectHex.toString(); } - @SuppressFBWarnings(value = "FORMAT_STRING_MANIPULATION", justification = "As this converts a String to a Hex string there is little that can be manipulated.") + @SuppressFBWarnings( + value = "FORMAT_STRING_MANIPULATION", + justification = "As this converts a String to a Hex string there is little that can be manipulated.") private void abort(String type) throws ConnectionRefusalException { aborted = true; if (LOGGER.isLoggable(Level.WARNING)) { - LOGGER.log(Level.WARNING, - "[{0}] {1} acknowledgement sequence, expected 0x{2} got 0x{3}", - new Object[]{stack().name(), type, toHexString(sendAck), toHexString(recvAck)}); + LOGGER.log(Level.WARNING, "[{0}] {1} acknowledgement sequence, expected 0x{2} got 0x{3}", new Object[] { + stack().name(), type, toHexString(sendAck), toHexString(recvAck) + }); } - ConnectionRefusalException cause = new ConnectionRefusalException( - String.format(type + " acknowledgement received, expected 0x%s got 0x%s", - toHexString(sendAck), toHexString(recvAck))); + ConnectionRefusalException cause = new ConnectionRefusalException(String.format( + type + " acknowledgement received, expected 0x%s got 0x%s", + toHexString(sendAck), + toHexString(recvAck))); abort(cause); throw cause; } @@ -172,17 +175,20 @@ private boolean receivedPartialAck() { @Override public void start() throws IOException { synchronized (sendLock) { - timeout = stack().executeLater(() -> { - LOGGER.info("Timeout waiting for ACK"); - IOException cause = new IOException("Timeout waiting for ACK"); - abort(cause); - try { - doCloseSend(); - onRecvClosed(cause); - } catch (IOException e) { - // ignore - } - }, stack().getHandshakingTimeout(), stack().getHandshakingUnits()); + timeout = stack().executeLater( + () -> { + LOGGER.info("Timeout waiting for ACK"); + IOException cause = new IOException("Timeout waiting for ACK"); + abort(cause); + try { + doCloseSend(); + onRecvClosed(cause); + } catch (IOException e) { + // ignore + } + }, + stack().getHandshakingTimeout(), + stack().getHandshakingUnits()); } try { doSend(EMPTY_BUFFER); @@ -199,9 +205,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { if (aborted) { // if aborted then the buffers are immutable, so no lock needed if (!sendAck.hasRemaining()) { - throw new ConnectionRefusalException( - String.format("Incorrect acknowledgement received, expected 0x%s got 0x%s", - toHexString(sendAck), toHexString(recvAck))); + throw new ConnectionRefusalException(String.format( + "Incorrect acknowledgement received, expected 0x%s got 0x%s", + toHexString(sendAck), toHexString(recvAck))); } throw new ConnectionRefusalException("Connection closed before acknowledgement send"); } @@ -213,8 +219,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { abort("Incorrect"); } else { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of acknowledgement", - new Object[]{stack().name(), recvAck.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of acknowledgement", new Object[] { + stack().name(), recvAck.remaining() + }); } } return; @@ -267,9 +274,11 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { public void onRecvClosed(IOException cause) throws IOException { synchronized (recvLock) { if (recvAck.hasRemaining() && recvAck.position() > 0) { - super.onRecvClosed(new ConnectionRefusalException(cause, + super.onRecvClosed(new ConnectionRefusalException( + cause, "Partial acknowledgement received, expecting 0x%s got 0x%s", - toHexString(sendAck), toHexString(recvAck))); + toHexString(sendAck), + toHexString(recvAck))); return; } } @@ -301,9 +310,9 @@ public boolean isRecvOpen() { public void doSend(@NonNull ByteBuffer data) throws IOException { if (aborted) { if (!sendAck.hasRemaining()) { - throw new ConnectionRefusalException( - String.format("Incorrect acknowledgement received, expected 0x%s got 0x%s", - toHexString(sendAck), toHexString(recvAck))); + throw new ConnectionRefusalException(String.format( + "Incorrect acknowledgement received, expected 0x%s got 0x%s", + toHexString(sendAck), toHexString(recvAck))); } throw new ConnectionRefusalException("Connection closed before acknowledgement send"); } @@ -358,5 +367,4 @@ private void complete() { completed(); } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/AgentProtocolClientFilterLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/AgentProtocolClientFilterLayer.java index ed06fac89..31af0a024 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/AgentProtocolClientFilterLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/AgentProtocolClientFilterLayer.java @@ -96,5 +96,4 @@ public synchronized void doSend(@NonNull ByteBuffer data) throws IOException { completed(); } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/BIONetworkLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/BIONetworkLayer.java index 24a9fd17d..ff98ca237 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/BIONetworkLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/BIONetworkLayer.java @@ -100,7 +100,7 @@ public BIONetworkLayer(IOHub ioHub, ReadableByteChannel in, WritableByteChannel @Override protected void write(@NonNull ByteBuffer data) throws IOException { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] SEND: {1} bytes", new Object[]{stack().name(), data.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] SEND: {1} bytes", new Object[] {stack().name(), data.remaining()}); } if (!data.hasRemaining()) { // no-op return immediately @@ -267,7 +267,7 @@ public void run() { // will likely be reported elsewhere, so we just trace this at FINER LogRecord record = new LogRecord(Level.FINER, "[{0}] Unexpected I/O exception"); record.setThrown(e); - record.setParameters(new Object[]{stack().name()}); + record.setParameters(new Object[] {stack().name()}); LOGGER.log(record); } onRecvClosed(); @@ -277,15 +277,18 @@ public void run() { if (LOGGER.isLoggable(Level.WARNING)) { LogRecord record = new LogRecord(Level.WARNING, "[{0}] Uncaught {1}"); record.setThrown(e); - record.setParameters(new Object[]{stack().name(), e.getClass().getSimpleName()}); + record.setParameters(new Object[] { + stack().name(), e.getClass().getSimpleName() + }); } onRecvClosed(); return; } ((Buffer) buffer).flip(); if (buffer.hasRemaining() && LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes", - new Object[]{stack().name(), buffer.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes", new Object[] { + stack().name(), buffer.remaining() + }); } while (buffer.hasRemaining()) { try { @@ -304,7 +307,8 @@ public void run() { if (LOGGER.isLoggable(Level.SEVERE)) { LogRecord record = new LogRecord(Level.SEVERE, "[{0}] Reader thread killed by {1}"); record.setThrown(e); - record.setParameters(new Object[]{stack().name(), e.getClass().getSimpleName()}); + record.setParameters( + new Object[] {stack().name(), e.getClass().getSimpleName()}); LOGGER.log(record); } if (e instanceof Error) { @@ -319,6 +323,5 @@ public void run() { } } } - } } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/ChannelApplicationLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/ChannelApplicationLayer.java index 88052e12c..b3b3b410e 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/ChannelApplicationLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/ChannelApplicationLayer.java @@ -92,6 +92,7 @@ public class ChannelApplicationLayer extends ApplicationLayer> { * Listener to notify when the {@link Channel} is connected. */ private final Listener listener; + private String cookie; /** @@ -100,8 +101,7 @@ public class ChannelApplicationLayer extends ApplicationLayer> { * @param executorService the {@link ExecutorService} to use for the {@link Channel}. * @param listener the {@link Listener} to notify when the {@link Channel} is available. */ - public ChannelApplicationLayer(@NonNull ExecutorService executorService, - @CheckForNull Listener listener) { + public ChannelApplicationLayer(@NonNull ExecutorService executorService, @CheckForNull Listener listener) { this.executorService = executorService; this.listener = listener; } @@ -114,8 +114,8 @@ public ChannelApplicationLayer(@NonNull ExecutorService executorService, * @param cookie a cookie to pass through the channel. */ @Restricted(NoExternalUse.class) - public ChannelApplicationLayer(@NonNull ExecutorService executorService, - @CheckForNull Listener listener, String cookie) { + public ChannelApplicationLayer( + @NonNull ExecutorService executorService, @CheckForNull Listener listener, String cookie) { this.executorService = executorService; this.listener = listener; this.cookie = cookie; @@ -149,8 +149,8 @@ public void onRead(@NonNull ByteBuffer data) throws IOException { if (capabilityLength.hasRemaining()) { return; } - capabilityContent = ByteBuffer - .allocate(((capabilityLength.get(0) & 0xff) << 8) + (capabilityLength.get(1) & 0xff)); + capabilityContent = + ByteBuffer.allocate(((capabilityLength.get(0) & 0xff) << 8) + (capabilityLength.get(1) & 0xff)); } assert capabilityContent != null; if (capabilityContent.hasRemaining()) { @@ -167,10 +167,11 @@ public void onRead(@NonNull ByteBuffer data) throws IOException { final Capability remoteCapability = Capability.read(new ByteArrayInputStream(capabilityBytes)); transport = new ByteBufferCommandTransport(remoteCapability); try { - ChannelBuilder builder = new ChannelBuilder(stack().name(), executorService) - .withMode(Channel.Mode.BINARY); + ChannelBuilder builder = + new ChannelBuilder(stack().name(), executorService).withMode(Channel.Mode.BINARY); if (listener instanceof ChannelDecorator) { - channel = decorate(((ChannelDecorator) listener).decorate(builder)).build(transport); + channel = decorate(((ChannelDecorator) listener).decorate(builder)) + .build(transport); } else { channel = decorate(builder).build(transport); } @@ -251,7 +252,8 @@ public void onReadClosed(IOException cause) { public void start() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try (ObjectOutputStream oos = AnonymousClassWarnings.checkingObjectOutputStream(BinarySafeStream.wrap(bos))) { + try (ObjectOutputStream oos = + AnonymousClassWarnings.checkingObjectOutputStream(BinarySafeStream.wrap(bos))) { oos.writeObject(new Capability()); } ByteBuffer buffer = ByteBufferUtils.wrapUTF8(bos.toString(StandardCharsets.US_ASCII)); @@ -321,16 +323,20 @@ public ByteBufferCommandTransport(Capability remoteCapability) { */ @Override protected void write(ByteBuffer headerAndData) throws IOException { - //TODO: Any way to get channel information here + // TODO: Any way to get channel information here if (isWriteOpen()) { try { ChannelApplicationLayer.this.write(headerAndData); } catch (ClosedChannelException e) { // Probably it should be another exception type at all - throw new ChannelClosedException(null, "Protocol stack cannot write data anymore. ChannelApplicationLayer reports that the NIO Channel is closed", e); + throw new ChannelClosedException( + null, + "Protocol stack cannot write data anymore. ChannelApplicationLayer reports that the NIO Channel is closed", + e); } } else { - throw new ChannelClosedException(null, "Protocol stack cannot write data anymore. It is not open for write", null); + throw new ChannelClosedException( + null, "Protocol stack cannot write data anymore. It is not open for write", null); } } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeaders.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeaders.java index 011401017..ce4e6131f 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeaders.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeaders.java @@ -163,7 +163,10 @@ public static Map fromString(@NonNull String data) throws ParseE if (isWhitespace) { continue; } - if (c == 'n' && i + 3 < n && data.charAt(i + 1) == 'u' && data.charAt(i + 2) == 'l' + if (c == 'n' + && i + 3 < n + && data.charAt(i + 1) == 'u' + && data.charAt(i + 2) == 'l' && data.charAt(i + 3) == 'l') { i += 3; result.put(key.toString(), null); @@ -300,7 +303,6 @@ private static int decodeEscape(StringBuilder val, char c, String str, int i, in default: throw new ParseException("Unknown character escape '" + c + "'"); } - } public static String encodeEscape(int c) { @@ -310,7 +312,6 @@ public static String encodeEscape(int c) { + Character.forDigit(c & 15, 16); } - public static class ParseException extends Exception { public ParseException(String message) { super(message); diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayer.java index e6125918f..167aa6edf 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayer.java @@ -53,7 +53,8 @@ public class ConnectionHeadersFilterLayer extends FilterLayer { /** * The abort confirmation message. */ - private static final ByteBuffer ABORT_MESSAGE = ByteBufferUtils.wrapUTF8("BYE").asReadOnlyBuffer(); + private static final ByteBuffer ABORT_MESSAGE = + ByteBufferUtils.wrapUTF8("BYE").asReadOnlyBuffer(); /** * The headers to send. */ @@ -154,8 +155,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { ByteBufferUtils.put(data, headerInputLength); if (headerInputLength.hasRemaining()) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] expecting {1} more bytes of header length", - new Object[]{stack().name(), headerInputLength.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] expecting {1} more bytes of header length", new Object[] { + stack().name(), headerInputLength.remaining() + }); } return; } @@ -164,8 +166,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { ((Buffer) headerInputLength).position(2); headerInputContent = ByteBuffer.allocate(length); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Expecting {1} bytes of headers", - new Object[]{stack().name(), length}); + LOGGER.log( + Level.FINEST, "[{0}] Expecting {1} bytes of headers", new Object[] {stack().name(), length + }); } } // safe-point @@ -176,8 +179,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { ByteBufferUtils.put(data, headerInputContent); if (headerInputContent.hasRemaining()) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of headers", - new Object[]{stack().name(), headerInputContent.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of headers", new Object[] { + stack().name(), headerInputContent.remaining() + }); } return; } @@ -186,14 +190,14 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { headerInputContent.get(headerBytes, 0, headerInputContent.remaining()); final String headerAsString = new String(headerBytes, StandardCharsets.UTF_8); if (LOGGER.isLoggable(Level.FINER)) { - LOGGER.log(Level.FINER, "[{0}] Received headers \"{1}\"", - new Object[]{stack().name(), headerAsString}); + LOGGER.log( + Level.FINER, "[{0}] Received headers \"{1}\"", new Object[] {stack().name(), headerAsString + }); } try { Map headers = ConnectionHeaders.fromString(headerAsString); if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "[{0}] Received headers {1}", - new Object[]{stack().name(), headers}); + LOGGER.log(Level.FINE, "[{0}] Received headers {1}", new Object[] {stack().name(), headers}); } listener.onReceiveHeaders(headers); if (LOGGER.isLoggable(Level.FINE)) { @@ -201,27 +205,31 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { } } catch (ConnectionHeaders.ParseException e) { if (LOGGER.isLoggable(Level.WARNING)) { - LOGGER.log(Level.WARNING, "[{0}] Remote headers \"{1}\" could not be parsed: {2}", - new Object[]{stack().name(), headerAsString, e.getMessage()}); + LOGGER.log( + Level.WARNING, + "[{0}] Remote headers \"{1}\" could not be parsed: {2}", + new Object[] {stack().name(), headerAsString, e.getMessage()}); } responseOutput = ByteBufferUtils.wrapUTF8("ERROR: Malformed connection header"); if (this.headerOutput.hasRemaining()) { // flush any headers we haven't sent yet as the other side is expecting them. next().doSend(this.headerOutput); } - doStartAbort(new ConnectionRefusalException("Malformed connection header"), + doStartAbort( + new ConnectionRefusalException("Malformed connection header"), ByteBuffer.allocate(ABORT_MESSAGE.capacity())); next().doSend(responseOutput); return; } catch (ConnectionRefusalException e) { if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.log(Level.INFO, "[{0}] {1} headers from remote: {2}", - new Object[]{stack().name(), - e instanceof PermanentConnectionRefusalException - ? "Permanently refusing" : "Refusing", - e.getMessage()}); + LOGGER.log(Level.INFO, "[{0}] {1} headers from remote: {2}", new Object[] { + stack().name(), + e instanceof PermanentConnectionRefusalException ? "Permanently refusing" : "Refusing", + e.getMessage() + }); } - responseOutput = ByteBufferUtils.wrapUTF8(String.format("%s: %s", + responseOutput = ByteBufferUtils.wrapUTF8(String.format( + "%s: %s", e instanceof PermanentConnectionRefusalException ? "FATAL" : "ERROR", e.getMessage())); if (this.headerOutput.hasRemaining()) { // flush any headers we haven't sent yet as the other side is expecting them. @@ -235,14 +243,16 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { if (this.headerOutput.hasRemaining()) { // flush any headers we haven't sent yet as the other side is expecting them. if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of headers", - new Object[]{stack().name(), this.headerOutput.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of headers", new Object[] { + stack().name(), this.headerOutput.remaining() + }); } next().doSend(this.headerOutput); } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of response", - new Object[]{stack().name(), this.responseOutput.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of response", new Object[] { + stack().name(), this.responseOutput.remaining() + }); } next().doSend(responseOutput); responseInputLength = ByteBuffer.allocate(2); @@ -261,10 +271,10 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { return; } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Received confirmation of {1} headers", - new Object[]{stack().name(), - abortCause instanceof PermanentConnectionRefusalException - ? "permanently refused" : "refused"}); + LOGGER.log(Level.FINEST, "[{0}] Received confirmation of {1} headers", new Object[] { + stack().name(), + abortCause instanceof PermanentConnectionRefusalException ? "permanently refused" : "refused" + }); } abortConfirmationTimeout.cancel(false); onAbortCompleted(); @@ -280,8 +290,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { ((Buffer) this.responseInputLength).position(2); responseInputContent = ByteBuffer.allocate(length); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Expecting {1} bytes of response", - new Object[]{stack().name(), length}); + LOGGER.log( + Level.FINEST, "[{0}] Expecting {1} bytes of response", new Object[] {stack().name(), length + }); } } // safe-point @@ -292,8 +303,9 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { ByteBufferUtils.put(data, responseInputContent); if (responseInputContent.hasRemaining()) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of response", - new Object[]{stack().name(), responseInputContent.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Expecting {1} more bytes of response", new Object[] { + stack().name(), responseInputContent.remaining() + }); } return; } @@ -302,19 +314,20 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { responseInputContent.get(responseBytes, 0, responseInputContent.remaining()); String response = new String(responseBytes, StandardCharsets.UTF_8); if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "[{0}] Received response \"{1}\"", - new Object[]{stack().name(), response}); + LOGGER.log(Level.FINE, "[{0}] Received response \"{1}\"", new Object[] {stack().name(), response}); } finished = true; if (response.startsWith("ERROR: ")) { String message = response.substring("ERROR: ".length()); if (LOGGER.isLoggable(Level.INFO)) { - LOGGER.log(Level.INFO, "[{0}] Local headers refused by remote: {1}", - new Object[]{stack().name(), message}); + LOGGER.log(Level.INFO, "[{0}] Local headers refused by remote: {1}", new Object[] { + stack().name(), message + }); } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Confirming receipt of refused connection: {1}", - new Object[]{stack().name(), message}); + LOGGER.log(Level.FINEST, "[{0}] Confirming receipt of refused connection: {1}", new Object[] { + stack().name(), message + }); } next().doSend(ABORT_MESSAGE.duplicate()); doStartAbort(new ConnectionRefusalException(message), EMPTY_BUFFER); @@ -323,12 +336,16 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { if (response.startsWith("FATAL: ")) { String message = response.substring("FATAL: ".length()); if (LOGGER.isLoggable(Level.WARNING)) { - LOGGER.log(Level.WARNING, "[{0}] Local headers permanently rejected by remote: {1}", - new Object[]{stack().name(), message}); + LOGGER.log( + Level.WARNING, + "[{0}] Local headers permanently rejected by remote: {1}", + new Object[] {stack().name(), message}); } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Confirming receipt of permanently rejected connection: {1}", - new Object[]{stack().name(), message}); + LOGGER.log( + Level.FINEST, + "[{0}] Confirming receipt of permanently rejected connection: {1}", + new Object[] {stack().name(), message}); } next().doSend(ABORT_MESSAGE.duplicate()); doStartAbort(new PermanentConnectionRefusalException(message), EMPTY_BUFFER); @@ -438,8 +455,8 @@ public synchronized void onRecvClosed(IOException cause) throws IOException { if (cause instanceof ClosedChannelException) { // we are still in the stack so we have not flushed our response yet // the remote end has closed because it refused our end before flushing the streams - ConnectionRefusalException newCause = new ConnectionRefusalException( - "Remote closed connection without specifying reason"); + ConnectionRefusalException newCause = + new ConnectionRefusalException("Remote closed connection without specifying reason"); super.onRecvClosed(ThrowableUtils.chain(newCause, cause)); } else { super.onRecvClosed(cause); @@ -467,8 +484,9 @@ public void doSend(@NonNull ByteBuffer data) throws IOException { if (this.headerOutput.hasRemaining()) { // flush any headers we haven't sent yet as the other side is expecting them. if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of headers", - new Object[]{stack().name(), this.headerOutput.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of headers", new Object[] { + stack().name(), this.headerOutput.remaining() + }); } next().doSend(this.headerOutput); if (!this.headerOutput.hasRemaining() && LOGGER.isLoggable(Level.FINE)) { @@ -478,8 +496,9 @@ public void doSend(@NonNull ByteBuffer data) throws IOException { if (this.responseOutput != null && this.responseOutput.hasRemaining()) { // flush any response we haven't sent yet as the other side is expecting them. if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of response", - new Object[]{stack().name(), this.responseOutput.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] Sending {1} bytes of response", new Object[] { + stack().name(), this.responseOutput.remaining() + }); } next().doSend(this.responseOutput); if (!this.responseOutput.hasRemaining() && LOGGER.isLoggable(Level.FINE)) { @@ -540,5 +559,4 @@ public void run() { onAbortCompleted(); } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionRefusalException.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionRefusalException.java index 251e41ff6..0a0285e5d 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionRefusalException.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/ConnectionRefusalException.java @@ -35,8 +35,7 @@ */ public class ConnectionRefusalException extends IOException { - public ConnectionRefusalException() { - } + public ConnectionRefusalException() {} public ConnectionRefusalException(String message) { super(message); @@ -74,7 +73,9 @@ public ConnectionRefusalException(String message, Object... args) { * insufficient arguments given the format string, or other * illegal conditions. */ - @SuppressFBWarnings(value = "FORMAT_STRING_MANIPULATION", justification = "This is only used with String conversion to hex string.") + @SuppressFBWarnings( + value = "FORMAT_STRING_MANIPULATION", + justification = "This is only used with String conversion to hex string.") public ConnectionRefusalException(Throwable cause, String message, Object... args) { super(String.format(message, args), cause); } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/NIONetworkLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/NIONetworkLayer.java index 0d2497f08..cd60c1e98 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/NIONetworkLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/NIONetworkLayer.java @@ -93,8 +93,7 @@ public class NIONetworkLayer extends NetworkLayer implements IOHubReadyListener * @param in the source of data. * @param out the sink for data. */ - public NIONetworkLayer(IOHub ioHub, ReadableByteChannel in, - WritableByteChannel out) { + public NIONetworkLayer(IOHub ioHub, ReadableByteChannel in, WritableByteChannel out) { super(ioHub); if (!(in instanceof SelectableChannel)) { throw new IllegalArgumentException("Input channel must be a SelectableChannel"); @@ -125,8 +124,9 @@ public NIONetworkLayer(IOHub ioHub, ReadableByteChannel in, @Override public void ready(boolean accept, boolean connect, boolean read, boolean write) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "{0} - entering ready({1}, {2}, {3}, {4})", - new Object[] { Thread.currentThread().getName(), accept, connect, read, write }); + LOGGER.log(Level.FINEST, "{0} - entering ready({1}, {2}, {3}, {4})", new Object[] { + Thread.currentThread().getName(), accept, connect, read, write + }); } if (read) { recvLock.lock(); @@ -154,8 +154,9 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) default: ((Buffer) recv).flip(); if (logFinest) { - LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes", - new Object[]{stack().name(), recv.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes", new Object[] { + stack().name(), recv.remaining() + }); } while (recv.hasRemaining()) { onRead(recv); @@ -173,7 +174,7 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) // will be reported elsewhere, so we just trace this at FINER LogRecord record = new LogRecord(Level.FINER, "[{0}] Unexpected I/O exception"); record.setThrown(e); - record.setParameters(new Object[]{stack().name()}); + record.setParameters(new Object[] {stack().name()}); LOGGER.log(record); } recvKey.cancel(); @@ -184,7 +185,9 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) if (LOGGER.isLoggable(Level.SEVERE)) { LogRecord record = new LogRecord(Level.SEVERE, "[{0}] Uncaught {1}"); record.setThrown(t); - record.setParameters(new Object[]{stack().name(), t.getClass().getSimpleName()}); + record.setParameters(new Object[] { + stack().name(), t.getClass().getSimpleName() + }); LOGGER.log(record); } } finally { @@ -213,15 +216,17 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) sendHasRemaining = sendQueue.hasRemaining(); } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] sendHasRemaining - has remaining: {1}", - new Object[] { Thread.currentThread().getName(), sendHasRemaining }); + LOGGER.log(Level.FINEST, "[{0}] sendHasRemaining - has remaining: {1}", new Object[] { + Thread.currentThread().getName(), sendHasRemaining + }); } ((Buffer) send).flip(); try { final int sentBytes = out.write(send); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] sentBytes - sent {1} bytes", - new Object[] { Thread.currentThread().getName(), sentBytes }); + LOGGER.log(Level.FINEST, "[{0}] sentBytes - sent {1} bytes", new Object[] { + Thread.currentThread().getName(), sentBytes + }); } if (sentBytes == -1) { sendKey.cancel(); @@ -235,7 +240,7 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) // will be reported elsewhere, so we just trace this at FINER LogRecord record = new LogRecord(Level.FINER, "[{0}] Unexpected I/O exception"); record.setThrown(e); - record.setParameters(new Object[]{stack().name()}); + record.setParameters(new Object[] {stack().name()}); LOGGER.log(record); } sendKey.cancel(); @@ -258,7 +263,10 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) } } if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "{0} - leaving ready(...)", Thread.currentThread().getName()); + LOGGER.log( + Level.FINEST, + "{0} - leaving ready(...)", + Thread.currentThread().getName()); } } @@ -268,7 +276,7 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) @Override protected void write(@NonNull ByteBuffer data) throws IOException { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] SEND: {1} bytes", new Object[]{stack().name(), data.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] SEND: {1} bytes", new Object[] {stack().name(), data.remaining()}); } if (!data.hasRemaining()) { return; @@ -315,15 +323,27 @@ public void start() throws IOException { final SelectableChannel out = (SelectableChannel) this.out; if (in == out) { in.configureBlocking(false); - getIoHub().register(in, this, false, false, true, pendingWrite, - new RegistrationCallbackImpl(true, true, pendingWrite) - ); + getIoHub() + .register( + in, + this, + false, + false, + true, + pendingWrite, + new RegistrationCallbackImpl(true, true, pendingWrite)); } else { in.configureBlocking(false); out.configureBlocking(false); - getIoHub().register(out, this, false, false, false, pendingWrite, - new RegistrationCallbackImpl(true, false, pendingWrite) - ); + getIoHub() + .register( + out, + this, + false, + false, + false, + pendingWrite, + new RegistrationCallbackImpl(true, false, pendingWrite)); getIoHub().register(in, this, false, false, true, false, new RegistrationCallbackImpl(false, true, false)); } super.start(); @@ -416,5 +436,4 @@ public void onClosedChannel(ClosedChannelException e) { onRecvClosed(); } } - } diff --git a/src/main/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayer.java b/src/main/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayer.java index 1c7709a8c..1b8242fd6 100644 --- a/src/main/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayer.java +++ b/src/main/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayer.java @@ -77,6 +77,7 @@ public class SSLEngineFilterLayer extends FilterLayer { */ @CheckForNull private ByteBuffer previous; + private final AtomicReference directBufferRef = new AtomicReference<>(); /** @@ -97,9 +98,7 @@ public SSLEngineFilterLayer(@NonNull SSLEngine engine, @CheckForNull Listener li @Override public void start() throws IOException { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "{0} Starting {1}", new Object[]{ - stack().name(), sslEngine.getHandshakeStatus() - }); + LOGGER.log(Level.FINEST, "{0} Starting {1}", new Object[] {stack().name(), sslEngine.getHandshakeStatus()}); } sslEngine.beginHandshake(); onRecv(EMPTY_BUFFER); @@ -111,8 +110,9 @@ public void start() throws IOException { @Override public void onRecv(@NonNull ByteBuffer readBuffer) throws IOException { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes plus {2} retained", - new Object[]{stack().name(), readBuffer.remaining(), previous == null ? 0 : previous.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] RECV: {1} bytes plus {2} retained", new Object[] { + stack().name(), readBuffer.remaining(), previous == null ? 0 : previous.remaining() + }); } try { processRead(readBuffer); @@ -278,9 +278,9 @@ private void switchToNoSecure() { onRecvClosed(null); } catch (IOException e) { if (LOGGER.isLoggable(Level.FINE)) { - LogRecord record = new LogRecord(Level.FINE, - "[{0}] Could not complete close of read after closure of SSL session"); - record.setParameters(new Object[]{stack().name()}); + LogRecord record = new LogRecord( + Level.FINE, "[{0}] Could not complete close of read after closure of SSL session"); + record.setParameters(new Object[] {stack().name()}); record.setThrown(e); LOGGER.log(record); } @@ -301,12 +301,12 @@ public interface Listener { void onHandshakeCompleted(SSLSession session) throws ConnectionRefusalException; } - //----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- // // The following code is a modified version of the code from Apache MINA's SslHelper class. // - //----------------------------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------------------------- /** * Process the read. @@ -344,24 +344,25 @@ private void processRead(@NonNull ByteBuffer readBuffer) throws IOException { switch (result.getStatus()) { case BUFFER_UNDERFLOW: - /* we need more data */ + /* we need more data */ case CLOSED: - /* connection is already closed */ + /* connection is already closed */ done = true; break; case BUFFER_OVERFLOW: - /* resize output buffer */ + /* resize output buffer */ int newCapacity = appBuffer.capacity() * 2; stack().release(appBuffer); appBuffer = stack().acquire(newCapacity); break; case OK: - if ((handshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) && ( - result.bytesProduced() > 0)) { + if ((handshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) + && (result.bytesProduced() > 0)) { ((Buffer) appBuffer).flip(); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] DECODE: {1} bytes", - new Object[]{stack().name(), appBuffer.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] DECODE: {1} bytes", new Object[] { + stack().name(), appBuffer.remaining() + }); } next().onRecv(appBuffer); ((Buffer) appBuffer).clear(); @@ -400,8 +401,9 @@ private void processRead(@NonNull ByteBuffer readBuffer) throws IOException { ((Buffer) appBuffer).flip(); if (appBuffer.hasRemaining()) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] HANDSHAKE SEND: {1} bytes", - new Object[]{stack().name(), appBuffer.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] HANDSHAKE SEND: {1} bytes", new Object[] { + stack().name(), appBuffer.remaining() + }); } next().doSend(appBuffer); } @@ -432,8 +434,9 @@ private void processRead(@NonNull ByteBuffer readBuffer) throws IOException { */ private void processResult(SSLEngineResult.HandshakeStatus sessionStatus, SSLEngineResult operationStatus) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Handshake status: {1} engine result: {2}", - new Object[]{stack().name(), sessionStatus, operationStatus}); + LOGGER.log(Level.FINEST, "[{0}] Handshake status: {1} engine result: {2}", new Object[] { + stack().name(), sessionStatus, operationStatus + }); } switch (sessionStatus) { case NEED_TASK: // $FALL-THROUGH$ @@ -482,13 +485,15 @@ private void processWrite(@NonNull ByteBuffer message) throws IOException { while (!done) { // Encrypt the message if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] APP ENCODE: {1} bytes", - new Object[]{stack().name(), message.remaining()}); + LOGGER.log( + Level.FINEST, "[{0}] APP ENCODE: {1} bytes", new Object[] {stack().name(), message.remaining() + }); } SSLEngineResult result = sslEngine.wrap(message, appBuffer); if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] Handshake status: {1} engine result: {2}", - new Object[]{stack().name(), result.getHandshakeStatus(), result}); + LOGGER.log(Level.FINEST, "[{0}] Handshake status: {1} engine result: {2}", new Object[] { + stack().name(), result.getHandshakeStatus(), result + }); } switch (result.getStatus()) { @@ -508,8 +513,9 @@ private void processWrite(@NonNull ByteBuffer message) throws IOException { done = !message.hasRemaining(); if (appBuffer.hasRemaining()) { if (LOGGER.isLoggable(Level.FINEST)) { - LOGGER.log(Level.FINEST, "[{0}] APP SEND: {1} bytes", - new Object[]{stack().name(), appBuffer.remaining()}); + LOGGER.log(Level.FINEST, "[{0}] APP SEND: {1} bytes", new Object[] { + stack().name(), appBuffer.remaining() + }); } while (appBuffer.hasRemaining()) { next().doSend(appBuffer); @@ -539,6 +545,5 @@ enum State { * Secure credentials are removed from the session, application messages are not encrypted anymore. */ NO_CREDENTIALS - } } diff --git a/src/main/java/org/jenkinsci/remoting/util/AnonymousClassWarnings.java b/src/main/java/org/jenkinsci/remoting/util/AnonymousClassWarnings.java index 4642f86ca..972e560fa 100644 --- a/src/main/java/org/jenkinsci/remoting/util/AnonymousClassWarnings.java +++ b/src/main/java/org/jenkinsci/remoting/util/AnonymousClassWarnings.java @@ -60,7 +60,8 @@ public static void check(@NonNull Class clazz) { if (channel == null) { doCheck(clazz); } else { - // May not call methods like Class#isAnonymousClass synchronously, since these can in turn trigger remote class loading. + // May not call methods like Class#isAnonymousClass synchronously, since these can in turn trigger remote + // class loading. try { channel.executor.submit(() -> doCheck(clazz)); } catch (RejectedExecutionException x) { @@ -70,7 +71,8 @@ public static void check(@NonNull Class clazz) { } private static void doCheck(@NonNull Class c) { - if (Enum.class.isAssignableFrom(c)) { // e.g., com.cloudbees.plugins.credentials.CredentialsScope$1 ~ CredentialsScope.SYSTEM + if (Enum.class.isAssignableFrom( + c)) { // e.g., com.cloudbees.plugins.credentials.CredentialsScope$1 ~ CredentialsScope.SYSTEM // ignore, enums serialize specially } else if (c.isAnonymousClass()) { // e.g., pkg.Outer$1 warn(c, "anonymous"); @@ -85,15 +87,16 @@ private static void warn(@NonNull Class c, String kind) { String name = c.getName(); String codeSource = codeSource(c); if (codeSource == null) { - LOGGER.warning("Attempt to (de-)serialize " + kind + " class " + name + "; see: https://jenkins.io/redirect/serialization-of-anonymous-classes/"); + LOGGER.warning("Attempt to (de-)serialize " + kind + " class " + name + + "; see: https://jenkins.io/redirect/serialization-of-anonymous-classes/"); } else { // most easily tracked back to source using javap -classpath -l '' - LOGGER.warning("Attempt to (de-)serialize " + kind + " class " + name + " in " + codeSource + "; see: https://jenkins.io/redirect/serialization-of-anonymous-classes/"); + LOGGER.warning("Attempt to (de-)serialize " + kind + " class " + name + " in " + codeSource + + "; see: https://jenkins.io/redirect/serialization-of-anonymous-classes/"); } } - private static @CheckForNull - String codeSource(@NonNull Class c) { + private static @CheckForNull String codeSource(@NonNull Class c) { CodeSource cs = c.getProtectionDomain().getCodeSource(); if (cs == null) { return null; @@ -108,7 +111,8 @@ String codeSource(@NonNull Class c) { /** * Like {@link ObjectOutputStream#ObjectOutputStream(OutputStream)} but applies {@link #check} when writing classes. */ - public static @NonNull ObjectOutputStream checkingObjectOutputStream(@NonNull OutputStream outputStream) throws IOException { + public static @NonNull ObjectOutputStream checkingObjectOutputStream(@NonNull OutputStream outputStream) + throws IOException { return new ObjectOutputStream(outputStream) { @Override protected void annotateClass(Class c) throws IOException { @@ -119,5 +123,4 @@ protected void annotateClass(Class c) throws IOException { } private AnonymousClassWarnings() {} - } diff --git a/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueue.java b/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueue.java index dab06791a..70183c973 100644 --- a/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueue.java +++ b/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueue.java @@ -306,7 +306,7 @@ public long skip(long bytes) { } int remaining = buffers[readIndex].position() - readPosition; if (remaining > bytes) { - readPosition += (int)bytes; + readPosition += (int) bytes; skipped += bytes; break; } else { @@ -526,18 +526,17 @@ public void unget(ByteBuffer src) { */ @Override public String toString() { - return getClass().getName() + - "[hasRemaining=" + - hasRemaining() + - ",readIndex=" + - readIndex + - ",writeIndex=" + - writeIndex + - ",capacity=" + - buffers.length + - ",bufSize=" + - bufferSize + - ']'; + return getClass().getName() + "[hasRemaining=" + + hasRemaining() + + ",readIndex=" + + readIndex + + ",writeIndex=" + + writeIndex + + ",capacity=" + + buffers.length + + ",bufSize=" + + bufferSize + + ']'; } /** diff --git a/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStream.java b/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStream.java index 1f028f851..ffffb0990 100644 --- a/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStream.java +++ b/src/main/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStream.java @@ -43,6 +43,7 @@ public class ByteBufferQueueInputStream extends InputStream { * The backing queue. */ private final ByteBufferQueue queue; + private final int length; private int pos; /** @@ -161,7 +162,7 @@ public long skip(long n) throws IOException { } int l = mark.limit(); int p = mark.position(); - ((Buffer) mark).limit(mark.position() + (int)n); + ((Buffer) mark).limit(mark.position() + (int) n); queue.get(mark); int skipped = mark.position() - p; ((Buffer) mark).limit(l); diff --git a/src/main/java/org/jenkinsci/remoting/util/DurationFormatter.java b/src/main/java/org/jenkinsci/remoting/util/DurationFormatter.java index d9d98de7e..dafa0cc8f 100644 --- a/src/main/java/org/jenkinsci/remoting/util/DurationFormatter.java +++ b/src/main/java/org/jenkinsci/remoting/util/DurationFormatter.java @@ -33,7 +33,7 @@ */ @Restricted(NoExternalUse.class) public final class DurationFormatter { - private DurationFormatter(){} + private DurationFormatter() {} public static String format(Duration d) { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/jenkinsci/remoting/util/DurationStyle.java b/src/main/java/org/jenkinsci/remoting/util/DurationStyle.java index 3a8e88b65..18438d827 100644 --- a/src/main/java/org/jenkinsci/remoting/util/DurationStyle.java +++ b/src/main/java/org/jenkinsci/remoting/util/DurationStyle.java @@ -52,8 +52,7 @@ public Duration parse(String value, ChronoUnit unit) { String suffix = matcher.group(2); return ((suffix != null && !suffix.isEmpty()) ? Unit.fromSuffix(suffix) : Unit.fromChronoUnit(unit)) .parse(matcher.group(1)); - } - catch (Exception ex) { + } catch (Exception ex) { throw new IllegalArgumentException("'" + value + "' is not a valid simple duration", ex); } } @@ -62,7 +61,6 @@ public Duration parse(String value, ChronoUnit unit) { public String print(Duration value, ChronoUnit unit) { return Unit.fromChronoUnit(unit).print(value); } - }, /** @@ -74,8 +72,7 @@ public String print(Duration value, ChronoUnit unit) { public Duration parse(String value, ChronoUnit unit) { try { return Duration.parse(value); - } - catch (Exception ex) { + } catch (Exception ex) { throw new IllegalArgumentException("'" + value + "' is not a valid ISO-8601 duration", ex); } } @@ -84,7 +81,6 @@ public Duration parse(String value, ChronoUnit unit) { public String print(Duration value, ChronoUnit unit) { return value.toString(); } - }; private final Pattern pattern; @@ -263,7 +259,5 @@ public static Unit fromSuffix(String suffix) { } throw new IllegalArgumentException("Unknown unit '" + suffix + "'"); } - } - } diff --git a/src/main/java/org/jenkinsci/remoting/util/ExecutorServiceUtils.java b/src/main/java/org/jenkinsci/remoting/util/ExecutorServiceUtils.java index ad7e15385..4bedd36d5 100644 --- a/src/main/java/org/jenkinsci/remoting/util/ExecutorServiceUtils.java +++ b/src/main/java/org/jenkinsci/remoting/util/ExecutorServiceUtils.java @@ -36,21 +36,22 @@ */ @Restricted(NoExternalUse.class) public class ExecutorServiceUtils { - + private ExecutorServiceUtils() { // The class cannot be constructed } - + /** - * Submits a task to the executor service without further handling. - * The original {@link ExecutorService#submit(Runnable)} method actually expects this return value + * Submits a task to the executor service without further handling. + * The original {@link ExecutorService#submit(Runnable)} method actually expects this return value * to be handled, but this method explicitly relies on the external logic to handle the future operation. * Use on your own risk. * @param es Executor service * @param runnable Operation to be executed * @throws ExecutionRejectedException Execution is rejected by the executor service */ - @SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", + @SuppressFBWarnings( + value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", justification = "User of this API explicitly submits the task in the async mode on his own risk") public static void submitAsync(@NonNull ExecutorService es, @NonNull Runnable runnable) throws ExecutionRejectedException { @@ -61,7 +62,7 @@ public static void submitAsync(@NonNull ExecutorService es, @NonNull Runnable ru throw new ExecutionRejectedException(es, ex); } } - + /** * Creates a runtime {@link RejectedExecutionException} for {@link ExecutionRejectedException}. * This version takes the {@link ExecutionRejectedException#isFatal()} value into account @@ -72,15 +73,14 @@ public static void submitAsync(@NonNull ExecutorService es, @NonNull Runnable ru */ @NonNull public static RejectedExecutionException createRuntimeException( - @NonNull String message, - @NonNull ExecutionRejectedException cause) { + @NonNull String message, @NonNull ExecutionRejectedException cause) { if (cause.isFatal()) { return new FatalRejectedExecutionException(message, cause); } else { return new RejectedExecutionException(message, cause); } } - + /** * Version of {@link RejectedExecutionException}, which treats the error as fatal. * It means that the Executor Service will never accept this or any other task in the future. @@ -89,17 +89,16 @@ public static RejectedExecutionException createRuntimeException( public static class FatalRejectedExecutionException extends RejectedExecutionException { private static final long serialVersionUID = 1L; - + public FatalRejectedExecutionException(String message) { super(message); } - + public FatalRejectedExecutionException(String message, Throwable cause) { super(message, cause); } - } - + /** * Wraps the runtime {@link RejectedExecutionException}. * The exception also caches the serializable metadata. @@ -111,7 +110,7 @@ public static class ExecutionRejectedException extends Exception { private final String executorServiceDisplayName; private final String runnableDisplayName; private final boolean fatal; - + /** * Constructor of the new exception. * @param es Executor service, which rejected the exception @@ -139,7 +138,7 @@ public String getRunnableDisplayName() { public boolean isFatal() { return fatal; } - - //TODO: inject the metadata into the toString() call? + + // TODO: inject the metadata into the toString() call? } } diff --git a/src/main/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStream.java b/src/main/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStream.java index f132c5bec..06052e26a 100644 --- a/src/main/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStream.java +++ b/src/main/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStream.java @@ -113,15 +113,13 @@ public int available() throws IOException { * {@inheritDoc} */ @Override - public synchronized void mark(int readlimit) { - } + public synchronized void mark(int readlimit) {} /** * {@inheritDoc} */ @Override - public synchronized void reset() throws IOException { - } + public synchronized void reset() throws IOException {} /** * {@inheritDoc} diff --git a/src/main/java/org/jenkinsci/remoting/util/IOUtils.java b/src/main/java/org/jenkinsci/remoting/util/IOUtils.java index 22c399cca..cf168999c 100644 --- a/src/main/java/org/jenkinsci/remoting/util/IOUtils.java +++ b/src/main/java/org/jenkinsci/remoting/util/IOUtils.java @@ -58,6 +58,4 @@ public static void closeQuietly(Closeable closeable) { // ignore } } - - } diff --git a/src/main/java/org/jenkinsci/remoting/util/SettableFuture.java b/src/main/java/org/jenkinsci/remoting/util/SettableFuture.java index f50c788ac..68daea3ca 100644 --- a/src/main/java/org/jenkinsci/remoting/util/SettableFuture.java +++ b/src/main/java/org/jenkinsci/remoting/util/SettableFuture.java @@ -107,8 +107,7 @@ public static SettableFuture create() { /** * Use {@link #create()}. */ - private SettableFuture() { - } + private SettableFuture() {} /** * Completes the future with the supplied value. @@ -273,8 +272,10 @@ public void addListener(@NonNull Runnable listener, @NonNull Executor executor) try { executor.execute(listener); } catch (RuntimeException e) { - LOGGER.log(Level.SEVERE, e, () -> - "RuntimeException while executing runnable " + listener + " with executor " + executor); + LOGGER.log( + Level.SEVERE, + e, + () -> "RuntimeException while executing runnable " + listener + " with executor " + executor); } } } @@ -294,11 +295,12 @@ private void notifyListeners() { try { entry.getValue().execute(entry.getKey()); } catch (RuntimeException e) { - LOGGER.log(Level.SEVERE, e, () -> - "RuntimeException while executing runnable " + entry.getKey() + " with executor " + LOGGER.log( + Level.SEVERE, + e, + () -> "RuntimeException while executing runnable " + entry.getKey() + " with executor " + entry.getValue()); } - } } } diff --git a/src/main/java/org/jenkinsci/remoting/util/ThrowableUtils.java b/src/main/java/org/jenkinsci/remoting/util/ThrowableUtils.java index 55987d0e3..66929ab65 100644 --- a/src/main/java/org/jenkinsci/remoting/util/ThrowableUtils.java +++ b/src/main/java/org/jenkinsci/remoting/util/ThrowableUtils.java @@ -51,8 +51,12 @@ private ThrowableUtils() { */ @CheckForNull public static T chain(@CheckForNull T1 e1, @CheckForNull T2 e2) { - if (e1 == null) return e2; - if (e2 == null) return e1; + if (e1 == null) { + return e2; + } + if (e2 == null) { + return e1; + } e1.addSuppressed(e2); return e1; } diff --git a/src/main/java/org/jenkinsci/remoting/util/VersionNumber.java b/src/main/java/org/jenkinsci/remoting/util/VersionNumber.java index 5eab6ca01..3908106fc 100644 --- a/src/main/java/org/jenkinsci/remoting/util/VersionNumber.java +++ b/src/main/java/org/jenkinsci/remoting/util/VersionNumber.java @@ -86,7 +86,8 @@ private interface Item { int WILDCARD_ITEM = 3; - // Cannot set name to compareTo because FindBugs will think this interface extend Comparable and fire CO_ABSTRACT_SELF bug + // Cannot set name to compareTo because FindBugs will think this interface extend Comparable and fire + // CO_ABSTRACT_SELF bug int compare(Item item); int getType(); @@ -101,8 +102,9 @@ private static class WildCardItem implements Item { @Override public int compare(Item item) { - if (item==null) // 1.* ( > 1.99) > 1 + if (item == null) { // 1.* ( > 1.99) > 1 return 1; + } switch (item.getType()) { case INTEGER_ITEM: case LIST_ITEM: @@ -134,8 +136,7 @@ public String toString() { /** * Represents a numeric item in the version item list. */ - private static class IntegerItem - implements Item { + private static class IntegerItem implements Item { private static final BigInteger BigInteger_ZERO = new BigInteger("0"); private final BigInteger value; @@ -196,11 +197,11 @@ public String toString() { * Represents a string in the version item list, usually a qualifier. */ private static class StringItem implements Item { - private final static String[] QUALIFIERS = {"snapshot", "alpha", "beta", "milestone", "rc", "", "sp"}; + private static final String[] QUALIFIERS = {"snapshot", "alpha", "beta", "milestone", "rc", "", "sp"}; - private final static List _QUALIFIERS = Arrays.asList(QUALIFIERS); + private static final List _QUALIFIERS = Arrays.asList(QUALIFIERS); - private final static Properties ALIASES = new Properties(); + private static final Properties ALIASES = new Properties(); static { ALIASES.put("ga", ""); @@ -398,7 +399,6 @@ public VersionNumber(String version) { private void parseVersion(String version) { this.value = version; - items = new ListItem(); Matcher matcher = SNAPSHOT.matcher(version); diff --git a/src/main/java/org/jenkinsci/remoting/util/https/NoCheckTrustManager.java b/src/main/java/org/jenkinsci/remoting/util/https/NoCheckTrustManager.java index f6f048a23..c93f0c511 100644 --- a/src/main/java/org/jenkinsci/remoting/util/https/NoCheckTrustManager.java +++ b/src/main/java/org/jenkinsci/remoting/util/https/NoCheckTrustManager.java @@ -39,12 +39,10 @@ @SuppressFBWarnings(value = "WEAK_TRUST_MANAGER", justification = "User set parameter to skip verifier.") public class NoCheckTrustManager implements X509TrustManager { @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) { - } + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {} @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) { - } + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} @Override public X509Certificate[] getAcceptedIssuers() { diff --git a/src/test/java/JarCertDump.java b/src/test/java/JarCertDump.java index cf6931292..a68cfdc33 100644 --- a/src/test/java/JarCertDump.java +++ b/src/test/java/JarCertDump.java @@ -15,7 +15,9 @@ public class JarCertDump { public static void main(String[] args) throws IOException { try (JarFile j = new JarFile(new File(args[0]))) { JarEntry je = j.getJarEntry("hudson/remoting/Channel.class"); - if (je==null) throw new IllegalArgumentException(); + if (je == null) { + throw new IllegalArgumentException(); + } IOUtils.readLines(j.getInputStream(je), StandardCharsets.UTF_8); for (Certificate c : je.getCertificates()) { System.out.println("################# Certificate #################"); diff --git a/src/test/java/OISInterception.java b/src/test/java/OISInterception.java index e2c265f45..0273ea4c7 100644 --- a/src/test/java/OISInterception.java +++ b/src/test/java/OISInterception.java @@ -14,7 +14,7 @@ public class OISInterception { public static void main(String[] args) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(Set.of("foo")); } diff --git a/src/test/java/hudson/remoting/AbstractNioChannelRunner.java b/src/test/java/hudson/remoting/AbstractNioChannelRunner.java index 7aa38eb12..f83f90ef6 100644 --- a/src/test/java/hudson/remoting/AbstractNioChannelRunner.java +++ b/src/test/java/hudson/remoting/AbstractNioChannelRunner.java @@ -17,7 +17,6 @@ public abstract class AbstractNioChannelRunner implements DualSideChannelRunner protected Channel south; - @Override public void stop(Channel channel) throws Exception { channel.close(); @@ -34,8 +33,9 @@ public void stop(Channel channel) throws Exception { nio.close(); executor.shutdown(); - if(failure!=null) - throw new AssertionError(failure); // report a failure in the south side + if (failure != null) { + throw new AssertionError(failure); // report a failure in the south side + } } @Override diff --git a/src/test/java/hudson/remoting/BinarySafeStreamTest.java b/src/test/java/hudson/remoting/BinarySafeStreamTest.java index efd79aca0..8df3111ca 100644 --- a/src/test/java/hudson/remoting/BinarySafeStreamTest.java +++ b/src/test/java/hudson/remoting/BinarySafeStreamTest.java @@ -55,7 +55,7 @@ public void test1() throws IOException { int ch = in.read(); assertEquals(b, ch); } - assertEquals(-1,in.read()); + assertEquals(-1, in.read()); } @Test @@ -67,7 +67,7 @@ public void testSingleWrite() throws IOException { try (OutputStream o = BinarySafeStream.wrap(buf)) { o.write(ds, 0, ds.length); } - assertEquals(buf.toString(),master); + assertEquals(buf.toString(), master); } @Test @@ -76,11 +76,11 @@ public void testChunkedWrites() throws IOException { String master = Base64.getEncoder().encodeToString(ds); Random r = new Random(0); - for( int i=0; i<16; i++) { + for (int i = 0; i < 16; i++) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); OutputStream o = BinarySafeStream.wrap(buf); - randomCopy(r,new ByteArrayInputStream(ds),o,false); - assertEquals(buf.toString(),master); + randomCopy(r, new ByteArrayInputStream(ds), o, false); + assertEquals(buf.toString(), master); } } @@ -98,30 +98,34 @@ private void _testRoundtrip(boolean flush) throws IOException { byte[] dataSet = getDataSet(65536); Random r = new Random(0); - for(int i=0; i<16; i++) { - if(dump) + for (int i = 0; i < 16; i++) { + if (dump) { System.out.println("test started"); + } ByteArrayOutputStream buf = new ByteArrayOutputStream(); - randomCopy(r,new ByteArrayInputStream(dataSet), BinarySafeStream.wrap(buf), flush); + randomCopy(r, new ByteArrayInputStream(dataSet), BinarySafeStream.wrap(buf), flush); - decodeByMaster(buf.toString(),dataSet); + decodeByMaster(buf.toString(), dataSet); - if(dump) + if (dump) { System.out.println("------"); + } ByteArrayOutputStream dst = new ByteArrayOutputStream(); - randomCopy(r,BinarySafeStream.wrap(new ByteArrayInputStream(buf.toByteArray())), dst,flush); + randomCopy(r, BinarySafeStream.wrap(new ByteArrayInputStream(buf.toByteArray())), dst, flush); byte[] result = dst.toByteArray(); - if(!Arrays.equals(dataSet, result)) { + if (!Arrays.equals(dataSet, result)) { String msg = print(result, 0, result.length); - for( int j=0; j= ch && ch >= -1); // make sure the range is [-1,255] + assertTrue(255 >= ch && ch >= -1); // make sure the range is [-1,255] if (ch == -1) { return; } @@ -175,7 +181,8 @@ private void randomCopy(Random r, InputStream in, OutputStream out, boolean rand byte[] tmp = new byte[start + chunk + trail]; int len = in.read(tmp, start, chunk); if (dump) { - System.out.println("read2(" + print(tmp, start, len) + ",len=" + len + ",chunk=" + chunk + ")"); + System.out.println( + "read2(" + print(tmp, start, len) + ",len=" + len + ",chunk=" + chunk + ")"); } if (len == -1) { return; @@ -219,9 +226,11 @@ private static String print(byte[] buf, int start, int len) { StringBuilder out = new StringBuilder(); out.append('{'); for (int i = 0; i < len; i++) { - byte b = buf[i+start]; - if(i>0) out.append(','); - out.append(((int)b)&0xFF); + byte b = buf[i + start]; + if (i > 0) { + out.append(','); + } + out.append(((int) b) & 0xFF); } return out.append('}').toString(); } diff --git a/src/test/java/hudson/remoting/CallableBase.java b/src/test/java/hudson/remoting/CallableBase.java index 995f81b7c..63929d359 100644 --- a/src/test/java/hudson/remoting/CallableBase.java +++ b/src/test/java/hudson/remoting/CallableBase.java @@ -6,10 +6,10 @@ /** * @author Kohsuke Kawaguchi */ -public abstract class CallableBase implements Callable { +public abstract class CallableBase implements Callable { @Override public void checkRoles(RoleChecker checker) throws SecurityException { - checker.check(this,ROLE); + checker.check(this, ROLE); } public static final Role ROLE = new Role("test callable"); diff --git a/src/test/java/hudson/remoting/ChannelFilterTest.java b/src/test/java/hudson/remoting/ChannelFilterTest.java index ab8f7e7ae..db1ee0e89 100644 --- a/src/test/java/hudson/remoting/ChannelFilterTest.java +++ b/src/test/java/hudson/remoting/ChannelFilterTest.java @@ -36,7 +36,7 @@ public V call(Callable callable) throws Exception { assertEquals("x", channel.call(new CallableCallable(c))); }); } - + private final ThreadLocal STORE = new ThreadLocal<>(); private static class CallableCallable extends CallableBase { @@ -48,8 +48,9 @@ public CallableCallable(Callable c) { @Override public Object call() throws Exception { - return c.call(); + return c.call(); } + private static final long serialVersionUID = 1L; } @@ -59,9 +60,11 @@ public void testBlacklisting(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { channel.addLocalExecutionInterceptor(new CallableDecorator() { @Override - public hudson.remoting.Callable userRequest(hudson.remoting.Callable op, hudson.remoting.Callable stem) { - if (op instanceof ShadyBusiness) + public hudson.remoting.Callable userRequest( + hudson.remoting.Callable op, hudson.remoting.Callable stem) { + if (op instanceof ShadyBusiness) { throw new SecurityException("Rejecting " + op.getClass().getName()); + } return stem; } }); @@ -69,12 +72,14 @@ public hudson.remoting.Callable userRequest(hudso // this direction is unrestricted assertEquals("gun", channel.call(new GunImporter())); - // the other direction should be rejected final IOException e = assertThrows(IOException.class, () -> channel.call(new ReverseGunImporter())); - assertEquals("Rejecting " + GunImporter.class.getName(), findSecurityException(e).getMessage()); + assertEquals( + "Rejecting " + GunImporter.class.getName(), + findSecurityException(e).getMessage()); }); } + private static SecurityException findSecurityException(Throwable x) { if (x instanceof SecurityException) { return (SecurityException) x; @@ -86,20 +91,21 @@ private static SecurityException findSecurityException(Throwable x) { } /* - Option 1: - define CallableFilter2 that decorates h.r.Callable, not j.u.c.Callable - like 'callUserRequest' maybe - Option 2: - define a separate interface. - */ + Option 1: + define CallableFilter2 that decorates h.r.Callable, not j.u.c.Callable + like 'callUserRequest' maybe + Option 2: + define a separate interface. + */ private interface ShadyBusiness {} - static class GunImporter extends CallableBase implements ShadyBusiness { + static class GunImporter extends CallableBase implements ShadyBusiness { @Override public String call() { return "gun"; } + private static final long serialVersionUID = 1L; } @@ -108,6 +114,7 @@ static class ReverseGunImporter extends CallableBase { public String call() throws Exception { return Channel.currentOrFail().call(new GunImporter()); } + private static final long serialVersionUID = 1L; } } diff --git a/src/test/java/hudson/remoting/ChannelRunner.java b/src/test/java/hudson/remoting/ChannelRunner.java index f43a6e8d4..4d44b3f14 100644 --- a/src/test/java/hudson/remoting/ChannelRunner.java +++ b/src/test/java/hudson/remoting/ChannelRunner.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, InfraDNA, Inc. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/test/java/hudson/remoting/ChannelRunners.java b/src/test/java/hudson/remoting/ChannelRunners.java index db3a2c582..c4e455702 100644 --- a/src/test/java/hudson/remoting/ChannelRunners.java +++ b/src/test/java/hudson/remoting/ChannelRunners.java @@ -15,7 +15,6 @@ public static Stream provider() { new NioPipeRunner(), new InProcessCompatibilityRunner(), new ForkRunner(), - new ForkEBCDICRunner() - ); + new ForkEBCDICRunner()); } } diff --git a/src/test/java/hudson/remoting/ChannelTest.java b/src/test/java/hudson/remoting/ChannelTest.java index e1b8c64ff..bfee8204b 100644 --- a/src/test/java/hudson/remoting/ChannelTest.java +++ b/src/test/java/hudson/remoting/ChannelTest.java @@ -40,7 +40,9 @@ public class ChannelTest { @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testCapability(ChannelRunner channelRunner) throws Exception { - assumeFalse(channelRunner instanceof InProcessCompatibilityRunner, "In-process runner does not support multi-classloader RPC"); + assumeFalse( + channelRunner instanceof InProcessCompatibilityRunner, + "In-process runner does not support multi-classloader RPC"); channelRunner.withChannel(channel -> assertTrue(channel.remoteCapability.supportsMultiClassLoaderRPC())); } @@ -55,7 +57,7 @@ public void testFailureInDeserialization(ChannelRunner channelRunner) throws Exc }); } - private static class CallableImpl extends CallableBase { + private static class CallableImpl extends CallableBase { @Override public Object call() { return null; @@ -64,6 +66,7 @@ public Object call() { private void readObject(ObjectInputStream ois) { throw new ClassCastException("foobar"); } + private static final long serialVersionUID = 1L; } @@ -79,7 +82,9 @@ public void testExportCallerDeallocation(ChannelRunner channelRunner) throws Exc final GreeterImpl g = new GreeterImpl(); channel.call(new GreetingTask(g)); assertEquals(g.name, "Kohsuke"); - assertFalse(channel.exportedObjects.isExported(g), "in this scenario, auto-unexport by the caller should kick in."); + assertFalse( + channel.exportedObjects.isExported(g), + "in this scenario, auto-unexport by the caller should kick in."); } }); } @@ -153,9 +158,10 @@ private static class WaitForRemotePropertyCallable extends CallableBase extends CallableBase { + private static class Echo extends CallableBase { private final T t; Echo(T t) { @@ -212,6 +219,7 @@ private static class Echo extends CallableBase { public T call() throws RuntimeException { return t; } + private static final long serialVersionUID = 1L; } @@ -246,7 +254,9 @@ public void testCallSiteStacktrace(ChannelRunner channelRunner) throws Exception assertEquals(RuntimeException.class, rootCause.getClass()); Throwable callSite = cause.getSuppressed()[0]; assertEquals("Remote call to north", callSite.getMessage()); - assertEquals("hudson.remoting.Channel$CallSiteStackTrace", callSite.getClass().getName()); + assertEquals( + "hudson.remoting.Channel$CallSiteStackTrace", + callSite.getClass().getName()); }); } @@ -259,12 +269,14 @@ private void failRemotelyToBeWrappedLocally(Channel channel) throws Exception { } private static class ThrowingCallable extends CallableBase { - @Override public Void call() throws IOException { + @Override + public Void call() throws IOException { throw new IOException("Node Nested", new RuntimeException("Node says hello!")); } + private static final long serialVersionUID = 1L; } - + /** * Checks if {@link UserRequest}s can be executed during the pending close operation. * @throws Exception Test Error @@ -302,14 +314,14 @@ public void testShouldNotAcceptUserRequestsWhenIsBeingClosed(ChannelRunner chann @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testShouldNotAcceptUserRPCRequestsWhenIsBeingClosed(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { - Collection src = new ArrayList<>(); src.add("Hello"); src.add("World"); - //TODO: System request will just hang. Once JENKINS-44785 is implemented, all system requests + // TODO: System request will just hang. Once JENKINS-44785 is implemented, all system requests // in Remoting codebase must have a timeout. - final Collection remoteList = channel.call(new RMIObjectExportedCallable<>(src, Collection.class, true)); + final Collection remoteList = + channel.call(new RMIObjectExportedCallable<>(src, Collection.class, true)); try (ChannelCloseLock ignored = new ChannelCloseLock(channel)) { // Call Async @@ -342,9 +354,8 @@ public TInterface call() { } @Override - public void checkRoles(RoleChecker checker) throws SecurityException { + public void checkRoles(RoleChecker checker) throws SecurityException {} - } private static final long serialVersionUID = 1L; } @@ -362,7 +373,7 @@ public void checkRoles(RoleChecker checker) throws SecurityException { throw new AssertionError("This method should be never executed"); } } - + /** * Auto-closable wrapper, which puts the {@link Channel} into the pending close state. * This state is achieved by a deadlock of the customer request, which blocks {@link Channel#close()}. @@ -376,7 +387,7 @@ private static final class ChannelCloseLock implements AutoCloseable { public ChannelCloseLock(final @NonNull Channel channel) throws AssertionError, InterruptedException { this.svc = Executors.newFixedThreadPool(2); this.channel = channel; - + // Lock channel java.util.concurrent.Future lockChannel = svc.submit(() -> { synchronized (channel) { @@ -400,17 +411,16 @@ public ChannelCloseLock(final @NonNull Channel channel) throws AssertionError, I assertTrue(channel.isClosingOrClosed(), "Channel should be closing"); assertFalse(channel.isOutClosed(), "Channel should not be closed due to the lock"); } - + @Override public void close() { svc.shutdownNow(); } - } - + private abstract static class TestRunnable { public abstract void run(Channel channel) throws Exception, AssertionError; - + private static TestRunnable forChannel_call(final Callable payload) { return new TestRunnable() { @Override @@ -419,7 +429,7 @@ public void run(Channel channel) throws Exception, AssertionError { } }; } - + private static TestRunnable forChannel_callAsync(final Callable payload) { return new TestRunnable() { @Override @@ -428,7 +438,7 @@ public void run(Channel channel) throws Exception, AssertionError { } }; } - + private static TestRunnable forUserRequest_constructor(final Callable payload) { return new TestRunnable() { @Override @@ -437,7 +447,7 @@ public void run(Channel channel) throws Exception, AssertionError { } }; } - + private static TestRunnable forUserRequest_call(final UserRequest req) { return new TestRunnable() { @Override @@ -446,7 +456,7 @@ public void run(Channel channel) throws Exception, AssertionError { } }; } - + private static TestRunnable forUserRequest_callAsync(final UserRequest req) { return new TestRunnable() { @Override @@ -456,11 +466,11 @@ public void run(Channel channel) throws Exception, AssertionError { }; } } - + private void assertFailsWithChannelClosedException(Channel channel, TestRunnable call) throws AssertionError { try { call.run(channel); - } catch(Exception ex) { + } catch (Exception ex) { LOGGER.log(Level.WARNING, "Call execution failed with exception", ex); Throwable cause = ex instanceof RemotingSystemException ? ex.getCause() : ex; if (cause instanceof ChannelClosedException) { diff --git a/src/test/java/hudson/remoting/ChecksumTest.java b/src/test/java/hudson/remoting/ChecksumTest.java index 5f265c124..6446ec639 100644 --- a/src/test/java/hudson/remoting/ChecksumTest.java +++ b/src/test/java/hudson/remoting/ChecksumTest.java @@ -24,7 +24,8 @@ public class ChecksumTest { private static final String FILE_CONTENTS1 = "These are the file contents"; private static final String FILE_CONTENTS2 = "These are some other file contents"; - @Rule public TemporaryFolder tmp = new TemporaryFolder(); + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); @Test public void testForFileAndURL() throws Exception { @@ -34,10 +35,12 @@ public void testForFileAndURL() throws Exception { HashCode hash2 = Files.asByteSource(tmpFile2).hash(Hashing.sha256()); assertEquals(createdExpectedChecksum(hash1), Checksum.forFile(tmpFile1)); - assertEquals(createdExpectedChecksum(hash1), Checksum.forURL(tmpFile1.toURI().toURL())); + assertEquals( + createdExpectedChecksum(hash1), Checksum.forURL(tmpFile1.toURI().toURL())); assertEquals(createdExpectedChecksum(hash2), Checksum.forFile(tmpFile2)); - assertEquals(createdExpectedChecksum(hash2), Checksum.forURL(tmpFile2.toURI().toURL())); + assertEquals( + createdExpectedChecksum(hash2), Checksum.forURL(tmpFile2.toURI().toURL())); assertNotEquals(Checksum.forFile(tmpFile1), Checksum.forFile(tmpFile2)); } @@ -56,8 +59,7 @@ static Checksum createdExpectedChecksum(HashCode hashCode) throws Exception { long nextLong = in.readLong(); if (i % 2 == 0) { sum1 ^= nextLong; - } - else { + } else { sum2 ^= nextLong; } } diff --git a/src/test/java/hudson/remoting/ChunkedInputStreamTest.java b/src/test/java/hudson/remoting/ChunkedInputStreamTest.java index 8b057f5c5..b6aa6d85d 100644 --- a/src/test/java/hudson/remoting/ChunkedInputStreamTest.java +++ b/src/test/java/hudson/remoting/ChunkedInputStreamTest.java @@ -22,9 +22,9 @@ */ public class ChunkedInputStreamTest extends Assert { - FifoBuffer buf = new FifoBuffer(53,1024*1024); + FifoBuffer buf = new FifoBuffer(53, 1024 * 1024); ChunkedInputStream i = new ChunkedInputStream(buf.getInputStream()); - ChunkedOutputStream o = new ChunkedOutputStream(37,buf.getOutputStream()); + ChunkedOutputStream o = new ChunkedOutputStream(37, buf.getOutputStream()); ExecutorService es = Executors.newFixedThreadPool(2); @@ -38,54 +38,55 @@ public void tearDown() { */ @Test public void tenMegaCopy() throws Exception { - test(new RandomWorkload(10*1024*1024), - i, new AutoChunkedOutputStream(o)); + test(new RandomWorkload(10 * 1024 * 1024), i, new AutoChunkedOutputStream(o)); } @Test public void boundaryPositionCheck() throws Exception { - test(new Workload() { - int size = 1024; - - @Override - public void write(OutputStream o) throws IOException { - Random boundary = new Random(0); - Random data = new Random(1); - - for (int j=0; j fw = es.submit(() -> { w.write(o); @@ -113,7 +114,7 @@ public void write(int b) throws IOException { @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { out.write(b, off, len); - ((ChunkedOutputStream)out).sendBreak(); + ((ChunkedOutputStream) out).sendBreak(); } } } diff --git a/src/test/java/hudson/remoting/ClassFilterTest.java b/src/test/java/hudson/remoting/ClassFilterTest.java index 81c192d32..693a91892 100644 --- a/src/test/java/hudson/remoting/ClassFilterTest.java +++ b/src/test/java/hudson/remoting/ClassFilterTest.java @@ -60,8 +60,7 @@ private void setUp() throws Exception { setUp(new InProcessRunner() { @Override protected ChannelBuilder configureNorth() { - return super.configureNorth() - .withClassFilter(new TestFilter()); + return super.configureNorth().withClassFilter(new TestFilter()); } }); } @@ -75,9 +74,7 @@ private void setUpWithNoCapacity() throws Exception { setUp(new InProcessRunner() { @Override protected ChannelBuilder configureNorth() { - return super.configureNorth() - .withCapability(Capability.NONE) - .withClassFilter(new TestFilter()); + return super.configureNorth().withCapability(Capability.NONE).withClassFilter(new TestFilter()); } @Override @@ -96,8 +93,9 @@ private void setUp(DualSideChannelRunner runner) throws Exception { @After public void tearDown() throws Exception { - if (runner!=null) + if (runner != null) { runner.stop(north); + } } /** @@ -110,8 +108,8 @@ public void capabilityRead() throws Exception { oos.writeObject(new Security218("rifle")); } - final SecurityException e = assertThrows(SecurityException.class, - () -> Capability.read(new ByteArrayInputStream(baos.toByteArray()))); + final SecurityException e = assertThrows( + SecurityException.class, () -> Capability.read(new ByteArrayInputStream(baos.toByteArray()))); assertEquals("Rejected: " + Security218.class.getName(), e.getMessage()); } @@ -188,8 +186,7 @@ public void transport_nio() throws Exception { setUp(new NioSocketRunner() { @Override protected NioChannelBuilder configureNorth() { - return super.configureNorth() - .withClassFilter(new TestFilter()); + return super.configureNorth().withClassFilter(new TestFilter()); } }); commandStreamTestSequence(); @@ -207,19 +204,19 @@ private void commandStreamTestSequence() throws Exception { try { south.send(new Security218("hitler")); north.syncIO(); // transport_chunking hangs if this is 'south.syncIO', because somehow south - // doesn't notice that the north has aborted and the connection is lost. - // this is indicative of a larger problem, but one that's not related to - // SECURITY-218 at hand, so I'm going to leave this with 'north.syncIO' - // it still achieves the effect of blocking until the command is processed by north, - // because the response from south back to north would have to come after Security218 - // command. + // doesn't notice that the north has aborted and the connection is lost. + // this is indicative of a larger problem, but one that's not related to + // SECURITY-218 at hand, so I'm going to leave this with 'north.syncIO' + // it still achieves the effect of blocking until the command is processed by north, + // because the response from south back to north would have to come after Security218 + // command. // fail("the receiving end will abort after receiving Security218, so syncIO should fail"); // ... except for NIO, which just discards that command and keeps on -// } catch (RequestAbortedException e) { -// // other transport kills the connection -// String msg = toString(e); -// assertTrue(msg, msg.contains("Rejected: " + Security218.class.getName())); + // } catch (RequestAbortedException e) { + // // other transport kills the connection + // String msg = toString(e); + // assertTrue(msg, msg.contains("Rejected: " + Security218.class.getName())); } catch (Exception e) { e.printStackTrace(); } @@ -248,7 +245,8 @@ public Security218(String attack) { private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); - System.setProperty("attack", attack + ">" + getChannelForSerialization().getName()); + System.setProperty( + "attack", attack + ">" + getChannelForSerialization().getName()); } @Override @@ -260,6 +258,7 @@ protected void execute(Channel channel) { public String toString() { return "Security218"; } + private static final long serialVersionUID = 1L; } @@ -280,10 +279,12 @@ public Security218Callable(Security218 a) { @Override public Void call() { - a.toString(); // this will ensure 'a' gets sent over + a.toString(); // this will ensure 'a' gets sent over return null; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/ClassRemoting2Test.java b/src/test/java/hudson/remoting/ClassRemoting2Test.java index 345e197df..07a4bb6d6 100644 --- a/src/test/java/hudson/remoting/ClassRemoting2Test.java +++ b/src/test/java/hudson/remoting/ClassRemoting2Test.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -49,9 +49,9 @@ * Capability.NONE. */ @WithRunner({ - InProcessRunner.class, - NioSocketRunner.class, - NioPipeRunner.class, + InProcessRunner.class, + NioSocketRunner.class, + NioPipeRunner.class, }) public class ClassRemoting2Test { @@ -59,11 +59,7 @@ public class ClassRemoting2Test { @SuppressWarnings("unused") // used by JUnit static Stream provider() { - return Stream.of( - new InProcessRunner(), - new NioSocketRunner(), - new NioPipeRunner() - ); + return Stream.of(new InProcessRunner(), new NioSocketRunner(), new NioPipeRunner()); } @After @@ -205,10 +201,12 @@ public void testContinuedInterruptionOfClassReferenceCreation(ChannelRunner chan @Issue("JENKINS-61103") @ParameterizedTest @MethodSource(PROVIDER_METHOD) - public void testSingleInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) throws Exception { + public void testSingleInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) + throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticResourceReference.class); - final Callable callable = (Callable) dcl.load(TestStaticResourceReference.class); + final Callable callable = + (Callable) dcl.load(TestStaticResourceReference.class); // make sure we get a remote interruption exception on "getResource" call RemoteClassLoader.TESTING_RESOURCE_LOAD = new InterruptInvocation(1, 1); Future f1 = ClassRemotingTest.scheduleCallableLoad(channel, callable); @@ -222,10 +220,12 @@ public void testSingleInterruptionOfClassInitializationWithStaticResourceReferen @Issue("JENKINS-61103") @ParameterizedTest @MethodSource(PROVIDER_METHOD) - public void testMultipleInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) throws Exception { + public void testMultipleInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) + throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticResourceReference.class); - final Callable callable = (Callable) dcl.load(TestStaticResourceReference.class); + final Callable callable = + (Callable) dcl.load(TestStaticResourceReference.class); // make sure we get a remote interruption exception on "getResource" call RemoteClassLoader.RETRY_SLEEP_DURATION_MILLISECONDS = 1; RemoteClassLoader.MAX_RETRIES = 10; @@ -241,10 +241,12 @@ public void testMultipleInterruptionOfClassInitializationWithStaticResourceRefer @Issue("JENKINS-61103") @ParameterizedTest @MethodSource(PROVIDER_METHOD) - public void testContinuedInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) throws Exception { + public void testContinuedInterruptionOfClassInitializationWithStaticResourceReference(ChannelRunner channelRunner) + throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticResourceReference.class); - final Callable callable = (Callable) dcl.load(TestStaticResourceReference.class); + final Callable callable = + (Callable) dcl.load(TestStaticResourceReference.class); // make sure we get a remote interruption exception on "getResource" call RemoteClassLoader.RETRY_SLEEP_DURATION_MILLISECONDS = 1; RemoteClassLoader.MAX_RETRIES = 3; @@ -261,7 +263,8 @@ public void testContinuedInterruptionOfClassInitializationWithStaticResourceRefe public void testSingleInterruptionOfFindResources(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticGetResources.class); - final Callable callable = (Callable) dcl.load(TestStaticGetResources.class); + final Callable callable = + (Callable) dcl.load(TestStaticGetResources.class); // make sure we get a remote interruption exception on "findResources" call RemoteClassLoader.TESTING_RESOURCE_LOAD = new InterruptInvocation(1, 1); Future f1 = ClassRemotingTest.scheduleCallableLoad(channel, callable); @@ -278,7 +281,8 @@ public void testSingleInterruptionOfFindResources(ChannelRunner channelRunner) t public void testMultipleInterruptionOfFindResources(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticGetResources.class); - final Callable callable = (Callable) dcl.load(TestStaticGetResources.class); + final Callable callable = + (Callable) dcl.load(TestStaticGetResources.class); // make sure we get a remote interruption exception on "getResource" call RemoteClassLoader.RETRY_SLEEP_DURATION_MILLISECONDS = 1; RemoteClassLoader.MAX_RETRIES = 10; @@ -297,7 +301,8 @@ public void testMultipleInterruptionOfFindResources(ChannelRunner channelRunner) public void testContinuedInterruptionOfFindResources(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticGetResources.class); - final Callable callable = (Callable) dcl.load(TestStaticGetResources.class); + final Callable callable = + (Callable) dcl.load(TestStaticGetResources.class); // make sure we get a remote interruption exception on "getResource" call RemoteClassLoader.RETRY_SLEEP_DURATION_MILLISECONDS = 1; RemoteClassLoader.MAX_RETRIES = 3; diff --git a/src/test/java/hudson/remoting/ClassRemotingTest.java b/src/test/java/hudson/remoting/ClassRemotingTest.java index 57d074b84..dc56ace96 100644 --- a/src/test/java/hudson/remoting/ClassRemotingTest.java +++ b/src/test/java/hudson/remoting/ClassRemotingTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -58,7 +58,8 @@ public void test1(ChannelRunner channelRunner) throws Throwable { channelRunner.withChannel(channel -> { // call a class that's only available on DummyClassLoader, so that on the remote channel // it will be fetched from this class loader and not from the system classloader. - Callable callable = (Callable) DummyClassLoader.apply(TestCallable.class); + Callable callable = + (Callable) DummyClassLoader.apply(TestCallable.class); Object[] result = (Object[]) channel.call(callable); @@ -73,14 +74,16 @@ public void test1(ChannelRunner channelRunner) throws Throwable { @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testRemoteProperty(ChannelRunner channelRunner) throws Exception { - assumeFalse(channelRunner instanceof InProcessCompatibilityRunner,"this test cannot run in the compatibility mode without the multi-classloader serialization support," + - "because it uses the class loader specified during proxy construction."); + assumeFalse( + channelRunner instanceof InProcessCompatibilityRunner, + "this test cannot run in the compatibility mode without the multi-classloader serialization support," + + "because it uses the class loader specified during proxy construction."); channelRunner.withChannel(channel -> { DummyClassLoader cl = new DummyClassLoader(TestCallable.class); Callable c = (Callable) cl.load(TestCallable.class); assertSame(c.getClass().getClassLoader(), cl); - channel.setProperty("test",c); + channel.setProperty("test", c); channel.call(new RemotePropertyVerifier()); }); @@ -94,11 +97,11 @@ public void testRaceCondition(ChannelRunner channelRunner) throws Throwable { channelRunner.withChannel(channel -> { DummyClassLoader parent = new DummyClassLoader(TestCallable.class); DummyClassLoader child1 = new DummyClassLoader(parent, TestCallable.Sub.class); - final Callable c1 = (Callable) child1.load(TestCallable.Sub.class); + final Callable c1 = (Callable) child1.load(TestCallable.Sub.class); assertEquals(child1, c1.getClass().getClassLoader()); assertEquals(parent, c1.getClass().getSuperclass().getClassLoader()); DummyClassLoader child2 = new DummyClassLoader(parent, TestCallable.Sub.class); - final Callable c2 = (Callable) child2.load(TestCallable.Sub.class); + final Callable c2 = (Callable) child2.load(TestCallable.Sub.class); assertEquals(child2, c2.getClass().getClassLoader()); assertEquals(parent, c2.getClass().getSuperclass().getClassLoader()); ExecutorService svc = Executors.newFixedThreadPool(2); @@ -107,8 +110,8 @@ public void testRaceCondition(ChannelRunner channelRunner) throws Throwable { java.util.concurrent.Future f2 = svc.submit(() -> channel.call(c2)); Object result1 = f1.get(); Object result2 = f2.get(); - assertTestCallableResults((Object[])result1); - assertTestCallableResults((Object[])result2); + assertTestCallableResults((Object[]) result1); + assertTestCallableResults((Object[]) result2); }); } @@ -118,14 +121,16 @@ public void testRaceCondition(ChannelRunner channelRunner) throws Throwable { public void testClassCreation_TestCallable(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { DummyClassLoader dummyClassLoader = new DummyClassLoader(TestCallable.class); - final Callable callable = (Callable) dummyClassLoader.load(TestCallable.class); + final Callable callable = + (Callable) dummyClassLoader.load(TestCallable.class); java.util.concurrent.Future f1 = scheduleCallableLoad(channel, callable); Object result = f1.get(); - assertTestCallableResults((Object[])result); + assertTestCallableResults((Object[]) result); Object loadResult = dummyClassLoader.load(TestCallable.class); - assertEquals(TESTCALLABLE_TRANSFORMED_CLASSNAME, loadResult.getClass().getName()); + assertEquals( + TESTCALLABLE_TRANSFORMED_CLASSNAME, loadResult.getClass().getName()); }); } @@ -153,7 +158,8 @@ public void testClassCreation_TestLinkage(ChannelRunner channelRunner) throws Ex public void testClassCreation_TestStaticResourceReference(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticResourceReference.class); - final Callable callable = (Callable) dcl.load(TestStaticResourceReference.class); + final Callable callable = + (Callable) dcl.load(TestStaticResourceReference.class); Future f1 = ClassRemotingTest.scheduleCallableLoad(channel, callable); Object result = f1.get(); @@ -168,7 +174,8 @@ public void testClassCreation_TestStaticResourceReference(ChannelRunner channelR public void testClassCreation_TestFindResources(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final DummyClassLoader dcl = new DummyClassLoader(TestStaticGetResources.class); - final Callable callable = (Callable) dcl.load(TestStaticGetResources.class); + final Callable callable = + (Callable) dcl.load(TestStaticGetResources.class); Future f1 = ClassRemotingTest.scheduleCallableLoad(channel, callable); Object result = f1.get(); @@ -176,7 +183,8 @@ public void testClassCreation_TestFindResources(ChannelRunner channelRunner) thr }); } - static void assertTestStaticResourceReferenceResults(Channel channel, Callable callable, Object result) throws Exception { + static void assertTestStaticResourceReferenceResults( + Channel channel, Callable callable, Object result) throws Exception { assertEquals(String.class, channel.call(callable).getClass()); assertTrue(result.toString().contains("impossible")); } @@ -186,13 +194,22 @@ static Future scheduleCallableLoad(Channel channel, final Callable channel.call(c)); } - static void assertTestLinkageResults(Channel channel, DummyClassLoader parent, DummyClassLoader child1, DummyClassLoader child2, Callable callable, Object result) throws Exception { + static void assertTestLinkageResults( + Channel channel, + DummyClassLoader parent, + DummyClassLoader child1, + DummyClassLoader child2, + Callable callable, + Object result) + throws Exception { assertEquals(String.class, channel.call(callable).getClass()); assertTrue(result.toString().startsWith(TESTLINKAGE_TRANSFORMED_CLASSNAME + "$B")); Object loadResult = parent.load(TestLinkage.B.class); - assertEquals(TESTLINKAGE_TRANSFORMED_CLASSNAME + "$B", loadResult.getClass().getName()); + assertEquals( + TESTLINKAGE_TRANSFORMED_CLASSNAME + "$B", loadResult.getClass().getName()); loadResult = child1.load(TestLinkage.A.class); - assertEquals(TESTLINKAGE_TRANSFORMED_CLASSNAME + "$A", loadResult.getClass().getName()); + assertEquals( + TESTLINKAGE_TRANSFORMED_CLASSNAME + "$A", loadResult.getClass().getName()); loadResult = child2.load(TestLinkage.class); assertEquals(TESTLINKAGE_TRANSFORMED_CLASSNAME, loadResult.getClass().getName()); } @@ -201,11 +218,11 @@ private static void assertTestCallableResults(Object[] result) { assertTrue(result[0].toString().startsWith("hudson.remoting.RemoteClassLoader@")); // make sure the bytes are what we are expecting - ClassReader cr = new ClassReader((byte[])result[1]); - cr.accept(new EmptyVisitor(),ClassReader.SKIP_DEBUG); + ClassReader cr = new ClassReader((byte[]) result[1]); + cr.accept(new EmptyVisitor(), ClassReader.SKIP_DEBUG); // make sure cache is taking effect - assertEquals(result[2],result[3]); + assertEquals(result[2], result[3]); assertTrue(result[2].toString().contains(TESTCALLABLE_TRANSFORMED_CLASSNAME.replace(".", "/") + ".class")); } @@ -217,6 +234,7 @@ public EmptyVisitor() { } private static class RemotePropertyVerifier extends CallableBase { + @Override public Object call() throws IOException { Object o = getOpenChannelOrFail().getRemoteProperty("test"); assertEquals(o.getClass().getName(), TESTCALLABLE_TRANSFORMED_CLASSNAME); diff --git a/src/test/java/hudson/remoting/Copier.java b/src/test/java/hudson/remoting/Copier.java index 165e35fe8..b89dfbe02 100644 --- a/src/test/java/hudson/remoting/Copier.java +++ b/src/test/java/hudson/remoting/Copier.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -29,7 +29,7 @@ /** * Thread that copies a stream. - * + * * @author Kohsuke Kawaguchi */ class Copier extends Thread { @@ -47,8 +47,9 @@ public void run() { try { byte[] buf = new byte[8192]; int len; - while((len=in.read(buf))>0) - out.write(buf,0,len); + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } in.close(); } catch (IOException e) { // TODO: what to do? diff --git a/src/test/java/hudson/remoting/DeadRemoteOutputStreamTest.java b/src/test/java/hudson/remoting/DeadRemoteOutputStreamTest.java index 5592a1940..9da6ce635 100644 --- a/src/test/java/hudson/remoting/DeadRemoteOutputStreamTest.java +++ b/src/test/java/hudson/remoting/DeadRemoteOutputStreamTest.java @@ -55,9 +55,8 @@ public Void call() throws Exception { System.gc(); Thread.sleep(1000); - final IOException e = assertThrows(IOException.class, () -> { - for (int i=0; i<100; i++) { + for (int i = 0; i < 100; i++) { os.write(0); System.gc(); Thread.sleep(10); @@ -69,7 +68,9 @@ public Void call() throws Exception { assertThat(whole, allOf(containsString(MESSAGE), containsString("hudson.rem0ting.TestCallable"))); return null; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/DefaultClassFilterTest.java b/src/test/java/hudson/remoting/DefaultClassFilterTest.java index 8b06fd247..8b3164937 100644 --- a/src/test/java/hudson/remoting/DefaultClassFilterTest.java +++ b/src/test/java/hudson/remoting/DefaultClassFilterTest.java @@ -45,14 +45,20 @@ public class DefaultClassFilterTest { /** Some classes that should be matched by the default class filter */ - private static final List defaultBadClasses = Arrays.asList("org.codehaus.groovy.runtime.Bob", - "org.apache.commons.collections.functors.Wibble", "org.apache.xalan.Bogus", - "com.sun.org.apache.xalan.bogus", "org.springframework.core.SomeClass", - "org.springframework.wibble.ExceptionHandler"); + private static final List defaultBadClasses = Arrays.asList( + "org.codehaus.groovy.runtime.Bob", + "org.apache.commons.collections.functors.Wibble", + "org.apache.xalan.Bogus", + "com.sun.org.apache.xalan.bogus", + "org.springframework.core.SomeClass", + "org.springframework.wibble.ExceptionHandler"); /** Some classes that should not be matched by the default class filter */ - private static final List defaultOKClasses = Arrays.asList("java.lang.String", "java.lang.Object", - "java.util.ArrayList", "org.springframework.core.NestedRuntimeException", - "org.springframework.a.b.c.yada.SomeSuperException"); + private static final List defaultOKClasses = Arrays.asList( + "java.lang.String", + "java.lang.Object", + "java.util.ArrayList", + "org.springframework.core.NestedRuntimeException", + "org.springframework.a.b.c.yada.SomeSuperException"); @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -67,10 +73,14 @@ public void clearProperty() { */ @Test public void testDefaultsNoOverride() { - assertThat("Default blacklist is not blacklisting some classes", defaultBadClasses, - everyItem(is(BlackListMatcher.blacklisted()))); - assertThat("Default blacklist is not allowing some classes", defaultOKClasses, - everyItem(is(not(BlackListMatcher.blacklisted())))); + assertThat( + "Default blacklist is not blacklisting some classes", + defaultBadClasses, + everyItem(is(BlackListMatcher.blacklisted()))); + assertThat( + "Default blacklist is not allowing some classes", + defaultOKClasses, + everyItem(is(not(BlackListMatcher.blacklisted())))); } /** @@ -87,15 +97,21 @@ public void testDefaultsOverrideExists() throws Exception { } } setOverrideProperty(f.getAbsolutePath()); - assertThat("Default blacklist should not be used", defaultBadClasses, everyItem(is(not(BlackListMatcher.blacklisted())))); + assertThat( + "Default blacklist should not be used", + defaultBadClasses, + everyItem(is(not(BlackListMatcher.blacklisted())))); assertThat("Custom blacklist should be used", badClasses, everyItem(is(BlackListMatcher.blacklisted()))); - assertThat("Custom blacklist is not allowing some classes", defaultOKClasses, everyItem(is(not(BlackListMatcher.blacklisted())))); + assertThat( + "Custom blacklist is not allowing some classes", + defaultOKClasses, + everyItem(is(not(BlackListMatcher.blacklisted())))); } /** * Checks that if given an invalid pattern in the overrides then the defaults are used. */ - @Test(expected=Error.class) + @Test(expected = Error.class) public void testDefaultsAreUsedIfOverridesAreGarbage() throws Exception { List badClasses = List.of("Z{100,0}" /* min > max for repetition */); File f = folder.newFile("overrides.txt"); @@ -113,10 +129,10 @@ public void testDefaultsAreUsedIfOverridesAreGarbage() throws Exception { /** * Checks that the defaults are loaded when the override property is provided and the file does not exist. */ - @Test(expected=Error.class) + @Test(expected = Error.class) public void testDefaultsRemainWhenOverrideDoesExists() throws Exception { - setOverrideProperty(folder.getRoot().toString() - + "/DO_NOT_CREATE_THIS_FILE_OR_ELSE_BAD_THINGS_WILL_HAPPEN_TO_YOU"); + setOverrideProperty( + folder.getRoot().toString() + "/DO_NOT_CREATE_THIS_FILE_OR_ELSE_BAD_THINGS_WILL_HAPPEN_TO_YOU"); ClassFilter.createDefaultInstance(); } @@ -157,5 +173,4 @@ public void describeTo(Description description) { description.appendText("blacklisted"); } } - } diff --git a/src/test/java/hudson/remoting/DiagnosedStreamCorruptionExceptionTest.java b/src/test/java/hudson/remoting/DiagnosedStreamCorruptionExceptionTest.java index 17f27b007..7c5a0311e 100644 --- a/src/test/java/hudson/remoting/DiagnosedStreamCorruptionExceptionTest.java +++ b/src/test/java/hudson/remoting/DiagnosedStreamCorruptionExceptionTest.java @@ -17,18 +17,27 @@ */ public class DiagnosedStreamCorruptionExceptionTest { byte[] payload = { - 0,0,0,0, /* binary stream preamble*/ - (byte)0xAC, (byte)0xED, 0x00, 0x05, /* object input stream header */ - 1, 2, 3, 4, 5 /* bogus data */ + 0, + 0, + 0, + 0, /* binary stream preamble*/ + (byte) 0xAC, + (byte) 0xED, + 0x00, + 0x05, /* object input stream header */ + 1, + 2, + 3, + 4, + 5 /* bogus data */ }; @Test public void exercise() throws Exception { - ClassicCommandTransport ct = (ClassicCommandTransport) - new ChannelBuilder("dummy",null) - .withMode(Channel.Mode.BINARY) - .withBaseLoader(getClass().getClassLoader()) - .negotiate(new ByteArrayInputStream(payload), OutputStream.nullOutputStream()); + ClassicCommandTransport ct = (ClassicCommandTransport) new ChannelBuilder("dummy", null) + .withMode(Channel.Mode.BINARY) + .withBaseLoader(getClass().getClassLoader()) + .negotiate(new ByteArrayInputStream(payload), OutputStream.nullOutputStream()); verify(ct); } @@ -44,8 +53,8 @@ private void verify(ClassicCommandTransport ct) throws IOException, ClassNotFoun } String msg = s.toString(); - assertTrue(msg,msg.contains("Read ahead: 0x02 0x03 0x04 0x05")); - assertTrue(msg,msg.contains("invalid type code: 01")); + assertTrue(msg, msg.contains("Read ahead: 0x02 0x03 0x04 0x05")); + assertTrue(msg, msg.contains("invalid type code: 01")); assertSame(StreamCorruptedException.class, e.getCause().getClass()); } } @@ -53,17 +62,16 @@ private void verify(ClassicCommandTransport ct) throws IOException, ClassNotFoun /** * This tests the behaviour of the diagnosis blocking on a non-completed stream, as the writer end is kept open. */ - @Test(timeout=3000) + @Test(timeout = 3000) public void blockingStreamShouldNotPreventDiagnosis() throws Exception { try (FastPipedInputStream in = new FastPipedInputStream(); - FastPipedOutputStream out = new FastPipedOutputStream(in)) { + FastPipedOutputStream out = new FastPipedOutputStream(in)) { out.write(payload); - ClassicCommandTransport ct = (ClassicCommandTransport) - new ChannelBuilder("dummy",null) - .withMode(Channel.Mode.BINARY) - .withBaseLoader(getClass().getClassLoader()) - .negotiate(in, OutputStream.nullOutputStream()); + ClassicCommandTransport ct = (ClassicCommandTransport) new ChannelBuilder("dummy", null) + .withMode(Channel.Mode.BINARY) + .withBaseLoader(getClass().getClassLoader()) + .negotiate(in, OutputStream.nullOutputStream()); verify(ct); } diff --git a/src/test/java/hudson/remoting/DummyClassLoader.java b/src/test/java/hudson/remoting/DummyClassLoader.java index a2b920207..882487a1a 100644 --- a/src/test/java/hudson/remoting/DummyClassLoader.java +++ b/src/test/java/hudson/remoting/DummyClassLoader.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,7 +23,6 @@ */ package hudson.remoting; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -87,7 +86,7 @@ public DummyClassLoader(Class... classes) { public DummyClassLoader(ClassLoader parent, Class... classes) { super(parent); - assert classes.length!=0; + assert classes.length != 0; for (Class c : classes) { entries.add(new Entry(c)); } @@ -106,11 +105,14 @@ public static Object apply(Class c) { */ public Object load(Class c) { for (Entry e : entries) { - if (e.c==c) { + if (e.c == c) { try { return loadClass(e.logicalName).getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException - | NoSuchMethodException | InvocationTargetException x) { + } catch (InstantiationException + | IllegalAccessException + | ClassNotFoundException + | NoSuchMethodException + | InvocationTargetException x) { throw new Error(x); } } @@ -118,17 +120,16 @@ public Object load(Class c) { throw new IllegalStateException(); } - @Override protected Class findClass(String name) throws ClassNotFoundException { for (Entry e : entries) { - if(name.equals(e.logicalName)) { + if (name.equals(e.logicalName)) { // rename a class try { byte[] bytes = e.loadTransformedClassImage(); - return defineClass(name,bytes,0,bytes.length); + return defineClass(name, bytes, 0, bytes.length); } catch (IOException x) { - throw new ClassNotFoundException("Bytecode manipulation failed",x); + throw new ClassNotFoundException("Bytecode manipulation failed", x); } } } @@ -136,7 +137,6 @@ protected Class findClass(String name) throws ClassNotFoundException { return super.findClass(name); } - @Override protected URL findResource(String name) { for (Entry e : entries) { @@ -156,8 +156,8 @@ protected URL findResource(String name) { return super.findResource(name); } - @Override public String toString() { + @Override + public String toString() { return super.toString() + "[" + entries + "]"; } - } diff --git a/src/test/java/hudson/remoting/DummyClassLoaderTest.java b/src/test/java/hudson/remoting/DummyClassLoaderTest.java index 433642301..cd9426bb5 100644 --- a/src/test/java/hudson/remoting/DummyClassLoaderTest.java +++ b/src/test/java/hudson/remoting/DummyClassLoaderTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -36,6 +36,6 @@ public void testLoad() throws Throwable { Callable c = (Callable) DummyClassLoader.apply(TestCallable.class); System.out.println(c.call()); // make sure that the returned class is loaded from the dummy classloader - assertTrue(((Object[])c.call())[0].toString().startsWith(DummyClassLoader.class.getName())); + assertTrue(((Object[]) c.call())[0].toString().startsWith(DummyClassLoader.class.getName())); } } diff --git a/src/test/java/hudson/remoting/EngineTest.java b/src/test/java/hudson/remoting/EngineTest.java index 1155e6842..aad85884e 100644 --- a/src/test/java/hudson/remoting/EngineTest.java +++ b/src/test/java/hudson/remoting/EngineTest.java @@ -46,48 +46,48 @@ * @author Oleg Nenashev */ public class EngineTest { - + private static final String SECRET_KEY = "Hello, world!"; private static final String AGENT_NAME = "testAgent"; private List jenkinsUrls; - + @Rule public TemporaryFolder tmpDir = new TemporaryFolder(); - + @Rule public WorkDirManagerRule mgr = new WorkDirManagerRule(); - + @Before public void init() throws Exception { jenkinsUrls = List.of(new URL("http://my.jenkins.not.existent")); } - + @Test @Issue("JENKINS-44290") public void shouldInitializeCorrectlyWithDefaults() throws Exception { EngineListener l = new TestEngineListener(); Engine engine = new Engine(l, jenkinsUrls, SECRET_KEY, AGENT_NAME); engine.startEngine(true); - + // Cache will go to ~/.jenkins , we do not want to worry anbout this repo - assertTrue("Default JarCache should be touched: " + JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION.getAbsolutePath(), + assertTrue( + "Default JarCache should be touched: " + JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION.getAbsolutePath(), JarCache.DEFAULT_NOWS_JAR_CACHE_LOCATION.exists()); } - + @Test public void shouldInitializeCorrectlyWithCustomCache() throws Exception { File jarCache = new File(tmpDir.getRoot(), "jarCache"); - + EngineListener l = new TestEngineListener(); Engine engine = new Engine(l, jenkinsUrls, SECRET_KEY, AGENT_NAME); engine.setJarCache(new FileSystemJarCache(jarCache, true)); engine.startEngine(true); - + // Cache will go to ~/.jenkins , should be touched by default - assertTrue("The specified JarCache should be touched: " + jarCache.getAbsolutePath(), - jarCache.exists()); + assertTrue("The specified JarCache should be touched: " + jarCache.getAbsolutePath(), jarCache.exists()); } - + @Test public void shouldInitializeCorrectlyWithWorkDir() throws Exception { File workDir = new File(tmpDir.getRoot(), "workDir"); @@ -95,14 +95,16 @@ public void shouldInitializeCorrectlyWithWorkDir() throws Exception { Engine engine = new Engine(l, jenkinsUrls, SECRET_KEY, AGENT_NAME); engine.setWorkDir(workDir.toPath()); engine.startEngine(true); - + WorkDirManager mgr = WorkDirManager.getInstance(); File workDirLoc = mgr.getLocation(WorkDirManager.DirType.WORK_DIR); - assertThat("The initialized work directory should equal to the one passed in parameters", - workDirLoc, equalTo(workDir)); + assertThat( + "The initialized work directory should equal to the one passed in parameters", + workDirLoc, + equalTo(workDir)); assertTrue("The work directory should exist", workDir.exists()); } - + @Test public void shouldUseCustomCacheDirIfRequired() throws Exception { File workDir = new File(tmpDir.getRoot(), "workDir"); @@ -112,7 +114,7 @@ public void shouldUseCustomCacheDirIfRequired() throws Exception { engine.setWorkDir(workDir.toPath()); engine.setJarCache(new FileSystemJarCache(jarCache, true)); engine.startEngine(true); - + WorkDirManager mgr = WorkDirManager.getInstance(); File location = mgr.getLocation(WorkDirManager.DirType.JAR_CACHE_DIR); assertThat("WorkDir manager should not be aware about external JAR cache location", location, nullValue()); @@ -195,6 +197,5 @@ public void onDisconnect() { public void onReconnect() { // Do nothing } - } } diff --git a/src/test/java/hudson/remoting/FileSystemJarCacheTest.java b/src/test/java/hudson/remoting/FileSystemJarCacheTest.java index 03e3b5ac2..6c539bdd2 100644 --- a/src/test/java/hudson/remoting/FileSystemJarCacheTest.java +++ b/src/test/java/hudson/remoting/FileSystemJarCacheTest.java @@ -41,10 +41,15 @@ public class FileSystemJarCacheTest { private static final String CONTENTS = "These are the contents"; - @Rule public TemporaryFolder tmp = new TemporaryFolder(); + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + @Mock + private Channel mockChannel; + + @Mock + private JarLoader mockJarLoader; - @Mock private Channel mockChannel; - @Mock private JarLoader mockJarLoader; private FileSystemJarCache fileSystemJarCache; private Checksum expectedChecksum; @@ -71,15 +76,13 @@ public void testRetrieveAlreadyExists() throws Exception { assertTrue(expectedFile.createNewFile()); writeToFile(expectedFile, CONTENTS); - URL url = fileSystemJarCache.retrieve( - mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); + URL url = fileSystemJarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); assertEquals(expectedFile.toURI().toURL(), url); // Changing the content after successfully cached is not an expected use-case. // Here used to verity checksums are cached. writeToFile(expectedFile, "Something else"); - url = fileSystemJarCache.retrieve( - mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); + url = fileSystemJarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); assertEquals(expectedFile.toURI().toURL(), url); } @@ -87,8 +90,7 @@ public void testRetrieveAlreadyExists() throws Exception { public void testSuccessfulRetrieve() throws Exception { mockCorrectLoad(); - URL url = fileSystemJarCache.retrieve( - mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); + URL url = fileSystemJarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2); assertEquals(expectedChecksum, Checksum.forURL(url)); } @@ -96,15 +98,15 @@ public void testSuccessfulRetrieve() throws Exception { public void testRetrieveChecksumDifferent() throws Exception { when(mockChannel.getProperty(JarLoader.THEIRS)).thenReturn(mockJarLoader); doAnswer((Answer) invocationOnMock -> { - RemoteOutputStream o = (RemoteOutputStream) invocationOnMock.getArguments()[2]; - o.write("Some other contents".getBytes(StandardCharsets.UTF_8)); - return null; - }).when(mockJarLoader).writeJarTo( - eq(expectedChecksum.sum1), - eq(expectedChecksum.sum2), - any(RemoteOutputStream.class)); - - final IOException ex = assertThrows(IOException.class, + RemoteOutputStream o = (RemoteOutputStream) invocationOnMock.getArguments()[2]; + o.write("Some other contents".getBytes(StandardCharsets.UTF_8)); + return null; + }) + .when(mockJarLoader) + .writeJarTo(eq(expectedChecksum.sum1), eq(expectedChecksum.sum2), any(RemoteOutputStream.class)); + + final IOException ex = assertThrows( + IOException.class, () -> fileSystemJarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2)); assertThat(ex.getCause(), hasMessage(containsString("Incorrect checksum of retrieved jar"))); } @@ -142,8 +144,8 @@ public void testRenameFailsAndNoTarget() throws Exception { when(spy.renameTo(expectedFile)).thenReturn(false); assertFalse(expectedFile.exists()); - final IOException ex = assertThrows(IOException.class, - () -> jarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2)); + final IOException ex = assertThrows( + IOException.class, () -> jarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2)); assertThat(ex.getCause(), hasMessage(containsString("Unable to create"))); } @@ -156,26 +158,28 @@ public void testRenameFailsAndBadPreviousTarget() throws Exception { mockCorrectLoad(); doAnswer((Answer) invocationOnMock -> { - Files.createParentDirs(expectedFile); - expectedFile.createNewFile(); - Files.asCharSink(expectedFile, StandardCharsets.UTF_8, FileWriteMode.APPEND).write("Some other contents"); - return false; - }).when(fileSpy).renameTo(expectedFile); - - final IOException ex = assertThrows(IOException.class, - () -> jarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2)); + Files.createParentDirs(expectedFile); + expectedFile.createNewFile(); + Files.asCharSink(expectedFile, StandardCharsets.UTF_8, FileWriteMode.APPEND) + .write("Some other contents"); + return false; + }) + .when(fileSpy) + .renameTo(expectedFile); + + final IOException ex = assertThrows( + IOException.class, () -> jarCache.retrieve(mockChannel, expectedChecksum.sum1, expectedChecksum.sum2)); assertThat(ex.getCause(), hasMessage(containsString("Incorrect checksum of previous jar"))); } private void mockCorrectLoad() throws IOException, InterruptedException { when(mockChannel.getProperty(JarLoader.THEIRS)).thenReturn(mockJarLoader); doAnswer((Answer) invocationOnMock -> { - RemoteOutputStream o = (RemoteOutputStream) invocationOnMock.getArguments()[2]; - o.write(CONTENTS.getBytes(StandardCharsets.UTF_8)); - return null; - }).when(mockJarLoader).writeJarTo( - eq(expectedChecksum.sum1), - eq(expectedChecksum.sum2), - any(RemoteOutputStream.class)); + RemoteOutputStream o = (RemoteOutputStream) invocationOnMock.getArguments()[2]; + o.write(CONTENTS.getBytes(StandardCharsets.UTF_8)); + return null; + }) + .when(mockJarLoader) + .writeJarTo(eq(expectedChecksum.sum1), eq(expectedChecksum.sum2), any(RemoteOutputStream.class)); } } diff --git a/src/test/java/hudson/remoting/FlightRecorderInputStreamTest.java b/src/test/java/hudson/remoting/FlightRecorderInputStreamTest.java index 088e2b839..524c24250 100644 --- a/src/test/java/hudson/remoting/FlightRecorderInputStreamTest.java +++ b/src/test/java/hudson/remoting/FlightRecorderInputStreamTest.java @@ -23,7 +23,7 @@ public void diagnosis() throws Exception { oos.writeObject("abc"); oos.writeObject("def"); oos.flush(); - baos.write(0xFF); // corruption + baos.write(0xFF); // corruption oos.writeObject("ghi"); FlightRecorderInputStream fis = new FlightRecorderInputStream(new ByteArrayInputStream(baos.toByteArray())); @@ -32,20 +32,22 @@ public void diagnosis() throws Exception { fis.clear(); assertEquals("def", ois.readObject()); - final StreamCorruptedException e = assertThrows("Expecting a corruption", StreamCorruptedException.class, ois::readObject); + final StreamCorruptedException e = + assertThrows("Expecting a corruption", StreamCorruptedException.class, ois::readObject); DiagnosedStreamCorruptionException t = fis.analyzeCrash(e, "test"); t.printStackTrace(); assertNull(t.getDiagnoseFailure()); // back buffer shouldn't contain 'abc' since the stream was reset - assertArrayEquals(new byte[]{TC_STRING, 0, 3, 'd', 'e', 'f', -1}, t.getReadBack()); - assertArrayEquals(new byte[]{TC_STRING, 0, 3, 'g', 'h', 'i'}, t.getReadAhead()); + assertArrayEquals(new byte[] {TC_STRING, 0, 3, 'd', 'e', 'f', -1}, t.getReadBack()); + assertArrayEquals(new byte[] {TC_STRING, 0, 3, 'g', 'h', 'i'}, t.getReadAhead()); } - @Test public void bounding() throws Exception { + @Test + public void bounding() throws Exception { int sz = (int) (FlightRecorderInputStream.BUFFER_SIZE * /* not a round multiple */ 5.3); byte[] stuff = new byte[sz]; for (int i = 0; i < sz; i++) { - stuff[i] = (byte) (i % /* arbitrary cycle, not a power of 2 */213); + stuff[i] = (byte) (i % /* arbitrary cycle, not a power of 2 */ 213); } FlightRecorderInputStream fris = new FlightRecorderInputStream(new ByteArrayInputStream(stuff)); byte[] stuff2 = new byte[sz]; diff --git a/src/test/java/hudson/remoting/ForkEBCDICRunner.java b/src/test/java/hudson/remoting/ForkEBCDICRunner.java index 7932c0378..a3022a6b6 100644 --- a/src/test/java/hudson/remoting/ForkEBCDICRunner.java +++ b/src/test/java/hudson/remoting/ForkEBCDICRunner.java @@ -9,7 +9,7 @@ public class ForkEBCDICRunner extends ForkRunner { @Override protected List buildCommandLine() { List r = super.buildCommandLine(); - r.add(0,"-Dfile.encoding=CP037"); + r.add(0, "-Dfile.encoding=CP037"); return r; } diff --git a/src/test/java/hudson/remoting/ForkRunner.java b/src/test/java/hudson/remoting/ForkRunner.java index c4a87a7c6..9a50b7c5d 100644 --- a/src/test/java/hudson/remoting/ForkRunner.java +++ b/src/test/java/hudson/remoting/ForkRunner.java @@ -1,6 +1,5 @@ package hudson.remoting; - import static org.junit.Assert.assertEquals; import java.io.OutputStream; @@ -31,10 +30,10 @@ protected List buildCommandLine() { @Override public Channel start() throws Exception { List cmds = buildCommandLine(); - cmds.add(0,"java"); + cmds.add(0, "java"); proc = Runtime.getRuntime().exec(cmds.toArray(new String[0])); - copier = new Copier("copier",proc.getErrorStream(),System.out); + copier = new Copier("copier", proc.getErrorStream(), System.out); copier.start(); executor = Executors.newCachedThreadPool(); @@ -45,7 +44,7 @@ public Channel start() throws Exception { @Override public void stop(Channel channel) throws Exception { channel.close(); - channel.join(10*1000); + channel.join(10 * 1000); executor.shutdown(); diff --git a/src/test/java/hudson/remoting/HexDumpTest.java b/src/test/java/hudson/remoting/HexDumpTest.java index 35f9d29d4..e05ec3664 100644 --- a/src/test/java/hudson/remoting/HexDumpTest.java +++ b/src/test/java/hudson/remoting/HexDumpTest.java @@ -9,7 +9,7 @@ */ public class HexDumpTest { @Test - public void test1() { + public void test1() { assertEquals("0x00 0x01 0xff 'A'", HexDump.toHex(new byte[] {0, 1, -1, 65})); assertEquals("0x00 0x01 0xff 'ABC'", HexDump.toHex(new byte[] {0, 1, -1, 65, 66, 67})); assertEquals("'AAAA' 0x00", HexDump.toHex(new byte[] {65, 65, 65, 65, 0})); @@ -17,6 +17,6 @@ public void test1() { @Test public void testMultiline() { - assertEquals("'A A' 0x0a\n' AA'", HexDump.toHex(new byte[] {65, 32, 65, 10, 32, 65, 65})); + assertEquals("'A A' 0x0a\n' AA'", HexDump.toHex(new byte[] {65, 32, 65, 10, 32, 65, 65})); } } diff --git a/src/test/java/hudson/remoting/InProcessCompatibilityRunner.java b/src/test/java/hudson/remoting/InProcessCompatibilityRunner.java index 18270245c..01ada9334 100644 --- a/src/test/java/hudson/remoting/InProcessCompatibilityRunner.java +++ b/src/test/java/hudson/remoting/InProcessCompatibilityRunner.java @@ -1,8 +1,8 @@ package hudson.remoting; /** -* @author Kohsuke Kawaguchi -*/ + * @author Kohsuke Kawaguchi + */ public class InProcessCompatibilityRunner extends InProcessRunner { @Override public String getName() { diff --git a/src/test/java/hudson/remoting/InProcessRunner.java b/src/test/java/hudson/remoting/InProcessRunner.java index eb381ff74..8e274f633 100644 --- a/src/test/java/hudson/remoting/InProcessRunner.java +++ b/src/test/java/hudson/remoting/InProcessRunner.java @@ -16,6 +16,7 @@ public class InProcessRunner implements DualSideChannelRunner { * failure occurred in the other {@link Channel}. */ private Exception failure; + private Channel south; @Override @@ -34,7 +35,7 @@ public Channel start() throws Exception { @Override public void run() { try { - Channel south = configureSouth().build(in2,out1); + Channel south = configureSouth().build(in2, out1); southHandoff.put(south); south.join(); System.out.println("south completed"); @@ -72,8 +73,9 @@ public void stop(Channel channel) throws Exception { executor.shutdown(); - if(failure!=null) - throw failure; // report a failure in the south side + if (failure != null) { + throw failure; // report a failure in the south side + } } @Override diff --git a/src/test/java/hudson/remoting/LauncherTest.java b/src/test/java/hudson/remoting/LauncherTest.java index f5d420c1c..4e56fde14 100644 --- a/src/test/java/hudson/remoting/LauncherTest.java +++ b/src/test/java/hudson/remoting/LauncherTest.java @@ -55,9 +55,8 @@ public void loadDom_EmbeddedDoctype() throws IOException { } private void shouldFailWithDoctype(FileInputStream jnlpFile) { - final SAXParseException spe = assertThrows("Dom loading should have failed.", SAXParseException.class, - () -> Launcher.loadDom(jnlpFile)); + final SAXParseException spe = assertThrows( + "Dom loading should have failed.", SAXParseException.class, () -> Launcher.loadDom(jnlpFile)); assertThat(spe.getMessage(), containsString("\"http://apache.org/xml/features/disallow-doctype-decl\"")); } - } diff --git a/src/test/java/hudson/remoting/NioPipeRunner.java b/src/test/java/hudson/remoting/NioPipeRunner.java index 812092bbc..698f26299 100644 --- a/src/test/java/hudson/remoting/NioPipeRunner.java +++ b/src/test/java/hudson/remoting/NioPipeRunner.java @@ -25,19 +25,20 @@ public Channel start() throws Exception { final Pipe s2n = Pipe.open(); nio = new NioChannelHub(executor); - nio.setFrameSize(132); // force unaligned boundaries to shake things up a bit + nio.setFrameSize(132); // force unaligned boundaries to shake things up a bit executor.submit(() -> { try { nio.run(); } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Faield to keep the NIO selector thread going",e); + LOGGER.log(Level.WARNING, "Faield to keep the NIO selector thread going", e); failure = e; } }); executor.submit(() -> { try { - Channel south = nio.newChannelBuilder("south",executor).withMode(Channel.Mode.NEGOTIATE) + Channel south = nio.newChannelBuilder("south", executor) + .withMode(Channel.Mode.NEGOTIATE) .build(n2s.source(), s2n.sink()); southHandoff.put(south); south.join(); @@ -49,7 +50,8 @@ public Channel start() throws Exception { }); // create a client channel that connects to the same hub - Channel north = nio.newChannelBuilder("north", executor).withMode(Channel.Mode.BINARY) + Channel north = nio.newChannelBuilder("north", executor) + .withMode(Channel.Mode.BINARY) .build(s2n.source(), n2s.sink()); south = southHandoff.poll(10, TimeUnit.SECONDS); return north; @@ -62,4 +64,3 @@ public String getName() { private static final Logger LOGGER = Logger.getLogger(NioSocketRunner.class.getName()); } - diff --git a/src/test/java/hudson/remoting/NioSocketRunner.java b/src/test/java/hudson/remoting/NioSocketRunner.java index b7e8d1235..38bc4bd26 100644 --- a/src/test/java/hudson/remoting/NioSocketRunner.java +++ b/src/test/java/hudson/remoting/NioSocketRunner.java @@ -47,12 +47,12 @@ protected void onSelected(SelectionKey key) { } }); } catch (IOException e) { - LOGGER.log(Level.WARNING, "Failed to accept a socket",e); + LOGGER.log(Level.WARNING, "Failed to accept a socket", e); failure = e; } } }; - nio.setFrameSize(115); // force unaligned boundaries to shake things up a bit + nio.setFrameSize(115); // force unaligned boundaries to shake things up a bit ss.register(nio.getSelector(), SelectionKey.OP_ACCEPT); LOGGER.info("Waiting for connection"); @@ -60,13 +60,14 @@ protected void onSelected(SelectionKey key) { try { nio.run(); } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to keep the NIO selector thread going",e); + LOGGER.log(Level.WARNING, "Failed to keep the NIO selector thread going", e); failure = e; } }); // create a client channel that connects to the same hub - SocketChannel client = SocketChannel.open(new InetSocketAddress("localhost", ss.socket().getLocalPort())); + SocketChannel client = SocketChannel.open( + new InetSocketAddress("localhost", ss.socket().getLocalPort())); Channel north = configureNorth().build(client); south = southHandoff.poll(10, TimeUnit.SECONDS); return north; @@ -80,7 +81,6 @@ protected NioChannelBuilder configureSouth() { return nio.newChannelBuilder("south", executor).withHeaderStream(System.out); } - @Override public String getName() { return "NIO+socket"; diff --git a/src/test/java/hudson/remoting/NoProxyEvaluatorTest.java b/src/test/java/hudson/remoting/NoProxyEvaluatorTest.java index f7983aa0d..d8fcd0051 100644 --- a/src/test/java/hudson/remoting/NoProxyEvaluatorTest.java +++ b/src/test/java/hudson/remoting/NoProxyEvaluatorTest.java @@ -80,7 +80,8 @@ public void testSubFWDNWithDotMinimalSuffix() { @Test public void testSubFWDNWithDotMinimalSuffixMixedCase() { - NoProxyEvaluator evaluator = new NoProxyEvaluator(".svc,.default,.local,localhost,.boehringer.com,10.250.0.0/16,10.251.0.0/16,10.183.195.106,10.183.195.107,10.183.195.108,10.183.195.109,10.183.195.11,10.183.195.111,10.183.195.112,10.183.195.113,10.183.195.13,10.250.127."); + NoProxyEvaluator evaluator = new NoProxyEvaluator( + ".svc,.default,.local,localhost,.boehringer.com,10.250.0.0/16,10.251.0.0/16,10.183.195.106,10.183.195.107,10.183.195.108,10.183.195.109,10.183.195.11,10.183.195.111,10.183.195.112,10.183.195.113,10.183.195.13,10.250.127."); assertFalse(evaluator.shouldProxyHost("bn-myproj.svc")); } @@ -247,5 +248,4 @@ public void testIPv6Compressed() { assertFalse(evaluator.shouldProxyHost("2001:0db8:0a0b:12f0:0000:0000:0000:0001")); assertFalse(evaluator.shouldProxyHost("2001:0db8:0a0b:12f0::0001")); } - -} \ No newline at end of file +} diff --git a/src/test/java/hudson/remoting/NonSerializableExceptionTest.java b/src/test/java/hudson/remoting/NonSerializableExceptionTest.java index 5cf10a9c9..1d2801c54 100644 --- a/src/test/java/hudson/remoting/NonSerializableExceptionTest.java +++ b/src/test/java/hudson/remoting/NonSerializableExceptionTest.java @@ -34,7 +34,7 @@ /** * @author Kohsuke Kawaguchi */ -public class NonSerializableExceptionTest { +public class NonSerializableExceptionTest { /** * Makes sure non-serializable exceptions are gracefully handled. * @@ -62,14 +62,16 @@ private static final class NoneSerializableException extends Exception { private NoneSerializableException(String msg, Throwable cause) { super(msg, cause); } + private static final long serialVersionUID = 1L; } private static final class Failure extends CallableBase { @Override public Object call() throws Throwable { - throw new NoneSerializableException("message1",new SocketException("message2")); + throw new NoneSerializableException("message1", new SocketException("message2")); } + private static final long serialVersionUID = 1L; } } diff --git a/src/test/java/hudson/remoting/PipeTest.java b/src/test/java/hudson/remoting/PipeTest.java index da62e2963..924822820 100644 --- a/src/test/java/hudson/remoting/PipeTest.java +++ b/src/test/java/hudson/remoting/PipeTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -65,10 +65,10 @@ public void testRemoteWrite(ChannelRunner channelRunner) throws Exception { int r = f.get(); System.out.println("result=" + r); - assertEquals(5,r); + assertEquals(5, r); }); } - + /** * Have the reader close the read end of the pipe while the writer is still writing. * The writer should pick up a failure. @@ -108,6 +108,7 @@ public Void call() throws Exception { Thread.sleep(10); } } + private static final long serialVersionUID = 1L; } @@ -123,6 +124,7 @@ public Integer call() throws IOException { write(pipe); return 5; } + private static final long serialVersionUID = 1L; } @@ -140,7 +142,7 @@ public void testLocalWrite(ChannelRunner channelRunner) throws Exception { int r = f.get(); System.out.println("result=" + r); - assertEquals(5,r); + assertEquals(5, r); }); } @@ -162,19 +164,26 @@ public void testLocalWrite2(ChannelRunner channelRunner) throws Exception { public interface ISaturationTest { void ensureConnected(); + int readFirst() throws IOException; + void readRest() throws IOException; } @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testSaturation(ChannelRunner channelRunner) throws Exception { - assumeFalse(channelRunner instanceof InProcessCompatibilityRunner, "can't do this test without the throttling support."); + assumeFalse( + channelRunner instanceof InProcessCompatibilityRunner, + "can't do this test without the throttling support."); channelRunner.withChannel(channel -> { final Pipe p = Pipe.createLocalToRemote(); Thread writer = new Thread() { - final Thread mainThread = Thread.currentThread(); // this makes it easy to see the relationship between the thread pair in the debugger + final Thread mainThread = + Thread.currentThread(); // this makes it easy to see the relationship between the thread pair + // in the + // debugger @Override public void run() { @@ -212,7 +221,7 @@ public void run() { }); } - private static class CreateSaturationTestProxy extends CallableBase { + private static class CreateSaturationTestProxy extends CallableBase { private final Pipe pipe; public CreateSaturationTestProxy(Pipe pipe) { @@ -223,6 +232,7 @@ public CreateSaturationTestProxy(Pipe pipe) { public ISaturationTest call() { return Channel.currentOrFail().export(ISaturationTest.class, new ISaturationTest() { private InputStream in; + @Override public void ensureConnected() { in = pipe.getIn(); @@ -235,10 +245,11 @@ public int readFirst() throws IOException { @Override public void readRest() throws IOException { - new DataInputStream(in).readFully(new byte[Channel.PIPE_WINDOW_SIZE*2]); + new DataInputStream(in).readFully(new byte[Channel.PIPE_WINDOW_SIZE * 2]); } }); } + private static final long serialVersionUID = 1L; } @@ -253,12 +264,13 @@ public ReadingCallable(Pipe pipe) { public Integer call() throws IOException { try { read(pipe); - } catch(AssertionError ex) { + } catch (AssertionError ex) { // Propagate the assetion to the remote side throw new IOException("Assertion failed", ex); } return 5; } + private static final long serialVersionUID = 1L; } @@ -274,14 +286,13 @@ private static void write(Pipe pipe) throws IOException { private static void read(Pipe p) throws IOException, AssertionError { try (InputStream in = p.getIn()) { - for( int cnt=0; cnt<256*256; cnt++ ) { - assertEquals(cnt/256,in.read()); + for (int cnt = 0; cnt < 256 * 256; cnt++) { + assertEquals(cnt / 256, in.read()); } - assertEquals(-1,in.read()); + assertEquals(-1, in.read()); } } - @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) @Disabled @@ -311,7 +322,7 @@ public void testQuickBurstWrite(ChannelRunner channelRunner) throws Exception { // at this point the async executable kicks in. // TODO: introduce a lock to ensure the ordering. - assertEquals(1,(int)f.get()); + assertEquals(1, (int) f.get()); }); } @@ -320,6 +331,7 @@ private static class DevNullSink extends CallableBase public OutputStream call() { return new RemoteOutputStream(OutputStream.nullOutputStream()); } + private static final long serialVersionUID = 1L; } @@ -340,7 +352,9 @@ public Integer call() throws IOException { IOUtils.copy(p.getIn(), baos); return baos.size(); } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/PipeWriterTest.java b/src/test/java/hudson/remoting/PipeWriterTest.java index b51962e3a..58276ec28 100644 --- a/src/test/java/hudson/remoting/PipeWriterTest.java +++ b/src/test/java/hudson/remoting/PipeWriterTest.java @@ -19,30 +19,36 @@ public class PipeWriterTest implements Serializable, PipeWriterTestChecker { * {@link OutputStream} that is slow to act. */ transient SlowOutputStream slow = new SlowOutputStream(); + RemoteOutputStream ros = new RemoteOutputStream(slow); /** * Proxy that can be used from the other side to verify the state. */ PipeWriterTestChecker checker; - void withChannel(ChannelRunner channelRunner, ChannelRunner.ConsumerThrowable f) throws Exception { + + void withChannel(ChannelRunner channelRunner, ChannelRunner.ConsumerThrowable f) + throws Exception { // Checker operates using the user-space RMI - channelRunner.withChannel(((ChannelRunner.ConsumerThrowable) channel -> checker = channel.export(PipeWriterTestChecker.class, PipeWriterTest.this, false, true, true)).andThen(f)); + channelRunner.withChannel(((ChannelRunner.ConsumerThrowable) channel -> + checker = channel.export(PipeWriterTestChecker.class, PipeWriterTest.this, false, true, true)) + .andThen(f)); } /** * Base test case for the response / IO coordination. */ - abstract class ResponseIoCoordCallable extends CallableBase { + abstract class ResponseIoCoordCallable extends CallableBase { @Override public Object call() throws Exception { long start = System.currentTimeMillis(); System.out.println("touch"); touch(); - assertTrue(System.currentTimeMillis()-start<1000); // write() itself shouldn't block + assertTrue(System.currentTimeMillis() - start < 1000); // write() itself shouldn't block class CheckerThread extends Thread { Throwable death; + @Override public void run() { try { @@ -61,8 +67,9 @@ public void run() { CheckerThread t = new CheckerThread(); t.start(); t.join(); - if (t.death!=null) + if (t.death != null) { throw new AssertionError(t.death); + } System.out.println("returning"); return null; @@ -72,6 +79,7 @@ public void run() { * This is where the actual I/O happens. */ abstract void touch() throws IOException; + private static final long serialVersionUID = 1L; } @@ -116,19 +124,18 @@ public void testResponseIoCoordClose(ChannelRunner channelRunner) throws Excepti }); } - /** * Base test case for the request / IO coordination. */ - abstract class RequestIoCoordCallable extends CallableBase { + abstract class RequestIoCoordCallable extends CallableBase { @Override public Object call() throws IOException { long start = System.currentTimeMillis(); System.out.println("touch"); touch(); System.out.println("verify"); - assertTrue(System.currentTimeMillis()-start<1000); // write() itself shouldn't block - checker.assertSlowStreamTouched(); // but this call should + assertTrue(System.currentTimeMillis() - start < 1000); // write() itself shouldn't block + checker.assertSlowStreamTouched(); // but this call should System.out.println("end"); return null; } @@ -137,6 +144,7 @@ public Object call() throws IOException { * This is where the actual I/O happens. */ abstract void touch() throws IOException; + private static final long serialVersionUID = 1L; } @@ -183,7 +191,7 @@ public void assertSlowStreamTouched() { * Induces delay. */ static class SlowOutputStream extends OutputStream { - boolean closed,flushed,written; + boolean closed, flushed, written; @Override public void write(int b) throws IOException { @@ -217,6 +225,7 @@ private class ResponseCallableWriter extends ResponseIoCoordCallable { void touch() throws IOException { ros.write(0); } + private static final long serialVersionUID = 1L; } @@ -225,6 +234,7 @@ private class ResponseCallableFlusher extends ResponseIoCoordCallable { void touch() throws IOException { ros.flush(); } + private static final long serialVersionUID = 1L; } @@ -233,6 +243,7 @@ private class ResponseCallableCloser extends ResponseIoCoordCallable { void touch() throws IOException { ros.close(); } + private static final long serialVersionUID = 1L; } @@ -241,6 +252,7 @@ private class RequestCallableWriter extends RequestIoCoordCallable { void touch() throws IOException { ros.write(0); } + private static final long serialVersionUID = 1L; } @@ -249,6 +261,7 @@ private class RequestCallableFlusher extends RequestIoCoordCallable { void touch() throws IOException { ros.flush(); } + private static final long serialVersionUID = 1L; } @@ -257,7 +270,9 @@ private class RequestCallableCloser extends RequestIoCoordCallable { void touch() throws IOException { ros.close(); } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/PipeWriterTestChecker.java b/src/test/java/hudson/remoting/PipeWriterTestChecker.java index c561403f6..11e72b11d 100644 --- a/src/test/java/hudson/remoting/PipeWriterTestChecker.java +++ b/src/test/java/hudson/remoting/PipeWriterTestChecker.java @@ -1,9 +1,10 @@ package hudson.remoting; /** -* @author Kohsuke Kawaguchi -*/ + * @author Kohsuke Kawaguchi + */ public interface PipeWriterTestChecker { void assertSlowStreamNotTouched(); + void assertSlowStreamTouched(); } diff --git a/src/test/java/hudson/remoting/PrefetchTest.java b/src/test/java/hudson/remoting/PrefetchTest.java index 09afdc8ce..fd342942a 100644 --- a/src/test/java/hudson/remoting/PrefetchTest.java +++ b/src/test/java/hudson/remoting/PrefetchTest.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -47,11 +47,12 @@ public void testPrefetch(ChannelRunner channelRunner) throws Exception { }); } - private static class VerifyTask extends CallableBase { + private static class VerifyTask extends CallableBase { @Override public String call() throws IOException { return "verified"; } + private static final long serialVersionUID = 1L; } } diff --git a/src/test/java/hudson/remoting/PrefetchingTest.java b/src/test/java/hudson/remoting/PrefetchingTest.java index 84aa58fa6..7f98918dc 100644 --- a/src/test/java/hudson/remoting/PrefetchingTest.java +++ b/src/test/java/hudson/remoting/PrefetchingTest.java @@ -34,13 +34,13 @@ public class PrefetchingTest implements Serializable { private File dir; // checksum of the jar files to force loading - private Checksum sum1,sum2; + private Checksum sum1, sum2; - void withChannel(ChannelRunner channelRunner, ChannelRunner.ConsumerThrowable f) throws Exception { + void withChannel(ChannelRunner channelRunner, ChannelRunner.ConsumerThrowable f) + throws Exception { channelRunner.withChannel(((ChannelRunner.ConsumerThrowable) this::setUp).andThen(f)); } - protected void setUp(Channel channel) throws Exception { URL jar1 = getClass().getClassLoader().getResource("remoting-test-client.jar"); URL jar2 = getClass().getClassLoader().getResource("remoting-test-client-tests.jar"); @@ -82,12 +82,14 @@ protected void tearDown() throws Exception { // because the dir is used by FIleSystemJarCache to asynchronously load stuff // we might fail to shut it down right away if (dir != null) { - for (int i=0; ; i++) { + for (int i = 0; ; i++) { try { FileUtils.deleteDirectory(dir); return; } catch (IOException e) { - if (i==3) throw e; + if (i == 3) { + throw e; + } Thread.sleep(1000); } } @@ -105,13 +107,16 @@ public void testJarLoadingTest(ChannelRunner channelRunner) throws Exception { channel.call(new ForceJarLoad(sum1)); channel.call(new ForceJarLoad(sum2)); - Callable sc = (Callable) cl.loadClass("test.ClassLoadingFromJarTester").getDeclaredConstructor().newInstance(); + Callable sc = + (Callable) cl.loadClass("test.ClassLoadingFromJarTester") + .getDeclaredConstructor() + .newInstance(); ((Function, Void>) sc).apply(new Verifier()); assertNull(channel.call(sc)); }); } - private static class Verifier implements Function, Serializable { + private static class Verifier implements Function, Serializable { @Override public Object apply(Object o) { try { @@ -124,6 +129,7 @@ public Object apply(Object o) { throw new Error(e); } } + private static final long serialVersionUID = 1L; } @@ -135,7 +141,9 @@ public void testGetResource(ChannelRunner channelRunner) throws Exception { channel.call(new ForceJarLoad(sum1)); channel.call(new ForceJarLoad(sum2)); - Callable c = (Callable) cl.loadClass("test.HelloGetResource").getDeclaredConstructor().newInstance(); + Callable c = (Callable) cl.loadClass("test.HelloGetResource") + .getDeclaredConstructor() + .newInstance(); String v = channel.call(c); System.out.println(v); @@ -147,7 +155,9 @@ public void testGetResource(ChannelRunner channelRunner) throws Exception { @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testGetResource_precache(ChannelRunner channelRunner) throws Exception { withChannel(channelRunner, channel -> { - Callable c = (Callable) cl.loadClass("test.HelloGetResource").getDeclaredConstructor().newInstance(); + Callable c = (Callable) cl.loadClass("test.HelloGetResource") + .getDeclaredConstructor() + .newInstance(); String v = channel.call(c); System.out.println(v); @@ -159,7 +169,10 @@ public void testGetResource_precache(ChannelRunner channelRunner) throws Excepti @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testGetResourceAsStream(ChannelRunner channelRunner) throws Exception { withChannel(channelRunner, channel -> { - Callable c = (Callable) cl.loadClass("test.HelloGetResourceAsStream").getDeclaredConstructor().newInstance(); + Callable c = + (Callable) cl.loadClass("test.HelloGetResourceAsStream") + .getDeclaredConstructor() + .newInstance(); String v = channel.call(c); assertEquals("hello", v); }); @@ -169,9 +182,7 @@ public void testGetResourceAsStream(ChannelRunner channelRunner) throws Exceptio * Validates that the resource is coming from a jar. */ private void verifyResource(String v) { - assertThat(v, allOf(startsWith("jar:file:"), - containsString(dir.toURI().getPath()), - endsWith("::hello"))); + assertThat(v, allOf(startsWith("jar:file:"), containsString(dir.toURI().getPath()), endsWith("::hello"))); } /** @@ -193,31 +204,36 @@ public void testGetResources(ChannelRunner channelRunner) throws Exception { channel.call(new ForceJarLoad(sum1)); channel.call(new ForceJarLoad(sum2)); - Callable c = (Callable) cl.loadClass("test.HelloGetResources").getDeclaredConstructor().newInstance(); + Callable c = (Callable) cl.loadClass("test.HelloGetResources") + .getDeclaredConstructor() + .newInstance(); String v = channel.call(c); - System.out.println(v); // should find two resources + System.out.println(v); // should find two resources String[] lines = v.split("\n"); verifyResource(lines[0]); - assertThat(lines[1], allOf(startsWith("jar:file:"), - containsString(dir.toURI().getPath()), - endsWith("::hello2"))); + assertThat( + lines[1], + allOf(startsWith("jar:file:"), containsString(dir.toURI().getPath()), endsWith("::hello2"))); }); } /** * Unlike {@link #testGetResources(ChannelRunner)}, the URL should begin with file:... before the jar file gets cached */ - @Disabled("TODO flakes: jar:file:/tmp/remoting-cache….jar!/test/hello.txt::hello ==> expected: but was: ") + @Disabled( + "TODO flakes: jar:file:/tmp/remoting-cache….jar!/test/hello.txt::hello ==> expected: but was: ") @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testGetResources_precache(ChannelRunner channelRunner) throws Exception { withChannel(channelRunner, channel -> { - Callable c = (Callable) cl.loadClass("test.HelloGetResources").getDeclaredConstructor().newInstance(); + Callable c = (Callable) cl.loadClass("test.HelloGetResources") + .getDeclaredConstructor() + .newInstance(); String v = channel.call(c); - System.out.println(v); // should find two resources + System.out.println(v); // should find two resources String[] lines = v.split("\n"); @@ -241,21 +257,22 @@ public void testInnerClass(ChannelRunner channelRunner) throws Exception { }); } - private static final class Echo extends CallableBase implements Serializable { + private static final class Echo extends CallableBase implements Serializable { V value; @Override public V call() { return value; } + private static final long serialVersionUID = 1L; } /** * Force the remote side to fetch the retrieval of the specific jar file. */ - private static final class ForceJarLoad extends CallableBase implements Serializable{ - private final long sum1,sum2; + private static final class ForceJarLoad extends CallableBase implements Serializable { + private final long sum1, sum2; private ForceJarLoad(Checksum sum) { this.sum1 = sum.sum1; @@ -270,12 +287,13 @@ public Void call() throws IOException { if (jarCache == null) { throw new IOException("Cannot Force JAR load, JAR cache is disabled"); } - jarCache.resolve(ch,sum1,sum2).get(); + jarCache.resolve(ch, sum1, sum2).get(); return null; } catch (InterruptedException | ExecutionException e) { throw new IOException(e); } } + private static final long serialVersionUID = 1L; } @@ -285,7 +303,9 @@ public Void call() { Channel.currentOrFail().setJarCache(new FileSystemJarCache(dir, true)); return null; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/ProxyExceptionTest.java b/src/test/java/hudson/remoting/ProxyExceptionTest.java index 622d668aa..647041b25 100644 --- a/src/test/java/hudson/remoting/ProxyExceptionTest.java +++ b/src/test/java/hudson/remoting/ProxyExceptionTest.java @@ -56,7 +56,7 @@ public void breaksCyclesInSuppressedExceptions() { ProxyException pe1 = new ProxyException(cyclic1); assertThat(pe1.getMessage(), is(cyclic1.toString())); assertThat(pe1.getStackTrace(), is(cyclic1.getStackTrace())); - ProxyException pe2 = (ProxyException)pe1.getSuppressed()[0]; + ProxyException pe2 = (ProxyException) pe1.getSuppressed()[0]; assertThat(pe2.getMessage(), is(cyclic2.toString())); assertThat(pe2.getStackTrace(), is(cyclic2.getStackTrace())); assertThat(pe2.getSuppressed(), is(emptyArray())); diff --git a/src/test/java/hudson/remoting/ProxyWriterTest.java b/src/test/java/hudson/remoting/ProxyWriterTest.java index ff23b8f41..a5cc4a900 100644 --- a/src/test/java/hudson/remoting/ProxyWriterTest.java +++ b/src/test/java/hudson/remoting/ProxyWriterTest.java @@ -25,7 +25,7 @@ */ public class ProxyWriterTest implements Serializable { ByteArrayOutputStream log = new ByteArrayOutputStream(); - StreamHandler logRecorder = new StreamHandler(log,new SimpleFormatter()) { + StreamHandler logRecorder = new StreamHandler(log, new SimpleFormatter()) { @Override public synchronized void publish(LogRecord record) { super.publish(record); @@ -44,7 +44,6 @@ public void tearDown() throws Exception { logger.removeHandler(logRecorder); } - volatile boolean streamClosed; /** @@ -63,20 +62,20 @@ public void testAllCalls(ChannelRunner channelRunner) throws Exception { writeBunchOfData(correct); assertEquals(sw.toString(), correct.toString()); - assertEquals(0, log.size()); // no warning should be reported + assertEquals(0, log.size()); // no warning should be reported }); } private static void writeBunchOfData(Writer w) throws IOException { - for (int i=0; i<1000; i++) { + for (int i = 0; i < 1000; i++) { w.write('1'); w.write("hello".toCharArray()); w.write("abcdef".toCharArray(), 0, 3); } w.flush(); - for (int i=0; i<1000; i++) { + for (int i = 0; i < 1000; i++) { w.write("hello"); - w.write("abcdef",0,3); + w.write("abcdef", 0, 3); } w.close(); } @@ -88,7 +87,9 @@ private static void writeBunchOfData(Writer w) throws IOException { @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testRemoteGC(ChannelRunner channelRunner) throws Exception { - assumeFalse(channelRunner instanceof InProcessCompatibilityRunner, "in the legacy mode ProxyWriter will try to close the stream, so can't run this test"); + assumeFalse( + channelRunner instanceof InProcessCompatibilityRunner, + "in the legacy mode ProxyWriter will try to close the stream, so can't run this test"); channelRunner.withChannel(channel -> { StringWriter sw = new StringWriter() { @Override @@ -103,12 +104,13 @@ public void close() { // induce a GC. There's no good reliable way to do this, // and if GC doesn't happen within this loop, the test can pass // even when the underlying problem exists. - for (int i=0; i<30; i++) { + for (int i = 0; i < 30; i++) { assertEquals(0, log.size(), "There shouldn't be any errors: " + log.toString()); Thread.sleep(100); - if (channel.call(new GcCallable())) + if (channel.call(new GcCallable())) { break; + } } channel.syncIO(); @@ -119,7 +121,6 @@ public void close() { static WeakReference W; - /** * Basic test of {@link RemoteWriter}/{@link ProxyWriter} test. */ @@ -130,12 +131,12 @@ public void testWriteAndSync(ChannelRunner channelRunner) throws Exception { StringWriter sw = new StringWriter(); final RemoteWriter w = new RemoteWriter(sw); - for (int i=0; i<16; i++) { + for (int i = 0; i < 16; i++) { channel.call(new WriterCallable(w)); w.write("2"); } - assertEquals("12121212121212121212121212121212",sw.toString()); + assertEquals("12121212121212121212121212121212", sw.toString()); }); } @@ -155,6 +156,7 @@ public Void call() throws IOException { writeBunchOfData(w); return null; } + private static final long serialVersionUID = 1L; } @@ -179,6 +181,7 @@ public Boolean call() { System.gc(); return W.get() == null; } + private static final long serialVersionUID = 1L; } @@ -194,7 +197,9 @@ public Void call() throws IOException { w.write("1--", 0, 1); return null; } + private static final long serialVersionUID = 1L; } + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/RegExpBenchmark.java b/src/test/java/hudson/remoting/RegExpBenchmark.java index eb41dffbb..d8a079379 100644 --- a/src/test/java/hudson/remoting/RegExpBenchmark.java +++ b/src/test/java/hudson/remoting/RegExpBenchmark.java @@ -35,62 +35,91 @@ @Ignore("This is not a test just a benchmark and is here for ease of running") public class RegExpBenchmark { - + final Pattern p1 = Pattern.compile("^org\\.codehaus\\.groovy\\.runtime\\..*"); final Pattern p2 = Pattern.compile("^org\\.apache\\.commons\\.collections\\.functors\\..*"); final Pattern p3 = Pattern.compile("^.*org\\.apache\\.xalan\\..*"); - - final Pattern p4 = Pattern.compile("^(?:(?:org\\.(?:codehaus\\.groovy\\.runtime|apache\\.commons\\.collections\\.functors))|.*?org\\.apache\\.xalan)\\..*"); + final Pattern p4 = Pattern.compile( + "^(?:(?:org\\.(?:codehaus\\.groovy\\.runtime|apache\\.commons\\.collections\\.functors))|.*?org\\.apache\\.xalan)\\..*"); final String s1 = "org.codehaus.groovy.runtime."; final String s2 = "org.apache.commons.collections.functors."; final String s3 = "org.apache.xalan."; - + @Test public void repeatedBenchMark() throws Exception { - for (int i=0; i < 10; i++) { + for (int i = 0; i < 10; i++) { benchmark(); - System.gc();System.gc();System.gc(); + System.gc(); + System.gc(); + System.gc(); } } - + @Test public void benchmark() throws Exception { System.out.println("there are " + getAllRTClasses().size()); - + List classes = getAllRTClasses(); final long startRegExp = System.nanoTime(); final List matchesRegExp = checkClassesRegExp(classes); final long durationRegexpNanos = System.nanoTime() - startRegExp; - System.gc();System.gc();System.gc(); - - // make sure we use new Strings each time so that hotpsot does not do funky caching (after all the strings we will be testing will come from the stream and be new). + System.gc(); + System.gc(); + System.gc(); + + // make sure we use new Strings each time so that hotpsot does not do funky caching (after all the strings we + // will be testing will come from the stream and be new). classes = getAllRTClasses(); final long startSingleRegExp = System.nanoTime(); final List matchesSingleRegExp = checkClassesSingleRegExp(classes); final long durationSingleRegexpNanos = System.nanoTime() - startSingleRegExp; - System.gc();System.gc();System.gc(); - - // make sure we use new Strings each time so that hotpsot does not do funky caching (after all the strings we will be testing will come from the stream and be new). + System.gc(); + System.gc(); + System.gc(); + + // make sure we use new Strings each time so that hotpsot does not do funky caching (after all the strings we + // will be testing will come from the stream and be new). classes = getAllRTClasses(); final long startString = System.nanoTime(); final List matchesString = checkClassesString(classes); final long durationStringNanos = System.nanoTime() - startString; - - System.out.printf(Locale.ENGLISH, "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", "RegExp ", matchesRegExp.size(), durationRegexpNanos, durationRegexpNanos/classes.size()); - System.out.printf(Locale.ENGLISH, "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", "SingleRegExp ", matchesSingleRegExp.size(), durationSingleRegexpNanos, durationSingleRegexpNanos/classes.size()); - System.out.printf(Locale.ENGLISH, "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", "String ", matchesString.size(), durationStringNanos, durationStringNanos/classes.size()); - - System.out.println("Regular Expression is " + durationRegexpNanos/durationStringNanos + " times slower"); - System.out.println("Single Regular Expression is " + durationSingleRegexpNanos/durationStringNanos + " times slower\n"); + + System.out.printf( + Locale.ENGLISH, + "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", + "RegExp ", + matchesRegExp.size(), + durationRegexpNanos, + durationRegexpNanos / classes.size()); + System.out.printf( + Locale.ENGLISH, + "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", + "SingleRegExp ", + matchesSingleRegExp.size(), + durationSingleRegexpNanos, + durationSingleRegexpNanos / classes.size()); + System.out.printf( + Locale.ENGLISH, + "%-13s: %d blacklisted classes in %9dns. Average class check time is %dns%n", + "String ", + matchesString.size(), + durationStringNanos, + durationStringNanos / classes.size()); + + System.out.println("Regular Expression is " + durationRegexpNanos / durationStringNanos + " times slower"); + System.out.println( + "Single Regular Expression is " + durationSingleRegexpNanos / durationStringNanos + " times slower\n"); } private List checkClassesRegExp(List classnames) { List blacklistedClasses = new ArrayList<>(); for (String s : classnames) { - if (p1.matcher(s).matches() || p2.matcher(s).matches() || p3.matcher(s).matches()) { + if (p1.matcher(s).matches() + || p2.matcher(s).matches() + || p3.matcher(s).matches()) { // something with a side effect blacklistedClasses.add(s); } @@ -108,7 +137,7 @@ private List checkClassesSingleRegExp(List classnames) { } return blacklistedClasses; } - + private List checkClassesString(List classnames) { List blacklistedClasses = new ArrayList<>(); for (String s : classnames) { @@ -119,12 +148,12 @@ private List checkClassesString(List classnames) { } return blacklistedClasses; } - + private List getAllRTClasses() throws Exception { List classes = new ArrayList<>(); // Object.class.getProtectionDomain().getCodeSource() returns null :( String javaHome = System.getProperty("java.home"); - JarFile jf = new JarFile(javaHome + "/lib/rt.jar"); + JarFile jf = new JarFile(javaHome + "/lib/rt.jar"); for (JarEntry je : Collections.list(jf.entries())) { if (!je.isDirectory() && je.getName().endsWith(".class")) { String name = je.getName().replace('/', '.'); diff --git a/src/test/java/hudson/remoting/RemoteInputStreamTest.java b/src/test/java/hudson/remoting/RemoteInputStreamTest.java index 874aa9515..6e213e062 100644 --- a/src/test/java/hudson/remoting/RemoteInputStreamTest.java +++ b/src/test/java/hudson/remoting/RemoteInputStreamTest.java @@ -44,9 +44,9 @@ public void testGreedy(ChannelRunner channelRunner) throws Exception { // not very reliable but the intention is to have it greedily read Thread.sleep(100); - if (channel.remoteCapability.supportsGreedyRemoteInputStream()) + if (channel.remoteCapability.supportsGreedyRemoteInputStream()) { assertEquals(-1, in.read()); - else { + } else { // if we are dealing with version that doesn't support GREEDY, we should be reading '5' assertEquals('5', in.read()); } @@ -56,7 +56,7 @@ public void testGreedy(ChannelRunner channelRunner) throws Exception { /** * Reads N bytes and verify that it matches what's expected. */ - private static class Read extends CallableBase { + private static class Read extends CallableBase { private final RemoteInputStream in; private final byte[] expected; @@ -70,10 +70,10 @@ public Object call() throws IOException { assertArrayEquals(readFully(in, expected.length), expected); return null; } + private static final long serialVersionUID = 1L; } - /** * Read in multiple chunks. */ @@ -89,7 +89,7 @@ public void testGreedy2(ChannelRunner channelRunner) throws Exception { }); } - private static class TestGreedy2 extends CallableBase { + private static class TestGreedy2 extends CallableBase { private final RemoteInputStream i; public TestGreedy2(RemoteInputStream i) { @@ -103,10 +103,10 @@ public Void call() throws IOException { assertEquals(-1, i.read()); return null; } + private static final long serialVersionUID = 1L; } - /** * Greedy {@link RemoteInputStream} should propagate error. */ @@ -116,9 +116,7 @@ public void testErrorPropagation(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { for (RemoteInputStream.Flag f : List.of(RemoteInputStream.Flag.GREEDY, RemoteInputStream.Flag.NOT_GREEDY)) { InputStream in = new SequenceInputStream( - new ByteArrayInputStream(toBytes("1234")), - new BrokenInputStream(new SkyIsFalling()) - ); + new ByteArrayInputStream(toBytes("1234")), new BrokenInputStream(new SkyIsFalling())); final RemoteInputStream i = new RemoteInputStream(in, f); channel.call(new TestErrorPropagation(i)); @@ -126,7 +124,9 @@ public void testErrorPropagation(ChannelRunner channelRunner) throws Exception { }); } - private static class SkyIsFalling extends IOException {private static final long serialVersionUID = 1L;} + private static class SkyIsFalling extends IOException { + private static final long serialVersionUID = 1L; + } private static class TestErrorPropagation extends CallableBase { private final RemoteInputStream i; @@ -146,15 +146,16 @@ public Void call() throws IOException { // but in case someone is using it as a signal I'm not changing that behaviour. return null; } catch (IOException e) { - if (e.getCause() instanceof SkyIsFalling) + if (e.getCause() instanceof SkyIsFalling) { return null; + } throw e; } } + private static final long serialVersionUID = 1L; } - private static byte[] readFully(InputStream in, int n) throws IOException { byte[] actual = new byte[n]; new DataInputStream(in).readFully(actual); @@ -162,8 +163,8 @@ private static byte[] readFully(InputStream in, int n) throws IOException { } private static void assertArrayEquals(byte[] b1, byte[] b2) { - if (!Arrays.equals(b1,b2)) { - fail("Expected "+ HexDump.toHex(b1)+" but got "+ HexDump.toHex(b2)); + if (!Arrays.equals(b1, b2)) { + fail("Expected " + HexDump.toHex(b1) + " but got " + HexDump.toHex(b2)); } } diff --git a/src/test/java/hudson/remoting/RemoteInvocationHandlerTest.java b/src/test/java/hudson/remoting/RemoteInvocationHandlerTest.java index 0b5c0ee83..51de00166 100644 --- a/src/test/java/hudson/remoting/RemoteInvocationHandlerTest.java +++ b/src/test/java/hudson/remoting/RemoteInvocationHandlerTest.java @@ -55,13 +55,16 @@ public interface Contract2 { private static class Impl implements Contract, SerializableOnlyOverRemoting, Contract2 { String arg; + public void meth(String arg1, String arg2) { assert false : "should be ignored"; } + @Override public void meth(String arg1) { this.arg = arg1; } + @Override public void meth2(String arg) { this.arg = arg; @@ -72,29 +75,35 @@ private Object writeReplace() throws ObjectStreamException { } } - private static class Task extends CallableBase { + private static class Task extends CallableBase { private final Contract c; + Task(Contract c) { this.c = c; } + @Override public Void call() throws Error { c.meth("value"); return null; } + private static final long serialVersionUID = 1L; } - private static class Task2 extends CallableBase { + private static class Task2 extends CallableBase { private final Contract2 c; + Task2(Contract2 c) { this.c = c; } + @Override public Void call() throws Error { c.meth2("value"); return null; } + private static final long serialVersionUID = 1L; } @@ -107,11 +116,12 @@ public void testAsyncCall(ChannelRunner channelRunner) throws Exception { synchronized (i) { channel.call(new AsyncTask(c)); - assertNull(i.arg); // async call should be blocking + assertNull(i.arg); // async call should be blocking - while (i.arg == null) + while (i.arg == null) { i.wait(); - assertEquals("value", i.arg); // once we let the call complete, we should see 'value' + } + assertEquals("value", i.arg); // once we let the call complete, we should see 'value' } }); } @@ -123,6 +133,7 @@ public interface AsyncContract { private static class AsyncImpl implements AsyncContract, Serializable { String arg; + @Override public void meth(String arg1) { synchronized (this) { @@ -130,19 +141,23 @@ public void meth(String arg1) { notifyAll(); } } + private static final long serialVersionUID = 1L; } - private static class AsyncTask extends CallableBase { + private static class AsyncTask extends CallableBase { private final AsyncContract c; + AsyncTask(AsyncContract c) { this.c = c; } + @Override public Void call() throws Error { c.meth("value"); return null; } + private static final long serialVersionUID = 1L; } } diff --git a/src/test/java/hudson/remoting/SimpleTest.java b/src/test/java/hudson/remoting/SimpleTest.java index a42c4ee46..c5aacdeeb 100644 --- a/src/test/java/hudson/remoting/SimpleTest.java +++ b/src/test/java/hudson/remoting/SimpleTest.java @@ -57,8 +57,8 @@ public void test1(ChannelRunner channelRunner) throws Exception { public void test1Async(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { Future r = channel.callAsync(new Callable1()); - System.out.println("result="+r.get()); - assertEquals(5,(int)r.get()); + System.out.println("result=" + r.get()); + assertEquals(5, (int) r.get()); }); } @@ -68,6 +68,7 @@ public Integer call() throws RuntimeException { System.err.println("invoked"); return 5; } + private static final long serialVersionUID = 1L; } @@ -76,7 +77,7 @@ public Integer call() throws RuntimeException { public void test2(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { final RuntimeException e = assertThrows(RuntimeException.class, () -> channel.call(new Callable2())); - assertEquals(e.getMessage(),"foo"); + assertEquals(e.getMessage(), "foo"); }); } @@ -88,7 +89,7 @@ public void test2Async(ChannelRunner channelRunner) throws Exception { Future r = channel.callAsync(new Callable2()); r.get(); }); - assertEquals(e.getCause().getMessage(),"foo"); + assertEquals(e.getCause().getMessage(), "foo"); }); } @@ -97,6 +98,7 @@ private static class Callable2 extends CallableBase { public Integer call() throws RuntimeException { throw new RuntimeException("foo"); } + private static final long serialVersionUID = 1L; } @@ -109,13 +111,13 @@ public void test3(ChannelRunner channelRunner) throws Exception { channelRunner.withChannel(channel -> { Foo c = new Foo() {}; Foo r = channel.call(new Echo<>(channel.export(Foo.class, c))); - assertSame(c,r); + assertSame(c, r); }); } public interface Foo {} - private static class Echo extends CallableBase { + private static class Echo extends CallableBase { private final T t; Echo(T t) { @@ -126,6 +128,7 @@ private static class Echo extends CallableBase { public T call() throws RuntimeException { return t; } + private static final long serialVersionUID = 1L; } @@ -134,7 +137,7 @@ public T call() throws RuntimeException { * Currently seems to be used by MavenBuilder.call and Proc.RemoteProc.kill * (in turn used by MercurialSCM.joinWithTimeout when polling on remote host). */ - //@Bug(4611) + // @Bug(4611) @ParameterizedTest @MethodSource(ChannelRunners.PROVIDER_METHOD) public void testCancellation(ChannelRunner channelRunner) throws Exception { @@ -150,15 +153,17 @@ public void testCancellation(ChannelRunner channelRunner) throws Exception { // TODO ought to also test various other aspects: cancelling before start, etc. }); } + private static class Cancellable extends CallableBase { boolean ran; + @Override public Integer call() throws InterruptedException { Thread.sleep(9999); ran = true; return 0; } + private static final long serialVersionUID = 1L; } - } diff --git a/src/test/java/hudson/remoting/SingleLaneExecutorServiceTest.java b/src/test/java/hudson/remoting/SingleLaneExecutorServiceTest.java index 6ca7ab751..944a11a4e 100644 --- a/src/test/java/hudson/remoting/SingleLaneExecutorServiceTest.java +++ b/src/test/java/hudson/remoting/SingleLaneExecutorServiceTest.java @@ -34,7 +34,8 @@ public void laneIndependence() throws Exception { final StringBuilder record = new StringBuilder(); synchronized (lock) { lane1.submit(() -> { - synchronized (lock) {} + synchronized (lock) { + } sleep(1000); record.append("x"); }); @@ -48,7 +49,7 @@ public void laneIndependence() throws Exception { waitForCompletion(lane1); waitForCompletion(lane2); - assertEquals("zxy",record.toString()); + assertEquals("zxy", record.toString()); } /** @@ -64,10 +65,10 @@ class Workload { ExecutorService lane = new SingleLaneExecutorService(base); Workload() { - for (char t='a'; t<='z'; t++) { + for (char t = 'a'; t <= 'z'; t++) { final char ch = t; tasks.add(() -> { - sleep(50+r.nextInt(100)); + sleep(50 + r.nextInt(100)); record.append(ch); }); } @@ -75,13 +76,14 @@ class Workload { } List works = new ArrayList<>(); - for (int i=0; i<5; i++) + for (int i = 0; i < 5; i++) { works.add(new Workload()); + } // submit them all in the queue List remaining = new ArrayList<>(works); int total = (('z' - 'a') + 1) * works.size(); - for (int i=0; i0) - baos.write(buf,0,len); + while ((len = in.read(buf)) > 0) { + baos.write(buf, 0, len); + } in.close(); r[1] = baos.toByteArray(); @@ -65,9 +66,11 @@ public Object call() throws Throwable { } @Override - public void checkRoles(RoleChecker checker) throws SecurityException { + public void checkRoles(RoleChecker checker) throws SecurityException {} + + public static class Sub extends TestCallable { + private static final long serialVersionUID = 1L; } - public static class Sub extends TestCallable {private static final long serialVersionUID = 1L;} private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/TestLinkage.java b/src/test/java/hudson/remoting/TestLinkage.java index 526a98f11..2a9c16e16 100644 --- a/src/test/java/hudson/remoting/TestLinkage.java +++ b/src/test/java/hudson/remoting/TestLinkage.java @@ -39,5 +39,6 @@ public static class A { } public static class B {} + private static final long serialVersionUID = 1L; } diff --git a/src/test/java/hudson/remoting/TestStaticGetResources.java b/src/test/java/hudson/remoting/TestStaticGetResources.java index 708816b06..5619eeebc 100644 --- a/src/test/java/hudson/remoting/TestStaticGetResources.java +++ b/src/test/java/hudson/remoting/TestStaticGetResources.java @@ -10,14 +10,17 @@ public class TestStaticGetResources extends CallableBase { static { try { - FIRST_RESOURCE = TestStaticGetResources.class.getClassLoader().getResources("BLAH").hasMoreElements(); + FIRST_RESOURCE = TestStaticGetResources.class + .getClassLoader() + .getResources("BLAH") + .hasMoreElements(); } catch (IOException e) { e.printStackTrace(); } } + @Override public Object call() { return "found the impossible: " + FIRST_RESOURCE; } - } diff --git a/src/test/java/hudson/remoting/TestStaticResourceReference.java b/src/test/java/hudson/remoting/TestStaticResourceReference.java index c21d10cd4..42e5f8028 100644 --- a/src/test/java/hudson/remoting/TestStaticResourceReference.java +++ b/src/test/java/hudson/remoting/TestStaticResourceReference.java @@ -5,10 +5,11 @@ public class TestStaticResourceReference extends CallableBase { private static final long serialVersionUID = 1L; // this is really just to check that we can initialize a static property from searching a classpath resource - private static boolean FALSE = TestStaticResourceReference.class.getClassLoader().getResource("BLAH") != null; + private static boolean FALSE = + TestStaticResourceReference.class.getClassLoader().getResource("BLAH") != null; + @Override public Object call() { return "found the impossible: " + FALSE; } - } diff --git a/src/test/java/hudson/remoting/TrafficAnalyzer.java b/src/test/java/hudson/remoting/TrafficAnalyzer.java index e260d1acb..a9a0d3389 100644 --- a/src/test/java/hudson/remoting/TrafficAnalyzer.java +++ b/src/test/java/hudson/remoting/TrafficAnalyzer.java @@ -18,26 +18,30 @@ public class TrafficAnalyzer { public static void main(String[] args) throws Exception { File f = new File("/home/kohsuke/ws/hudson/investigations/javafx-windows-hang/out.log"); try (DataInputStream fin = new DataInputStream(new FileInputStream(f))) { - fin.readFully(new byte[4]); // skip preamble - try (ObjectInputStream ois = new ObjectInputStream(fin)) { - for (int n=0; ; n++) { - Command o = (Command)ois.readObject(); - System.out.println("#"+n+" : "+o); - if (o instanceof RemoteInvocationHandler.RPCRequest) { - RemoteInvocationHandler.RPCRequest request = (RemoteInvocationHandler.RPCRequest) o; - System.out.print(" ("); - boolean first=true; - for (Object argument : request.getArguments()) { - if(first) first=false; - else System.out.print(","); - System.out.print(argument); + fin.readFully(new byte[4]); // skip preamble + try (ObjectInputStream ois = new ObjectInputStream(fin)) { + for (int n = 0; ; n++) { + Command o = (Command) ois.readObject(); + System.out.println("#" + n + " : " + o); + if (o instanceof RemoteInvocationHandler.RPCRequest) { + RemoteInvocationHandler.RPCRequest request = (RemoteInvocationHandler.RPCRequest) o; + System.out.print(" ("); + boolean first = true; + for (Object argument : request.getArguments()) { + if (first) { + first = false; + } else { + System.out.print(","); + } + System.out.print(argument); + } + System.out.println(")"); + } + if (o.createdAt != null) { + o.createdAt.printStackTrace(System.out); } - System.out.println(")"); } - if (o.createdAt!=null) - o.createdAt.printStackTrace(System.out); } } } - } } diff --git a/src/test/java/hudson/remoting/URLDeserializatinHelperTest.java b/src/test/java/hudson/remoting/URLDeserializatinHelperTest.java index 17cec2ed3..1a03e6ba8 100644 --- a/src/test/java/hudson/remoting/URLDeserializatinHelperTest.java +++ b/src/test/java/hudson/remoting/URLDeserializatinHelperTest.java @@ -5,11 +5,9 @@ import java.net.URL; import org.junit.Test; -public class URLDeserializatinHelperTest -{ +public class URLDeserializatinHelperTest { @Test - public void openURLWithProxy() throws IOException - { + public void openURLWithProxy() throws IOException { URL original = new URL("https://localhost"); URL url = URLDeserializationHelper.wrapIfRequired(original); url.openConnection(Proxy.NO_PROXY); diff --git a/src/test/java/hudson/remoting/pipe/RandomWorkload.java b/src/test/java/hudson/remoting/pipe/RandomWorkload.java index a48ed0989..357a3ae24 100644 --- a/src/test/java/hudson/remoting/pipe/RandomWorkload.java +++ b/src/test/java/hudson/remoting/pipe/RandomWorkload.java @@ -28,16 +28,17 @@ public void write(OutputStream o) throws IOException { Random data = new Random(0); Random boundary = new Random(1); - for (long l=0; l f = ch.callAsync(new DigestCallable(p)); System.out.println("Started"); long start = System.nanoTime(); - IOUtils.copy(new ByteArrayInputStream(payload),p.getOut()); + IOUtils.copy(new ByteArrayInputStream(payload), p.getOut()); p.getOut().close(); f.get(); - System.out.println("Done: "+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-start)); + System.out.println("Done: " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)); assertArrayEquals(digest, f.get()); // verify the correctness of the result @@ -58,13 +59,14 @@ public static void main(String[] args) throws Exception { } private static byte[] digest(InputStream in) throws NoSuchAlgorithmException, IOException { - DigestOutputStream dos = new DigestOutputStream(OutputStream.nullOutputStream(), MessageDigest.getInstance("MD5")); + DigestOutputStream dos = + new DigestOutputStream(OutputStream.nullOutputStream(), MessageDigest.getInstance("MD5")); IOUtils.copy(in, dos); return dos.getMessageDigest().digest(); } private static byte[] getRandomSequence() { - byte[] buf = new byte[10*1024*1024]; + byte[] buf = new byte[10 * 1024 * 1024]; new Random(0).nextBytes(buf); return buf; } diff --git a/src/test/java/hudson/remoting/util/GCTask.java b/src/test/java/hudson/remoting/util/GCTask.java index 6a884f76c..07f6a7730 100644 --- a/src/test/java/hudson/remoting/util/GCTask.java +++ b/src/test/java/hudson/remoting/util/GCTask.java @@ -23,7 +23,7 @@ public GCTask(boolean agressive) { public Object call() throws IOException { if (agressive) { Set objects = new HashSet<>(); - int size = ((int)Math.min(Runtime.getRuntime().freeMemory(), Integer.MAX_VALUE)) / 32; + int size = ((int) Math.min(Runtime.getRuntime().freeMemory(), Integer.MAX_VALUE)) / 32; while (true) { try { objects.add(new Object[size]); diff --git a/src/test/java/org/jenkinsci/remoting/engine/HandlerLoopbackLoadStress.java b/src/test/java/org/jenkinsci/remoting/engine/HandlerLoopbackLoadStress.java index 82f7bf5c0..fda043049 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/HandlerLoopbackLoadStress.java +++ b/src/test/java/org/jenkinsci/remoting/engine/HandlerLoopbackLoadStress.java @@ -140,7 +140,7 @@ public class HandlerLoopbackLoadStress { public HandlerLoopbackLoadStress(Config config) throws IOException, NoSuchAlgorithmException, CertificateException, KeyStoreException, - UnrecoverableKeyException, KeyManagementException, OperatorCreationException { + UnrecoverableKeyException, KeyManagementException, OperatorCreationException { this.config = config; KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); gen.initialize(2048); // maximum supported by JVM with export restrictions @@ -160,20 +160,12 @@ public HandlerLoopbackLoadStress(Config config) .build(); X509v3CertificateBuilder certGen = new X509v3CertificateBuilder( - subject, - BigInteger.ONE, - firstDate, - lastDate, - subject, - subjectPublicKeyInfo - ); + subject, BigInteger.ONE, firstDate, lastDate, subject, subjectPublicKeyInfo); JcaX509ExtensionUtils instance = new JcaX509ExtensionUtils(); - certGen.addExtension(Extension.subjectKeyIdentifier, - false, - instance.createSubjectKeyIdentifier(subjectPublicKeyInfo) - ); + certGen.addExtension( + Extension.subjectKeyIdentifier, false, instance.createSubjectKeyIdentifier(subjectPublicKeyInfo)); ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA") .setProvider(BOUNCY_CASTLE_PROVIDER) @@ -187,14 +179,13 @@ public HandlerLoopbackLoadStress(Config config) KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); store.load(null, password); - store.setKeyEntry("alias", keyPair.getPrivate(), password, new Certificate[]{certificate}); + store.setKeyEntry("alias", keyPair.getPrivate(), password, new Certificate[] {certificate}); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(store, password); SSLContext context = SSLContext.getInstance("TLS"); - context.init(kmf.getKeyManagers(), - new TrustManager[]{new BlindTrustX509ExtendedTrustManager()}, null); + context.init(kmf.getKeyManagers(), new TrustManager[] {new BlindTrustX509ExtendedTrustManager()}, null); mainHub = IOHub.create(executorService); // on windows there is a bug whereby you cannot mix ServerSockets and Sockets on the same selector @@ -299,10 +290,15 @@ public static void main(String[] args) throws Exception { p.printUsage(System.err); System.exit(0); } - System.out.printf("Starting stress test of %s with %d clients making calls (payload %d bytes) every %dms " + System.out.printf( + "Starting stress test of %s with %d clients making calls (payload %d bytes) every %dms " + "(%.1f/sec) to give a total expected rate of %.1f/sec%n", - config.name, config.numClients, config.payload, config.clientIntervalMs, - 1000.0 / config.clientIntervalMs, 1000.0 / config.clientIntervalMs * config.numClients); + config.name, + config.numClients, + config.payload, + config.clientIntervalMs, + 1000.0 / config.clientIntervalMs, + 1000.0 / config.clientIntervalMs * config.numClients); System.out.println(!config.bio ? "Preferring NIO" : "Prefering BIO"); final HandlerLoopbackLoadStress stress = new HandlerLoopbackLoadStress(config); stress.mainHub.execute(stress.stats); @@ -325,18 +321,16 @@ public static void main(String[] args) throws Exception { System.out.println("Starting client " + i); } final int clientNumber = i; - clients.add( - stress.executorService.submit(() -> { + clients.add(stress.executorService.submit(() -> { try { - stress.startClient(clientNumber, serverAddress, config.clientIntervalMs, - config.payload); + stress.startClient(clientNumber, serverAddress, config.clientIntervalMs, config.payload); } finally { started.countDown(); } return null; })); } - for (Future future: clients) { + for (Future future : clients) { future.get(60, TimeUnit.SECONDS); } started.await(60, TimeUnit.SECONDS); @@ -389,7 +383,7 @@ private SocketAddress startServer(String listen) private Long getProcessCpuTime() { Object r = null; if (operatingSystemMXBean instanceof com.sun.management.OperatingSystemMXBean) { - r = ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getProcessCpuTime(); + r = ((com.sun.management.OperatingSystemMXBean) operatingSystemMXBean).getProcessCpuTime(); } else if (_getProcessCpuTime != null) { // Then we try reflection, if the method was located try { @@ -416,52 +410,58 @@ private void startClient(int n, SocketAddress serverAddress, final int clientInt String clientName = runtimeMXBean.getName() + "-client-" + n; headers.put(JnlpConnectionState.CLIENT_NAME_KEY, clientName); headers.put(JnlpConnectionState.SECRET_KEY, secretFor(clientName)); - final Channel clientChannel = handler.connect(toServer.socket(), headers, clientListener) - .get(15, TimeUnit.SECONDS); - timer[n % timer.length].scheduleAtFixedRate(new TimerTask() { - long start = System.currentTimeMillis(); - int index = 0; - int times = 0; - private NoOpCallable callable = new NoOpCallable(payloadSize == -1 ? null : new byte[payloadSize]); - - @Override - public void run() { - try { + final Channel clientChannel = + handler.connect(toServer.socket(), headers, clientListener).get(15, TimeUnit.SECONDS); + timer[n % timer.length].scheduleAtFixedRate( + new TimerTask() { long start = System.currentTimeMillis(); - clientChannel.call(callable); - if (config.client != null) { - NoOpCallable.noops.incrementAndGet(); - } - times++; - if (times % 1000 == 0) { - System.out.printf(" %s has run %d No-op callables. Rate %.1f/s expect %.1f/s%n", - clientChannel.getName(), times, - times * 1000.0 / (System.currentTimeMillis() - this.start), 1000.0 / clientIntervalMs); - } - long duration = System.currentTimeMillis() - start; - if (duration > 250L) { - System.err.printf(" %s took %dms to complete a callable%n", clientChannel.getName(), - duration); - } - if (callable.payload != null && callable.payload.length > 0) { - // mutate the payload to prevent compression - int count = callable.payload.length; - if (count > 100) { - count = 100; - } - for (int j = 0; j < count; j++) { - callable.payload[index] = (byte) (callable.payload[index] * 31 + times); - index = Math.abs(index + 1) % callable.payload.length; + int index = 0; + int times = 0; + private NoOpCallable callable = new NoOpCallable(payloadSize == -1 ? null : new byte[payloadSize]); + + @Override + public void run() { + try { + long start = System.currentTimeMillis(); + clientChannel.call(callable); + if (config.client != null) { + NoOpCallable.noops.incrementAndGet(); + } + times++; + if (times % 1000 == 0) { + System.out.printf( + " %s has run %d No-op callables. Rate %.1f/s expect %.1f/s%n", + clientChannel.getName(), + times, + times * 1000.0 / (System.currentTimeMillis() - this.start), + 1000.0 / clientIntervalMs); + } + long duration = System.currentTimeMillis() - start; + if (duration > 250L) { + System.err.printf( + " %s took %dms to complete a callable%n", clientChannel.getName(), duration); + } + if (callable.payload != null && callable.payload.length > 0) { + // mutate the payload to prevent compression + int count = callable.payload.length; + if (count > 100) { + count = 100; + } + for (int j = 0; j < count; j++) { + callable.payload[index] = (byte) (callable.payload[index] * 31 + times); + index = Math.abs(index + 1) % callable.payload.length; + } + } + } catch (Exception e) { + e.printStackTrace(System.err); + IOUtils.closeQuietly(clientChannel); + cancel(); + System.exit(2); } } - } catch (Exception e) { - e.printStackTrace(System.err); - IOUtils.closeQuietly(clientChannel); - cancel(); - System.exit(2); - } - } - }, entropy.nextInt(clientIntervalMs), clientIntervalMs); + }, + entropy.nextInt(clientIntervalMs), + clientIntervalMs); } public static class Config { @@ -471,7 +471,8 @@ public static class Config { @Option(name = "--clients", metaVar = "CLIENTS", usage = "The number of clients to simulate") public int numClients = 100; - @Option(name = "--interval", + @Option( + name = "--interval", metaVar = "MILLISECONDS", usage = "The number of milliseconds each client waits before sending a command") public int clientIntervalMs = 100; @@ -479,12 +480,14 @@ public static class Config { @Option(name = "--size", metaVar = "BYTES", usage = "The number of bytes to pad the command with") public int payload = -1; - @Option(name = "--warmup", + @Option( + name = "--warmup", metaVar = "SECONDS", usage = "The number of seconds after all connections are established to warm up before resetting stats") public int warmup = -1; - @Option(name = "--collect", + @Option( + name = "--collect", metaVar = "SECONDS", usage = "The number of seconds after all connections are established to collect stats for before " + "stopping") @@ -502,16 +505,21 @@ public static class Config { @Option(name = "--server", usage = "Specify to run as a server only") public boolean server; - @Option(name = "--client", + @Option( + name = "--client", metaVar = "HOST:PORT", usage = "Specify to run as a client only and connect to a server on the specified HOST:PORT") public String client; - @Option(name="--connect", metaVar = "MILLIS", + @Option( + name = "--connect", + metaVar = "MILLIS", usage = "The number of milliseconds to wait between client starts") public int connectDelay = -1; - @Option(name = "--help", aliases = {"-h", "-?"}) + @Option( + name = "--help", + aliases = {"-h", "-?"}) public boolean help; } @@ -536,7 +544,8 @@ public void beforeChannel(@NonNull JnlpConnectionState event) { public void afterChannel(@NonNull JnlpConnectionState event) { String clientName = event.getProperty(JnlpConnectionState.CLIENT_NAME_KEY); if (clientName != null) { - System.out.println("Accepted connection from client " + clientName + " on " + event.getRemoteEndpointDescription()); + System.out.println("Accepted connection from client " + clientName + " on " + + event.getRemoteEndpointDescription()); } } } @@ -558,9 +567,8 @@ public Void call() throws IOException { } @Override - public void checkRoles(RoleChecker checker) throws SecurityException { + public void checkRoles(RoleChecker checker) throws SecurityException {} - } private static final long serialVersionUID = 1L; } @@ -578,14 +586,22 @@ public synchronized void clearStats() { memoryA = Runtime.getRuntime().totalMemory(); memoryS = 0; memoryCount = 1; - System.out.printf("%n%-7s %-29s %-20s %8s %14s%n", - "", " Calls rate", "JVM CPU utilization", "", ""); - System.out.printf("%-7s %9s %9s %9s %6s %6s %6s %8s %14s%n", - "Time", "cur", "all", "expect", "cur", "all", - "expect", "Sys load", "Average Memory"); - System.out.printf("%7s %9s %9s %9s %6s %6s %6s %8s %14s%n", - "=======", "=========", "=========", "=========", "======", "======", - "======", "========", "=============="); + System.out.printf( + "%n%-7s %-29s %-20s %8s %14s%n", "", " Calls rate", "JVM CPU utilization", "", ""); + System.out.printf( + "%-7s %9s %9s %9s %6s %6s %6s %8s %14s%n", + "Time", "cur", "all", "expect", "cur", "all", "expect", "Sys load", "Average Memory"); + System.out.printf( + "%7s %9s %9s %9s %6s %6s %6s %8s %14s%n", + "=======", + "=========", + "=========", + "=========", + "======", + "======", + "======", + "========", + "=============="); } private synchronized void clientsStarted() { @@ -625,7 +641,8 @@ public void run() { double noopsPerSecond = current.noopsPerSecond(last); double vmLoad0 = current.vmLoad(start); double vmLoad = current.vmLoad(last); - System.out.printf("%-4.1fmin %7.1f/s %7.1f/s %7.1f/s %6.2f %6.2f %6.2f %8.2f %7.1fkB ± %.1f %ddf %s%n", + System.out.printf( + "%-4.1fmin %7.1f/s %7.1f/s %7.1f/s %6.2f %6.2f %6.2f %8.2f %7.1fkB ± %.1f %ddf %s%n", (current.uptime - start.uptime) / 60000.0, noopsPerSecond, noopsPerSecond0, @@ -637,16 +654,18 @@ public void run() { memoryCount > 0 ? memoryA / 1024 : Double.NaN, memoryCount > 1 ? Math.sqrt(memoryS / (memoryCount - 1)) / 1024 : Double.NaN, memoryCount, - current.gcSummary(start) - ); + current.gcSummary(start)); System.out.flush(); last = current; - if (started && !warmed && (config.warmup <= 0 - || current.uptime - start.uptime > config.warmup * 1000L)) { + if (started + && !warmed + && (config.warmup <= 0 || current.uptime - start.uptime > config.warmup * 1000L)) { System.out.println("Warmup completed"); clearStats(); warmed = true; - } else if (started && warmed && config.collect > 0 + } else if (started + && warmed + && config.collect > 0 && current.uptime - start.uptime > config.collect * 1000L) { if (config.file != null) { try { @@ -663,7 +682,8 @@ public void run() { pw = new PrintWriter(new FileWriter(f, true)); } try { - pw.printf("\"%s\",\"%s\",%d,%d,%d,%.1f,%.1f,%.2f,%.2f,%d,%.2f,%.2f,%d,%.2f,%s%n", + pw.printf( + "\"%s\",\"%s\",%d,%d,%d,%.1f,%.1f,%.2f,%.2f,%d,%.2f,%.2f,%d,%.2f,%s%n", config.name, config.bio ? "blocking" : "non-blocking", config.numClients, @@ -678,8 +698,7 @@ public void run() { memoryCount > 1 ? Math.sqrt(memoryS / (memoryCount - 1)) / 1024 : Double.NaN, memoryCount, Runtime.getRuntime().maxMemory() / 1024.0, - current.gcData(start) - ); + current.gcData(start)); } finally { pw.close(); } @@ -707,13 +726,11 @@ public void run() { memoryCount > 1 ? Math.sqrt(memoryS / (memoryCount - 1)) / 1024 : Double.NaN, memoryCount, Runtime.getRuntime().maxMemory() / 1024.0, - current.gcData(start) - ); + current.gcData(start)); System.exit(0); } } } - } private static class GCStats { @@ -731,7 +748,7 @@ private class Metrics { private long noops; private long uptime; private @CheckForNull Long cpu; - private Map gc; + private Map gc; public Metrics() { time = System.currentTimeMillis(); @@ -739,7 +756,7 @@ public Metrics() { uptime = runtimeMXBean.getUptime(); cpu = getProcessCpuTime(); gc = new TreeMap<>(); - for (GarbageCollectorMXBean bean: garbageCollectorMXBeans) { + for (GarbageCollectorMXBean bean : garbageCollectorMXBeans) { this.gc.put(bean.getName(), new GCStats(bean)); } } @@ -780,7 +797,7 @@ public double vmLoad(Metrics reference) { public String gcData(Metrics reference) { StringBuilder result = new StringBuilder(); boolean first = true; - for (GarbageCollectorMXBean g: garbageCollectorMXBeans) { + for (GarbageCollectorMXBean g : garbageCollectorMXBeans) { String name = g.getName(); GCStats s = reference.gc.get(name); GCStats x = gc.get(name); @@ -792,8 +809,8 @@ public String gcData(Metrics reference) { result.append("\"").append(name).append("\","); if (x == null) { result.append(0).append(',').append(0.0); - } else if (s == null) { - result.append(x.count).append(',').append(x.time/1000.0); + } else if (s == null) { + result.append(x.count).append(',').append(x.time / 1000.0); } else { result.append(x.count - s.count).append(',').append((x.time - s.time) / 1000.0); } @@ -805,7 +822,9 @@ public String gcTitles() { StringBuilder result = new StringBuilder(); int i = 0; for (GarbageCollectorMXBean g : garbageCollectorMXBeans) { - if (i > 0) result.append(","); + if (i > 0) { + result.append(","); + } result.append("\"gc[").append(i).append("].name\","); result.append("\"gc[").append(i).append("].count\","); result.append("\"gc[").append(i).append("].time\""); @@ -902,9 +921,6 @@ public void onRegistered(SelectionKey selectionKey) { } @Override - public void onClosedChannel(ClosedChannelException e) { - - } + public void onClosedChannel(ClosedChannelException e) {} } - } diff --git a/src/test/java/org/jenkinsci/remoting/engine/HostPortTest.java b/src/test/java/org/jenkinsci/remoting/engine/HostPortTest.java index f8ef7b8cd..df5a389af 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/HostPortTest.java +++ b/src/test/java/org/jenkinsci/remoting/engine/HostPortTest.java @@ -101,7 +101,7 @@ public void testEmptyPort() { public void testSeparatorNoPort() { HostPort hostPort = new HostPort("hostname:", null, 7777); assertThat(hostPort.getHost(), is("hostname")); - assertThat(hostPort.getPort(), is( 7777)); + assertThat(hostPort.getPort(), is(7777)); } @Test(expected = IllegalArgumentException.class) @@ -118,12 +118,11 @@ public void testPortTooHigh() { public void testOnlySeparator() { HostPort hostPort = new HostPort(":", "hostname", 7777); assertThat(hostPort.getHost(), is("hostname")); - assertThat(hostPort.getPort(), is( 7777)); + assertThat(hostPort.getPort(), is(7777)); } @Test(expected = NumberFormatException.class) public void testPortNotANumber() { new HostPort("hostname:notAPort"); } - } diff --git a/src/test/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerTest.java b/src/test/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerTest.java index a2fa47180..014e2fe50 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerTest.java +++ b/src/test/java/org/jenkinsci/remoting/engine/JnlpProtocolHandlerTest.java @@ -49,9 +49,9 @@ public class JnlpProtocolHandlerTest { private static final Consumer APPROVING_STATE_CONSUMER = JnlpConnectionState::approve; - private static final Consumer REJECTING_STATE_CONSUMER = (event) -> event.reject(new ConnectionRefusalException("I don't like you")); - private static final Consumer IGNORING_STATE_CONSUMER = (event) -> { - }; + private static final Consumer REJECTING_STATE_CONSUMER = + event -> event.reject(new ConnectionRefusalException("I don't like you")); + private static final Consumer IGNORING_STATE_CONSUMER = event -> {}; private static final String SECRET_KEY = "SecretKey-1234"; private static ExecutorService executorService; @@ -62,40 +62,35 @@ public class JnlpProtocolHandlerTest { private static RSAKeyPairRule serverKey = new RSAKeyPairRule(); private static RSAKeyPairRule caRootKey = new RSAKeyPairRule(); private static X509CertificateRule caRootCert = X509CertificateRule.create("caRoot", caRootKey, caRootKey, null); - private static X509CertificateRule clientCert = X509CertificateRule.create("client", clientKey, caRootKey, caRootCert); - private static X509CertificateRule serverCert = X509CertificateRule.create("server", serverKey, caRootKey, caRootCert); + private static X509CertificateRule clientCert = + X509CertificateRule.create("client", clientKey, caRootKey, caRootCert); + private static X509CertificateRule serverCert = + X509CertificateRule.create("server", serverKey, caRootKey, caRootCert); private static X509CertificateRule expiredClientCert = X509CertificateRule.create("expiredClient", clientKey, caRootKey, caRootCert, -10, -5, TimeUnit.DAYS); private static X509CertificateRule notYetValidServerCert = X509CertificateRule.create("notYetValidServer", serverKey, caRootKey, caRootCert, +5, +10, TimeUnit.DAYS); - private static SSLContextRule clientCtx = - new SSLContextRule("client") - .as(clientKey, clientCert, caRootCert) - .trusting(caRootCert) - .trusting(serverCert); - private static SSLContextRule serverCtx = - new SSLContextRule("server") - .as(serverKey, serverCert, caRootCert) - .trusting(caRootCert) - .trusting(clientCert); - private static SSLContextRule expiredClientCtx = - new SSLContextRule("expiredClient") - .as(clientKey, expiredClientCert, caRootCert) - .trusting(caRootCert) - .trusting(serverCert); - private static SSLContextRule notYetValidServerCtx = - new SSLContextRule("notYetValidServer") - .as(serverKey, notYetValidServerCert, caRootCert) - .trusting(caRootCert) - .trusting(clientCert); + private static SSLContextRule clientCtx = new SSLContextRule("client") + .as(clientKey, clientCert, caRootCert) + .trusting(caRootCert) + .trusting(serverCert); + private static SSLContextRule serverCtx = new SSLContextRule("server") + .as(serverKey, serverCert, caRootCert) + .trusting(caRootCert) + .trusting(clientCert); + private static SSLContextRule expiredClientCtx = new SSLContextRule("expiredClient") + .as(clientKey, expiredClientCert, caRootCert) + .trusting(caRootCert) + .trusting(serverCert); + private static SSLContextRule notYetValidServerCtx = new SSLContextRule("notYetValidServer") + .as(serverKey, notYetValidServerCert, caRootCert) + .trusting(caRootCert) + .trusting(clientCert); private static SSLContextRule untrustingClientCtx = - new SSLContextRule("untrustingClient") - .as(clientKey, clientCert) - .trusting(caRootCert); + new SSLContextRule("untrustingClient").as(clientKey, clientCert).trusting(caRootCert); private static SSLContextRule untrustingServerCtx = - new SSLContextRule("untrustingServer") - .as(serverKey, serverCert) - .trusting(caRootCert); + new SSLContextRule("untrustingServer").as(serverKey, serverCert).trusting(caRootCert); + @ClassRule public static RuleChain staticCtx = RuleChain.outerRule(caRootKey) .around(clientKey) @@ -154,12 +149,16 @@ public void tearDown() { @Theory public void happyPath(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Throwable { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); serverRemotingChannel = serverChannelFuture.get(10, TimeUnit.SECONDS); assertThat(serverRemotingChannel, notNullValue()); serverRemotingChannel.call(new TestCallable()); @@ -169,81 +168,113 @@ public void happyPath(Factory factory, boolean useNioHubServer, boolean useNioHu @Theory public void serverRejects(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), REJECTING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), REJECTING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, ConnectionRefusalException.class); } @Theory public void serverIgnores(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, IGNORING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, IGNORING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, IOException.class); } @Theory public void clientRejects(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), REJECTING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), REJECTING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, IOException.class); } @Theory public void clientIgnores(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), IGNORING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), IGNORING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, ConnectionRefusalException.class); } @Theory public void doesNotExist(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, false); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, false); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, SECRET_KEY); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, ConnectionRefusalException.class); } @Theory public void wrongSecret(Factory factory, boolean useNioHubServer, boolean useNioHubClient) throws Exception { Logger.getLogger(JnlpProtocol4Handler.class.getName()).setLevel(Level.SEVERE); - JnlpProtocolHandler serverProtocolHandler = createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); - JnlpProtocolHandler clientProtocolHandler = createClientProtocolHandler(factory, useNioHubClient); + JnlpProtocolHandler serverProtocolHandler = + createServerProtocolHandler(factory, useNioHubServer, SECRET_KEY, true); + JnlpProtocolHandler clientProtocolHandler = + createClientProtocolHandler(factory, useNioHubClient); HashMap clientProps = createClientProperties(factory, "WrongSecret"); - Future clientChannelFuture = createChannelConnector(clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); + Future clientChannelFuture = createChannelConnector( + clientSocketChannel, clientProtocolHandler, clientProps, APPROVING_STATE_CONSUMER); readAndCheckProtocol(factory); - Future serverChannelFuture = createChannelHandler(serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); + Future serverChannelFuture = createChannelHandler( + serverSocketChannel, serverProtocolHandler, new HashMap<>(), APPROVING_STATE_CONSUMER); assertChannelFails(clientChannelFuture, serverChannelFuture, ConnectionRefusalException.class); } - private Future createChannelConnector(SocketChannel channel, JnlpProtocolHandler protocolHandler, - HashMap properties, - Consumer afterPropertiesConsumer) throws IOException { - return protocolHandler.connect(channel.socket(), properties, new StateListener(afterPropertiesConsumer, Channel.Mode.BINARY)); + private Future createChannelConnector( + SocketChannel channel, + JnlpProtocolHandler protocolHandler, + HashMap properties, + Consumer afterPropertiesConsumer) + throws IOException { + return protocolHandler.connect( + channel.socket(), properties, new StateListener(afterPropertiesConsumer, Channel.Mode.BINARY)); } - private Future createChannelHandler(SocketChannel channel, JnlpProtocolHandler protocolHandler, - HashMap properties, - Consumer afterPropertiesConsumer) throws IOException { - return protocolHandler.handle(channel.socket(), properties, new StateListener(afterPropertiesConsumer, Channel.Mode.NEGOTIATE)); + private Future createChannelHandler( + SocketChannel channel, + JnlpProtocolHandler protocolHandler, + HashMap properties, + Consumer afterPropertiesConsumer) + throws IOException { + return protocolHandler.handle( + channel.socket(), properties, new StateListener(afterPropertiesConsumer, Channel.Mode.NEGOTIATE)); } private HashMap createClientProperties(Factory factory, String secretKey) { @@ -253,25 +284,31 @@ private HashMap createClientProperties(Factory factory, String s return clientProps; } - private JnlpProtocolHandler createClientProtocolHandler(Factory factory, boolean useNioHubClient) { - return factory.create(null, executorService, selector, useNioHubClient ? hub : null, clientCtx.context(), useNioHubClient); + private JnlpProtocolHandler createClientProtocolHandler( + Factory factory, boolean useNioHubClient) { + return factory.create( + null, executorService, selector, useNioHubClient ? hub : null, clientCtx.context(), useNioHubClient); } - private JnlpProtocolHandler createServerProtocolHandler(Factory factory, - boolean useNioHubServer, - String secretKey, - boolean exists) { - return factory.create(new JnlpClientDatabase() { - @Override - public boolean exists(String clientName) { - return exists; - } + private JnlpProtocolHandler createServerProtocolHandler( + Factory factory, boolean useNioHubServer, String secretKey, boolean exists) { + return factory.create( + new JnlpClientDatabase() { + @Override + public boolean exists(String clientName) { + return exists; + } - @Override - public String getSecretOf(@NonNull String clientName) { - return secretKey; - } - }, executorService, selector, hub, serverCtx.context(), useNioHubServer); + @Override + public String getSecretOf(@NonNull String clientName) { + return secretKey; + } + }, + executorService, + selector, + hub, + serverCtx.context(), + useNioHubServer); } private void readAndCheckProtocol(Factory factory) throws IOException { @@ -287,9 +324,11 @@ private void readAndCheckProtocol(Factory factory) throws IOException { assertThat(new String(bytes, StandardCharsets.UTF_8), is("Protocol:" + factory.toString())); } - private void assertChannelFails(Future clientChannelFuture, - Future serverChannelFuture, - Class serverExceptionType) throws InterruptedException, TimeoutException { + private void assertChannelFails( + Future clientChannelFuture, + Future serverChannelFuture, + Class serverExceptionType) + throws InterruptedException, TimeoutException { try { serverRemotingChannel = serverChannelFuture.get(10, TimeUnit.SECONDS); fail(); @@ -306,28 +345,29 @@ private void assertChannelFails(Future clientChannelFuture, @DataPoints public static boolean[] useNioHub() { - return new boolean[]{true, false}; + return new boolean[] {true, false}; } @DataPoints public static Factory[] protocols() { - return new Factory[]{ - new Factory() { - @Override - public JnlpProtocolHandler create(JnlpClientDatabase db, - ExecutorService svc, - IOHub selector, NioChannelHub hub, - SSLContext ctx, - boolean preferNio) { - return new JnlpProtocol4Handler(db, svc, selector, ctx, false, preferNio); - - } + return new Factory[] { + new Factory() { + @Override + public JnlpProtocolHandler create( + JnlpClientDatabase db, + ExecutorService svc, + IOHub selector, + NioChannelHub hub, + SSLContext ctx, + boolean preferNio) { + return new JnlpProtocol4Handler(db, svc, selector, ctx, false, preferNio); + } - @Override - public String toString() { - return "JNLP4-connect"; - } + @Override + public String toString() { + return "JNLP4-connect"; } + } }; } @@ -351,14 +391,16 @@ public void beforeChannel(@NonNull JnlpConnectionState event) { } @Override - public void afterChannel(@NonNull JnlpConnectionState event) { - } + public void afterChannel(@NonNull JnlpConnectionState event) {} } public interface Factory { - JnlpProtocolHandler create(JnlpClientDatabase db, ExecutorService svc, - IOHub selector, NioChannelHub hub, SSLContext ctx, - boolean preferNio); + JnlpProtocolHandler create( + JnlpClientDatabase db, + ExecutorService svc, + IOHub selector, + NioChannelHub hub, + SSLContext ctx, + boolean preferNio); } - } diff --git a/src/test/java/org/jenkinsci/remoting/engine/PropertiesStringMatcher.java b/src/test/java/org/jenkinsci/remoting/engine/PropertiesStringMatcher.java index 8167bdf1e..f84040770 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/PropertiesStringMatcher.java +++ b/src/test/java/org/jenkinsci/remoting/engine/PropertiesStringMatcher.java @@ -35,8 +35,7 @@ public class PropertiesStringMatcher implements ArgumentMatcher { private String expected; public PropertiesStringMatcher(String expected) { - this.expected = expected.substring( - expected.indexOf(System.getProperty("line.separator"))); + this.expected = expected.substring(expected.indexOf(System.getProperty("line.separator"))); } @Override diff --git a/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerRule.java b/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerRule.java index 961180d12..7e3c0ee9e 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerRule.java +++ b/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerRule.java @@ -44,7 +44,7 @@ public Statement apply(Statement base, Description description) { instance = WorkDirManager.getInstance(); return super.apply(base, description); } - + @Override protected void after() { WorkDirManager.reset(); diff --git a/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerTest.java b/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerTest.java index c152cd85f..0796fa012 100644 --- a/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerTest.java +++ b/src/test/java/org/jenkinsci/remoting/engine/WorkDirManagerTest.java @@ -75,12 +75,20 @@ public void shouldInitializeCorrectlyForExistingDirectory() throws Exception { Files.writeString(probeFileInInternalDir, "Hello!", StandardCharsets.UTF_8); // Initialize and check the results - final Path createdDir = WorkDirManager.getInstance().initializeWorkDir(dir, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); - assertThat("The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", createdDir, equalTo(remotingDir)); + final Path createdDir = WorkDirManager.getInstance() + .initializeWorkDir(dir, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); + assertThat( + "The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", + createdDir, + equalTo(remotingDir)); // Ensure that the files have not been wiped - Assert.assertTrue("Probe file in the " + WorkDirManager.DirType.WORK_DIR + " has been wiped", Files.exists(probeFileInWorkDir)); - Assert.assertTrue("Probe file in the " + WorkDirManager.DirType.INTERNAL_DIR + " has been wiped", Files.exists(probeFileInInternalDir)); + Assert.assertTrue( + "Probe file in the " + WorkDirManager.DirType.WORK_DIR + " has been wiped", + Files.exists(probeFileInWorkDir)); + Assert.assertTrue( + "Probe file in the " + WorkDirManager.DirType.INTERNAL_DIR + " has been wiped", + Files.exists(probeFileInInternalDir)); // Ensure that sub directories are in place assertExists(WorkDirManager.DirType.JAR_CACHE_DIR); @@ -91,15 +99,22 @@ public void shouldInitializeCorrectlyForExistingDirectory() throws Exception { public void shouldPerformMkdirsIfRequired() throws Exception { final File tmpDirFile = tmpDir.newFolder("foo"); final File workDir = new File(tmpDirFile, "just/a/long/non/existent/path"); - Assert.assertFalse("The " + WorkDirManager.DirType.INTERNAL_DIR + " should not exist in the test", workDir.exists()); + Assert.assertFalse( + "The " + WorkDirManager.DirType.INTERNAL_DIR + " should not exist in the test", workDir.exists()); // Probe files to confirm the directory does not get wiped; final File remotingDir = new File(workDir, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation()); // Initialize and check the results - final Path createdDir = WorkDirManager.getInstance().initializeWorkDir(workDir, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); - assertThat("The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", createdDir.toFile(), equalTo(remotingDir)); - Assert.assertTrue("Remoting " + WorkDirManager.DirType.INTERNAL_DIR + " should have been initialized", remotingDir.exists()); + final Path createdDir = WorkDirManager.getInstance() + .initializeWorkDir(workDir, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); + assertThat( + "The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", + createdDir.toFile(), + equalTo(remotingDir)); + Assert.assertTrue( + "Remoting " + WorkDirManager.DirType.INTERNAL_DIR + " should have been initialized", + remotingDir.exists()); } @Test @@ -107,28 +122,39 @@ public void shouldProperlyCreateDirectoriesForCustomInternalDirs() throws Except final String internalDirectoryName = "myRemotingLogs"; final File tmpDirFile = tmpDir.newFolder("foo"); final File workDir = new File(tmpDirFile, "just/another/path"); - Assert.assertFalse("The " + WorkDirManager.DirType.WORK_DIR + " should not exist in the test", workDir.exists()); + Assert.assertFalse( + "The " + WorkDirManager.DirType.WORK_DIR + " should not exist in the test", workDir.exists()); // Probe files to confirm the directory does not get wiped; final File remotingDir = new File(workDir, internalDirectoryName); // Initialize and check the results final Path createdDir = WorkDirManager.getInstance().initializeWorkDir(workDir, internalDirectoryName, false); - assertThat("The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", createdDir.toFile(), equalTo(remotingDir)); - Assert.assertTrue("Remoting " + WorkDirManager.DirType.INTERNAL_DIR + " should have been initialized", remotingDir.exists()); + assertThat( + "The initialized " + WorkDirManager.DirType.INTERNAL_DIR + " differs from the expected one", + createdDir.toFile(), + equalTo(remotingDir)); + Assert.assertTrue( + "Remoting " + WorkDirManager.DirType.INTERNAL_DIR + " should have been initialized", + remotingDir.exists()); } @Test public void shouldFailIfWorkDirIsAFile() throws IOException { File foo = tmpDir.newFile("foo"); try { - WorkDirManager.getInstance().initializeWorkDir(foo, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); + WorkDirManager.getInstance() + .initializeWorkDir(foo, WorkDirManager.DirType.INTERNAL_DIR.getDefaultLocation(), false); } catch (IOException ex) { - assertThat("Wrong exception message", - ex.getMessage(), containsString("The specified " + WorkDirManager.DirType.WORK_DIR + " path points to a non-directory file")); + assertThat( + "Wrong exception message", + ex.getMessage(), + containsString("The specified " + WorkDirManager.DirType.WORK_DIR + + " path points to a non-directory file")); return; } - Assert.fail("The " + WorkDirManager.DirType.WORK_DIR + " has been initialized, but it should fail due to the conflicting file"); + Assert.fail("The " + WorkDirManager.DirType.WORK_DIR + + " has been initialized, but it should fail due to the conflicting file"); } @Test @@ -141,7 +167,6 @@ public void shouldFailIfWorkDirIsNotWritable() throws IOException { verifyDirectoryFlag(WorkDirManager.DirType.WORK_DIR, DirectoryFlag.NOT_WRITABLE); } - @Test public void shouldFailIfWorkDirIsNotReadable() throws IOException { verifyDirectoryFlag(WorkDirManager.DirType.WORK_DIR, DirectoryFlag.NOT_READABLE); @@ -157,7 +182,6 @@ public void shouldFailIfInternalDirIsNotWritable() throws IOException { verifyDirectoryFlag(WorkDirManager.DirType.INTERNAL_DIR, DirectoryFlag.NOT_WRITABLE); } - @Test public void shouldFailIfInternalDirIsNotReadable() throws IOException { verifyDirectoryFlag(WorkDirManager.DirType.INTERNAL_DIR, DirectoryFlag.NOT_READABLE); @@ -180,7 +204,8 @@ public void shouldNotSupportPathDelimitersAndSpacesInTheInternalDirName() throws public void shouldFailToStartupIf_WorkDir_IsMissing_andRequired() throws Exception { final File tmpDirFile = tmpDir.newFolder("foo"); final File workDir = new File(tmpDirFile, "just/a/long/non/existent/path"); - Assert.assertFalse("The " + WorkDirManager.DirType.INTERNAL_DIR + " should not exist in the test", workDir.exists()); + Assert.assertFalse( + "The " + WorkDirManager.DirType.INTERNAL_DIR + " should not exist in the test", workDir.exists()); assertAllocationFailsForMissingDir(workDir, WorkDirManager.DirType.WORK_DIR); } @@ -238,7 +263,8 @@ public void shouldUseLoggingSettingsFromFileDefinedByAPI() throws Exception { @Test public void shouldUseLoggingSettingsFromFileDefinedBySystemProperty() throws Exception { final File loggingConfigFile = new File(tmpDir.getRoot(), "julSettings.prop"); - final String oldValue = System.setProperty(WorkDirManager.JUL_CONFIG_FILE_SYSTEM_PROPERTY_NAME, loggingConfigFile.getAbsolutePath()); + final String oldValue = System.setProperty( + WorkDirManager.JUL_CONFIG_FILE_SYSTEM_PROPERTY_NAME, loggingConfigFile.getAbsolutePath()); try { doTestLoggingConfig(loggingConfigFile, false); } finally { @@ -247,13 +273,15 @@ public void shouldUseLoggingSettingsFromFileDefinedBySystemProperty() throws Exc } } - private void doTestLoggingConfig(File loggingConfigFile, boolean passToManager) throws IOException, AssertionError{ + private void doTestLoggingConfig(File loggingConfigFile, boolean passToManager) throws IOException, AssertionError { final File workDir = tmpDir.newFolder("workDir"); final File customLogDir = tmpDir.newFolder("mylogs"); Properties p = new Properties(); p.setProperty("handlers", "java.util.logging.FileHandler"); - p.setProperty("java.util.logging.FileHandler.pattern", customLogDir.getAbsolutePath() + File.separator + "mylog.log.%g"); + p.setProperty( + "java.util.logging.FileHandler.pattern", + customLogDir.getAbsolutePath() + File.separator + "mylog.log.%g"); p.setProperty("java.util.logging.FileHandler.limit", "81920"); p.setProperty("java.util.logging.FileHandler.count", "5"); @@ -277,7 +305,8 @@ private void doTestLoggingConfig(File loggingConfigFile, boolean passToManager) // Assert that logs directory still exists, but has no default logs assertExists(WorkDirManager.DirType.LOGS_DIR); File defaultLog0 = new File(mngr.getLocation(WorkDirManager.DirType.LOGS_DIR), "remoting.log.0"); - Assert.assertFalse("Log settings have been passed from the config file, the default log should not exist: " + defaultLog0, + Assert.assertFalse( + "Log settings have been passed from the config file, the default log should not exist: " + defaultLog0, defaultLog0.exists()); // Assert that logs have been written to the specified custom destination @@ -288,7 +317,7 @@ private void doTestLoggingConfig(File loggingConfigFile, boolean passToManager) } private void assertFileLogsExist(File logsDir, String prefix, int logFilesNumber) { - for (int i=0; i if ProxyOutputStream can't write, set the bytes aside and don't look for OP_READ - in corresponding reader. - -> when window size becomes available, notify and act + InputStream needs to be SelectableChannel or FileInputStream on Linux. + Now OutputStream, this is a bigger problem! + - SelectableChannel, such as another FileOutputStream or Socket is fine + - ProxyOutputStream, to send bits remotely. But this involves window support. + -> if ProxyOutputStream can't write, set the bytes aside and don't look for OP_READ + in corresponding reader. + -> when window size becomes available, notify and act - -> but ProxyOutputStream is still a blocking write. + -> but ProxyOutputStream is still a blocking write. - Pumping executors forking builds aren't too interesting. But ChannelReaderThread can - benefit from this. + Pumping executors forking builds aren't too interesting. But ChannelReaderThread can + benefit from this. - Need an additional framing mechanism + Need an additional framing mechanism - */ + */ public static void main(String[] args) throws Exception { testProcessSelection(); @@ -62,8 +62,8 @@ private static void testProcessSelection() throws Exception { while (true) { sel.select(); for (SelectionKey sk : sel.selectedKeys()) { - System.out.println("==== "+sk.attachment()); - SocketChannel c = (SocketChannel)sk.channel(); + System.out.println("==== " + sk.attachment()); + SocketChannel c = (SocketChannel) sk.channel(); ByteBuffer buf = ByteBuffer.allocate(1024); c.read(buf); @@ -78,13 +78,13 @@ private static FileInputStream unwrap(InputStream i) throws Exception { if (i instanceof FilterInputStream) { Field $in = FilterInputStream.class.getDeclaredField("in"); $in.setAccessible(true); - i = (InputStream)$in.get(i); + i = (InputStream) $in.get(i); continue; } if (i instanceof FileInputStream) { return (FileInputStream) i; } - return null; // unknown type + return null; // unknown type } } diff --git a/src/test/java/org/jenkinsci/remoting/nio/SocketClientMain.java b/src/test/java/org/jenkinsci/remoting/nio/SocketClientMain.java index 2a55b033a..af007620f 100644 --- a/src/test/java/org/jenkinsci/remoting/nio/SocketClientMain.java +++ b/src/test/java/org/jenkinsci/remoting/nio/SocketClientMain.java @@ -14,7 +14,7 @@ public class SocketClientMain { public static void main(String[] args) throws Exception { final ExecutorService es = Executors.newCachedThreadPool(); - Socket s = new Socket("localhost",9953); + Socket s = new Socket("localhost", 9953); LOGGER.info("Cnonected"); Channel ch = new ChannelBuilder("client", es) .withHeaderStream(new FlushEveryByteStream(System.out)) @@ -22,7 +22,7 @@ public static void main(String[] args) throws Exception { .build(s); LOGGER.info("Established."); - LOGGER.info("Got "+echo(ch,"Hello!")); + LOGGER.info("Got " + echo(ch, "Hello!")); ch.close(); ch.join(); @@ -47,6 +47,7 @@ public String call() throws Exception { LOGGER.info("Echoing back " + arg); return arg; } + private static final long serialVersionUID = 1L; } } diff --git a/src/test/java/org/jenkinsci/remoting/nio/SocketServerMain.java b/src/test/java/org/jenkinsci/remoting/nio/SocketServerMain.java index 922d74a98..993d67221 100644 --- a/src/test/java/org/jenkinsci/remoting/nio/SocketServerMain.java +++ b/src/test/java/org/jenkinsci/remoting/nio/SocketServerMain.java @@ -44,7 +44,7 @@ protected void onSelected(SelectionKey key) { } }); } catch (IOException e) { - LOGGER.log(Level.WARNING, "Failed to accept a soccket",e); + LOGGER.log(Level.WARNING, "Failed to accept a soccket", e); } } }; diff --git a/src/test/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtilsTest.java b/src/test/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtilsTest.java index 405e9fb83..a4ad55142 100644 --- a/src/test/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtilsTest.java +++ b/src/test/java/org/jenkinsci/remoting/org/apache/commons/net/util/SubnetUtilsTest.java @@ -45,7 +45,9 @@ public void testAddresses() { assertEquals(-1062731775, info.asInteger("192.168.0.1")); assertThrows(IllegalArgumentException.class, () -> info.asInteger("bad")); // - assertArrayEquals(new String[] { "192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6" }, info.getAllAddresses()); + assertArrayEquals( + new String[] {"192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6"}, + info.getAllAddresses()); } public void testAddressIllegalArgument() { @@ -217,7 +219,6 @@ public void testCidrAddresses() { info = utils.getInfo(); assertEquals("255.255.255.255", info.getNetmask()); assertEquals(1, info.getAddressCount()); - } public void testInvalidMasks() { @@ -310,15 +311,15 @@ public void testNext() { public void testParseSimpleNetmask() { final String address = "192.168.0.1"; - final String[] masks = { "255.0.0.0", "255.255.0.0", "255.255.255.0", "255.255.255.248" }; - final String[] bcastAddresses = { "192.255.255.255", "192.168.255.255", "192.168.0.255", "192.168.0.7" }; - final String[] lowAddresses = { "192.0.0.1", "192.168.0.1", "192.168.0.1", "192.168.0.1" }; - final String[] highAddresses = { "192.255.255.254", "192.168.255.254", "192.168.0.254", "192.168.0.6" }; - final String[] nextAddresses = { "192.168.0.2", "192.168.0.2", "192.168.0.2", "192.168.0.2" }; - final String[] previousAddresses = { "192.168.0.0", "192.168.0.0", "192.168.0.0", "192.168.0.0" }; - final String[] networkAddresses = { "192.0.0.0", "192.168.0.0", "192.168.0.0", "192.168.0.0" }; - final String[] cidrSignatures = { "192.168.0.1/8", "192.168.0.1/16", "192.168.0.1/24", "192.168.0.1/29" }; - final int[] usableAddresses = { 16777214, 65534, 254, 6 }; + final String[] masks = {"255.0.0.0", "255.255.0.0", "255.255.255.0", "255.255.255.248"}; + final String[] bcastAddresses = {"192.255.255.255", "192.168.255.255", "192.168.0.255", "192.168.0.7"}; + final String[] lowAddresses = {"192.0.0.1", "192.168.0.1", "192.168.0.1", "192.168.0.1"}; + final String[] highAddresses = {"192.255.255.254", "192.168.255.254", "192.168.0.254", "192.168.0.6"}; + final String[] nextAddresses = {"192.168.0.2", "192.168.0.2", "192.168.0.2", "192.168.0.2"}; + final String[] previousAddresses = {"192.168.0.0", "192.168.0.0", "192.168.0.0", "192.168.0.0"}; + final String[] networkAddresses = {"192.0.0.0", "192.168.0.0", "192.168.0.0", "192.168.0.0"}; + final String[] cidrSignatures = {"192.168.0.1/8", "192.168.0.1/16", "192.168.0.1/24", "192.168.0.1/29"}; + final int[] usableAddresses = {16777214, 65534, 254, 6}; for (int i = 0; i < masks.length; ++i) { final SubnetUtils utils = new SubnetUtils(address, masks[i]); @@ -337,13 +338,13 @@ public void testParseSimpleNetmask() { public void testParseSimpleNetmaskExclusive() { final String address = "192.168.15.7"; - final String[] masks = { "255.255.255.252", "255.255.255.254", "255.255.255.255" }; - final String[] bcast = { "192.168.15.7", "192.168.15.7", "192.168.15.7" }; - final String[] netwk = { "192.168.15.4", "192.168.15.6", "192.168.15.7" }; - final String[] lowAd = { "192.168.15.5", "0.0.0.0", "0.0.0.0" }; - final String[] highA = { "192.168.15.6", "0.0.0.0", "0.0.0.0" }; - final String[] cidrS = { "192.168.15.7/30", "192.168.15.7/31", "192.168.15.7/32" }; - final int[] usableAd = { 2, 0, 0 }; + final String[] masks = {"255.255.255.252", "255.255.255.254", "255.255.255.255"}; + final String[] bcast = {"192.168.15.7", "192.168.15.7", "192.168.15.7"}; + final String[] netwk = {"192.168.15.4", "192.168.15.6", "192.168.15.7"}; + final String[] lowAd = {"192.168.15.5", "0.0.0.0", "0.0.0.0"}; + final String[] highA = {"192.168.15.6", "0.0.0.0", "0.0.0.0"}; + final String[] cidrS = {"192.168.15.7/30", "192.168.15.7/31", "192.168.15.7/32"}; + final int[] usableAd = {2, 0, 0}; // low and high addresses don't exist for (int i = 0; i < masks.length; ++i) { @@ -361,13 +362,13 @@ public void testParseSimpleNetmaskExclusive() { public void testParseSimpleNetmaskInclusive() { final String address = "192.168.15.7"; - final String[] masks = { "255.255.255.252", "255.255.255.254", "255.255.255.255" }; - final String[] bcast = { "192.168.15.7", "192.168.15.7", "192.168.15.7" }; - final String[] netwk = { "192.168.15.4", "192.168.15.6", "192.168.15.7" }; - final String[] lowAd = { "192.168.15.4", "192.168.15.6", "192.168.15.7" }; - final String[] highA = { "192.168.15.7", "192.168.15.7", "192.168.15.7" }; - final String[] cidrS = { "192.168.15.7/30", "192.168.15.7/31", "192.168.15.7/32" }; - final int[] usableAd = { 4, 2, 1 }; + final String[] masks = {"255.255.255.252", "255.255.255.254", "255.255.255.255"}; + final String[] bcast = {"192.168.15.7", "192.168.15.7", "192.168.15.7"}; + final String[] netwk = {"192.168.15.4", "192.168.15.6", "192.168.15.7"}; + final String[] lowAd = {"192.168.15.4", "192.168.15.6", "192.168.15.7"}; + final String[] highA = {"192.168.15.7", "192.168.15.7", "192.168.15.7"}; + final String[] cidrS = {"192.168.15.7/30", "192.168.15.7/31", "192.168.15.7/32"}; + final int[] usableAd = {4, 2, 1}; for (int i = 0; i < masks.length; ++i) { final SubnetUtils utils = new SubnetUtils(address, masks[i]); diff --git a/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidatorTest.java b/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidatorTest.java index 831ad227f..5ae0cebe8 100644 --- a/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidatorTest.java +++ b/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/InetAddressValidatorTest.java @@ -44,14 +44,16 @@ protected void setUp() { * Test IPs that point to real, well-known hosts (without actually looking them up). */ public void testInetAddressesFromTheWild() { - assertTrue("www.apache.org IP should be valid", validator.isValid("140.211.11.130")); - assertTrue("www.l.google.com IP should be valid", validator.isValid("72.14.253.103")); - assertTrue("fsf.org IP should be valid", validator.isValid("199.232.41.5")); - assertTrue("appscs.ign.com IP should be valid", validator.isValid("216.35.123.87")); + assertTrue("www.apache.org IP should be valid", validator.isValid("140.211.11.130")); + assertTrue("www.l.google.com IP should be valid", validator.isValid("72.14.253.103")); + assertTrue("fsf.org IP should be valid", validator.isValid("199.232.41.5")); + assertTrue("appscs.ign.com IP should be valid", validator.isValid("216.35.123.87")); } public void testVALIDATOR_335() { - assertTrue("2001:0438:FFFE:0000:0000:0000:0000:0A35 should be valid", validator.isValid("2001:0438:FFFE:0000:0000:0000:0000:0A35")); + assertTrue( + "2001:0438:FFFE:0000:0000:0000:0000:0A35 should be valid", + validator.isValid("2001:0438:FFFE:0000:0000:0000:0000:0A35")); } public void testVALIDATOR_419() { @@ -75,14 +77,14 @@ public void testVALIDATOR_419() { * Inet6Address may also contain a scope id */ public void testVALIDATOR_445() { - String [] valid = { + String[] valid = { "2001:0000:1234:0000:0000:C1C0:ABCD:0876", "2001:0000:1234:0000:0000:C1C0:ABCD:0876/123", "2001:0000:1234:0000:0000:C1C0:ABCD:0876/0", "2001:0000:1234:0000:0000:C1C0:ABCD:0876%0", "2001:0000:1234:0000:0000:C1C0:ABCD:0876%abcdefgh", - }; - String [] invalid = { + }; + String[] invalid = { "2001:0000:1234:0000:0000:C1C0:ABCD:0876/129", // too big "2001:0000:1234:0000:0000:C1C0:ABCD:0876/-0", // sign not allowed "2001:0000:1234:0000:0000:C1C0:ABCD:0876/+0", // sign not allowed @@ -90,7 +92,7 @@ public void testVALIDATOR_445() { "2001:0000:1234:0000:0000:C1C0:ABCD:0876/0%0", // /bits before %node-id "2001:0000:1234:0000:0000:C1C0:ABCD:0876%abc defgh", // space in node id "2001:0000:1234:0000:0000:C1C0:ABCD:0876%abc%defgh", // '%' in node id - }; + }; for (String item : valid) { assertTrue(String.format("%s should be valid", item), validator.isValid(item)); } @@ -103,40 +105,40 @@ public void testVALIDATOR_445() { * Test valid and invalid IPs from each address class. */ public void testInetAddressesByClass() { - assertTrue("class A IP should be valid", validator.isValid("24.25.231.12")); - assertFalse("illegal class A IP should be invalid", validator.isValid("2.41.32.324")); + assertTrue("class A IP should be valid", validator.isValid("24.25.231.12")); + assertFalse("illegal class A IP should be invalid", validator.isValid("2.41.32.324")); - assertTrue("class B IP should be valid", validator.isValid("135.14.44.12")); - assertFalse("illegal class B IP should be invalid", validator.isValid("154.123.441.123")); + assertTrue("class B IP should be valid", validator.isValid("135.14.44.12")); + assertFalse("illegal class B IP should be invalid", validator.isValid("154.123.441.123")); - assertTrue("class C IP should be valid", validator.isValid("213.25.224.32")); - assertFalse("illegal class C IP should be invalid", validator.isValid("201.543.23.11")); + assertTrue("class C IP should be valid", validator.isValid("213.25.224.32")); + assertFalse("illegal class C IP should be invalid", validator.isValid("201.543.23.11")); - assertTrue("class D IP should be valid", validator.isValid("229.35.159.6")); - assertFalse("illegal class D IP should be invalid", validator.isValid("231.54.11.987")); + assertTrue("class D IP should be valid", validator.isValid("229.35.159.6")); + assertFalse("illegal class D IP should be invalid", validator.isValid("231.54.11.987")); - assertTrue("class E IP should be valid", validator.isValid("248.85.24.92")); - assertFalse("illegal class E IP should be invalid", validator.isValid("250.21.323.48")); + assertTrue("class E IP should be valid", validator.isValid("248.85.24.92")); + assertFalse("illegal class E IP should be invalid", validator.isValid("250.21.323.48")); } /** * Test reserved IPs. */ public void testReservedInetAddresses() { - assertTrue("localhost IP should be valid", validator.isValid("127.0.0.1")); - assertTrue("broadcast IP should be valid", validator.isValid("255.255.255.255")); + assertTrue("localhost IP should be valid", validator.isValid("127.0.0.1")); + assertTrue("broadcast IP should be valid", validator.isValid("255.255.255.255")); } /** * Test obviously broken IPs. */ public void testBrokenInetAddresses() { - assertFalse("IP with characters should be invalid", validator.isValid("124.14.32.abc")); + assertFalse("IP with characters should be invalid", validator.isValid("124.14.32.abc")); // TODO: there is some debate as to whether leading zeros should be allowed // They are ambiguous: does the leading 0 mean octal? assertFalse("IP with leading zeroes should be invalid", validator.isValid("124.14.32.01")); - assertFalse("IP with three groups should be invalid", validator.isValid("23.64.12")); - assertFalse("IP with five groups should be invalid", validator.isValid("26.34.23.77.234")); + assertFalse("IP with three groups should be invalid", validator.isValid("23.64.12")); + assertFalse("IP with five groups should be invalid", validator.isValid("26.34.23.77.234")); assertFalse("IP empty string should be invalid", validator.isValidInet6Address("")); // empty string } @@ -150,30 +152,76 @@ public void testIPv6() { // The original Perl script contained a lot of duplicate tests. // I removed the duplicates I noticed, but there may be more. assertFalse("IPV6 empty string should be invalid", validator.isValidInet6Address("")); // empty string - assertTrue("IPV6 ::1 should be valid", validator.isValidInet6Address("::1")); // loopback, compressed, non-routable - assertTrue("IPV6 :: should be valid", validator.isValidInet6Address("::")); // unspecified, compressed, non-routable - assertTrue("IPV6 0:0:0:0:0:0:0:1 should be valid", validator.isValidInet6Address("0:0:0:0:0:0:0:1")); // loopback, full - assertTrue("IPV6 0:0:0:0:0:0:0:0 should be valid", validator.isValidInet6Address("0:0:0:0:0:0:0:0")); // unspecified, full - assertTrue("IPV6 2001:DB8:0:0:8:800:200C:417A should be valid", validator.isValidInet6Address("2001:DB8:0:0:8:800:200C:417A")); // unicast, full - assertTrue("IPV6 FF01:0:0:0:0:0:0:101 should be valid", validator.isValidInet6Address("FF01:0:0:0:0:0:0:101")); // multicast, full - assertTrue("IPV6 2001:DB8::8:800:200C:417A should be valid", validator.isValidInet6Address("2001:DB8::8:800:200C:417A")); // unicast, compressed - assertTrue("IPV6 FF01::101 should be valid", validator.isValidInet6Address("FF01::101")); // multicast, compressed - assertFalse("IPV6 2001:DB8:0:0:8:800:200C:417A:221 should be invalid", validator.isValidInet6Address("2001:DB8:0:0:8:800:200C:417A:221")); // unicast, full - assertFalse("IPV6 FF01::101::2 should be invalid", validator.isValidInet6Address("FF01::101::2")); // multicast, compressed - assertTrue("IPV6 fe80::217:f2ff:fe07:ed62 should be valid", validator.isValidInet6Address("fe80::217:f2ff:fe07:ed62")); - assertTrue("IPV6 2001:0000:1234:0000:0000:C1C0:ABCD:0876 should be valid", validator.isValidInet6Address("2001:0000:1234:0000:0000:C1C0:ABCD:0876")); - assertTrue("IPV6 3ffe:0b00:0000:0000:0001:0000:0000:000a should be valid", validator.isValidInet6Address("3ffe:0b00:0000:0000:0001:0000:0000:000a")); - assertTrue("IPV6 FF02:0000:0000:0000:0000:0000:0000:0001 should be valid", validator.isValidInet6Address("FF02:0000:0000:0000:0000:0000:0000:0001")); - assertTrue("IPV6 0000:0000:0000:0000:0000:0000:0000:0001 should be valid", validator.isValidInet6Address("0000:0000:0000:0000:0000:0000:0000:0001")); - assertTrue("IPV6 0000:0000:0000:0000:0000:0000:0000:0000 should be valid", validator.isValidInet6Address("0000:0000:0000:0000:0000:0000:0000:0000")); - assertFalse("IPV6 02001:0000:1234:0000:0000:C1C0:ABCD:0876 should be invalid", validator.isValidInet6Address("02001:0000:1234:0000:0000:C1C0:ABCD:0876")); // extra 0 not allowed! - assertFalse("IPV6 2001:0000:1234:0000:00001:C1C0:ABCD:0876 should be invalid", validator.isValidInet6Address("2001:0000:1234:0000:00001:C1C0:ABCD:0876")); // extra 0 not allowed! - assertFalse("IPV6 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0 should be invalid", validator.isValidInet6Address("2001:0000:1234:0000:0000:C1C0:ABCD:0876 0")); // junk after valid address - assertFalse("IPV6 2001:0000:1234: 0000:0000:C1C0:ABCD:0876 should be invalid", validator.isValidInet6Address("2001:0000:1234: 0000:0000:C1C0:ABCD:0876")); // internal space - assertFalse("IPV6 3ffe:0b00:0000:0001:0000:0000:000a should be invalid", validator.isValidInet6Address("3ffe:0b00:0000:0001:0000:0000:000a")); // seven segments - assertFalse("IPV6 FF02:0000:0000:0000:0000:0000:0000:0000:0001 should be invalid", validator.isValidInet6Address("FF02:0000:0000:0000:0000:0000:0000:0000:0001")); // nine segments - assertFalse("IPV6 3ffe:b00::1::a should be invalid", validator.isValidInet6Address("3ffe:b00::1::a")); // double "::" - assertFalse("IPV6 ::1111:2222:3333:4444:5555:6666:: should be invalid", validator.isValidInet6Address("::1111:2222:3333:4444:5555:6666::")); // double "::" + assertTrue( + "IPV6 ::1 should be valid", validator.isValidInet6Address("::1")); // loopback, compressed, non-routable + assertTrue( + "IPV6 :: should be valid", + validator.isValidInet6Address("::")); // unspecified, compressed, non-routable + assertTrue( + "IPV6 0:0:0:0:0:0:0:1 should be valid", + validator.isValidInet6Address("0:0:0:0:0:0:0:1")); // loopback, full + assertTrue( + "IPV6 0:0:0:0:0:0:0:0 should be valid", + validator.isValidInet6Address("0:0:0:0:0:0:0:0")); // unspecified, full + assertTrue( + "IPV6 2001:DB8:0:0:8:800:200C:417A should be valid", + validator.isValidInet6Address("2001:DB8:0:0:8:800:200C:417A")); // unicast, full + assertTrue( + "IPV6 FF01:0:0:0:0:0:0:101 should be valid", + validator.isValidInet6Address("FF01:0:0:0:0:0:0:101")); // multicast, full + assertTrue( + "IPV6 2001:DB8::8:800:200C:417A should be valid", + validator.isValidInet6Address("2001:DB8::8:800:200C:417A")); // unicast, compressed + assertTrue( + "IPV6 FF01::101 should be valid", validator.isValidInet6Address("FF01::101")); // multicast, compressed + assertFalse( + "IPV6 2001:DB8:0:0:8:800:200C:417A:221 should be invalid", + validator.isValidInet6Address("2001:DB8:0:0:8:800:200C:417A:221")); // unicast, full + assertFalse( + "IPV6 FF01::101::2 should be invalid", + validator.isValidInet6Address("FF01::101::2")); // multicast, compressed + assertTrue( + "IPV6 fe80::217:f2ff:fe07:ed62 should be valid", + validator.isValidInet6Address("fe80::217:f2ff:fe07:ed62")); + assertTrue( + "IPV6 2001:0000:1234:0000:0000:C1C0:ABCD:0876 should be valid", + validator.isValidInet6Address("2001:0000:1234:0000:0000:C1C0:ABCD:0876")); + assertTrue( + "IPV6 3ffe:0b00:0000:0000:0001:0000:0000:000a should be valid", + validator.isValidInet6Address("3ffe:0b00:0000:0000:0001:0000:0000:000a")); + assertTrue( + "IPV6 FF02:0000:0000:0000:0000:0000:0000:0001 should be valid", + validator.isValidInet6Address("FF02:0000:0000:0000:0000:0000:0000:0001")); + assertTrue( + "IPV6 0000:0000:0000:0000:0000:0000:0000:0001 should be valid", + validator.isValidInet6Address("0000:0000:0000:0000:0000:0000:0000:0001")); + assertTrue( + "IPV6 0000:0000:0000:0000:0000:0000:0000:0000 should be valid", + validator.isValidInet6Address("0000:0000:0000:0000:0000:0000:0000:0000")); + assertFalse( + "IPV6 02001:0000:1234:0000:0000:C1C0:ABCD:0876 should be invalid", + validator.isValidInet6Address("02001:0000:1234:0000:0000:C1C0:ABCD:0876")); // extra 0 not allowed! + assertFalse( + "IPV6 2001:0000:1234:0000:00001:C1C0:ABCD:0876 should be invalid", + validator.isValidInet6Address("2001:0000:1234:0000:00001:C1C0:ABCD:0876")); // extra 0 not allowed! + assertFalse( + "IPV6 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0 should be invalid", + validator.isValidInet6Address("2001:0000:1234:0000:0000:C1C0:ABCD:0876 0")); // junk after valid address + assertFalse( + "IPV6 2001:0000:1234: 0000:0000:C1C0:ABCD:0876 should be invalid", + validator.isValidInet6Address("2001:0000:1234: 0000:0000:C1C0:ABCD:0876")); // internal space + assertFalse( + "IPV6 3ffe:0b00:0000:0001:0000:0000:000a should be invalid", + validator.isValidInet6Address("3ffe:0b00:0000:0001:0000:0000:000a")); // seven segments + assertFalse( + "IPV6 FF02:0000:0000:0000:0000:0000:0000:0000:0001 should be invalid", + validator.isValidInet6Address("FF02:0000:0000:0000:0000:0000:0000:0000:0001")); // nine segments + assertFalse( + "IPV6 3ffe:b00::1::a should be invalid", + validator.isValidInet6Address("3ffe:b00::1::a")); // double "::" + assertFalse( + "IPV6 ::1111:2222:3333:4444:5555:6666:: should be invalid", + validator.isValidInet6Address("::1111:2222:3333:4444:5555:6666::")); // double "::" assertTrue("IPV6 2::10 should be valid", validator.isValidInet6Address("2::10")); assertTrue("IPV6 ff02::1 should be valid", validator.isValidInet6Address("ff02::1")); assertTrue("IPV6 fe80:: should be valid", validator.isValidInet6Address("fe80::")); @@ -207,7 +255,9 @@ public void testIPv6() { assertTrue("IPV6 1:2:: should be valid", validator.isValidInet6Address("1:2::")); assertTrue("IPV6 1:: should be valid", validator.isValidInet6Address("1::")); assertTrue("IPV6 1:2:3:4:5::7:8 should be valid", validator.isValidInet6Address("1:2:3:4:5::7:8")); - assertFalse("IPV6 1:2:3::4:5::7:8 should be invalid", validator.isValidInet6Address("1:2:3::4:5::7:8")); // Double "::" + assertFalse( + "IPV6 1:2:3::4:5::7:8 should be invalid", + validator.isValidInet6Address("1:2:3::4:5::7:8")); // Double "::" assertFalse("IPV6 12345::6:7:8 should be invalid", validator.isValidInet6Address("12345::6:7:8")); assertTrue("IPV6 1:2:3:4::7:8 should be valid", validator.isValidInet6Address("1:2:3:4::7:8")); assertTrue("IPV6 1:2:3::7:8 should be valid", validator.isValidInet6Address("1:2:3::7:8")); @@ -239,7 +289,8 @@ public void testIPv6() { assertFalse("IPV6 1::5:1.900.3.4 should be invalid", validator.isValidInet6Address("1::5:1.900.3.4")); assertFalse("IPV6 1::5:1.2.900.4 should be invalid", validator.isValidInet6Address("1::5:1.2.900.4")); assertFalse("IPV6 1::5:1.2.3.900 should be invalid", validator.isValidInet6Address("1::5:1.2.3.900")); - assertFalse("IPV6 1::5:300.300.300.300 should be invalid", validator.isValidInet6Address("1::5:300.300.300.300")); + assertFalse( + "IPV6 1::5:300.300.300.300 should be invalid", validator.isValidInet6Address("1::5:300.300.300.300")); assertFalse("IPV6 1::5:3000.30.30.30 should be invalid", validator.isValidInet6Address("1::5:3000.30.30.30")); assertFalse("IPV6 1::400.2.3.4 should be invalid", validator.isValidInet6Address("1::400.2.3.4")); assertFalse("IPV6 1::260.2.3.4 should be invalid", validator.isValidInet6Address("1::260.2.3.4")); @@ -273,132 +324,288 @@ public void testIPv6() { assertFalse("IPV6 ::1.2.3.900 should be invalid", validator.isValidInet6Address("::1.2.3.900")); assertFalse("IPV6 ::300.300.300.300 should be invalid", validator.isValidInet6Address("::300.300.300.300")); assertFalse("IPV6 ::3000.30.30.30 should be invalid", validator.isValidInet6Address("::3000.30.30.30")); - assertTrue("IPV6 fe80::217:f2ff:254.7.237.98 should be valid", validator.isValidInet6Address("fe80::217:f2ff:254.7.237.98")); + assertTrue( + "IPV6 fe80::217:f2ff:254.7.237.98 should be valid", + validator.isValidInet6Address("fe80::217:f2ff:254.7.237.98")); assertTrue("IPV6 ::ffff:192.168.1.26 should be valid", validator.isValidInet6Address("::ffff:192.168.1.26")); - assertFalse("IPV6 2001:1:1:1:1:1:255Z255X255Y255 should be invalid", validator.isValidInet6Address("2001:1:1:1:1:1:255Z255X255Y255")); // garbage instead of "." in IPv4 - assertFalse("IPV6 ::ffff:192x168.1.26 should be invalid", validator.isValidInet6Address("::ffff:192x168.1.26")); // ditto + assertFalse( + "IPV6 2001:1:1:1:1:1:255Z255X255Y255 should be invalid", + validator.isValidInet6Address("2001:1:1:1:1:1:255Z255X255Y255")); // garbage instead of "." in IPv4 + assertFalse( + "IPV6 ::ffff:192x168.1.26 should be invalid", + validator.isValidInet6Address("::ffff:192x168.1.26")); // ditto assertTrue("IPV6 ::ffff:192.168.1.1 should be valid", validator.isValidInet6Address("::ffff:192.168.1.1")); - assertTrue("IPV6 0:0:0:0:0:0:13.1.68.3 should be valid", validator.isValidInet6Address("0:0:0:0:0:0:13.1.68.3")); // IPv4-compatible IPv6 address, full, deprecated - assertTrue("IPV6 0:0:0:0:0:FFFF:129.144.52.38 should be valid", validator.isValidInet6Address("0:0:0:0:0:FFFF:129.144.52.38")); // IPv4-mapped IPv6 address, full - assertTrue("IPV6 ::13.1.68.3 should be valid", validator.isValidInet6Address("::13.1.68.3")); // IPv4-compatible IPv6 address, compressed, deprecated - assertTrue("IPV6 ::FFFF:129.144.52.38 should be valid", validator.isValidInet6Address("::FFFF:129.144.52.38")); // IPv4-mapped IPv6 address, compressed - assertTrue("IPV6 fe80:0:0:0:204:61ff:254.157.241.86 should be valid", validator.isValidInet6Address("fe80:0:0:0:204:61ff:254.157.241.86")); - assertTrue("IPV6 fe80::204:61ff:254.157.241.86 should be valid", validator.isValidInet6Address("fe80::204:61ff:254.157.241.86")); + assertTrue( + "IPV6 0:0:0:0:0:0:13.1.68.3 should be valid", + validator.isValidInet6Address( + "0:0:0:0:0:0:13.1.68.3")); // IPv4-compatible IPv6 address, full, deprecated + assertTrue( + "IPV6 0:0:0:0:0:FFFF:129.144.52.38 should be valid", + validator.isValidInet6Address("0:0:0:0:0:FFFF:129.144.52.38")); // IPv4-mapped IPv6 address, full + assertTrue( + "IPV6 ::13.1.68.3 should be valid", + validator.isValidInet6Address("::13.1.68.3")); // IPv4-compatible IPv6 address, compressed, deprecated + assertTrue( + "IPV6 ::FFFF:129.144.52.38 should be valid", + validator.isValidInet6Address("::FFFF:129.144.52.38")); // IPv4-mapped IPv6 address, compressed + assertTrue( + "IPV6 fe80:0:0:0:204:61ff:254.157.241.86 should be valid", + validator.isValidInet6Address("fe80:0:0:0:204:61ff:254.157.241.86")); + assertTrue( + "IPV6 fe80::204:61ff:254.157.241.86 should be valid", + validator.isValidInet6Address("fe80::204:61ff:254.157.241.86")); assertTrue("IPV6 ::ffff:12.34.56.78 should be valid", validator.isValidInet6Address("::ffff:12.34.56.78")); assertFalse("IPV6 ::ffff:2.3.4 should be invalid", validator.isValidInet6Address("::ffff:2.3.4")); assertFalse("IPV6 ::ffff:257.1.2.3 should be invalid", validator.isValidInet6Address("::ffff:257.1.2.3")); assertFalse("IPV6 1.2.3.4 should be invalid", validator.isValidInet6Address("1.2.3.4")); - assertFalse("IPV6 1.2.3.4:1111:2222:3333:4444::5555 should be invalid", validator.isValidInet6Address("1.2.3.4:1111:2222:3333:4444::5555")); - assertFalse("IPV6 1.2.3.4:1111:2222:3333::5555 should be invalid", validator.isValidInet6Address("1.2.3.4:1111:2222:3333::5555")); - assertFalse("IPV6 1.2.3.4:1111:2222::5555 should be invalid", validator.isValidInet6Address("1.2.3.4:1111:2222::5555")); + assertFalse( + "IPV6 1.2.3.4:1111:2222:3333:4444::5555 should be invalid", + validator.isValidInet6Address("1.2.3.4:1111:2222:3333:4444::5555")); + assertFalse( + "IPV6 1.2.3.4:1111:2222:3333::5555 should be invalid", + validator.isValidInet6Address("1.2.3.4:1111:2222:3333::5555")); + assertFalse( + "IPV6 1.2.3.4:1111:2222::5555 should be invalid", + validator.isValidInet6Address("1.2.3.4:1111:2222::5555")); assertFalse("IPV6 1.2.3.4:1111::5555 should be invalid", validator.isValidInet6Address("1.2.3.4:1111::5555")); assertFalse("IPV6 1.2.3.4::5555 should be invalid", validator.isValidInet6Address("1.2.3.4::5555")); assertFalse("IPV6 1.2.3.4:: should be invalid", validator.isValidInet6Address("1.2.3.4::")); // Testing IPv4 addresses represented as dotted-quads - // Leading zeroes in IPv4 addresses not allowed: some systems treat the leading "0" in ".086" as the start of an octal number + // Leading zeroes in IPv4 addresses not allowed: some systems treat the leading "0" in ".086" as the start of an + // octal number // Update: The BNF in RFC-3986 explicitly defines the dec-octet (for IPv4 addresses) not to have a leading zero - assertFalse("IPV6 fe80:0000:0000:0000:0204:61ff:254.157.241.086 should be invalid", validator.isValidInet6Address("fe80:0000:0000:0000:0204:61ff:254.157.241.086")); - assertTrue("IPV6 ::ffff:192.0.2.128 should be valid", validator.isValidInet6Address("::ffff:192.0.2.128")); // but this is OK, since there's a single digit - assertFalse("IPV6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4 should be invalid", validator.isValidInet6Address("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:00.00.00.00 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:00.00.00.00")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:000.000.000.000 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:000.000.000.000")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:256.256.256.256 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:256.256.256.256")); - assertTrue("IPV6 fe80:0000:0000:0000:0204:61ff:fe9d:f156 should be valid", validator.isValidInet6Address("fe80:0000:0000:0000:0204:61ff:fe9d:f156")); - assertTrue("IPV6 fe80:0:0:0:204:61ff:fe9d:f156 should be valid", validator.isValidInet6Address("fe80:0:0:0:204:61ff:fe9d:f156")); - assertTrue("IPV6 fe80::204:61ff:fe9d:f156 should be valid", validator.isValidInet6Address("fe80::204:61ff:fe9d:f156")); + assertFalse( + "IPV6 fe80:0000:0000:0000:0204:61ff:254.157.241.086 should be invalid", + validator.isValidInet6Address("fe80:0000:0000:0000:0204:61ff:254.157.241.086")); + assertTrue( + "IPV6 ::ffff:192.0.2.128 should be valid", + validator.isValidInet6Address("::ffff:192.0.2.128")); // but this is OK, since there's a single digit + assertFalse( + "IPV6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4 should be invalid", + validator.isValidInet6Address("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:00.00.00.00 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:00.00.00.00")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:000.000.000.000 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:000.000.000.000")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:256.256.256.256 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:256.256.256.256")); + assertTrue( + "IPV6 fe80:0000:0000:0000:0204:61ff:fe9d:f156 should be valid", + validator.isValidInet6Address("fe80:0000:0000:0000:0204:61ff:fe9d:f156")); + assertTrue( + "IPV6 fe80:0:0:0:204:61ff:fe9d:f156 should be valid", + validator.isValidInet6Address("fe80:0:0:0:204:61ff:fe9d:f156")); + assertTrue( + "IPV6 fe80::204:61ff:fe9d:f156 should be valid", + validator.isValidInet6Address("fe80::204:61ff:fe9d:f156")); assertFalse("IPV6 : should be invalid", validator.isValidInet6Address(":")); assertTrue("IPV6 ::ffff:c000:280 should be valid", validator.isValidInet6Address("::ffff:c000:280")); - assertFalse("IPV6 1111:2222:3333:4444::5555: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::5555:")); - assertFalse("IPV6 1111:2222:3333::5555: should be invalid", validator.isValidInet6Address("1111:2222:3333::5555:")); + assertFalse( + "IPV6 1111:2222:3333:4444::5555: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::5555:")); + assertFalse( + "IPV6 1111:2222:3333::5555: should be invalid", validator.isValidInet6Address("1111:2222:3333::5555:")); assertFalse("IPV6 1111:2222::5555: should be invalid", validator.isValidInet6Address("1111:2222::5555:")); assertFalse("IPV6 1111::5555: should be invalid", validator.isValidInet6Address("1111::5555:")); assertFalse("IPV6 ::5555: should be invalid", validator.isValidInet6Address("::5555:")); assertFalse("IPV6 ::: should be invalid", validator.isValidInet6Address(":::")); assertFalse("IPV6 1111: should be invalid", validator.isValidInet6Address("1111:")); - assertFalse("IPV6 :1111:2222:3333:4444::5555 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::5555")); - assertFalse("IPV6 :1111:2222:3333::5555 should be invalid", validator.isValidInet6Address(":1111:2222:3333::5555")); + assertFalse( + "IPV6 :1111:2222:3333:4444::5555 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::5555")); + assertFalse( + "IPV6 :1111:2222:3333::5555 should be invalid", validator.isValidInet6Address(":1111:2222:3333::5555")); assertFalse("IPV6 :1111:2222::5555 should be invalid", validator.isValidInet6Address(":1111:2222::5555")); assertFalse("IPV6 :1111::5555 should be invalid", validator.isValidInet6Address(":1111::5555")); assertFalse("IPV6 :::5555 should be invalid", validator.isValidInet6Address(":::5555")); - assertTrue("IPV6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 should be valid", validator.isValidInet6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334")); - assertTrue("IPV6 2001:db8:85a3:0:0:8a2e:370:7334 should be valid", validator.isValidInet6Address("2001:db8:85a3:0:0:8a2e:370:7334")); - assertTrue("IPV6 2001:db8:85a3::8a2e:370:7334 should be valid", validator.isValidInet6Address("2001:db8:85a3::8a2e:370:7334")); - assertTrue("IPV6 2001:0db8:0000:0000:0000:0000:1428:57ab should be valid", validator.isValidInet6Address("2001:0db8:0000:0000:0000:0000:1428:57ab")); - assertTrue("IPV6 2001:0db8:0000:0000:0000::1428:57ab should be valid", validator.isValidInet6Address("2001:0db8:0000:0000:0000::1428:57ab")); - assertTrue("IPV6 2001:0db8:0:0:0:0:1428:57ab should be valid", validator.isValidInet6Address("2001:0db8:0:0:0:0:1428:57ab")); - assertTrue("IPV6 2001:0db8:0:0::1428:57ab should be valid", validator.isValidInet6Address("2001:0db8:0:0::1428:57ab")); + assertTrue( + "IPV6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 should be valid", + validator.isValidInet6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334")); + assertTrue( + "IPV6 2001:db8:85a3:0:0:8a2e:370:7334 should be valid", + validator.isValidInet6Address("2001:db8:85a3:0:0:8a2e:370:7334")); + assertTrue( + "IPV6 2001:db8:85a3::8a2e:370:7334 should be valid", + validator.isValidInet6Address("2001:db8:85a3::8a2e:370:7334")); + assertTrue( + "IPV6 2001:0db8:0000:0000:0000:0000:1428:57ab should be valid", + validator.isValidInet6Address("2001:0db8:0000:0000:0000:0000:1428:57ab")); + assertTrue( + "IPV6 2001:0db8:0000:0000:0000::1428:57ab should be valid", + validator.isValidInet6Address("2001:0db8:0000:0000:0000::1428:57ab")); + assertTrue( + "IPV6 2001:0db8:0:0:0:0:1428:57ab should be valid", + validator.isValidInet6Address("2001:0db8:0:0:0:0:1428:57ab")); + assertTrue( + "IPV6 2001:0db8:0:0::1428:57ab should be valid", + validator.isValidInet6Address("2001:0db8:0:0::1428:57ab")); assertTrue("IPV6 2001:0db8::1428:57ab should be valid", validator.isValidInet6Address("2001:0db8::1428:57ab")); assertTrue("IPV6 2001:db8::1428:57ab should be valid", validator.isValidInet6Address("2001:db8::1428:57ab")); assertTrue("IPV6 ::ffff:0c22:384e should be valid", validator.isValidInet6Address("::ffff:0c22:384e")); - assertTrue("IPV6 2001:0db8:1234:0000:0000:0000:0000:0000 should be valid", validator.isValidInet6Address("2001:0db8:1234:0000:0000:0000:0000:0000")); - assertTrue("IPV6 2001:0db8:1234:ffff:ffff:ffff:ffff:ffff should be valid", validator.isValidInet6Address("2001:0db8:1234:ffff:ffff:ffff:ffff:ffff")); + assertTrue( + "IPV6 2001:0db8:1234:0000:0000:0000:0000:0000 should be valid", + validator.isValidInet6Address("2001:0db8:1234:0000:0000:0000:0000:0000")); + assertTrue( + "IPV6 2001:0db8:1234:ffff:ffff:ffff:ffff:ffff should be valid", + validator.isValidInet6Address("2001:0db8:1234:ffff:ffff:ffff:ffff:ffff")); assertTrue("IPV6 2001:db8:a::123 should be valid", validator.isValidInet6Address("2001:db8:a::123")); assertFalse("IPV6 123 should be invalid", validator.isValidInet6Address("123")); assertFalse("IPV6 ldkfj should be invalid", validator.isValidInet6Address("ldkfj")); assertFalse("IPV6 2001::FFD3::57ab should be invalid", validator.isValidInet6Address("2001::FFD3::57ab")); - assertFalse("IPV6 2001:db8:85a3::8a2e:37023:7334 should be invalid", validator.isValidInet6Address("2001:db8:85a3::8a2e:37023:7334")); - assertFalse("IPV6 2001:db8:85a3::8a2e:370k:7334 should be invalid", validator.isValidInet6Address("2001:db8:85a3::8a2e:370k:7334")); + assertFalse( + "IPV6 2001:db8:85a3::8a2e:37023:7334 should be invalid", + validator.isValidInet6Address("2001:db8:85a3::8a2e:37023:7334")); + assertFalse( + "IPV6 2001:db8:85a3::8a2e:370k:7334 should be invalid", + validator.isValidInet6Address("2001:db8:85a3::8a2e:370k:7334")); assertFalse("IPV6 1:2:3:4:5:6:7:8:9 should be invalid", validator.isValidInet6Address("1:2:3:4:5:6:7:8:9")); assertFalse("IPV6 1::2::3 should be invalid", validator.isValidInet6Address("1::2::3")); assertFalse("IPV6 1:::3:4:5 should be invalid", validator.isValidInet6Address("1:::3:4:5")); assertFalse("IPV6 1:2:3::4:5:6:7:8:9 should be invalid", validator.isValidInet6Address("1:2:3::4:5:6:7:8:9")); - assertTrue("IPV6 1111:2222:3333:4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888")); - assertTrue("IPV6 1111:2222:3333:4444:5555:6666:7777:: should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777::")); - assertTrue("IPV6 1111:2222:3333:4444:5555:6666:: should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::")); - assertTrue("IPV6 1111:2222:3333:4444:5555:: should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555::")); - assertTrue("IPV6 1111:2222:3333:4444:: should be valid", validator.isValidInet6Address("1111:2222:3333:4444::")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:6666:7777:: should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777::")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:6666:: should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:: should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::")); + assertTrue( + "IPV6 1111:2222:3333:4444:: should be valid", validator.isValidInet6Address("1111:2222:3333:4444::")); assertTrue("IPV6 1111:2222:3333:: should be valid", validator.isValidInet6Address("1111:2222:3333::")); assertTrue("IPV6 1111:2222:: should be valid", validator.isValidInet6Address("1111:2222::")); assertTrue("IPV6 1111:: should be valid", validator.isValidInet6Address("1111::")); - assertTrue("IPV6 1111:2222:3333:4444:5555:6666::8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::8888")); - assertTrue("IPV6 1111:2222:3333:4444:5555::8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555::8888")); - assertTrue("IPV6 1111:2222:3333:4444::8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444::8888")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:6666::8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::8888")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555::8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::8888")); + assertTrue( + "IPV6 1111:2222:3333:4444::8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444::8888")); assertTrue("IPV6 1111:2222:3333::8888 should be valid", validator.isValidInet6Address("1111:2222:3333::8888")); assertTrue("IPV6 1111:2222::8888 should be valid", validator.isValidInet6Address("1111:2222::8888")); assertTrue("IPV6 1111::8888 should be valid", validator.isValidInet6Address("1111::8888")); assertTrue("IPV6 ::8888 should be valid", validator.isValidInet6Address("::8888")); - assertTrue("IPV6 1111:2222:3333:4444:5555::7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555::7777:8888")); - assertTrue("IPV6 1111:2222:3333:4444::7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444::7777:8888")); - assertTrue("IPV6 1111:2222:3333::7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333::7777:8888")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555::7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::7777:8888")); + assertTrue( + "IPV6 1111:2222:3333:4444::7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444::7777:8888")); + assertTrue( + "IPV6 1111:2222:3333::7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333::7777:8888")); assertTrue("IPV6 1111:2222::7777:8888 should be valid", validator.isValidInet6Address("1111:2222::7777:8888")); assertTrue("IPV6 1111::7777:8888 should be valid", validator.isValidInet6Address("1111::7777:8888")); assertTrue("IPV6 ::7777:8888 should be valid", validator.isValidInet6Address("::7777:8888")); - assertTrue("IPV6 1111:2222:3333:4444::6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333:4444::6666:7777:8888")); - assertTrue("IPV6 1111:2222:3333::6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333::6666:7777:8888")); - assertTrue("IPV6 1111:2222::6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222::6666:7777:8888")); + assertTrue( + "IPV6 1111:2222:3333:4444::6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444::6666:7777:8888")); + assertTrue( + "IPV6 1111:2222:3333::6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333::6666:7777:8888")); + assertTrue( + "IPV6 1111:2222::6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222::6666:7777:8888")); assertTrue("IPV6 1111::6666:7777:8888 should be valid", validator.isValidInet6Address("1111::6666:7777:8888")); assertTrue("IPV6 ::6666:7777:8888 should be valid", validator.isValidInet6Address("::6666:7777:8888")); - assertTrue("IPV6 1111:2222:3333::5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222:3333::5555:6666:7777:8888")); - assertTrue("IPV6 1111:2222::5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222::5555:6666:7777:8888")); - assertTrue("IPV6 1111::5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111::5555:6666:7777:8888")); - assertTrue("IPV6 ::5555:6666:7777:8888 should be valid", validator.isValidInet6Address("::5555:6666:7777:8888")); - assertTrue("IPV6 1111:2222::4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111:2222::4444:5555:6666:7777:8888")); - assertTrue("IPV6 1111::4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111::4444:5555:6666:7777:8888")); - assertTrue("IPV6 ::4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("::4444:5555:6666:7777:8888")); - assertTrue("IPV6 1111::3333:4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("1111::3333:4444:5555:6666:7777:8888")); - assertTrue("IPV6 ::3333:4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("::3333:4444:5555:6666:7777:8888")); - assertTrue("IPV6 ::2222:3333:4444:5555:6666:7777:8888 should be valid", validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888")); - assertTrue("IPV6 1111:2222:3333:4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:123.123.123.123")); - assertTrue("IPV6 1111:2222:3333:4444:5555::123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333:4444:5555::123.123.123.123")); - assertTrue("IPV6 1111:2222:3333:4444::123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333:4444::123.123.123.123")); - assertTrue("IPV6 1111:2222:3333::123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333::123.123.123.123")); - assertTrue("IPV6 1111:2222::123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222::123.123.123.123")); - assertTrue("IPV6 1111::123.123.123.123 should be valid", validator.isValidInet6Address("1111::123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333::5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222:3333::5555:6666:7777:8888")); + assertTrue( + "IPV6 1111:2222::5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222::5555:6666:7777:8888")); + assertTrue( + "IPV6 1111::5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111::5555:6666:7777:8888")); + assertTrue( + "IPV6 ::5555:6666:7777:8888 should be valid", validator.isValidInet6Address("::5555:6666:7777:8888")); + assertTrue( + "IPV6 1111:2222::4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111:2222::4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 1111::4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111::4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 ::4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("::4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 1111::3333:4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("1111::3333:4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 ::3333:4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("::3333:4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 ::2222:3333:4444:5555:6666:7777:8888 should be valid", + validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333:4444:5555::123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333:4444::123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444::123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333::123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333::123.123.123.123")); + assertTrue( + "IPV6 1111:2222::123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222::123.123.123.123")); + assertTrue( + "IPV6 1111::123.123.123.123 should be valid", validator.isValidInet6Address("1111::123.123.123.123")); assertTrue("IPV6 ::123.123.123.123 should be valid", validator.isValidInet6Address("::123.123.123.123")); - assertTrue("IPV6 1111:2222:3333:4444::6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333:4444::6666:123.123.123.123")); - assertTrue("IPV6 1111:2222:3333::6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333::6666:123.123.123.123")); - assertTrue("IPV6 1111:2222::6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222::6666:123.123.123.123")); - assertTrue("IPV6 1111::6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111::6666:123.123.123.123")); - assertTrue("IPV6 ::6666:123.123.123.123 should be valid", validator.isValidInet6Address("::6666:123.123.123.123")); - assertTrue("IPV6 1111:2222:3333::5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222:3333::5555:6666:123.123.123.123")); - assertTrue("IPV6 1111:2222::5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222::5555:6666:123.123.123.123")); - assertTrue("IPV6 1111::5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111::5555:6666:123.123.123.123")); - assertTrue("IPV6 ::5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("::5555:6666:123.123.123.123")); - assertTrue("IPV6 1111:2222::4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111:2222::4444:5555:6666:123.123.123.123")); - assertTrue("IPV6 1111::4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111::4444:5555:6666:123.123.123.123")); - assertTrue("IPV6 ::4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("::4444:5555:6666:123.123.123.123")); - assertTrue("IPV6 1111::3333:4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("1111::3333:4444:5555:6666:123.123.123.123")); - assertTrue("IPV6 ::2222:3333:4444:5555:6666:123.123.123.123 should be valid", validator.isValidInet6Address("::2222:3333:4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333:4444::6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333:4444::6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333::6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333::6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222::6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222::6666:123.123.123.123")); + assertTrue( + "IPV6 1111::6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111::6666:123.123.123.123")); + assertTrue( + "IPV6 ::6666:123.123.123.123 should be valid", validator.isValidInet6Address("::6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222:3333::5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222:3333::5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222::5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222::5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111::5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111::5555:6666:123.123.123.123")); + assertTrue( + "IPV6 ::5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("::5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111:2222::4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111:2222::4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111::4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111::4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 ::4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("::4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 1111::3333:4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("1111::3333:4444:5555:6666:123.123.123.123")); + assertTrue( + "IPV6 ::2222:3333:4444:5555:6666:123.123.123.123 should be valid", + validator.isValidInet6Address("::2222:3333:4444:5555:6666:123.123.123.123")); // Trying combinations of "0" and "::" // These are all syntactically correct, but are bad form // because "0" adjacent to "::" should be combined into "::" @@ -417,124 +624,302 @@ public void testIPv6() { assertTrue("IPV6 0:0:: should be valid", validator.isValidInet6Address("0:0::")); assertTrue("IPV6 0:: should be valid", validator.isValidInet6Address("0::")); // Invalid data - assertFalse("IPV6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX should be invalid", validator.isValidInet6Address("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); + assertFalse( + "IPV6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX should be invalid", + validator.isValidInet6Address("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); // Too many components - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777:8888:9999 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:9999")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777:8888:: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888::")); - assertFalse("IPV6 ::2222:3333:4444:5555:6666:7777:8888:9999 should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888:9999")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777:8888:9999 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:9999")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777:8888:: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888::")); + assertFalse( + "IPV6 ::2222:3333:4444:5555:6666:7777:8888:9999 should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888:9999")); // Too few components - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666")); - assertFalse("IPV6 1111:2222:3333:4444:5555 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555")); assertFalse("IPV6 1111:2222:3333:4444 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444")); assertFalse("IPV6 1111:2222:3333 should be invalid", validator.isValidInet6Address("1111:2222:3333")); assertFalse("IPV6 1111:2222 should be invalid", validator.isValidInet6Address("1111:2222")); assertFalse("IPV6 1111 should be invalid", validator.isValidInet6Address("1111")); // Missing : - assertFalse("IPV6 11112222:3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("11112222:3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:22223333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:22223333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:33334444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:33334444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:44445555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:44445555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:55556666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:55556666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:5555:66667777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:66667777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:77778888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:77778888")); + assertFalse( + "IPV6 11112222:3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("11112222:3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:22223333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:22223333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:33334444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:33334444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:44445555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:44445555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:55556666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:55556666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:66667777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:66667777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:77778888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:77778888")); // Missing : intended for :: - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:")); - assertFalse("IPV6 1111:2222:3333:4444:5555: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:")); - assertFalse("IPV6 1111:2222:3333:4444: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:")); + assertFalse( + "IPV6 1111:2222:3333:4444: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:")); assertFalse("IPV6 1111:2222:3333: should be invalid", validator.isValidInet6Address("1111:2222:3333:")); assertFalse("IPV6 1111:2222: should be invalid", validator.isValidInet6Address("1111:2222:")); assertFalse("IPV6 :8888 should be invalid", validator.isValidInet6Address(":8888")); assertFalse("IPV6 :7777:8888 should be invalid", validator.isValidInet6Address(":7777:8888")); assertFalse("IPV6 :6666:7777:8888 should be invalid", validator.isValidInet6Address(":6666:7777:8888")); - assertFalse("IPV6 :5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":5555:6666:7777:8888")); - assertFalse("IPV6 :4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":4444:5555:6666:7777:8888")); - assertFalse("IPV6 :3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 :2222:3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":2222:3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":5555:6666:7777:8888")); + assertFalse( + "IPV6 :4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :2222:3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":2222:3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:7777:8888")); // ::: - assertFalse("IPV6 :::2222:3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":::2222:3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:::3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:::3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:::4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:::4444:5555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:::5555:6666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:::6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:::6666:7777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:5555:::7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:::7777:8888")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:::8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:::8888")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777::: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:::")); + assertFalse( + "IPV6 :::2222:3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":::2222:3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:::3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:::3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:::4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:::4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:::5555:6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:::6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:::6666:7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:::7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:::7777:8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:::8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:::8888")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777::: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:::")); // Double :: - assertFalse("IPV6 ::2222::4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("::2222::4444:5555:6666:7777:8888")); - assertFalse("IPV6 ::2222:3333::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("::2222:3333::5555:6666:7777:8888")); - assertFalse("IPV6 ::2222:3333:4444::6666:7777:8888 should be invalid", validator.isValidInet6Address("::2222:3333:4444::6666:7777:8888")); - assertFalse("IPV6 ::2222:3333:4444:5555::7777:8888 should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555::7777:8888")); - assertFalse("IPV6 ::2222:3333:4444:5555:7777::8888 should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555:7777::8888")); - assertFalse("IPV6 ::2222:3333:4444:5555:7777:8888:: should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555:7777:8888::")); - assertFalse("IPV6 1111::3333::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address("1111::3333::5555:6666:7777:8888")); - assertFalse("IPV6 1111::3333:4444::6666:7777:8888 should be invalid", validator.isValidInet6Address("1111::3333:4444::6666:7777:8888")); - assertFalse("IPV6 1111::3333:4444:5555::7777:8888 should be invalid", validator.isValidInet6Address("1111::3333:4444:5555::7777:8888")); - assertFalse("IPV6 1111::3333:4444:5555:6666::8888 should be invalid", validator.isValidInet6Address("1111::3333:4444:5555:6666::8888")); - assertFalse("IPV6 1111::3333:4444:5555:6666:7777:: should be invalid", validator.isValidInet6Address("1111::3333:4444:5555:6666:7777::")); - assertFalse("IPV6 1111:2222::4444::6666:7777:8888 should be invalid", validator.isValidInet6Address("1111:2222::4444::6666:7777:8888")); - assertFalse("IPV6 1111:2222::4444:5555::7777:8888 should be invalid", validator.isValidInet6Address("1111:2222::4444:5555::7777:8888")); - assertFalse("IPV6 1111:2222::4444:5555:6666::8888 should be invalid", validator.isValidInet6Address("1111:2222::4444:5555:6666::8888")); - assertFalse("IPV6 1111:2222::4444:5555:6666:7777:: should be invalid", validator.isValidInet6Address("1111:2222::4444:5555:6666:7777::")); - assertFalse("IPV6 1111:2222:3333::5555::7777:8888 should be invalid", validator.isValidInet6Address("1111:2222:3333::5555::7777:8888")); - assertFalse("IPV6 1111:2222:3333::5555:6666::8888 should be invalid", validator.isValidInet6Address("1111:2222:3333::5555:6666::8888")); - assertFalse("IPV6 1111:2222:3333::5555:6666:7777:: should be invalid", validator.isValidInet6Address("1111:2222:3333::5555:6666:7777::")); - assertFalse("IPV6 1111:2222:3333:4444::6666::8888 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::6666::8888")); - assertFalse("IPV6 1111:2222:3333:4444::6666:7777:: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::6666:7777::")); - assertFalse("IPV6 1111:2222:3333:4444:5555::7777:: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555::7777::")); + assertFalse( + "IPV6 ::2222::4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("::2222::4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 ::2222:3333::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("::2222:3333::5555:6666:7777:8888")); + assertFalse( + "IPV6 ::2222:3333:4444::6666:7777:8888 should be invalid", + validator.isValidInet6Address("::2222:3333:4444::6666:7777:8888")); + assertFalse( + "IPV6 ::2222:3333:4444:5555::7777:8888 should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555::7777:8888")); + assertFalse( + "IPV6 ::2222:3333:4444:5555:7777::8888 should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555:7777::8888")); + assertFalse( + "IPV6 ::2222:3333:4444:5555:7777:8888:: should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555:7777:8888::")); + assertFalse( + "IPV6 1111::3333::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111::3333::5555:6666:7777:8888")); + assertFalse( + "IPV6 1111::3333:4444::6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111::3333:4444::6666:7777:8888")); + assertFalse( + "IPV6 1111::3333:4444:5555::7777:8888 should be invalid", + validator.isValidInet6Address("1111::3333:4444:5555::7777:8888")); + assertFalse( + "IPV6 1111::3333:4444:5555:6666::8888 should be invalid", + validator.isValidInet6Address("1111::3333:4444:5555:6666::8888")); + assertFalse( + "IPV6 1111::3333:4444:5555:6666:7777:: should be invalid", + validator.isValidInet6Address("1111::3333:4444:5555:6666:7777::")); + assertFalse( + "IPV6 1111:2222::4444::6666:7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222::4444::6666:7777:8888")); + assertFalse( + "IPV6 1111:2222::4444:5555::7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222::4444:5555::7777:8888")); + assertFalse( + "IPV6 1111:2222::4444:5555:6666::8888 should be invalid", + validator.isValidInet6Address("1111:2222::4444:5555:6666::8888")); + assertFalse( + "IPV6 1111:2222::4444:5555:6666:7777:: should be invalid", + validator.isValidInet6Address("1111:2222::4444:5555:6666:7777::")); + assertFalse( + "IPV6 1111:2222:3333::5555::7777:8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333::5555::7777:8888")); + assertFalse( + "IPV6 1111:2222:3333::5555:6666::8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333::5555:6666::8888")); + assertFalse( + "IPV6 1111:2222:3333::5555:6666:7777:: should be invalid", + validator.isValidInet6Address("1111:2222:3333::5555:6666:7777::")); + assertFalse( + "IPV6 1111:2222:3333:4444::6666::8888 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::6666::8888")); + assertFalse( + "IPV6 1111:2222:3333:4444::6666:7777:: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::6666:7777::")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555::7777:: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::7777::")); // Too many components" - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666::1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::1.2.3.4")); - assertFalse("IPV6 ::2222:3333:4444:5555:6666:7777:1.2.3.4 should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:1.2.3.4.5 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:1.2.3.4.5")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666::1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::1.2.3.4")); + assertFalse( + "IPV6 ::2222:3333:4444:5555:6666:7777:1.2.3.4 should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:1.2.3.4.5 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:1.2.3.4.5")); // Too few components - assertFalse("IPV6 1111:2222:3333:4444:5555:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:1.2.3.4")); assertFalse("IPV6 1111:2222:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:1.2.3.4")); assertFalse("IPV6 1111:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:1.2.3.4")); assertFalse("IPV6 1.2.3.4 should be invalid", validator.isValidInet6Address("1.2.3.4")); // Missing : - assertFalse("IPV6 11112222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("11112222:3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:22223333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:22223333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:33334444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:33334444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:44445555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:44445555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:55556666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:55556666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:66661.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:66661.2.3.4")); + assertFalse( + "IPV6 11112222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("11112222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:22223333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:22223333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:33334444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:33334444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:44445555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:44445555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:55556666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:55556666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:66661.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:66661.2.3.4")); // Missing . - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:255255.255.255 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255255.255.255")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:255.255255.255 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255.255255.255")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:255.255.255255 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255.255.255255")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:255255.255.255 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255255.255.255")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:255.255255.255 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255.255255.255")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:255.255.255255 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:255.255.255255")); // Missing : intended for :: assertFalse("IPV6 :1.2.3.4 should be invalid", validator.isValidInet6Address(":1.2.3.4")); assertFalse("IPV6 :6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":6666:1.2.3.4")); assertFalse("IPV6 :5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":5555:6666:1.2.3.4")); - assertFalse("IPV6 :4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :2222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":2222:3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :2222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":2222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:1.2.3.4")); // ::: - assertFalse("IPV6 :::2222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::2222:3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:::3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:::3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:::4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:::4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:::5555:6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:::6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:::6666:1.2.3.4")); - assertFalse("IPV6 1111:2222:3333:4444:5555:::1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:::1.2.3.4")); + assertFalse( + "IPV6 :::2222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":::2222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:::3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:::3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:::4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:::4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:::6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:::1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:::1.2.3.4")); // Double :: - assertFalse("IPV6 ::2222::4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("::2222::4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 ::2222:3333::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("::2222:3333::5555:6666:1.2.3.4")); - assertFalse("IPV6 ::2222:3333:4444::6666:1.2.3.4 should be invalid", validator.isValidInet6Address("::2222:3333:4444::6666:1.2.3.4")); - assertFalse("IPV6 ::2222:3333:4444:5555::1.2.3.4 should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555::1.2.3.4")); - assertFalse("IPV6 1111::3333::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111::3333::5555:6666:1.2.3.4")); - assertFalse("IPV6 1111::3333:4444::6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111::3333:4444::6666:1.2.3.4")); - assertFalse("IPV6 1111::3333:4444:5555::1.2.3.4 should be invalid", validator.isValidInet6Address("1111::3333:4444:5555::1.2.3.4")); - assertFalse("IPV6 1111:2222::4444::6666:1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222::4444::6666:1.2.3.4")); - assertFalse("IPV6 1111:2222::4444:5555::1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222::4444:5555::1.2.3.4")); - assertFalse("IPV6 1111:2222:3333::5555::1.2.3.4 should be invalid", validator.isValidInet6Address("1111:2222:3333::5555::1.2.3.4")); + assertFalse( + "IPV6 ::2222::4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("::2222::4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 ::2222:3333::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("::2222:3333::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 ::2222:3333:4444::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("::2222:3333:4444::6666:1.2.3.4")); + assertFalse( + "IPV6 ::2222:3333:4444:5555::1.2.3.4 should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555::1.2.3.4")); + assertFalse( + "IPV6 1111::3333::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111::3333::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 1111::3333:4444::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111::3333:4444::6666:1.2.3.4")); + assertFalse( + "IPV6 1111::3333:4444:5555::1.2.3.4 should be invalid", + validator.isValidInet6Address("1111::3333:4444:5555::1.2.3.4")); + assertFalse( + "IPV6 1111:2222::4444::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222::4444::6666:1.2.3.4")); + assertFalse( + "IPV6 1111:2222::4444:5555::1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222::4444:5555::1.2.3.4")); + assertFalse( + "IPV6 1111:2222:3333::5555::1.2.3.4 should be invalid", + validator.isValidInet6Address("1111:2222:3333::5555::1.2.3.4")); // Missing parts assertFalse("IPV6 ::. should be invalid", validator.isValidInet6Address("::.")); assertFalse("IPV6 ::.. should be invalid", validator.isValidInet6Address("::..")); @@ -549,100 +934,232 @@ public void testIPv6() { assertFalse("IPV6 ::..3.4 should be invalid", validator.isValidInet6Address("::..3.4")); assertFalse("IPV6 ::...4 should be invalid", validator.isValidInet6Address("::...4")); // Extra : in front - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666:7777:: should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:7777::")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666:: should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666::")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:: should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555::")); - assertFalse("IPV6 :1111:2222:3333:4444:: should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666:7777:: should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:7777::")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666:: should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666::")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:: should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555::")); + assertFalse( + "IPV6 :1111:2222:3333:4444:: should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::")); assertFalse("IPV6 :1111:2222:3333:: should be invalid", validator.isValidInet6Address(":1111:2222:3333::")); assertFalse("IPV6 :1111:2222:: should be invalid", validator.isValidInet6Address(":1111:2222::")); assertFalse("IPV6 :1111:: should be invalid", validator.isValidInet6Address(":1111::")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666::8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666::8888")); - assertFalse("IPV6 :1111:2222:3333:4444:5555::8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555::8888")); - assertFalse("IPV6 :1111:2222:3333:4444::8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::8888")); - assertFalse("IPV6 :1111:2222:3333::8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333::8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666::8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666::8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555::8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555::8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444::8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::8888")); + assertFalse( + "IPV6 :1111:2222:3333::8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333::8888")); assertFalse("IPV6 :1111:2222::8888 should be invalid", validator.isValidInet6Address(":1111:2222::8888")); assertFalse("IPV6 :1111::8888 should be invalid", validator.isValidInet6Address(":1111::8888")); assertFalse("IPV6 :::8888 should be invalid", validator.isValidInet6Address(":::8888")); - assertFalse("IPV6 :1111:2222:3333:4444:5555::7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555::7777:8888")); - assertFalse("IPV6 :1111:2222:3333:4444::7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::7777:8888")); - assertFalse("IPV6 :1111:2222:3333::7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333::7777:8888")); - assertFalse("IPV6 :1111:2222::7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222::7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555::7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555::7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444::7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333::7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::7777:8888")); + assertFalse( + "IPV6 :1111:2222::7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222::7777:8888")); assertFalse("IPV6 :1111::7777:8888 should be invalid", validator.isValidInet6Address(":1111::7777:8888")); assertFalse("IPV6 :::7777:8888 should be invalid", validator.isValidInet6Address(":::7777:8888")); - assertFalse("IPV6 :1111:2222:3333:4444::6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::6666:7777:8888")); - assertFalse("IPV6 :1111:2222:3333::6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333::6666:7777:8888")); - assertFalse("IPV6 :1111:2222::6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222::6666:7777:8888")); - assertFalse("IPV6 :1111::6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111::6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444::6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333::6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222::6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222::6666:7777:8888")); + assertFalse( + "IPV6 :1111::6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111::6666:7777:8888")); assertFalse("IPV6 :::6666:7777:8888 should be invalid", validator.isValidInet6Address(":::6666:7777:8888")); - assertFalse("IPV6 :1111:2222:3333::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222:3333::5555:6666:7777:8888")); - assertFalse("IPV6 :1111:2222::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222::5555:6666:7777:8888")); - assertFalse("IPV6 :1111::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111::5555:6666:7777:8888")); - assertFalse("IPV6 :::5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":::5555:6666:7777:8888")); - assertFalse("IPV6 :1111:2222::4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111:2222::4444:5555:6666:7777:8888")); - assertFalse("IPV6 :1111::4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111::4444:5555:6666:7777:8888")); - assertFalse("IPV6 :::4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":::4444:5555:6666:7777:8888")); - assertFalse("IPV6 :1111::3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":1111::3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 :::3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":::3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 :::2222:3333:4444:5555:6666:7777:8888 should be invalid", validator.isValidInet6Address(":::2222:3333:4444:5555:6666:7777:8888")); - assertFalse("IPV6 :1111:2222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333:4444:5555::1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444:5555::1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333:4444::1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333::1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333::1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222::5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111::5555:6666:7777:8888")); + assertFalse( + "IPV6 :::5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":::5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222::4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111:2222::4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111::4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111::4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :::4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":::4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111::3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":1111::3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :::3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":::3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :::2222:3333:4444:5555:6666:7777:8888 should be invalid", + validator.isValidInet6Address(":::2222:3333:4444:5555:6666:7777:8888")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333:4444:5555::1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444:5555::1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333:4444::1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333::1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::1.2.3.4")); assertFalse("IPV6 :1111:2222::1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222::1.2.3.4")); assertFalse("IPV6 :1111::1.2.3.4 should be invalid", validator.isValidInet6Address(":1111::1.2.3.4")); assertFalse("IPV6 :::1.2.3.4 should be invalid", validator.isValidInet6Address(":::1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333:4444::6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333:4444::6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333::6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333::6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222::6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222::6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333:4444::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333:4444::6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222::6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222::6666:1.2.3.4")); assertFalse("IPV6 :1111::6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111::6666:1.2.3.4")); assertFalse("IPV6 :::6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222:3333::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222:3333::5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222::5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111::5555:6666:1.2.3.4")); - assertFalse("IPV6 :::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111:2222::4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111:2222::4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111::4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111::4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :::4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :1111::3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":1111::3333:4444:5555:6666:1.2.3.4")); - assertFalse("IPV6 :::2222:3333:4444:5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::2222:3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222:3333::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222:3333::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111::5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :::5555:6666:1.2.3.4 should be invalid", validator.isValidInet6Address(":::5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111:2222::4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111:2222::4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111::4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111::4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :::4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":::4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :1111::3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":1111::3333:4444:5555:6666:1.2.3.4")); + assertFalse( + "IPV6 :::2222:3333:4444:5555:6666:1.2.3.4 should be invalid", + validator.isValidInet6Address(":::2222:3333:4444:5555:6666:1.2.3.4")); // Extra : at end - assertFalse("IPV6 1111:2222:3333:4444:5555:6666:7777::: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:::")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666::: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:::")); - assertFalse("IPV6 1111:2222:3333:4444:5555::: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:::")); - assertFalse("IPV6 1111:2222:3333:4444::: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:::")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666:7777::: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:7777:::")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666::: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666:::")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555::: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:::")); + assertFalse( + "IPV6 1111:2222:3333:4444::: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:::")); assertFalse("IPV6 1111:2222:3333::: should be invalid", validator.isValidInet6Address("1111:2222:3333:::")); assertFalse("IPV6 1111:2222::: should be invalid", validator.isValidInet6Address("1111:2222:::")); assertFalse("IPV6 1111::: should be invalid", validator.isValidInet6Address("1111:::")); - assertFalse("IPV6 1111:2222:3333:4444:5555:6666::8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::8888:")); - assertFalse("IPV6 1111:2222:3333:4444:5555::8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555::8888:")); - assertFalse("IPV6 1111:2222:3333:4444::8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::8888:")); - assertFalse("IPV6 1111:2222:3333::8888: should be invalid", validator.isValidInet6Address("1111:2222:3333::8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555:6666::8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555:6666::8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555::8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444::8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::8888:")); + assertFalse( + "IPV6 1111:2222:3333::8888: should be invalid", validator.isValidInet6Address("1111:2222:3333::8888:")); assertFalse("IPV6 1111:2222::8888: should be invalid", validator.isValidInet6Address("1111:2222::8888:")); assertFalse("IPV6 1111::8888: should be invalid", validator.isValidInet6Address("1111::8888:")); assertFalse("IPV6 ::8888: should be invalid", validator.isValidInet6Address("::8888:")); - assertFalse("IPV6 1111:2222:3333:4444:5555::7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444:5555::7777:8888:")); - assertFalse("IPV6 1111:2222:3333:4444::7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::7777:8888:")); - assertFalse("IPV6 1111:2222:3333::7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333::7777:8888:")); - assertFalse("IPV6 1111:2222::7777:8888: should be invalid", validator.isValidInet6Address("1111:2222::7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444:5555::7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444:5555::7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444::7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333::7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333::7777:8888:")); + assertFalse( + "IPV6 1111:2222::7777:8888: should be invalid", validator.isValidInet6Address("1111:2222::7777:8888:")); assertFalse("IPV6 1111::7777:8888: should be invalid", validator.isValidInet6Address("1111::7777:8888:")); assertFalse("IPV6 ::7777:8888: should be invalid", validator.isValidInet6Address("::7777:8888:")); - assertFalse("IPV6 1111:2222:3333:4444::6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333:4444::6666:7777:8888:")); - assertFalse("IPV6 1111:2222:3333::6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333::6666:7777:8888:")); - assertFalse("IPV6 1111:2222::6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222::6666:7777:8888:")); - assertFalse("IPV6 1111::6666:7777:8888: should be invalid", validator.isValidInet6Address("1111::6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333:4444::6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333:4444::6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333::6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333::6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222::6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222::6666:7777:8888:")); + assertFalse( + "IPV6 1111::6666:7777:8888: should be invalid", validator.isValidInet6Address("1111::6666:7777:8888:")); assertFalse("IPV6 ::6666:7777:8888: should be invalid", validator.isValidInet6Address("::6666:7777:8888:")); - assertFalse("IPV6 1111:2222:3333::5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222:3333::5555:6666:7777:8888:")); - assertFalse("IPV6 1111:2222::5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222::5555:6666:7777:8888:")); - assertFalse("IPV6 1111::5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111::5555:6666:7777:8888:")); - assertFalse("IPV6 ::5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("::5555:6666:7777:8888:")); - assertFalse("IPV6 1111:2222::4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111:2222::4444:5555:6666:7777:8888:")); - assertFalse("IPV6 1111::4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111::4444:5555:6666:7777:8888:")); - assertFalse("IPV6 ::4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("::4444:5555:6666:7777:8888:")); - assertFalse("IPV6 1111::3333:4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("1111::3333:4444:5555:6666:7777:8888:")); - assertFalse("IPV6 ::3333:4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("::3333:4444:5555:6666:7777:8888:")); - assertFalse("IPV6 ::2222:3333:4444:5555:6666:7777:8888: should be invalid", validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222:3333::5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222:3333::5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222::5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222::5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111::5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111::5555:6666:7777:8888:")); + assertFalse( + "IPV6 ::5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("::5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111:2222::4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111:2222::4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111::4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111::4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 ::4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("::4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 1111::3333:4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("1111::3333:4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 ::3333:4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("::3333:4444:5555:6666:7777:8888:")); + assertFalse( + "IPV6 ::2222:3333:4444:5555:6666:7777:8888: should be invalid", + validator.isValidInet6Address("::2222:3333:4444:5555:6666:7777:8888:")); assertTrue("IPV6 0:a:b:c:d:e:f:: should be valid", validator.isValidInet6Address("0:a:b:c:d:e:f::")); - assertTrue("IPV6 ::0:a:b:c:d:e:f should be valid", validator.isValidInet6Address("::0:a:b:c:d:e:f")); // syntactically correct, but bad form (::0:... could be combined) + assertTrue( + "IPV6 ::0:a:b:c:d:e:f should be valid", + validator.isValidInet6Address( + "::0:a:b:c:d:e:f")); // syntactically correct, but bad form (::0:... could be combined) assertTrue("IPV6 a:b:c:d:e:f:0:: should be valid", validator.isValidInet6Address("a:b:c:d:e:f:0::")); assertFalse("IPV6 ':10.0.0.1 should be invalid", validator.isValidInet6Address("':10.0.0.1")); } diff --git a/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidatorTest.java b/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidatorTest.java index 7f2475141..9548bde58 100644 --- a/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidatorTest.java +++ b/src/test/java/org/jenkinsci/remoting/org/apache/commons/validator/routines/RegexValidatorTest.java @@ -30,15 +30,17 @@ */ public class RegexValidatorTest extends TestCase { - private static final String REGEX = "^([abc]*)(?:\\-)([DEF]*)(?:\\-)([123]*)$"; + private static final String REGEX = "^([abc]*)(?:\\-)([DEF]*)(?:\\-)([123]*)$"; private static final String COMPONENT_1 = "([abc]{3})"; private static final String COMPONENT_2 = "([DEF]{3})"; private static final String COMPONENT_3 = "([123]{3})"; - private static final String SEPARATOR_1 = "(?:\\-)"; - private static final String SEPARATOR_2 = "(?:\\s)"; - private static final String REGEX_1 = "^" + COMPONENT_1 + SEPARATOR_1 + COMPONENT_2 + SEPARATOR_1 + COMPONENT_3 + "$"; - private static final String REGEX_2 = "^" + COMPONENT_1 + SEPARATOR_2 + COMPONENT_2 + SEPARATOR_2 + COMPONENT_3 + "$"; + private static final String SEPARATOR_1 = "(?:\\-)"; + private static final String SEPARATOR_2 = "(?:\\s)"; + private static final String REGEX_1 = + "^" + COMPONENT_1 + SEPARATOR_1 + COMPONENT_2 + SEPARATOR_1 + COMPONENT_3 + "$"; + private static final String REGEX_2 = + "^" + COMPONENT_1 + SEPARATOR_2 + COMPONENT_2 + SEPARATOR_2 + COMPONENT_3 + "$"; private static final String REGEX_3 = "^" + COMPONENT_1 + COMPONENT_2 + COMPONENT_3 + "$"; private static final String[] MULTIPLE_REGEX = new String[] {REGEX_1, REGEX_2, REGEX_3}; @@ -54,7 +56,7 @@ public RegexValidatorTest(String name) { * Test instance methods with single regular expression. */ public void testSingle() { - RegexValidator sensitive = new RegexValidator(REGEX); + RegexValidator sensitive = new RegexValidator(REGEX); RegexValidator insensitive = new RegexValidator(REGEX, false); // isValid() @@ -64,16 +66,16 @@ public void testSingle() { assertFalse("Insensitive isValid() invalid", insensitive.isValid("ABd-de-1")); // validate() - assertEquals("Sensitive validate() valid", "acDE1", sensitive.validate("ac-DE-1")); + assertEquals("Sensitive validate() valid", "acDE1", sensitive.validate("ac-DE-1")); assertNull("Sensitive validate() invalid", sensitive.validate("AB-de-1")); - assertEquals("Insensitive validate() valid", "ABde1", insensitive.validate("AB-de-1")); + assertEquals("Insensitive validate() valid", "ABde1", insensitive.validate("AB-de-1")); assertNull("Insensitive validate() invalid", insensitive.validate("ABd-de-1")); // match() - checkArray("Sensitive match() valid", new String[] {"ac", "DE", "1"}, sensitive.match("ac-DE-1")); - checkArray("Sensitive match() invalid", null, sensitive.match("AB-de-1")); - checkArray("Insensitive match() valid", new String[] {"AB", "de", "1"}, insensitive.match("AB-de-1")); - checkArray("Insensitive match() invalid", null, insensitive.match("ABd-de-1")); + checkArray("Sensitive match() valid", new String[] {"ac", "DE", "1"}, sensitive.match("ac-DE-1")); + checkArray("Sensitive match() invalid", null, sensitive.match("AB-de-1")); + checkArray("Insensitive match() valid", new String[] {"AB", "de", "1"}, insensitive.match("AB-de-1")); + checkArray("Insensitive match() invalid", null, insensitive.match("ABd-de-1")); assertEquals("validate one", "ABC", (new RegexValidator("^([A-Z]*)$")).validate("ABC")); checkArray("match one", new String[] {"ABC"}, (new RegexValidator("^([A-Z]*)$")).match("ABC")); } @@ -84,10 +86,10 @@ public void testSingle() { public void testMultipleSensitive() { // ------------ Set up Sensitive Validators - RegexValidator multiple = new RegexValidator(MULTIPLE_REGEX); - RegexValidator single1 = new RegexValidator(REGEX_1); - RegexValidator single2 = new RegexValidator(REGEX_2); - RegexValidator single3 = new RegexValidator(REGEX_3); + RegexValidator multiple = new RegexValidator(MULTIPLE_REGEX); + RegexValidator single1 = new RegexValidator(REGEX_1); + RegexValidator single2 = new RegexValidator(REGEX_2); + RegexValidator single3 = new RegexValidator(REGEX_3); // ------------ Set up test values String value = "aac FDE 321"; @@ -103,14 +105,14 @@ public void testMultipleSensitive() { // validate() assertEquals("Sensitive validate() Multiple", expect, multiple.validate(value)); assertNull("Sensitive validate() 1st", single1.validate(value)); - assertEquals("Sensitive validate() 2nd", expect, single2.validate(value)); + assertEquals("Sensitive validate() 2nd", expect, single2.validate(value)); assertNull("Sensitive validate() 3rd", single3.validate(value)); // match() checkArray("Sensitive match() Multiple", array, multiple.match(value)); - checkArray("Sensitive match() 1st", null, single1.match(value)); - checkArray("Sensitive match() 2nd", array, single2.match(value)); - checkArray("Sensitive match() 3rd", null, single3.match(value)); + checkArray("Sensitive match() 1st", null, single1.match(value)); + checkArray("Sensitive match() 2nd", array, single2.match(value)); + checkArray("Sensitive match() 3rd", null, single3.match(value)); // All invalid value = "AAC*FDE*321"; @@ -126,9 +128,9 @@ public void testMultipleInsensitive() { // ------------ Set up In-sensitive Validators RegexValidator multiple = new RegexValidator(MULTIPLE_REGEX, false); - RegexValidator single1 = new RegexValidator(REGEX_1, false); - RegexValidator single2 = new RegexValidator(REGEX_2, false); - RegexValidator single3 = new RegexValidator(REGEX_3, false); + RegexValidator single1 = new RegexValidator(REGEX_1, false); + RegexValidator single2 = new RegexValidator(REGEX_2, false); + RegexValidator single3 = new RegexValidator(REGEX_3, false); // ------------ Set up test values String value = "AAC FDE 321"; @@ -144,14 +146,14 @@ public void testMultipleInsensitive() { // validate() assertEquals("validate() Multiple", expect, multiple.validate(value)); assertNull("validate() 1st", single1.validate(value)); - assertEquals("validate() 2nd", expect, single2.validate(value)); + assertEquals("validate() 2nd", expect, single2.validate(value)); assertNull("validate() 3rd", single3.validate(value)); // match() checkArray("match() Multiple", array, multiple.match(value)); - checkArray("match() 1st", null, single1.match(value)); - checkArray("match() 2nd", array, single2.match(value)); - checkArray("match() 3rd", null, single3.match(value)); + checkArray("match() 1st", null, single1.match(value)); + checkArray("match() 2nd", array, single2.match(value)); + checkArray("match() 3rd", null, single3.match(value)); // All invalid value = "AAC*FDE*321"; @@ -178,45 +180,57 @@ public void testMissingRegex() { // Single Regular Expression - null { - final IllegalArgumentException e = assertThrows("Single Null - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator((String) null)); + final IllegalArgumentException e = assertThrows( + "Single Null - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator((String) null)); assertEquals("Single Null", "Regular expression[0] is missing", e.getMessage()); } // Single Regular Expression - Zero Length { - final IllegalArgumentException e = assertThrows("Single Zero Length - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator("")); + final IllegalArgumentException e = assertThrows( + "Single Zero Length - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator("")); assertEquals("Single Zero Length", "Regular expression[0] is missing", e.getMessage()); } // Multiple Regular Expression - Null array { - final IllegalArgumentException e = assertThrows("Null Array - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator((String[]) null)); + final IllegalArgumentException e = assertThrows( + "Null Array - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator((String[]) null)); assertEquals("Null Array", "Regular expressions are missing", e.getMessage()); } // Multiple Regular Expression - Zero Length array { - final IllegalArgumentException e = assertThrows("Zero Length Array - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator(new String[0])); + final IllegalArgumentException e = assertThrows( + "Zero Length Array - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator(new String[0])); assertEquals("Zero Length Array", "Regular expressions are missing", e.getMessage()); } // Multiple Regular Expression - Array has Null { String[] expressions = new String[] {"ABC", null}; - final IllegalArgumentException e = assertThrows("Array has Null - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator(expressions)); + final IllegalArgumentException e = assertThrows( + "Array has Null - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator(expressions)); assertEquals("Array has Null", "Regular expression[1] is missing", e.getMessage()); } // Multiple Regular Expression - Array has Zero Length { String[] expressions = new String[] {"", "ABC"}; - final IllegalArgumentException e = assertThrows("Array has Zero Length - expected IllegalArgumentException", - IllegalArgumentException.class, () -> new RegexValidator(expressions)); + final IllegalArgumentException e = assertThrows( + "Array has Zero Length - expected IllegalArgumentException", + IllegalArgumentException.class, + () -> new RegexValidator(expressions)); assertEquals("Array has Zero Length", "Regular expression[0] is missing", e.getMessage()); } } @@ -268,5 +282,4 @@ private void checkArray(String label, String[] expect, String[] result) { assertEquals(label + " value[" + i + "]", expect[i], result[i]); } } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcher.java b/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcher.java index dcbd54587..4533e701f 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcher.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcher.java @@ -68,6 +68,7 @@ public abstract class IOBufferMatcher { * A name to differentiate multiple instances. */ private final String name; + private final ByteArrayOutputStream recv = new ByteArrayOutputStream(); private final WritableByteChannel channel = Channels.newChannel(recv); private final CompletableFuture closed = new CompletableFuture<>(); @@ -136,7 +137,7 @@ public void close() throws IOException { public void receive(@NonNull ByteBuffer data) { int r = data.remaining(); if (name != null) { - LOGGER.log(Level.INFO, "[{0}] Receiving {1} bytes", new Object[]{name, r}); + LOGGER.log(Level.INFO, "[{0}] Receiving {1} bytes", new Object[] {name, r}); } try { channel.write(data); @@ -151,7 +152,7 @@ public void receive(@NonNull ByteBuffer data) { // ignore } if (name != null) { - LOGGER.log(Level.INFO, "[{0}] Received {1} bytes: «{2}»", new Object[]{name, r - data.remaining(), this}); + LOGGER.log(Level.INFO, "[{0}] Received {1} bytes: «{2}»", new Object[] {name, r - data.remaining(), this}); } } @@ -165,9 +166,7 @@ public String asString() { @Override public String toString() { - return "SimpleBufferReceiver{" + "name='" + name + '\'' + - ", content='" + asString() + '\'' + - '}'; + return "SimpleBufferReceiver{" + "name='" + name + '\'' + ", content='" + asString() + '\'' + '}'; } /** @@ -225,7 +224,6 @@ public void awaitStringContent(Matcher matcher) throws InterruptedExcept } finally { state.unlock(); } - } public boolean awaitStringContent(Matcher matcher, long timeout, TimeUnit unit) @@ -255,11 +253,9 @@ public void awaitByteContent(Matcher matcher) throws InterruptedExceptio } finally { state.unlock(); } - } - public boolean awaitByteContent(Matcher matcher, long timeout, TimeUnit unit) - throws InterruptedException { + public boolean awaitByteContent(Matcher matcher, long timeout, TimeUnit unit) throws InterruptedException { long giveUp = System.nanoTime() + unit.toNanos(timeout); state.lock(); try { @@ -275,5 +271,4 @@ public boolean awaitByteContent(Matcher matcher, long timeout, TimeUnit state.unlock(); } } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcherLayer.java b/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcherLayer.java index 47afd6571..5794285fd 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcherLayer.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/IOBufferMatcherLayer.java @@ -57,13 +57,11 @@ public void close(IOException cause) throws IOException { doCloseWrite(); super.close(cause); } - }; } @Override - public void start() { - } + public void start() {} @Override public IOBufferMatcher get() { diff --git a/src/test/java/org/jenkinsci/remoting/protocol/IOHubRule.java b/src/test/java/org/jenkinsci/remoting/protocol/IOHubRule.java index 4ffad9775..41faf56bc 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/IOHubRule.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/IOHubRule.java @@ -82,22 +82,23 @@ public IOHub hub() { @Override public Statement apply(final Statement base, final Description description) { Skip skip = description.getAnnotation(Skip.class); - if (skip != null && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { + if (skip != null + && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { return base; } final AtomicInteger counter = new AtomicInteger(); return new Statement() { @Override public void evaluate() throws Throwable { - executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2 - 1, + executorService = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors() * 2 - 1, r -> new Thread( r, String.format( "%s%s-%d", description.getDisplayName(), id == null || id.isEmpty() ? "" : "-" + id, - counter.incrementAndGet()) - )); + counter.incrementAndGet()))); selector = IOHub.create(executorService); try { base.evaluate(); diff --git a/src/test/java/org/jenkinsci/remoting/protocol/IOHubTest.java b/src/test/java/org/jenkinsci/remoting/protocol/IOHubTest.java index 4dc247613..8aee6b7b2 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/IOHubTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/IOHubTest.java @@ -52,7 +52,6 @@ public class IOHubTest { - @Rule public IOHubRule hub = new IOHubRule(); @@ -100,40 +99,45 @@ public void canAcceptSocketConnections() throws Exception { final AtomicReference key = new AtomicReference<>(); final AtomicBoolean oops = new AtomicBoolean(false); IOHub h = hub.hub(); - h.register(srv, new IOHubReadyListener() { + h.register( + srv, + new IOHubReadyListener() { - final AtomicInteger count = new AtomicInteger(0); + final AtomicInteger count = new AtomicInteger(0); - @Override - public void ready(boolean accept, boolean connect, boolean read, boolean write) { - if (accept) { - try { - SocketChannel channel = srv.accept(); - channel.write(ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) - .getBytes(StandardCharsets.UTF_8))); - channel.close(); - } catch (IOException e) { - // ignore + @Override + public void ready(boolean accept, boolean connect, boolean read, boolean write) { + if (accept) { + try { + SocketChannel channel = srv.accept(); + channel.write(ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) + .getBytes(StandardCharsets.UTF_8))); + channel.close(); + } catch (IOException e) { + // ignore + } + h.addInterestAccept(key.get()); + } else { + oops.set(true); + } + if (connect || read || write) { + oops.set(true); + } + } + }, + true, + false, + false, + false, + new IOHubRegistrationCallback() { + @Override + public void onRegistered(SelectionKey selectionKey) { + key.set(selectionKey); } - h.addInterestAccept(key.get()); - } else { - oops.set(true); - } - if (connect || read || write) { - oops.set(true); - } - } - }, true, false, false, false, new IOHubRegistrationCallback() { - @Override - public void onRegistered(SelectionKey selectionKey) { - key.set(selectionKey); - } - - @Override - public void onClosedChannel(ClosedChannelException e) { - } - }); + @Override + public void onClosedChannel(ClosedChannelException e) {} + }); Socket client = new Socket(); client.connect(srv.getLocalAddress(), 100); assertThat(IOUtils.toString(client.getInputStream(), StandardCharsets.UTF_8), is("Go away #1")); @@ -152,39 +156,46 @@ public void afterReadyInterestIsCleared() throws Exception { srv.configureBlocking(false); final AtomicReference key = new AtomicReference<>(); final AtomicBoolean oops = new AtomicBoolean(false); - hub.hub().register(srv, new IOHubReadyListener() { + hub.hub() + .register( + srv, + new IOHubReadyListener() { - final AtomicInteger count = new AtomicInteger(0); + final AtomicInteger count = new AtomicInteger(0); - @Override - public void ready(boolean accept, boolean connect, boolean read, boolean write) { - if (accept) { - try { - SocketChannel channel = srv.accept(); - channel.write(ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) - .getBytes(StandardCharsets.UTF_8))); - channel.close(); - } catch (IOException e) { - // ignore - } - } else { - oops.set(true); - } - if (connect || read || write) { - oops.set(true); - } - } - }, true, false, false, false, new IOHubRegistrationCallback() { - @Override - public void onRegistered(SelectionKey selectionKey) { - key.set(selectionKey); - } + @Override + public void ready(boolean accept, boolean connect, boolean read, boolean write) { + if (accept) { + try { + SocketChannel channel = srv.accept(); + channel.write( + ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) + .getBytes(StandardCharsets.UTF_8))); + channel.close(); + } catch (IOException e) { + // ignore + } + } else { + oops.set(true); + } + if (connect || read || write) { + oops.set(true); + } + } + }, + true, + false, + false, + false, + new IOHubRegistrationCallback() { + @Override + public void onRegistered(SelectionKey selectionKey) { + key.set(selectionKey); + } - @Override - public void onClosedChannel(ClosedChannelException e) { - - } - }); + @Override + public void onClosedChannel(ClosedChannelException e) {} + }); try (Socket client = new Socket()) { client.setSoTimeout(100); client.connect(srv.getLocalAddress(), 100); @@ -194,8 +205,10 @@ public void onClosedChannel(ClosedChannelException e) { client.setSoTimeout(100); client.connect(srv.getLocalAddress(), 100); - final SocketTimeoutException e = assertThrows(SocketTimeoutException.class, - () -> assertThat(IOUtils.toString(client.getInputStream(), StandardCharsets.UTF_8), is("Go away #2"))); + final SocketTimeoutException e = assertThrows( + SocketTimeoutException.class, + () -> assertThat( + IOUtils.toString(client.getInputStream(), StandardCharsets.UTF_8), is("Go away #2"))); assertThat(e.getMessage(), containsString("timed out")); hub.hub().addInterestAccept(key.get()); @@ -204,7 +217,8 @@ public void onClosedChannel(ClosedChannelException e) { } } - @Ignore("TODO flakes: Read timed out; or expected java.net.SocketTimeoutException to be thrown, but nothing was thrown") + @Ignore( + "TODO flakes: Read timed out; or expected java.net.SocketTimeoutException to be thrown, but nothing was thrown") @Test public void noReadyCallbackIfInterestRemoved() throws Exception { final ServerSocketChannel srv = ServerSocketChannel.open(); @@ -213,40 +227,45 @@ public void noReadyCallbackIfInterestRemoved() throws Exception { final AtomicReference key = new AtomicReference<>(); final AtomicBoolean oops = new AtomicBoolean(false); IOHub h = hub.hub(); - h.register(srv, new IOHubReadyListener() { + h.register( + srv, + new IOHubReadyListener() { - final AtomicInteger count = new AtomicInteger(0); + final AtomicInteger count = new AtomicInteger(0); - @Override - public void ready(boolean accept, boolean connect, boolean read, boolean write) { - if (accept) { - try { - SocketChannel channel = srv.accept(); - channel.write(ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) - .getBytes(StandardCharsets.UTF_8))); - channel.close(); - } catch (IOException e) { - // ignore + @Override + public void ready(boolean accept, boolean connect, boolean read, boolean write) { + if (accept) { + try { + SocketChannel channel = srv.accept(); + channel.write(ByteBuffer.wrap(String.format("Go away #%d", count.incrementAndGet()) + .getBytes(StandardCharsets.UTF_8))); + channel.close(); + } catch (IOException e) { + // ignore + } + h.addInterestAccept(key.get()); + } else { + oops.set(true); + } + if (connect || read || write) { + oops.set(true); + } + } + }, + true, + false, + false, + false, + new IOHubRegistrationCallback() { + @Override + public void onRegistered(SelectionKey selectionKey) { + key.set(selectionKey); } - h.addInterestAccept(key.get()); - } else { - oops.set(true); - } - if (connect || read || write) { - oops.set(true); - } - } - }, true, false, false, false, new IOHubRegistrationCallback() { - @Override - public void onRegistered(SelectionKey selectionKey) { - key.set(selectionKey); - } - - @Override - public void onClosedChannel(ClosedChannelException e) { - } - }); + @Override + public void onClosedChannel(ClosedChannelException e) {} + }); // Wait for registration, in other case we get unpredictable timing related results due to late registration while (key.get() == null) { @@ -267,8 +286,10 @@ public void onClosedChannel(ClosedChannelException e) { client.setSoTimeout(100); client.connect(srv.getLocalAddress(), 100); - final SocketTimeoutException e = assertThrows(SocketTimeoutException.class, - () -> assertThat(IOUtils.toString(client.getInputStream(), StandardCharsets.UTF_8), is("Go away #2"))); + final SocketTimeoutException e = assertThrows( + SocketTimeoutException.class, + () -> assertThat( + IOUtils.toString(client.getInputStream(), StandardCharsets.UTF_8), is("Go away #2"))); assertThat(e.getMessage(), containsString("timed out")); h.addInterestAccept(key.get()); diff --git a/src/test/java/org/jenkinsci/remoting/protocol/NetworkLayerFactory.java b/src/test/java/org/jenkinsci/remoting/protocol/NetworkLayerFactory.java index d107a86e1..02955820c 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/NetworkLayerFactory.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/NetworkLayerFactory.java @@ -30,10 +30,9 @@ public interface NetworkLayerFactory { - NetworkLayerFactory[] ALL = new NetworkLayerFactory[]{new NIO(), new BIO()}; + NetworkLayerFactory[] ALL = new NetworkLayerFactory[] {new NIO(), new BIO()}; - NetworkLayer create(IOHub selector, ReadableByteChannel in, - WritableByteChannel out); + NetworkLayer create(IOHub selector, ReadableByteChannel in, WritableByteChannel out); class NIO implements NetworkLayerFactory { diff --git a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackImplTest.java b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackImplTest.java index e5a9d7e20..7597ffd4f 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackImplTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackImplTest.java @@ -69,27 +69,30 @@ public class ProtocolStackImplTest { @Rule public IOHubRule selector = new IOHubRule(); + @Rule public TestName name = new TestName(); + private static RSAKeyPairRule keys = new RSAKeyPairRule(); private static X509CertificateRule certificate = X509CertificateRule.selfSigned(keys); - private static SSLContextRule context = new SSLContextRule().as(keys, certificate).trusting(certificate); + private static SSLContextRule context = + new SSLContextRule().as(keys, certificate).trusting(certificate); + @ClassRule - public static RuleChain staticCtx = RuleChain.outerRule(keys) - .around(certificate) - .around(context); + public static RuleChain staticCtx = + RuleChain.outerRule(keys).around(certificate).around(context); + @Rule - public RuleChain ctx = RuleChain.outerRule(new RepeatRule()) - .around(new Timeout(60, TimeUnit.SECONDS)); + public RuleChain ctx = RuleChain.outerRule(new RepeatRule()).around(new Timeout(60, TimeUnit.SECONDS)); @Test public void basicReadthrough() throws Exception { Pipe input = Pipe.open(); Pipe output = Pipe.open(); - ProtocolStack instance = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), input.source(), output.sink())) - .build(new IOBufferMatcherLayer()); + ProtocolStack instance = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), input.source(), output.sink())) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); data.put(expected); @@ -107,9 +110,9 @@ public void basicWritethrough() throws Exception { Pipe input = Pipe.open(); Pipe output = Pipe.open(); - ProtocolStack instance = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), input.source(), output.sink())) - .build(new IOBufferMatcherLayer()); + ProtocolStack instance = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), input.source(), output.sink())) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); data.put(expected); @@ -198,13 +201,13 @@ public void pipeCloseSinkAfterWrite() throws Exception { public void pipeBasicBackToBack() throws Exception { Pipe eastToWest = Pipe.open(); Pipe westToEast = Pipe.open(); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .build(new IOBufferMatcherLayer()); + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .build(new IOBufferMatcherLayer()); - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); data.put(expected); @@ -223,13 +226,13 @@ public void socketBasicBackToBack() throws Exception { SocketChannel westChannel = SocketChannel.open(); westChannel.connect(eastServer.getLocalAddress()); SocketChannel eastChannel = eastServer.accept(); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .build(new IOBufferMatcherLayer()); + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .build(new IOBufferMatcherLayer()); - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westChannel, westChannel)) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westChannel, westChannel)) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); data.put(expected); @@ -245,16 +248,15 @@ public void socketBasicBackToBack() throws Exception { public void pipeBasicBackToBackWithAck() throws Exception { Pipe eastToWest = Pipe.open(); Pipe westToEast = Pipe.open(); - ProtocolStack east = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .filter(new AckFilterLayer()) - .build(new IOBufferMatcherLayer()); + ProtocolStack east = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .filter(new AckFilterLayer()) + .build(new IOBufferMatcherLayer()); - - ProtocolStack west = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .filter(new AckFilterLayer()) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .filter(new AckFilterLayer()) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -274,16 +276,15 @@ public void socketBasicBackToBackWithAck() throws Exception { SocketChannel westChannel = SocketChannel.open(); westChannel.connect(eastServer.getLocalAddress()); SocketChannel eastChannel = eastServer.accept(); - ProtocolStack east = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .filter(new AckFilterLayer()) - .build(new IOBufferMatcherLayer()); - + ProtocolStack east = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .filter(new AckFilterLayer()) + .build(new IOBufferMatcherLayer()); - ProtocolStack west = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), westChannel, westChannel)) - .filter(new AckFilterLayer()) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), westChannel, westChannel)) + .filter(new AckFilterLayer()) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -306,18 +307,17 @@ public void pipeBasicBackToBackWithAckSSLEngine() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .build(new IOBufferMatcherLayer()); + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .build(new IOBufferMatcherLayer()); - - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -343,18 +343,17 @@ public void socketBasicBackToBackWithAckSSLEngine() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .build(new IOBufferMatcherLayer()); - + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westChannel, westChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westChannel, westChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -377,22 +376,19 @@ public void pipeBasicBackToBackWithAckSSLEngineHeaders() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new IOBufferMatcherLayer()); - - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -418,22 +414,19 @@ public void socketBasicBackToBackWithAckSSLEngineHeaders() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new IOBufferMatcherLayer()); - + ProtocolStack east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new IOBufferMatcherLayer()); - ProtocolStack west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westChannel, westChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westChannel, westChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -456,21 +449,19 @@ public void pipeChannelFullProtocolBIO() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack> east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); east.get().get().call(new ProbeCallable()); west.get().get().call(new ProbeCallable()); west.get().get().close(); @@ -490,23 +481,21 @@ public void socketChannelFullProtocolBIO() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack> east = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .named("east") - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> west = - ProtocolStack.on(new BIONetworkLayer(selector.hub(), westChannel, westChannel)) - .named("west") - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> east = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .named("east") + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> west = ProtocolStack.on( + new BIONetworkLayer(selector.hub(), westChannel, westChannel)) + .named("west") + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); east.get().get().call(new ProbeCallable()); west.get().get().call(new ProbeCallable()); west.get().get().close(); @@ -523,26 +512,23 @@ public void pipeFullProtocolNIO() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack> east = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> west = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> east = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), westToEast.source(), eastToWest.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> west = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), eastToWest.source(), westToEast.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); east.get().get().call(new ProbeCallable()); west.get().get().call(new ProbeCallable()); west.get().get().close(); east.get().get().close(); - } @Test @@ -558,26 +544,23 @@ public void socketChannelFullProtocolNIO() throws Exception { SSLEngine eastEngine = context.createSSLEngine(); eastEngine.setUseClientMode(true); - ProtocolStack> east = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), eastChannel, eastChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(eastEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> west = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), westChannel, westChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(westEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> east = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), eastChannel, eastChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(eastEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "east"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> west = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), westChannel, westChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(westEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "west"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); east.get().get().call(new ProbeCallable()); west.get().get().call(new ProbeCallable()); west.get().get().close(); east.get().get().close(); - } @Test @@ -591,34 +574,35 @@ public void pipeChannelFullProtocolNIO_clientRejects() throws Exception { SSLEngine clientEngine = context.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack> client = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> { - throw new ConnectionRefusalException("I don't like you, Mr. Server"); - })) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> server = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> { + throw new ConnectionRefusalException("I don't like you, Mr. Server"); + })) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); assertThat(ce.getCause(), instanceOf(ConnectionRefusalException.class)); - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); - assertThat(se.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); + assertThat( + se.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); } @Test @@ -635,32 +619,35 @@ public void socketChannelFullProtocolNIO_clientRejects() throws Exception { SSLEngine clientEngine = context.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack> client = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> { - throw new ConnectionRefusalException("I don't like you, Mr. Server"); - })) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> server = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> { + throw new ConnectionRefusalException("I don't like you, Mr. Server"); + })) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); assertThat(ce.getCause(), instanceOf(ConnectionRefusalException.class)); - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); - assertThat(se.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); + assertThat( + se.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); } @Test @@ -674,33 +661,34 @@ public void pipeChannelFullProtocolNIO_serverRejects() throws Exception { SSLEngine clientEngine = context.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack> client = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> server = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> { - throw new ConnectionRefusalException("I don't like you, Mr. Server"); - })) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); - assertThat(ce.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); - - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> { + throw new ConnectionRefusalException("I don't like you, Mr. Server"); + })) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); + assertThat( + ce.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); + + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); assertThat(se.getCause(), instanceOf(ConnectionRefusalException.class)); } @@ -718,31 +706,34 @@ public void socketChannelFullProtocolNIO_serverRejects() throws Exception { SSLEngine clientEngine = context.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack> client = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - ProtocolStack> server = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> { - throw new ConnectionRefusalException("I don't like you, Mr. Client"); - })) - .build(new ChannelApplicationLayer(selector.executorService(), null)); - - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); - assertThat(ce.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); - - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> { + throw new ConnectionRefusalException("I don't like you, Mr. Client"); + })) + .build(new ChannelApplicationLayer(selector.executorService(), null)); + + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); + assertThat( + ce.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); + + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); assertThat(se.getCause(), instanceOf(ConnectionRefusalException.class)); } @@ -759,41 +750,44 @@ public void pipeChannelFullProtocolNIO_invalidAck() throws Exception { clientEngine.setUseClientMode(true); HoldFilterLayer clientHold = new HoldFilterLayer(); - ProtocolStack> client = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(clientHold) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(clientHold) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); HoldFilterLayer serverHold = new HoldFilterLayer(); - ProtocolStack> server = - ProtocolStack - .on(new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(serverHold) - .filter(new AckFilterLayer("ACk")) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(serverHold) + .filter(new AckFilterLayer("ACk")) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); clientHold.release(); serverHold.release(); - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); - assertThat(ce.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); - - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); - assertThat(se.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); + assertThat( + ce.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); + + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); + assertThat( + se.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); } - @Ignore("TODO flake: ConnectionRefusalException: Incorrect acknowledgement received, expected 0x000341436b got 0x0000000000") + @Ignore( + "TODO flake: ConnectionRefusalException: Incorrect acknowledgement received, expected 0x000341436b got 0x0000000000") @Test @Repeat(16) public void socketChannelFullProtocolNIO_invalidAck() throws Exception { @@ -809,36 +803,40 @@ public void socketChannelFullProtocolNIO_invalidAck() throws Exception { clientEngine.setUseClientMode(true); HoldFilterLayer clientHold = new HoldFilterLayer(); - ProtocolStack> client = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) - .filter(clientHold) - .filter(new AckFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> client = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), clientSocketChannel, clientSocketChannel)) + .filter(clientHold) + .filter(new AckFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); HoldFilterLayer serverHold = new HoldFilterLayer(); - ProtocolStack> server = - ProtocolStack.on(new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) - .filter(serverHold) - .filter(new AckFilterLayer("ACk")) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> {})) - .build(new ChannelApplicationLayer(selector.executorService(), null)); + ProtocolStack> server = ProtocolStack.on( + new NIONetworkLayer(selector.hub(), serverSocketChannel, serverSocketChannel)) + .filter(serverHold) + .filter(new AckFilterLayer("ACk")) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> {})) + .build(new ChannelApplicationLayer(selector.executorService(), null)); clientHold.release(); serverHold.release(); - final ExecutionException ce = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> client.get().get().call(new ProbeCallable())); - assertThat(ce.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); - - final ExecutionException se = assertThrows("Expected Connection refusal", ExecutionException.class, - () -> server.get().get().call(new ProbeCallable())); - assertThat(se.getCause(), anyOf(instanceOf(ConnectionRefusalException.class), instanceOf( - ClosedChannelException.class))); + final ExecutionException ce = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> client.get() + .get() + .call(new ProbeCallable())); + assertThat( + ce.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); + + final ExecutionException se = + assertThrows("Expected Connection refusal", ExecutionException.class, () -> server.get() + .get() + .call(new ProbeCallable())); + assertThat( + se.getCause(), + anyOf(instanceOf(ConnectionRefusalException.class), instanceOf(ClosedChannelException.class))); } private static class ProbeCallable implements Callable { @@ -849,10 +847,8 @@ public String call() throws IOException { } @Override - public void checkRoles(RoleChecker checker) throws SecurityException { + public void checkRoles(RoleChecker checker) throws SecurityException {} - } private static final long serialVersionUID = 1L; } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackLoopbackLoadStress.java b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackLoopbackLoadStress.java index 2cbd760bb..c3858edc9 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackLoopbackLoadStress.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackLoopbackLoadStress.java @@ -109,7 +109,7 @@ private Timer[] createTimers() { public ProtocolStackLoopbackLoadStress(boolean nio, boolean ssl) throws IOException, NoSuchAlgorithmException, CertificateException, KeyStoreException, - UnrecoverableKeyException, KeyManagementException, OperatorCreationException { + UnrecoverableKeyException, KeyManagementException, OperatorCreationException { KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); gen.initialize(2048); // maximum supported by JVM with export restrictions KeyPair keyPair = gen.generateKeyPair(); @@ -128,20 +128,12 @@ public ProtocolStackLoopbackLoadStress(boolean nio, boolean ssl) .build(); X509v3CertificateBuilder certGen = new X509v3CertificateBuilder( - subject, - BigInteger.ONE, - firstDate, - lastDate, - subject, - subjectPublicKeyInfo - ); + subject, BigInteger.ONE, firstDate, lastDate, subject, subjectPublicKeyInfo); JcaX509ExtensionUtils instance = new JcaX509ExtensionUtils(); - certGen.addExtension(Extension.subjectKeyIdentifier, - false, - instance.createSubjectKeyIdentifier(subjectPublicKeyInfo) - ); + certGen.addExtension( + Extension.subjectKeyIdentifier, false, instance.createSubjectKeyIdentifier(subjectPublicKeyInfo)); ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA") .setProvider(BOUNCY_CASTLE_PROVIDER) @@ -155,14 +147,16 @@ public ProtocolStackLoopbackLoadStress(boolean nio, boolean ssl) KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); store.load(null, password); - store.setKeyEntry("alias", keyPair.getPrivate(), password, new Certificate[]{certificate}); + store.setKeyEntry("alias", keyPair.getPrivate(), password, new Certificate[] {certificate}); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(store, password); context = SSLContext.getInstance("TLS"); - context.init(kmf.getKeyManagers(), - new TrustManager[]{new PublicKeyMatchingX509ExtendedTrustManager(keyPair.getPublic())}, null); + context.init( + kmf.getKeyManagers(), + new TrustManager[] {new PublicKeyMatchingX509ExtendedTrustManager(keyPair.getPublic())}, + null); hub = IOHub.create(executorService); serverSocketChannel = ServerSocketChannel.open(); @@ -187,9 +181,8 @@ public Void call() throws IOException { } @Override - public void checkRoles(RoleChecker checker) throws SecurityException { + public void checkRoles(RoleChecker checker) throws SecurityException {} - } private static final long serialVersionUID = 1L; } @@ -213,13 +206,14 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) SSLEngine sslEngine = context.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(true); - final ProtocolStack> channelFromClient = - ProtocolStack.on(nio ? new NIONetworkLayer(hub, fromClient, fromClient) : new BIONetworkLayer(hub, fromClient, fromClient)) + final ProtocolStack> channelFromClient = ProtocolStack.on( + nio + ? new NIONetworkLayer(hub, fromClient, fromClient) + : new BIONetworkLayer(hub, fromClient, fromClient)) .named(String.format("Serving client %s", fromClient.toString())) .filter(new AckFilterLayer()) .filter(ssl ? new SSLEngineFilterLayer(sslEngine, null) : null) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), - headers -> {})) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "server"), headers -> {})) .build(new ChannelApplicationLayer(executorService, null)); hub.execute(() -> { try { @@ -234,7 +228,6 @@ public void ready(boolean accept, boolean connect, boolean read, boolean write) e.printStackTrace(System.err); } } - } @Override @@ -256,9 +249,7 @@ public void onRegistered(SelectionKey selectionKey) { } @Override - public void onClosedChannel(ClosedChannelException e) { - - } + public void onClosedChannel(ClosedChannelException e) {} } public static void main(String[] args) throws Exception { @@ -267,7 +258,9 @@ public static void main(String[] args) throws Exception { boolean nio = args.length < 3 || !"bio".equalsIgnoreCase(args[2]); final boolean ssl = args.length < 4 || !"cleartext".equalsIgnoreCase(args[3]); final double expectNoopsPerSecond = 1000.0 / clientIntervalMs * numClients; - System.out.printf("Starting stress test with %d clients making calls every %dms (%.1f/sec) to give a total expected rate of %.1f/sec%n", numClients, clientIntervalMs, 1000.0 / clientIntervalMs, expectNoopsPerSecond); + System.out.printf( + "Starting stress test with %d clients making calls every %dms (%.1f/sec) to give a total expected rate of %.1f/sec%n", + numClients, clientIntervalMs, 1000.0 / clientIntervalMs, expectNoopsPerSecond); System.out.printf("Server using %s%n", nio ? "Non-blocking I/O" : "Reader thread per client I/O"); System.out.printf("Protocol stack using %s%n", ssl ? "TLS encrypted transport" : "cleartext transport"); ProtocolStackLoopbackLoadStress stress = new ProtocolStackLoopbackLoadStress(nio, ssl); @@ -290,8 +283,9 @@ public static void main(String[] args) throws Exception { long currentNoops = NoOpCallable.noops.get(); double noopsPerSecond = (currentNoops - initialNoops) * 1000.0 / (now - start); double instantNoopsPerSecond = (currentNoops - previousNoops) * 1000.0 / (now - last); - System.out.printf("%nTotal rate %.1f/sec, instant %.1f/sec, expect %.1f/sec%n", noopsPerSecond, - instantNoopsPerSecond, expectNoopsPerSecond); + System.out.printf( + "%nTotal rate %.1f/sec, instant %.1f/sec, expect %.1f/sec%n", + noopsPerSecond, instantNoopsPerSecond, expectNoopsPerSecond); System.out.flush(); last = now; previousNoops = currentNoops; @@ -306,48 +300,55 @@ public static void main(String[] args) throws Exception { stress.startClient(i, serverAddress, clientIntervalMs, ssl); } System.out.println("All clients started"); - } - private void startClient(int n, SocketAddress serverAddress, final int clientIntervalMs, boolean ssl) throws IOException, ExecutionException, InterruptedException { + private void startClient(int n, SocketAddress serverAddress, final int clientIntervalMs, boolean ssl) + throws IOException, ExecutionException, InterruptedException { SocketChannel toServer = SocketChannel.open(); toServer.connect(serverAddress); SSLEngine sslEngine = context.createSSLEngine(); sslEngine.setUseClientMode(true); - final Channel clientChannel = - ProtocolStack.on(new NIONetworkLayer(hub, toServer, toServer)) - .named(String.format("Client %d: %s -> %s", n, toServer.getLocalAddress(), serverAddress)) - .filter(new AckFilterLayer()) - .filter(ssl ? new SSLEngineFilterLayer(sslEngine, null) : null) - .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), - headers -> {})) - .build(new ChannelApplicationLayer(executorService, null)).get().get(); - timer[n % timer.length].scheduleAtFixedRate(new TimerTask() { - private NoOpCallable callable = new NoOpCallable(); - long start = System.currentTimeMillis(); - int times = 0; - @Override - public void run() { - try { + final Channel clientChannel = ProtocolStack.on(new NIONetworkLayer(hub, toServer, toServer)) + .named(String.format("Client %d: %s -> %s", n, toServer.getLocalAddress(), serverAddress)) + .filter(new AckFilterLayer()) + .filter(ssl ? new SSLEngineFilterLayer(sslEngine, null) : null) + .filter(new ConnectionHeadersFilterLayer(Map.of("id", "client"), headers -> {})) + .build(new ChannelApplicationLayer(executorService, null)) + .get() + .get(); + timer[n % timer.length].scheduleAtFixedRate( + new TimerTask() { + private NoOpCallable callable = new NoOpCallable(); long start = System.currentTimeMillis(); - clientChannel.call(callable); - times++; - if (times % 1000 == 0) { - System.out.printf(" %s has run %d No-op callables. Rate %.1f/s expect %.1f/s%n", - clientChannel.getName(), times, - times * 1000.0 / (System.currentTimeMillis() - this.start), 1000.0 / clientIntervalMs); - } - long duration = System.currentTimeMillis() - start; - if (duration > 250L) { - System.err.printf(" %s took %dms to complete a callable%n", clientChannel.getName(), duration); + int times = 0; + + @Override + public void run() { + try { + long start = System.currentTimeMillis(); + clientChannel.call(callable); + times++; + if (times % 1000 == 0) { + System.out.printf( + " %s has run %d No-op callables. Rate %.1f/s expect %.1f/s%n", + clientChannel.getName(), + times, + times * 1000.0 / (System.currentTimeMillis() - this.start), + 1000.0 / clientIntervalMs); + } + long duration = System.currentTimeMillis() - start; + if (duration > 250L) { + System.err.printf( + " %s took %dms to complete a callable%n", clientChannel.getName(), duration); + } + } catch (Exception e) { + e.printStackTrace(System.err); + IOUtils.closeQuietly(clientChannel); + cancel(); + } } - } catch (Exception e) { - e.printStackTrace(System.err); - IOUtils.closeQuietly(clientChannel); - cancel(); - } - } - }, entropy.nextInt(clientIntervalMs), clientIntervalMs); + }, + entropy.nextInt(clientIntervalMs), + clientIntervalMs); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackTest.java b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackTest.java index f8b74a020..db01e7a49 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/ProtocolStackTest.java @@ -77,91 +77,85 @@ public void initSequence() throws IOException { final AtomicInteger state = new AtomicInteger(); ProtocolStack.on(new NetworkLayer(selector) { - @Override - protected void write(@NonNull ByteBuffer data) { - } - - @Override - public void start() { - state.compareAndSet(0, 1); - } - - @Override - public void doCloseSend() { - } - - @Override - public void doCloseRecv() { - } - - @Override - public boolean isSendOpen() { - return true; - } - - }).filter(new FilterLayer() { - @Override - public void start() { - state.compareAndSet(1, 2); - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - }).filter(new FilterLayer() { - @Override - public void start() { - state.compareAndSet(2, 3); - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - }).named("initSeq").build(new ApplicationLayer() { - @Override - public Void get() { - return null; - } - - @Override - public void onRead(@NonNull ByteBuffer data) { - } - - @Override - public void start() { - state.compareAndSet(3, 4); - } - - - @Override - public void onReadClosed(IOException cause) { - } - - @Override - public boolean isReadOpen() { - return true; - } - - }); + @Override + protected void write(@NonNull ByteBuffer data) {} + + @Override + public void start() { + state.compareAndSet(0, 1); + } + + @Override + public void doCloseSend() {} + + @Override + public void doCloseRecv() {} + + @Override + public boolean isSendOpen() { + return true; + } + }) + .filter(new FilterLayer() { + @Override + public void start() { + state.compareAndSet(1, 2); + } + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + }) + .filter(new FilterLayer() { + @Override + public void start() { + state.compareAndSet(2, 3); + } + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + }) + .named("initSeq") + .build(new ApplicationLayer() { + @Override + public Void get() { + return null; + } + + @Override + public void onRead(@NonNull ByteBuffer data) {} + + @Override + public void start() { + state.compareAndSet(3, 4); + } + + @Override + public void onReadClosed(IOException cause) {} + + @Override + public boolean isReadOpen() { + return true; + } + }); assertThat("Init in sequence", state.get(), is(4)); - assertThat(handler.logRecords, contains( - allOf(hasProperty("message", is("[{0}] Initializing")), - hasProperty("parameters", is(new Object[]{"initSeq"}))), - allOf(hasProperty("message", is("[{0}] Starting")), - hasProperty("parameters", is(new Object[]{"initSeq"}))), - allOf(hasProperty("message", is("[{0}] Started")), - hasProperty("parameters", is(new Object[]{"initSeq"}))) - )); + assertThat( + handler.logRecords, + contains( + allOf( + hasProperty("message", is("[{0}] Initializing")), + hasProperty("parameters", is(new Object[] {"initSeq"}))), + allOf( + hasProperty("message", is("[{0}] Starting")), + hasProperty("parameters", is(new Object[] {"initSeq"}))), + allOf( + hasProperty("message", is("[{0}] Started")), + hasProperty("parameters", is(new Object[] {"initSeq"}))))); } finally { logger.removeHandler(handler); logger.setLevel(oldLevel); @@ -181,101 +175,96 @@ public void initSequenceFailure() { final AtomicInteger state = new AtomicInteger(); final IOException e = assertThrows(IOException.class, () -> ProtocolStack.on(new NetworkLayer(selector) { - @Override - protected void write(@NonNull ByteBuffer data) { - } - - @Override - public void start() { - state.compareAndSet(0, 1); - } - - @Override - public void doCloseSend() { - } - - @Override - public void doCloseRecv() { - } - - - @Override - public boolean isSendOpen() { - return true; - } - - }).filter(new FilterLayer() { - @Override - public void start() throws IOException { - state.compareAndSet(1, 2); - throw new IOException("boom"); - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - }).filter(new FilterLayer() { - @Override - public void start() { - state.set(-2); - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - @Override - public void onRecvClosed(IOException cause) throws IOException { - state.compareAndSet(2, 3); - super.onRecvClosed(cause); - } - }).named("initSeq").build(new ApplicationLayer() { - @Override - public Void get() { - return null; - } - - @Override - public void onRead(@NonNull ByteBuffer data) { - } - - @Override - public void start() { - state.set(-3); - } - - - @Override - public void onReadClosed(IOException cause) { - state.compareAndSet(3, 4); - } - - @Override - public boolean isReadOpen() { - return true; - } - - })); + @Override + protected void write(@NonNull ByteBuffer data) {} + + @Override + public void start() { + state.compareAndSet(0, 1); + } + + @Override + public void doCloseSend() {} + + @Override + public void doCloseRecv() {} + + @Override + public boolean isSendOpen() { + return true; + } + }) + .filter(new FilterLayer() { + @Override + public void start() throws IOException { + state.compareAndSet(1, 2); + throw new IOException("boom"); + } + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + }) + .filter(new FilterLayer() { + @Override + public void start() { + state.set(-2); + } + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + + @Override + public void onRecvClosed(IOException cause) throws IOException { + state.compareAndSet(2, 3); + super.onRecvClosed(cause); + } + }) + .named("initSeq") + .build(new ApplicationLayer() { + @Override + public Void get() { + return null; + } + + @Override + public void onRead(@NonNull ByteBuffer data) {} + + @Override + public void start() { + state.set(-3); + } + + @Override + public void onReadClosed(IOException cause) { + state.compareAndSet(3, 4); + } + + @Override + public boolean isReadOpen() { + return true; + } + })); assertThat(e.getMessage(), is("boom")); - assertThat(handler.logRecords, contains( - allOf(hasProperty("message", is("[{0}] Initializing")), - hasProperty("parameters", is(new Object[]{"initSeq"}))), - allOf(hasProperty("message", is("[{0}] Starting")), - hasProperty("parameters", is(new Object[]{"initSeq"}))), - allOf(hasProperty("message", is("[{0}] Start failure")), - hasProperty("parameters", is(new Object[]{"initSeq"})), - hasProperty("thrown", hasProperty("message", is("boom")))) - )); + assertThat( + handler.logRecords, + contains( + allOf( + hasProperty("message", is("[{0}] Initializing")), + hasProperty("parameters", is(new Object[] {"initSeq"}))), + allOf( + hasProperty("message", is("[{0}] Starting")), + hasProperty("parameters", is(new Object[] {"initSeq"}))), + allOf( + hasProperty("message", is("[{0}] Start failure")), + hasProperty("parameters", is(new Object[] {"initSeq"})), + hasProperty("thrown", hasProperty("message", is("boom")))))); assertThat("Init in sequence", state.get(), is(4)); } finally { logger.removeHandler(handler); @@ -297,118 +286,116 @@ public void stackCloseSequence() throws IOException { final AtomicInteger state = new AtomicInteger(); ProtocolStack.on(new NetworkLayer(selector) { - @Override - public void start() { - } - - @Override - protected void write(@NonNull ByteBuffer data) { - } - - @Override - public void doCloseRecv() { - state.compareAndSet(3, 4); - onRecvClosed(); - } - - @Override - public void doCloseSend() { - state.compareAndSet(2, 3); - doCloseRecv(); - } - - @Override - public boolean isSendOpen() { - return true; - } - - }).filter(new FilterLayer() { - @Override - public void start() { - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - @Override - public void doCloseSend() throws IOException { - state.compareAndSet(1, 2); - super.doCloseSend(); - } - - @Override - public void onRecvClosed(IOException cause) throws IOException { - state.compareAndSet(4, 5); - super.onRecvClosed(cause); - } - }).filter(new FilterLayer() { - @Override - public void start() { - } - - @Override - public void onRecv(@NonNull ByteBuffer data) { - } - - @Override - public void doSend(@NonNull ByteBuffer data) { - } - - @Override - public void doCloseSend() throws IOException { - state.compareAndSet(0, 1); - super.doCloseSend(); - } - - @Override - public void onRecvClosed(IOException cause) throws IOException { - state.compareAndSet(5, 6); - super.onRecvClosed(cause); - } - }).named("closeSeq").build(new ApplicationLayer() { - @Override - public boolean isReadOpen() { - return true; - } - - @Override - public void onRead(@NonNull ByteBuffer data) { - } - - @Override - public Void get() { - return null; - } - - @Override - public void start() { - } - - - @Override - public void onReadClosed(IOException cause) { - state.compareAndSet(6, 7); - } - - }).close(); + @Override + public void start() {} + + @Override + protected void write(@NonNull ByteBuffer data) {} + + @Override + public void doCloseRecv() { + state.compareAndSet(3, 4); + onRecvClosed(); + } + + @Override + public void doCloseSend() { + state.compareAndSet(2, 3); + doCloseRecv(); + } + + @Override + public boolean isSendOpen() { + return true; + } + }) + .filter(new FilterLayer() { + @Override + public void start() {} + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + + @Override + public void doCloseSend() throws IOException { + state.compareAndSet(1, 2); + super.doCloseSend(); + } + + @Override + public void onRecvClosed(IOException cause) throws IOException { + state.compareAndSet(4, 5); + super.onRecvClosed(cause); + } + }) + .filter(new FilterLayer() { + @Override + public void start() {} + + @Override + public void onRecv(@NonNull ByteBuffer data) {} + + @Override + public void doSend(@NonNull ByteBuffer data) {} + + @Override + public void doCloseSend() throws IOException { + state.compareAndSet(0, 1); + super.doCloseSend(); + } + + @Override + public void onRecvClosed(IOException cause) throws IOException { + state.compareAndSet(5, 6); + super.onRecvClosed(cause); + } + }) + .named("closeSeq") + .build(new ApplicationLayer() { + @Override + public boolean isReadOpen() { + return true; + } + + @Override + public void onRead(@NonNull ByteBuffer data) {} + + @Override + public Void get() { + return null; + } + + @Override + public void start() {} + + @Override + public void onReadClosed(IOException cause) { + state.compareAndSet(6, 7); + } + }) + .close(); assertThat("Close in sequence", state.get(), is(7)); - assertThat(handler.logRecords, contains( - allOf(hasProperty("message", is("[{0}] Initializing")), - hasProperty("parameters", is(new Object[]{"closeSeq"}))), - allOf(hasProperty("message", is("[{0}] Starting")), - hasProperty("parameters", is(new Object[]{"closeSeq"}))), - allOf(hasProperty("message", is("[{0}] Started")), - hasProperty("parameters", is(new Object[]{"closeSeq"}))), - allOf(hasProperty("message", is("[{0}] Closing")), - hasProperty("parameters", is(new Object[]{"closeSeq"}))), - allOf(hasProperty("message", is("[{0}] Closed")), - hasProperty("parameters", is(new Object[]{"closeSeq"}))) - )); + assertThat( + handler.logRecords, + contains( + allOf( + hasProperty("message", is("[{0}] Initializing")), + hasProperty("parameters", is(new Object[] {"closeSeq"}))), + allOf( + hasProperty("message", is("[{0}] Starting")), + hasProperty("parameters", is(new Object[] {"closeSeq"}))), + allOf( + hasProperty("message", is("[{0}] Started")), + hasProperty("parameters", is(new Object[] {"closeSeq"}))), + allOf( + hasProperty("message", is("[{0}] Closing")), + hasProperty("parameters", is(new Object[] {"closeSeq"}))), + allOf( + hasProperty("message", is("[{0}] Closed")), + hasProperty("parameters", is(new Object[] {"closeSeq"}))))); } finally { logger.removeHandler(handler); logger.setLevel(oldLevel); @@ -429,11 +416,9 @@ public void publish(LogRecord record) { } @Override - public void flush() { - } + public void flush() {} @Override - public void close() throws SecurityException { - } + public void close() throws SecurityException {} } } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/Repeat.java b/src/test/java/org/jenkinsci/remoting/protocol/Repeat.java index b3a110748..e8956d39b 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/Repeat.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/Repeat.java @@ -33,6 +33,8 @@ @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Repeat { int value() default 0; + long stopAfter() default 0L; + TimeUnit stopAfterUnits() default TimeUnit.SECONDS; } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/RepeatRule.java b/src/test/java/org/jenkinsci/remoting/protocol/RepeatRule.java index 1ec2119d9..63ac3f6a0 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/RepeatRule.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/RepeatRule.java @@ -36,51 +36,65 @@ public class RepeatRule implements TestRule { @Override public Statement apply(final Statement base, final Description description) { final Repeat repeat = description.getAnnotation(Repeat.class); - return repeat == null || (repeat.value() <= 0 && repeat.stopAfter() <= 0L) ? base : new Statement() { - @Override - public void evaluate() throws Throwable { - long nextProgress = System.currentTimeMillis() + 10000; - int lastLoopCount = 0; - int maxLoops; - long stopNanos; - String text; - if (repeat.stopAfter() <= 0L) { - stopNanos = Long.MAX_VALUE; - if (repeat.value() <= 0) { - maxLoops = 1; - text = "once"; - } else { - maxLoops = repeat.value(); - text = String.format("%d times", maxLoops); + return repeat == null || (repeat.value() <= 0 && repeat.stopAfter() <= 0L) + ? base + : new Statement() { + @Override + public void evaluate() throws Throwable { + long nextProgress = System.currentTimeMillis() + 10000; + int lastLoopCount = 0; + int maxLoops; + long stopNanos; + String text; + if (repeat.stopAfter() <= 0L) { + stopNanos = Long.MAX_VALUE; + if (repeat.value() <= 0) { + maxLoops = 1; + text = "once"; + } else { + maxLoops = repeat.value(); + text = String.format("%d times", maxLoops); + } + } else { + if (repeat.value() <= 0) { + maxLoops = Integer.MAX_VALUE; + text = String.format( + "for %d %s", + repeat.stopAfter(), + repeat.stopAfterUnits().name()); + } else { + maxLoops = repeat.value(); + text = String.format( + "for %d times or %d %s", + maxLoops, + repeat.stopAfter(), + repeat.stopAfterUnits().name()); + } + stopNanos = System.currentTimeMillis() + + repeat.stopAfterUnits().toMillis(repeat.stopAfter()); + } + int loopCount; + for (loopCount = 0; + loopCount < maxLoops && System.currentTimeMillis() < stopNanos; + loopCount++) { + base.evaluate(); + if (System.currentTimeMillis() > nextProgress) { + double loopsPerSec = (loopCount - lastLoopCount + 1) / 10.0; + LOGGER.log( + Level.INFO, + "Repeating {0} {1} at {2,number,0.0} runs per second, {3,number} done", + new Object[] {description.getDisplayName(), text, loopsPerSec, loopCount + 1}); + lastLoopCount = loopCount; + nextProgress = System.currentTimeMillis() + 10000; + System.gc(); + } + } + if (repeat.stopAfter() > 0) { + LOGGER.log(Level.INFO, "Repeated {0} {1,number} times", new Object[] { + description.getDisplayName(), loopCount + }); + } } - } else { - if (repeat.value() <= 0) { - maxLoops = Integer.MAX_VALUE; - text = String.format("for %d %s", repeat.stopAfter(), repeat.stopAfterUnits().name()); - } else { - maxLoops = repeat.value(); - text = String.format("for %d times or %d %s", maxLoops, repeat.stopAfter(), - repeat.stopAfterUnits().name()); - } - stopNanos = System.currentTimeMillis() + repeat.stopAfterUnits().toMillis(repeat.stopAfter()); - } - int loopCount; - for (loopCount = 0; loopCount < maxLoops && System.currentTimeMillis() < stopNanos; loopCount++) { - base.evaluate(); - if (System.currentTimeMillis() > nextProgress) { - double loopsPerSec = (loopCount - lastLoopCount + 1) / 10.0; - LOGGER.log(Level.INFO, "Repeating {0} {1} at {2,number,0.0} runs per second, {3,number} done", - new Object[]{description.getDisplayName(), text, loopsPerSec, loopCount + 1}); - lastLoopCount = loopCount; - nextProgress = System.currentTimeMillis() + 10000; - System.gc(); - } - } - if (repeat.stopAfter() > 0) { - LOGGER.log(Level.INFO, "Repeated {0} {1,number} times", - new Object[]{description.getDisplayName(), loopCount}); - } - } - }; + }; } } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/BlindTrustX509ExtendedTrustManagerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/BlindTrustX509ExtendedTrustManagerTest.java index 0c9881801..40d75a4ed 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/BlindTrustX509ExtendedTrustManagerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/BlindTrustX509ExtendedTrustManagerTest.java @@ -43,12 +43,11 @@ public class BlindTrustX509ExtendedTrustManagerTest { public static X509CertificateRule cert = new X509CertificateRule("main", key, key, null, -1, 1, TimeUnit.HOURS); @ClassRule - public static RuleChain chain = RuleChain.outerRule(key) - .around(cert); + public static RuleChain chain = RuleChain.outerRule(key).around(cert); @Test public void checkClientTrusted() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -58,17 +57,17 @@ public void checkClientTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkServerTrusted() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -78,17 +77,17 @@ public void checkServerTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkClientTrusted1() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -98,17 +97,17 @@ public void checkClientTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkServerTrusted1() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -118,57 +117,56 @@ public void checkServerTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkClientTrusted2() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nullNonNull() throws Exception { - instance.checkClientTrusted(null, "RSA", (SSLEngine)null); + instance.checkClientTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test public void checkServerTrusted2() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nullNonNull() throws Exception { - instance.checkServerTrusted(null, "RSA", (SSLEngine)null); + instance.checkServerTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test public void getAcceptedIssuers() { assertThat(instance.getAcceptedIssuers(), notNullValue()); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/KeyPairRule.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/KeyPairRule.java index 32d486f95..89151ee20 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/KeyPairRule.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/KeyPairRule.java @@ -60,7 +60,8 @@ public PRIV getPrivate() { @Override public Statement apply(final Statement base, Description description) { Skip skip = description.getAnnotation(Skip.class); - if (skip != null && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { + if (skip != null + && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { return base; } return new Statement() { diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManagerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManagerTest.java index 013249d57..22fe02288 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManagerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/PublicKeyMatchingX509ExtendedTrustManagerTest.java @@ -37,23 +37,23 @@ public class PublicKeyMatchingX509ExtendedTrustManagerTest { - private PublicKeyMatchingX509ExtendedTrustManager instance = new PublicKeyMatchingX509ExtendedTrustManager(key.getPublic()); + private PublicKeyMatchingX509ExtendedTrustManager instance = + new PublicKeyMatchingX509ExtendedTrustManager(key.getPublic()); public static RSAKeyPairRule key = new RSAKeyPairRule("main"); public static RSAKeyPairRule altKey = new RSAKeyPairRule("main"); public static X509CertificateRule cert = new X509CertificateRule("main", key, key, null, -1, 1, TimeUnit.HOURS); - public static X509CertificateRule altCert = new X509CertificateRule("main", altKey, altKey, null, -1, 1, TimeUnit.HOURS); + public static X509CertificateRule altCert = + new X509CertificateRule("main", altKey, altKey, null, -1, 1, TimeUnit.HOURS); @ClassRule - public static RuleChain chain = RuleChain.outerRule(key) - .around(cert) - .around(altKey) - .around(altCert); + public static RuleChain chain = + RuleChain.outerRule(key).around(cert).around(altKey).around(altCert); @Test public void checkClientTrusted() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -63,17 +63,17 @@ public void checkClientTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkServerTrusted() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -83,17 +83,17 @@ public void checkServerTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkClientTrusted1() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -103,17 +103,17 @@ public void checkClientTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkServerTrusted1() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -123,87 +123,86 @@ public void checkServerTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkClientTrusted2() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nullNonNull() throws Exception { - instance.checkClientTrusted(null, "RSA", (SSLEngine)null); + instance.checkClientTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test public void checkServerTrusted2() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nullNonNull() throws Exception { - instance.checkServerTrusted(null, "RSA", (SSLEngine)null); + instance.checkServerTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test(expected = CertificateException.class) public void checkClientUntrusted() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{altCert.certificate()}, "RSA"); + instance.checkClientTrusted(new X509Certificate[] {altCert.certificate()}, "RSA"); } @Test(expected = CertificateException.class) public void checkServerUntrusted() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{altCert.certificate()}, "RSA"); + instance.checkServerTrusted(new X509Certificate[] {altCert.certificate()}, "RSA"); } @Test(expected = CertificateException.class) public void checkClientUntrusted1() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{altCert.certificate()}, "RSA", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {altCert.certificate()}, "RSA", new Socket()); } @Test(expected = CertificateException.class) public void checkServerUntrusted1() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{altCert.certificate()}, "RSA", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {altCert.certificate()}, "RSA", new Socket()); } @Test(expected = CertificateException.class) public void checkClientUntrusted2() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{altCert.certificate()}, "RSA", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {altCert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = CertificateException.class) public void checkServerUntrusted2() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{altCert.certificate()}, "RSA", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {altCert.certificate()}, "RSA", (SSLEngine) null); } @Test public void getAcceptedIssuers() { assertThat(instance.getAcceptedIssuers(), notNullValue()); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/SSLContextRule.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/SSLContextRule.java index 47856d1ad..b663977f6 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/SSLContextRule.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/SSLContextRule.java @@ -74,9 +74,10 @@ public SSLContextRule(String id) { this.id = id; } - private static KeyStore createKeyStore(@CheckForNull List certificates, - @CheckForNull List keys, - @NonNull char[] password) + private static KeyStore createKeyStore( + @CheckForNull List certificates, + @CheckForNull List keys, + @NonNull char[] password) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); int id = 1; @@ -179,7 +180,8 @@ public SSLParameters getSupportedSSLParameters() { @Override public Statement apply(final Statement base, Description description) { Skip skip = description.getAnnotation(Skip.class); - if (skip != null && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { + if (skip != null + && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { return base; } return new Statement() { @@ -195,9 +197,10 @@ public void evaluate() throws Throwable { TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(createKeyStore(certificates, null, password)); TrustManager[] trustManagers = new TrustManager[1]; - trustManagers[0] = validityChecking ? new ValidityCheckingX509ExtendedTrustManager( - findFirst(X509ExtendedTrustManager.class, tmf.getTrustManagers())) : findFirst( - X509ExtendedTrustManager.class, tmf.getTrustManagers()); + trustManagers[0] = validityChecking + ? new ValidityCheckingX509ExtendedTrustManager( + findFirst(X509ExtendedTrustManager.class, tmf.getTrustManagers())) + : findFirst(X509ExtendedTrustManager.class, tmf.getTrustManagers()); context.init(keyManagers, trustManagers, null); try { @@ -227,5 +230,4 @@ public KeyWithChain(RSAKeyPairRule key, X509CertificateRule... chain) { this.chain = chain; } } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManagerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManagerTest.java index cec65575c..2479a8ee6 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManagerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/ValidityCheckingX509ExtendedTrustManagerTest.java @@ -42,16 +42,15 @@ public class ValidityCheckingX509ExtendedTrustManagerTest { public static RSAKeyPairRule key = new RSAKeyPairRule("main"); public static X509CertificateRule cert = new X509CertificateRule("main", key, key, null, -1, 1, TimeUnit.HOURS); - public static X509CertificateRule expired = new X509CertificateRule("main", key, key, null, -100, -99, TimeUnit.HOURS); + public static X509CertificateRule expired = + new X509CertificateRule("main", key, key, null, -100, -99, TimeUnit.HOURS); @ClassRule - public static RuleChain chain = RuleChain.outerRule(key) - .around(cert) - .around(expired); + public static RuleChain chain = RuleChain.outerRule(key).around(cert).around(expired); @Test public void checkClientTrusted() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -61,17 +60,17 @@ public void checkClientTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkServerTrusted() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA"); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA"); } @Test(expected = IllegalArgumentException.class) @@ -81,17 +80,17 @@ public void checkServerTrusted_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, ""); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, ""); } @Test public void checkClientTrusted1() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -101,17 +100,17 @@ public void checkClientTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted1_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkServerTrusted1() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", new Socket()); } @Test(expected = IllegalArgumentException.class) @@ -121,87 +120,86 @@ public void checkServerTrusted1_nullNonNull() throws Exception { @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, new Socket()); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted1_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", new Socket()); } @Test public void checkClientTrusted2() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nullNonNull() throws Exception { - instance.checkClientTrusted(null, "RSA", (SSLEngine)null); + instance.checkClientTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullNull() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkClientTrusted2_nonNullEmpty() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test public void checkServerTrusted2() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "RSA", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nullNonNull() throws Exception { - instance.checkServerTrusted(null, "RSA", (SSLEngine)null); + instance.checkServerTrusted(null, "RSA", (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullNull() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, null, (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, null, (SSLEngine) null); } @Test(expected = IllegalArgumentException.class) public void checkServerTrusted2_nonNullEmpty() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{cert.certificate()}, "", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {cert.certificate()}, "", (SSLEngine) null); } @Test(expected = CertificateException.class) public void checkClientExpired() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{expired.certificate()}, "RSA"); + instance.checkClientTrusted(new X509Certificate[] {expired.certificate()}, "RSA"); } @Test(expected = CertificateException.class) public void checkServerExpired() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{expired.certificate()}, "RSA"); + instance.checkServerTrusted(new X509Certificate[] {expired.certificate()}, "RSA"); } @Test(expected = CertificateException.class) public void checkClientExpired1() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{expired.certificate()}, "RSA", new Socket()); + instance.checkClientTrusted(new X509Certificate[] {expired.certificate()}, "RSA", new Socket()); } @Test(expected = CertificateException.class) public void checkServerExpired1() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{expired.certificate()}, "RSA", new Socket()); + instance.checkServerTrusted(new X509Certificate[] {expired.certificate()}, "RSA", new Socket()); } @Test(expected = CertificateException.class) public void checkClientExpired2() throws Exception { - instance.checkClientTrusted(new X509Certificate[]{expired.certificate()}, "RSA", (SSLEngine)null); + instance.checkClientTrusted(new X509Certificate[] {expired.certificate()}, "RSA", (SSLEngine) null); } @Test(expected = CertificateException.class) public void checkServerExpired2() throws Exception { - instance.checkServerTrusted(new X509Certificate[]{expired.certificate()}, "RSA", (SSLEngine)null); + instance.checkServerTrusted(new X509Certificate[] {expired.certificate()}, "RSA", (SSLEngine) null); } @Test public void getAcceptedIssuers() { assertThat(instance.getAcceptedIssuers(), notNullValue()); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/cert/X509CertificateRule.java b/src/test/java/org/jenkinsci/remoting/protocol/cert/X509CertificateRule.java index 2f2c39e67..f426bb702 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/cert/X509CertificateRule.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/cert/X509CertificateRule.java @@ -59,36 +59,48 @@ public class X509CertificateRule implements TestRule { private final String id; private X509Certificate certificate; - public static X509CertificateRule selfSigned(String id, KeyPairRule subject) { + public static X509CertificateRule selfSigned( + String id, KeyPairRule subject) { return new X509CertificateRule(id, subject, subject, null, -7, 7, TimeUnit.DAYS); } - public static X509CertificateRule create(String id, KeyPairRule subject, - KeyPairRule signer, X509CertificateRule signerCertificate) { + public static X509CertificateRule create( + String id, + KeyPairRule subject, + KeyPairRule signer, + X509CertificateRule signerCertificate) { return new X509CertificateRule(id, subject, signer, signerCertificate, -7, 7, TimeUnit.DAYS); } - public static X509CertificateRule selfSigned(KeyPairRule subject) { + public static X509CertificateRule selfSigned( + KeyPairRule subject) { return selfSigned("", subject); } - public static X509CertificateRule create(KeyPairRule subject, - KeyPairRule signer, X509CertificateRule signerCertificate) { + public static X509CertificateRule create( + KeyPairRule subject, KeyPairRule signer, X509CertificateRule signerCertificate) { return create("", subject, signer, signerCertificate); } - public static X509CertificateRule create(String id, - KeyPairRule subject, - KeyPairRule signer, - X509CertificateRule signerCertificate, - long startDateOffset, - long endDateOffset, - TimeUnit units) { + public static X509CertificateRule create( + String id, + KeyPairRule subject, + KeyPairRule signer, + X509CertificateRule signerCertificate, + long startDateOffset, + long endDateOffset, + TimeUnit units) { return new X509CertificateRule(id, subject, signer, signerCertificate, startDateOffset, endDateOffset, units); } - public X509CertificateRule(String id, KeyPairRule subjectKey, - KeyPairRule signerKey, X509CertificateRule signerCertificate, long startDateOffset, long endDateOffset, TimeUnit units) { + public X509CertificateRule( + String id, + KeyPairRule subjectKey, + KeyPairRule signerKey, + X509CertificateRule signerCertificate, + long startDateOffset, + long endDateOffset, + TimeUnit units) { this.id = id; this.subjectKey = subjectKey; this.signerKey = signerKey; @@ -104,7 +116,8 @@ public X509Certificate certificate() { @Override public Statement apply(final Statement base, final Description description) { Skip skip = description.getAnnotation(Skip.class); - if (skip != null && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { + if (skip != null + && (skip.value().length == 0 || Arrays.asList(skip.value()).contains(id))) { return base; } return new Statement() { @@ -121,25 +134,22 @@ public void evaluate() throws Throwable { X500Principal subject = new X500Principal(nameBuilder .addRDN(BCStyle.CN, description.getDisplayName()) .addRDN(BCStyle.C, "US") - .build().toString()); + .build() + .toString()); - X500Principal issuer = signerCertificate != null ? signerCertificate.certificate().getSubjectX500Principal() : subject; + X500Principal issuer = signerCertificate != null + ? signerCertificate.certificate().getSubjectX500Principal() + : subject; X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( - issuer, - BigInteger.ONE, - firstDate, - lastDate, - subject, - subjectKey.getPublic() - ); + issuer, BigInteger.ONE, firstDate, lastDate, subject, subjectKey.getPublic()); JcaX509ExtensionUtils instance = new JcaX509ExtensionUtils(); - certGen.addExtension(Extension.subjectKeyIdentifier, + certGen.addExtension( + Extension.subjectKeyIdentifier, false, - instance.createSubjectKeyIdentifier(subjectKey.getPublic()) - ); + instance.createSubjectKeyIdentifier(subjectKey.getPublic())); ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA") .setProvider(BOUNCY_CASTLE_PROVIDER) @@ -153,7 +163,6 @@ public void evaluate() throws Throwable { } finally { certificate = null; } - } }; } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayerTest.java index f47e32731..0975db67b 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/AckFilterLayerTest.java @@ -55,11 +55,12 @@ public class AckFilterLayerTest { @Rule public TestName name = new TestName(); + private IOHubRule selector = new IOHubRule(); + @Rule - public RuleChain chain = RuleChain.outerRule(selector) - .around(new RepeatRule()) - .around(new Timeout(10, TimeUnit.SECONDS)); + public RuleChain chain = + RuleChain.outerRule(selector).around(new RepeatRule()).around(new Timeout(10, TimeUnit.SECONDS)); private Pipe clientToServer; private Pipe serverToClient; @@ -90,18 +91,15 @@ public void tearDownPipe() { @Theory public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer("ACK")) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer("ACK")) + .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer("ACK")) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer("ACK")) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -117,18 +115,15 @@ public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory client @Theory public void clientSendsShortAck(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer("AC")) - .build(new IOBufferMatcherLayer()); - + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer("AC")) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer("ACK")) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer("ACK")) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); assertThat(client.get().getCloseCause(), instanceOf(ConnectionRefusalException.class)); @@ -140,18 +135,15 @@ public void clientSendsShortAck(NetworkLayerFactory serverFactory, NetworkLayerF @Repeat(100) public void serverSendsShortAck(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer("ACK")) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer("ACK")) + .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer("AC")) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer("AC")) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); assertThat(client.get().getCloseCause(), instanceOf(ConnectionRefusalException.class)); @@ -162,23 +154,19 @@ public void serverSendsShortAck(NetworkLayerFactory serverFactory, NetworkLayerF @Theory @Repeat(100) public void ackMismatch(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new AckFilterLayer("AcK")) - .build(new IOBufferMatcherLayer()); - + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new AckFilterLayer("AcK")) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new AckFilterLayer("ACK")) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new AckFilterLayer("ACK")) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); assertThat(client.get().getCloseCause(), instanceOf(ConnectionRefusalException.class)); server.get().awaitClose(); assertThat(server.get().getCloseCause(), instanceOf(ConnectionRefusalException.class)); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayerTest.java index 7610ece23..5ff332be1 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersFilterLayerTest.java @@ -63,11 +63,12 @@ public class ConnectionHeadersFilterLayerTest { @Rule public TestName name = new TestName(); + private IOHubRule selector = new IOHubRule(); + @Rule - public RuleChain chain = RuleChain.outerRule(selector) - .around(new RepeatRule()) - .around(new Timeout(10, TimeUnit.SECONDS)); + public RuleChain chain = + RuleChain.outerRule(selector).around(new RepeatRule()).around(new Timeout(10, TimeUnit.SECONDS)); private Pipe clientToServer; private Pipe serverToClient; @@ -98,19 +99,15 @@ public void tearDownPipe() { @Theory public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -125,21 +122,17 @@ public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory client @Theory public void clientRejects(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new PermanentConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new PermanentConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); assertThat(client.get().getCloseCause(), instanceOf(PermanentConnectionRefusalException.class)); @@ -149,21 +142,17 @@ public void clientRejects(NetworkLayerFactory serverFactory, NetworkLayerFactory @Theory public void serverRejects(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new PermanentConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new PermanentConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); assertThat(client.get().getCloseCause(), instanceOf(PermanentConnectionRefusalException.class)); @@ -173,116 +162,110 @@ public void serverRejects(NetworkLayerFactory serverFactory, NetworkLayerFactory @Theory public void bothReject(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new PermanentConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new PermanentConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new PermanentConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new PermanentConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); - assertThat(client.get().getCloseCause(), - instanceOf(PermanentConnectionRefusalException.class) - ); + assertThat(client.get().getCloseCause(), instanceOf(PermanentConnectionRefusalException.class)); server.get().awaitClose(); - assertThat(server.get().getCloseCause(), - instanceOf(PermanentConnectionRefusalException.class) - ); + assertThat(server.get().getCloseCause(), instanceOf(PermanentConnectionRefusalException.class)); } @Theory public void clientRefuses(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new ConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new ConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); - assertThat(client.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class)))); + assertThat( + client.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); server.get().awaitClose(); - assertThat(server.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class))) - ); + assertThat( + server.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); } @Theory public void serverRefuses(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> {})) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new ConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> {})) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new ConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); - assertThat(client.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class))) - ); + assertThat( + client.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); server.get().awaitClose(); - assertThat(server.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class)))); + assertThat( + server.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); } @Theory public void bothRefuse(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new ConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), - headers -> { - throw new ConnectionRefusalException("Go away"); - })) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new ConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); + + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(Collections.emptyMap(), headers -> { + throw new ConnectionRefusalException("Go away"); + })) + .build(new IOBufferMatcherLayer()); client.get().awaitClose(); - assertThat(client.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class))) - ); + assertThat( + client.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); server.get().awaitClose(); - assertThat(server.get().getCloseCause(), - allOf(instanceOf(ConnectionRefusalException.class), not(instanceOf(PermanentConnectionRefusalException.class))) - ); + assertThat( + server.get().getCloseCause(), + allOf( + instanceOf(ConnectionRefusalException.class), + not(instanceOf(PermanentConnectionRefusalException.class)))); } @Theory @@ -293,24 +276,20 @@ public void headerExchange(NetworkLayerFactory serverFactory, NetworkLayerFactor for (int i = 1 + entropy.nextInt(50); i > 0; i--) { clientExpectedHeaders.put(Long.toHexString(entropy.nextLong()), Long.toHexString(entropy.nextLong())); } - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(clientExpectedHeaders, - serverActualHeaders::complete)) - .build(new IOBufferMatcherLayer()); + ProtocolStack client = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(clientExpectedHeaders, serverActualHeaders::complete)) + .build(new IOBufferMatcherLayer()); final CompletableFuture> clientActualHeaders = new CompletableFuture<>(); Map serverExpectedHeaders = new HashMap<>(); for (int i = 1 + entropy.nextInt(50); i > 0; i--) { serverExpectedHeaders.put(Long.toHexString(entropy.nextLong()), Long.toHexString(entropy.nextLong())); } - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new ConnectionHeadersFilterLayer(serverExpectedHeaders, - clientActualHeaders::complete)) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new ConnectionHeadersFilterLayer(serverExpectedHeaders, clientActualHeaders::complete)) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -334,13 +313,10 @@ public void tooBigHeader(NetworkLayerFactory serverFactory, NetworkLayerFactory } final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> { - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new ConnectionHeadersFilterLayer(clientExpectedHeaders, - serverActualHeaders::complete)) + ProtocolStack.on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new ConnectionHeadersFilterLayer(clientExpectedHeaders, serverActualHeaders::complete)) .build(new IOBufferMatcherLayer()); }); assertThat(e.getMessage(), containsString("less than 65536")); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersTest.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersTest.java index 408bc56bc..068347906 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/ConnectionHeadersTest.java @@ -41,14 +41,14 @@ public class ConnectionHeadersTest { @Test public void emptyRoundTrip() throws Exception { - assertThat(ConnectionHeaders.fromString(ConnectionHeaders.toString(Collections.emptyMap())), + assertThat( + ConnectionHeaders.fromString(ConnectionHeaders.toString(Collections.emptyMap())), is(Collections.emptyMap())); } @Test public void singleValueRoundTrip() throws Exception { - assertThat(ConnectionHeaders.fromString(ConnectionHeaders.toString(Map.of("a", "b"))), - is(Map.of("a", "b"))); + assertThat(ConnectionHeaders.fromString(ConnectionHeaders.toString(Map.of("a", "b"))), is(Map.of("a", "b"))); } @Test @@ -62,14 +62,12 @@ public void multiValueRoundTrip() throws Exception { payload.put("e\u0009", "'hi\u0008there'"); payload.put("\f\b\n\r\t/\\", "null"); payload.put("a/b/c/d", "e\\f\\g\\h"); - assertThat(ConnectionHeaders.fromString(ConnectionHeaders.toString(payload)), - is(payload)); + assertThat(ConnectionHeaders.fromString(ConnectionHeaders.toString(payload)), is(payload)); } @Test public void newlineEscaping() { - assertThat(ConnectionHeaders.toString(Map.of("a\nmultiline\nkey", "b")), - not(containsString("\n"))); + assertThat(ConnectionHeaders.toString(Map.of("a\nmultiline\nkey", "b")), not(containsString("\n"))); } @Test @@ -77,7 +75,8 @@ public void paddedData_1() throws Exception { Map expected = new TreeMap<>(); expected.put("key", "value"); expected.put("foo", "bar"); - assertThat(ConnectionHeaders.fromString("\n{\n \"key\"\t:\f\"value\"\n,\n\"foo\" : \"bar\"\n}\n\n"), + assertThat( + ConnectionHeaders.fromString("\n{\n \"key\"\t:\f\"value\"\n,\n\"foo\" : \"bar\"\n}\n\n"), is(expected)); } @@ -86,9 +85,10 @@ public void paddedData_2() throws Exception { Map expected = new TreeMap<>(); expected.put("key", "value/other"); expected.put("foo", "bar\\manchu"); - assertThat(ConnectionHeaders.fromString( - " \b\t\n\r\f{ \b\t\n\r\f\"key\" \b\t\n\r\f: \b\t\n\r\f\"value\\/other\" \b\t\n\r\f, \b\t\n\r\f\"foo\" " - + "\b\t\n\r\f: \b\t\n\r\f\"bar\\\\manchu\" \b\t\n\r\f} \b\t\n\r\f"), + assertThat( + ConnectionHeaders.fromString( + " \b\t\n\r\f{ \b\t\n\r\f\"key\" \b\t\n\r\f: \b\t\n\r\f\"value\\/other\" \b\t\n\r\f, \b\t\n\r\f\"foo\" " + + "\b\t\n\r\f: \b\t\n\r\f\"bar\\\\manchu\" \b\t\n\r\f} \b\t\n\r\f"), is(expected)); } @@ -205,5 +205,4 @@ public void utilityClass_2() throws Exception { final InvocationTargetException e = assertThrows(InvocationTargetException.class, constructor::newInstance); assertThat(e.getCause(), instanceOf(IllegalAccessError.class)); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/HoldFilterLayer.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/HoldFilterLayer.java index a0f22d6f5..834228d9b 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/HoldFilterLayer.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/HoldFilterLayer.java @@ -96,5 +96,4 @@ public void doSend(@NonNull ByteBuffer data) throws IOException { } } } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/NetworkLayerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/NetworkLayerTest.java index 3ea80d19e..8cfd89ebc 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/NetworkLayerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/NetworkLayerTest.java @@ -81,17 +81,15 @@ public void tearDown() throws Exception { } @Theory - public void doBasicSendReceive(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - ProtocolStack client = - ProtocolStack - .on(clientFactory.create(hub, serverToClient.source(), clientToServer.sink())) - .build(new IOBufferMatcherLayer()); + public void doBasicSendReceive(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) + throws Exception { + ProtocolStack client = ProtocolStack.on( + clientFactory.create(hub, serverToClient.source(), clientToServer.sink())) + .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack - .on(serverFactory.create(hub, clientToServer.source(), serverToClient.sink())) - .build(new IOBufferMatcherLayer()); + ProtocolStack server = ProtocolStack.on( + serverFactory.create(hub, clientToServer.source(), serverToClient.sink())) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -103,5 +101,4 @@ public void doBasicSendReceive(NetworkLayerFactory serverFactory, NetworkLayerFa server.get().close(null); client.get().awaitClose(); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/NoOpFilterLayer.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/NoOpFilterLayer.java index 7e8ffe35c..007818af5 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/NoOpFilterLayer.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/NoOpFilterLayer.java @@ -38,5 +38,4 @@ public void onRecv(@NonNull ByteBuffer data) throws IOException { public void doSend(@NonNull ByteBuffer data) throws IOException { next().doSend(data); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayerTest.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayerTest.java index 9d91621d2..a39932eb8 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayerTest.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/SSLEngineFilterLayerTest.java @@ -74,40 +74,35 @@ public class SSLEngineFilterLayerTest { private static RSAKeyPairRule serverKey = new RSAKeyPairRule(); private static RSAKeyPairRule caRootKey = new RSAKeyPairRule(); private static X509CertificateRule caRootCert = X509CertificateRule.create("caRoot", caRootKey, caRootKey, null); - private static X509CertificateRule clientCert = X509CertificateRule.create("client", clientKey, caRootKey, caRootCert); - private static X509CertificateRule serverCert = X509CertificateRule.create("server", serverKey, caRootKey, caRootCert); + private static X509CertificateRule clientCert = + X509CertificateRule.create("client", clientKey, caRootKey, caRootCert); + private static X509CertificateRule serverCert = + X509CertificateRule.create("server", serverKey, caRootKey, caRootCert); private static X509CertificateRule expiredClientCert = X509CertificateRule.create("expiredClient", clientKey, caRootKey, caRootCert, -10, -5, TimeUnit.DAYS); private static X509CertificateRule notYetValidServerCert = X509CertificateRule.create("notYetValidServer", serverKey, caRootKey, caRootCert, +5, +10, TimeUnit.DAYS); - private static SSLContextRule clientCtx = - new SSLContextRule("client") - .as(clientKey, clientCert, caRootCert) - .trusting(caRootCert) - .trusting(serverCert); - private static SSLContextRule serverCtx = - new SSLContextRule("server") - .as(serverKey, serverCert, caRootCert) - .trusting(caRootCert) - .trusting(clientCert); - private static SSLContextRule expiredClientCtx = - new SSLContextRule("expiredClient") - .as(clientKey, expiredClientCert, caRootCert) - .trusting(caRootCert) - .trusting(serverCert); - private static SSLContextRule notYetValidServerCtx = - new SSLContextRule("notYetValidServer") - .as(serverKey, notYetValidServerCert, caRootCert) - .trusting(caRootCert) - .trusting(clientCert); + private static SSLContextRule clientCtx = new SSLContextRule("client") + .as(clientKey, clientCert, caRootCert) + .trusting(caRootCert) + .trusting(serverCert); + private static SSLContextRule serverCtx = new SSLContextRule("server") + .as(serverKey, serverCert, caRootCert) + .trusting(caRootCert) + .trusting(clientCert); + private static SSLContextRule expiredClientCtx = new SSLContextRule("expiredClient") + .as(clientKey, expiredClientCert, caRootCert) + .trusting(caRootCert) + .trusting(serverCert); + private static SSLContextRule notYetValidServerCtx = new SSLContextRule("notYetValidServer") + .as(serverKey, notYetValidServerCert, caRootCert) + .trusting(caRootCert) + .trusting(clientCert); private static SSLContextRule untrustingClientCtx = - new SSLContextRule("untrustingClient") - .as(clientKey, clientCert) - .trusting(caRootCert); + new SSLContextRule("untrustingClient").as(clientKey, clientCert).trusting(caRootCert); private static SSLContextRule untrustingServerCtx = - new SSLContextRule("untrustingServer") - .as(serverKey, serverCert) - .trusting(caRootCert); + new SSLContextRule("untrustingServer").as(serverKey, serverCert).trusting(caRootCert); + @ClassRule public static RuleChain staticCtx = RuleChain.outerRule(caRootKey) .around(clientKey) @@ -126,11 +121,15 @@ public class SSLEngineFilterLayerTest { @Rule public IOHubRule selector = new IOHubRule(); + @Rule public TestName name = new TestName(); + private Timeout globalTimeout = new Timeout(30, TimeUnit.SECONDS); + @Rule public RuleChain ctx = RuleChain.outerRule(new RepeatRule()).around(globalTimeout); + private Pipe clientToServer; private Pipe serverToClient; @@ -187,18 +186,15 @@ public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory client SSLEngine clientEngine = clientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); - + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); byte[] expected = "Here is some sample data".getBytes(StandardCharsets.UTF_8); ByteBuffer data = ByteBuffer.allocate(expected.length); @@ -212,27 +208,25 @@ public void smokes(NetworkLayerFactory serverFactory, NetworkLayerFactory client } @Theory - public void clientRejectsServer(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { + public void clientRejectsServer(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) + throws Exception { SSLEngine serverEngine = serverCtx.createSSLEngine(); serverEngine.setUseClientMode(false); serverEngine.setNeedClientAuth(true); SSLEngine clientEngine = clientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, session -> { - throw new ConnectionRefusalException("Bad server"); - })) - .build(new IOBufferMatcherLayer()); - + .filter(new SSLEngineFilterLayer(clientEngine, session -> { + throw new ConnectionRefusalException("Bad server"); + })) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); IOBufferMatcher clientMatcher = client.get(); IOBufferMatcher serverMatcher = server.get(); @@ -243,13 +237,13 @@ public void clientRejectsServer(NetworkLayerFactory serverFactory, NetworkLayerF assertThat(serverMatcher.getCloseCause(), instanceOf(ClosedChannelException.class)); } - @Theory - public void serverRejectsClient(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { - Logger.getLogger(name.getMethodName()).log( - Level.INFO, "Starting test with server {0} client {1}", new Object[]{ - serverFactory.getClass().getSimpleName(), - clientFactory.getClass().getSimpleName(), + public void serverRejectsClient(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) + throws Exception { + Logger.getLogger(name.getMethodName()) + .log(Level.INFO, "Starting test with server {0} client {1}", new Object[] { + serverFactory.getClass().getSimpleName(), + clientFactory.getClass().getSimpleName(), }); SSLEngine serverEngine = serverCtx.createSSLEngine(); serverEngine.setUseClientMode(false); @@ -257,20 +251,17 @@ public void serverRejectsClient(NetworkLayerFactory serverFactory, NetworkLayerF SSLEngine clientEngine = clientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); - + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, session -> { - throw new ConnectionRefusalException("Bad client"); - })) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, session -> { + throw new ConnectionRefusalException("Bad client"); + })) + .build(new IOBufferMatcherLayer()); IOBufferMatcher clientMatcher = client.get(); IOBufferMatcher serverMatcher = server.get(); @@ -293,18 +284,15 @@ public void untrustingClientDoesNotConnect(NetworkLayerFactory serverFactory, Ne SSLEngine clientEngine = untrustingClientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); - + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); IOBufferMatcher clientMatcher = client.get(); IOBufferMatcher serverMatcher = server.get(); @@ -324,18 +312,15 @@ public void expiredClientDoesNotConnect(NetworkLayerFactory serverFactory, Netwo SSLEngine clientEngine = expiredClientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); IOBufferMatcher clientMatcher = client.get(); IOBufferMatcher serverMatcher = server.get(); @@ -347,26 +332,23 @@ public void expiredClientDoesNotConnect(NetworkLayerFactory serverFactory, Netwo } @Theory - public void clientDoesNotConnectToNotYetValidServer(NetworkLayerFactory serverFactory, - NetworkLayerFactory clientFactory) throws Exception { + public void clientDoesNotConnectToNotYetValidServer( + NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory) throws Exception { SSLEngine serverEngine = notYetValidServerCtx.createSSLEngine(); serverEngine.setUseClientMode(false); serverEngine.setNeedClientAuth(true); SSLEngine clientEngine = expiredClientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack client = - ProtocolStack.on( + ProtocolStack client = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); - + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack server = - ProtocolStack.on( + ProtocolStack server = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); IOBufferMatcher clientMatcher = client.get(); IOBufferMatcher serverMatcher = server.get(); @@ -461,33 +443,34 @@ public void concurrentStress_64k_64k(NetworkLayerFactory serverFactory, NetworkL concurrentStress(serverFactory, clientFactory, 65536, 65536); } - private void concurrentStress(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, int serverLimit, - int clientLimit) + private void concurrentStress( + NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, int serverLimit, int clientLimit) throws IOException, InterruptedException, ExecutionException { - Logger.getLogger(name.getMethodName()).log( - Level.INFO, "Starting test with server {0} client {1} serverLimit {2} clientLimit {3}", new Object[]{ - serverFactory.getClass().getSimpleName(), - clientFactory.getClass().getSimpleName(), - serverLimit, clientLimit - }); + Logger.getLogger(name.getMethodName()) + .log( + Level.INFO, + "Starting test with server {0} client {1} serverLimit {2} clientLimit {3}", + new Object[] { + serverFactory.getClass().getSimpleName(), + clientFactory.getClass().getSimpleName(), + serverLimit, + clientLimit + }); SSLEngine serverEngine = serverCtx.createSSLEngine(); serverEngine.setUseClientMode(false); serverEngine.setNeedClientAuth(true); SSLEngine clientEngine = clientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack clientStack = - ProtocolStack.on( + ProtocolStack clientStack = ProtocolStack.on( clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - - ProtocolStack serverStack = - ProtocolStack.on( + ProtocolStack serverStack = ProtocolStack.on( serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .build(new IOBufferMatcherLayer()); + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .build(new IOBufferMatcherLayer()); final IOBufferMatcher client = clientStack.get(); final IOBufferMatcher server = serverStack.get(); @@ -511,14 +494,14 @@ private void concurrentStress(NetworkLayerFactory serverFactory, NetworkLayerFac } @Theory - public void sendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, - BatchSendBufferingFilterLayer batch) + public void sendingBiggerAndBiggerBatches( + NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, BatchSendBufferingFilterLayer batch) throws IOException, InterruptedException, ExecutionException { - Logger.getLogger(name.getMethodName()).log( - Level.INFO, "Starting test with server {0} client {1} batch {2}", new Object[]{ - serverFactory.getClass().getSimpleName(), - clientFactory.getClass().getSimpleName(), - batch + Logger.getLogger(name.getMethodName()) + .log(Level.INFO, "Starting test with server {0} client {1} batch {2}", new Object[] { + serverFactory.getClass().getSimpleName(), + clientFactory.getClass().getSimpleName(), + batch }); SSLEngine serverEngine = serverCtx.createSSLEngine(); serverEngine.setUseClientMode(false); @@ -526,19 +509,16 @@ public void sendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, Net SSLEngine clientEngine = clientCtx.createSSLEngine(); clientEngine.setUseClientMode(true); - ProtocolStack clientStack = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .build(new IOBufferMatcherLayer()); - + ProtocolStack clientStack = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .build(new IOBufferMatcherLayer()); - ProtocolStack serverStack = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(batch) - .build(new IOBufferMatcherLayer()); + ProtocolStack serverStack = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(batch) + .build(new IOBufferMatcherLayer()); final IOBufferMatcher client = clientStack.get(); final IOBufferMatcher server = serverStack.get(); @@ -560,14 +540,14 @@ public void sendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, Net } @Theory - public void bidiSendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, - BatchSendBufferingFilterLayer batch) + public void bidiSendingBiggerAndBiggerBatches( + NetworkLayerFactory serverFactory, NetworkLayerFactory clientFactory, BatchSendBufferingFilterLayer batch) throws IOException, InterruptedException, ExecutionException { - Logger.getLogger(name.getMethodName()).log( - Level.INFO, "Starting test with server {0} client {1} batch {2}", new Object[]{ - serverFactory.getClass().getSimpleName(), - clientFactory.getClass().getSimpleName(), - batch + Logger.getLogger(name.getMethodName()) + .log(Level.INFO, "Starting test with server {0} client {1} batch {2}", new Object[] { + serverFactory.getClass().getSimpleName(), + clientFactory.getClass().getSimpleName(), + batch }); SSLEngine serverEngine = serverCtx.createSSLEngine(); serverEngine.setUseClientMode(false); @@ -576,24 +556,21 @@ public void bidiSendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, clientEngine.setUseClientMode(true); BatchSendBufferingFilterLayer clientBatch = batch.clone(); - ProtocolStack clientStack = - ProtocolStack - .on(clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) - .filter(new NoOpFilterLayer()) - .filter(new SSLEngineFilterLayer(clientEngine, null)) - .filter(clientBatch) - .filter(new NoOpFilterLayer()) - .build(new IOBufferMatcherLayer()); - - - ProtocolStack serverStack = - ProtocolStack - .on(serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) - .filter(new NoOpFilterLayer()) - .filter(new SSLEngineFilterLayer(serverEngine, null)) - .filter(batch) - .filter(new NoOpFilterLayer()) - .build(new IOBufferMatcherLayer()); + ProtocolStack clientStack = ProtocolStack.on( + clientFactory.create(selector.hub(), serverToClient.source(), clientToServer.sink())) + .filter(new NoOpFilterLayer()) + .filter(new SSLEngineFilterLayer(clientEngine, null)) + .filter(clientBatch) + .filter(new NoOpFilterLayer()) + .build(new IOBufferMatcherLayer()); + + ProtocolStack serverStack = ProtocolStack.on( + serverFactory.create(selector.hub(), clientToServer.source(), serverToClient.sink())) + .filter(new NoOpFilterLayer()) + .filter(new SSLEngineFilterLayer(serverEngine, null)) + .filter(batch) + .filter(new NoOpFilterLayer()) + .build(new IOBufferMatcherLayer()); final IOBufferMatcher client = clientStack.get(); final IOBufferMatcher server = serverStack.get(); @@ -610,5 +587,4 @@ public void bidiSendingBiggerAndBiggerBatches(NetworkLayerFactory serverFactory, client.awaitByteContent(SequentialSender.matcher(clientAmount)); server.awaitByteContent(SequentialSender.matcher(serverAmount)); } - } diff --git a/src/test/java/org/jenkinsci/remoting/protocol/impl/SequentialSender.java b/src/test/java/org/jenkinsci/remoting/protocol/impl/SequentialSender.java index 12c9a04f4..18adfbcc6 100644 --- a/src/test/java/org/jenkinsci/remoting/protocol/impl/SequentialSender.java +++ b/src/test/java/org/jenkinsci/remoting/protocol/impl/SequentialSender.java @@ -123,10 +123,10 @@ public Void call() throws Exception { } if (nextLog - System.nanoTime() < 0) { nextLog = System.nanoTime() + TimeUnit.SECONDS.toNanos(5); - LOGGER.log(Level.INFO, "Sent {0} in {1} blocks", new Object[]{count, n}); + LOGGER.log(Level.INFO, "Sent {0} in {1} blocks", new Object[] {count, n}); } } - LOGGER.log(Level.INFO, "Done {0} in {1} blocks", new Object[]{limit, n}); + LOGGER.log(Level.INFO, "Done {0} in {1} blocks", new Object[] {limit, n}); return null; } diff --git a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStreamTest.java b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStreamTest.java index 0313c2087..b73cfec63 100644 --- a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStreamTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueInputStreamTest.java @@ -112,7 +112,7 @@ public void skipRead() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - try (ByteBufferQueueInputStream instance = new ByteBufferQueueInputStream(queue) ) { + try (ByteBufferQueueInputStream instance = new ByteBufferQueueInputStream(queue)) { StringBuilder buf = new StringBuilder(); int b; do { diff --git a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueOutputStreamTest.java b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueOutputStreamTest.java index 8591c6a13..a54c68b00 100644 --- a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueOutputStreamTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueOutputStreamTest.java @@ -76,5 +76,4 @@ private String read(ByteBufferQueue queue) { } return r.toString(); } - } diff --git a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueTest.java b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueTest.java index 7b41836bc..b62934a03 100644 --- a/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/ByteBufferQueueTest.java @@ -59,7 +59,7 @@ public void putOneByteAndHasRemaining() { public void putGetByteAndHasRemaining() { ByteBufferQueue queue = new ByteBufferQueue(100); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - byte b = (byte)i; + byte b = (byte) i; queue.put(b); assertThat(queue.hasRemaining(), is(true)); assertThat(queue.get(), is(b)); @@ -72,7 +72,7 @@ public void putOneByteGetSequences() { ByteBufferQueue queue = new ByteBufferQueue(100); ByteBuffer src = ByteBuffer.allocate(1); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - byte b = (byte)i; + byte b = (byte) i; src.clear(); src.put(b); src.flip(); @@ -92,7 +92,7 @@ public void putGetOneByteSequences() { ByteBufferQueue queue = new ByteBufferQueue(100); ByteBuffer src = ByteBuffer.allocate(1); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - byte b = (byte)i; + byte b = (byte) i; queue.put(b); assertThat(queue.hasRemaining(), is(true)); } @@ -111,7 +111,7 @@ public void putGetOneByteSequences() { public void putGetByteSequences() { ByteBufferQueue queue = new ByteBufferQueue(100); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - byte b = (byte)i; + byte b = (byte) i; queue.put(b); assertThat(queue.hasRemaining(), is(true)); } @@ -128,7 +128,7 @@ public void putGetByteArraySequences() { ByteBufferQueue queue = new ByteBufferQueue(100); byte[] dst = new byte[1]; for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - byte b = (byte)i; + byte b = (byte) i; queue.put(b); assertThat(queue.hasRemaining(), is(true)); } @@ -484,21 +484,22 @@ public void interleavedReadWrite(int intSize, int srcSize, int srcCount, int dst } @Test - public void interleavingReadWrite_7_11_13_853_19_5(){ + public void interleavingReadWrite_7_11_13_853_19_5() { interleavingReadWrite(7, 11, 13, 853, 19, 5); } @Test - public void interleavingReadWrite_7_11_13_853_5_19(){ + public void interleavingReadWrite_7_11_13_853_5_19() { interleavingReadWrite(7, 11, 13, 853, 19, 5); } @Test - public void interleavingReadWrite_23_37_53_1051_13_29(){ + public void interleavingReadWrite_23_37_53_1051_13_29() { interleavingReadWrite(23, 37, 53, 1051, 13, 29); } - public void interleavingReadWrite(int intSize, int srcSize, int dstSize, int srcCount, int srcModulus, int dstModulus) { + public void interleavingReadWrite( + int intSize, int srcSize, int dstSize, int srcCount, int srcModulus, int dstModulus) { ByteBufferQueue queue = new ByteBufferQueue(intSize); ByteBuffer src = ByteBuffer.allocate(srcSize); ByteBuffer dst = ByteBuffer.allocate(dstSize); diff --git a/src/test/java/org/jenkinsci/remoting/util/DurationFormatterTest.java b/src/test/java/org/jenkinsci/remoting/util/DurationFormatterTest.java index b74bc7766..c957c94f1 100644 --- a/src/test/java/org/jenkinsci/remoting/util/DurationFormatterTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/DurationFormatterTest.java @@ -10,13 +10,17 @@ public class DurationFormatterTest { public void typical() { assertEquals("1 second", DurationFormatter.format(Duration.ofSeconds(1))); assertEquals("2 seconds", DurationFormatter.format(Duration.ofSeconds(2))); - assertEquals("1 day, 2 seconds", DurationFormatter.format(Duration.ofDays(1).plus(Duration.ofSeconds(2)))); - assertEquals("2 days, 3 hours, 2 seconds", DurationFormatter.format(Duration.ofDays(2).plus(Duration.ofHours(3)).plus(Duration.ofSeconds(2)))); - assertEquals("2 days, 3 hours, 1 minute, 2 seconds", DurationFormatter.format( - Duration.ofDays(2) - .plus(Duration.ofHours(3)) - .plus(Duration.ofMinutes(1)) - .plus(Duration.ofSeconds(2) - ))); + assertEquals( + "1 day, 2 seconds", DurationFormatter.format(Duration.ofDays(1).plus(Duration.ofSeconds(2)))); + assertEquals( + "2 days, 3 hours, 2 seconds", + DurationFormatter.format( + Duration.ofDays(2).plus(Duration.ofHours(3)).plus(Duration.ofSeconds(2)))); + assertEquals( + "2 days, 3 hours, 1 minute, 2 seconds", + DurationFormatter.format(Duration.ofDays(2) + .plus(Duration.ofHours(3)) + .plus(Duration.ofMinutes(1)) + .plus(Duration.ofSeconds(2)))); } } diff --git a/src/test/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStreamTest.java b/src/test/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStreamTest.java index 5d7e36cf4..cba9923fa 100644 --- a/src/test/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStreamTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/FastByteBufferQueueInputStreamTest.java @@ -62,7 +62,7 @@ public void readSome() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue,26); + FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue, 26); assertThat(read(instance, 10), is("AbCdEfGhIj")); } @@ -73,7 +73,7 @@ public void readBytes() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue,26); + FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue, 26); byte[] bytes = new byte[10]; assertThat(instance.read(bytes), is(10)); @@ -91,10 +91,10 @@ public void readBytesOffset() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue,26); + FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue, 26); byte[] bytes = new byte[10]; - assertThat(instance.read(bytes,5,3), is(3)); + assertThat(instance.read(bytes, 5, 3), is(3)); assertThat(new String(bytes, StandardCharsets.UTF_8), is("\u0000\u0000\u0000\u0000\u0000AbC\u0000\u0000")); assertThat(instance.read(bytes, 0, 2), is(2)); assertThat(new String(bytes, StandardCharsets.UTF_8), is("dE\u0000\u0000\u0000AbC\u0000\u0000")); @@ -113,7 +113,7 @@ public void skipRead() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - try (FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue,26)) { + try (FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue, 26)) { StringBuilder buf = new StringBuilder(); int b; do { @@ -137,7 +137,7 @@ public void markRead() throws Exception { ByteBufferQueue queue = new ByteBufferQueue(10); queue.put(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8))); - FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue,26); + FastByteBufferQueueInputStream instance = new FastByteBufferQueueInputStream(queue, 26); assertThat(instance.markSupported(), is(false)); instance.close(); } diff --git a/src/test/java/org/jenkinsci/remoting/util/SettableFutureTest.java b/src/test/java/org/jenkinsci/remoting/util/SettableFutureTest.java index 6cb4988da..1940883a8 100644 --- a/src/test/java/org/jenkinsci/remoting/util/SettableFutureTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/SettableFutureTest.java @@ -142,8 +142,7 @@ public void cancel_beforeSet() { assertFalse(async.set(42)); } - public void assertCompletedFuture(@Nullable Object expectedValue) - throws InterruptedException, ExecutionException { + public void assertCompletedFuture(@Nullable Object expectedValue) throws InterruptedException, ExecutionException { assertTrue(future.isDone()); assertFalse(future.isCancelled()); @@ -154,8 +153,7 @@ public void assertCompletedFuture(@Nullable Object expectedValue) assertEquals(expectedValue, future.get()); } - public void assertCancelledFuture() - throws InterruptedException, ExecutionException { + public void assertCancelledFuture() throws InterruptedException, ExecutionException { assertTrue(future.isDone()); assertTrue(future.isCancelled()); @@ -163,12 +161,13 @@ public void assertCancelledFuture() assertTrue(future.isDone()); assertTrue(future.isCancelled()); - assertThrows("Future should throw CancellationException on cancel.", - CancellationException.class, () -> future.get()); + assertThrows( + "Future should throw CancellationException on cancel.", + CancellationException.class, + () -> future.get()); } - public void assertFailedFuture(@Nullable String message) - throws InterruptedException { + public void assertFailedFuture(@Nullable String message) throws InterruptedException { assertTrue(future.isDone()); assertFalse(future.isCancelled()); @@ -176,9 +175,8 @@ public void assertFailedFuture(@Nullable String message) assertTrue(future.isDone()); assertFalse(future.isCancelled()); - final ExecutionException e = assertThrows("Future should rethrow the exception.", - ExecutionException.class, () -> future.get()); + final ExecutionException e = + assertThrows("Future should rethrow the exception.", ExecutionException.class, () -> future.get()); assertThat(e.getCause().getMessage(), is(message)); } - } diff --git a/src/test/java/org/jenkinsci/remoting/util/VersionNumberTest.java b/src/test/java/org/jenkinsci/remoting/util/VersionNumberTest.java index 13912d096..6e8479677 100644 --- a/src/test/java/org/jenkinsci/remoting/util/VersionNumberTest.java +++ b/src/test/java/org/jenkinsci/remoting/util/VersionNumberTest.java @@ -30,35 +30,40 @@ /** * @author Xavier Le Vourch */ -// Copied from https://github.com/jenkinsci/lib-version-number/blob/master/src/test/java/hudson/util/VersionNumberTest.java +// Copied from +// https://github.com/jenkinsci/lib-version-number/blob/master/src/test/java/hudson/util/VersionNumberTest.java // We didn't want to introduce a dependency on another library and had troubles getting shading to work. public class VersionNumberTest extends TestCase { public void testIsNewerThan() { - assertTrue(new VersionNumber("2.0.*").isNewerThan(new VersionNumber("2.0"))); - assertTrue(new VersionNumber("2.1-SNAPSHOT").isNewerThan(new VersionNumber("2.0.*"))); - assertTrue(new VersionNumber("2.1").isNewerThan(new VersionNumber("2.1-SNAPSHOT"))); - assertTrue(new VersionNumber("2.0.*").isNewerThan(new VersionNumber("2.0.1"))); - assertTrue(new VersionNumber("2.0.1").isNewerThan(new VersionNumber("2.0.1-SNAPSHOT"))); - assertTrue(new VersionNumber("2.0.1-SNAPSHOT").isNewerThan(new VersionNumber("2.0.0.99"))); - assertTrue(new VersionNumber("2.0.0.99").isNewerThan(new VersionNumber("2.0.0"))); - assertTrue(new VersionNumber("2.0.0").isNewerThan(new VersionNumber("2.0.ea"))); - assertTrue(new VersionNumber("2.0").isNewerThan(new VersionNumber("2.0.ea"))); - // the inversion of the previous test case from the old behaviour is explained by - // which makes more sense than before - assertEquals(new VersionNumber("2.0.0"), new VersionNumber("2.0")); + assertTrue(new VersionNumber("2.0.*").isNewerThan(new VersionNumber("2.0"))); + assertTrue(new VersionNumber("2.1-SNAPSHOT").isNewerThan(new VersionNumber("2.0.*"))); + assertTrue(new VersionNumber("2.1").isNewerThan(new VersionNumber("2.1-SNAPSHOT"))); + assertTrue(new VersionNumber("2.0.*").isNewerThan(new VersionNumber("2.0.1"))); + assertTrue(new VersionNumber("2.0.1").isNewerThan(new VersionNumber("2.0.1-SNAPSHOT"))); + assertTrue(new VersionNumber("2.0.1-SNAPSHOT").isNewerThan(new VersionNumber("2.0.0.99"))); + assertTrue(new VersionNumber("2.0.0.99").isNewerThan(new VersionNumber("2.0.0"))); + assertTrue(new VersionNumber("2.0.0").isNewerThan(new VersionNumber("2.0.ea"))); + assertTrue(new VersionNumber("2.0").isNewerThan(new VersionNumber("2.0.ea"))); + // the inversion of the previous test case from the old behaviour is explained by + // which makes more sense than before + assertEquals(new VersionNumber("2.0.0"), new VersionNumber("2.0")); } public void testEarlyAccess() { - assertTrue(new VersionNumber("2.0.ea2").isNewerThan(new VersionNumber("2.0.ea1"))); - assertTrue(new VersionNumber("2.0.ea1").isNewerThan(new VersionNumber("2.0.ea"))); - assertEquals(new VersionNumber("2.0.ea"), new VersionNumber("2.0.ea0")); + assertTrue(new VersionNumber("2.0.ea2").isNewerThan(new VersionNumber("2.0.ea1"))); + assertTrue(new VersionNumber("2.0.ea1").isNewerThan(new VersionNumber("2.0.ea"))); + assertEquals(new VersionNumber("2.0.ea"), new VersionNumber("2.0.ea0")); } public void testSnapshots() { - assertTrue(new VersionNumber("1.12").isNewerThan(new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)"))); - assertTrue(new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)").isNewerThan(new VersionNumber("1.11"))); - assertEquals(new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)"), new VersionNumber("1.12-SNAPSHOT")); + assertTrue(new VersionNumber("1.12") + .isNewerThan(new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)"))); + assertTrue(new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)") + .isNewerThan(new VersionNumber("1.11"))); + assertEquals( + new VersionNumber("1.12-SNAPSHOT (private-08/24/2008 12:13-hudson)"), + new VersionNumber("1.12-SNAPSHOT")); // This is changed from the old impl because snapshots are no longer a "magic" number assertNotEquals(new VersionNumber("1.12-SNAPSHOT"), new VersionNumber("1.11.*")); assertTrue(new VersionNumber("1.11.*").isNewerThan(new VersionNumber("1.11.9"))); @@ -68,10 +73,15 @@ public void testTimestamps() { assertTrue(new VersionNumber("2.0.3-20170207.105042-1").isNewerThan(new VersionNumber("2.0.2"))); assertTrue(new VersionNumber("2.0.3").isNewerThan(new VersionNumber("2.0.3-20170207.105042-1"))); assertEquals(new VersionNumber("2.0.3-20170207.105042-1"), new VersionNumber("2.0.3-SNAPSHOT")); - assertEquals(new VersionNumber("2.0.3-20170207.105042-1"), new VersionNumber("2.0.3-SNAPSHOT (private-08/24/2008 12:13-hudson)")); - assertTrue(new VersionNumber("2.0.3-20170207.105043-2").isNewerThan(new VersionNumber("2.0.3-20170207.105042-1"))); - assertTrue(new VersionNumber("2.0.3-20170207.105042-2").isNewerThan(new VersionNumber("2.0.3-20170207.105042-1"))); - assertTrue(new VersionNumber("2.0.3-20170207.105042-13").isNewerThan(new VersionNumber("2.0.3-20170207.105042-2"))); + assertEquals( + new VersionNumber("2.0.3-20170207.105042-1"), + new VersionNumber("2.0.3-SNAPSHOT (private-08/24/2008 12:13-hudson)")); + assertTrue( + new VersionNumber("2.0.3-20170207.105043-2").isNewerThan(new VersionNumber("2.0.3-20170207.105042-1"))); + assertTrue( + new VersionNumber("2.0.3-20170207.105042-2").isNewerThan(new VersionNumber("2.0.3-20170207.105042-1"))); + assertTrue(new VersionNumber("2.0.3-20170207.105042-13") + .isNewerThan(new VersionNumber("2.0.3-20170207.105042-2"))); assertFalse(new VersionNumber("2.0.3-20170207.105042-1").isNewerThan(new VersionNumber("2.0.3-SNAPSHOT"))); assertFalse(new VersionNumber("2.0.3-20170207.105042-1").isOlderThan(new VersionNumber("2.0.3-SNAPSHOT"))); }