Skip to content

Commit

Permalink
Wrapping all methods of the EntityInputStream
Browse files Browse the repository at this point in the history
Signed-off-by: Maxim Nesen <[email protected]>
  • Loading branch information
senivam committed Nov 5, 2024
1 parent 7903c97 commit 0de97f4
Show file tree
Hide file tree
Showing 3 changed files with 289 additions and 4 deletions.
41 changes: 38 additions & 3 deletions core-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -310,21 +310,39 @@
</goals>
</execution>
<execution>
<!-- Compile these files with jdk 8 and put them aside to be included in multirelase jar -->
<!-- Compile these files with jdk 8 and put them aside to be included in multi-release jar -->
<!-- Multi-release jar is built by jdk 11+, but these classes are buildable by jdk 8 only -->
<id>compile-2-java8</id>
<phase>process-resources</phase>
<configuration>
<target>
<mkdir dir="${java8.build.outputDirectory}" />
<javac srcdir="${java8.sourceDirectory}" destdir="${java8.build.outputDirectory}"
<javac srcdir="${java8.sourceDirectory}/org/glassfish/jersey/internal" destdir="${java8.build.outputDirectory}"
classpath="${project.build.outputDirectory}" includeantruntime="false" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>compile-3-java8</id>
<phase>process-classes</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<property name="compile.classpath" refid="maven.compile.classpath"/>
<mkdir dir="${java8.build.outputDirectory}" />
<javac srcdir="${java8.sourceDirectory}/org/glassfish/jersey/message/internal"
destdir="${java8.build.outputDirectory}"
classpath="${project.build.outputDirectory}${path.separator}${compile.classpath}"
includeantruntime="false" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
Expand Down Expand Up @@ -381,14 +399,31 @@
<configuration>
<target>
<mkdir dir="${java11.build.outputDirectory}" />
<javac srcdir="${java11.sourceDirectory}" destdir="${java11.build.outputDirectory}"
<javac srcdir="${java11.sourceDirectory}/org/glassfish/jersey/internal" destdir="${java11.build.outputDirectory}"
classpath="${project.build.outputDirectory}" includeantruntime="false" release="11" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>compile-3-java11</id>
<phase>process-classes</phase>
<configuration>
<target>
<property name="compile_classpath" refid="maven.compile.classpath"/>

<mkdir dir="${java11.build.outputDirectory}" />
<javac srcdir="${java11.sourceDirectory}/org/glassfish/jersey/message/internal" destdir="${java11.build.outputDirectory}"
classpath="${project.build.outputDirectory}${path.separator}${compile_classpath}"
includeantruntime="false" release="11" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.message.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;

import javax.ws.rs.ProcessingException;

import org.glassfish.jersey.internal.LocalizationMessages;

/**
* Entity input stream customized for entity message processing:
* <ul>
* <li>contains {@link #isEmpty()} method.</li>
* <li>{@link #close()} method throws Jersey-specific runtime exception in case of an IO error.</li>
* </ul>
*
* @author Marek Potociar
*/
public class EntityInputStream extends InputStream {

private InputStream input;
private boolean closed = false;

/**
* Create an entity input stream instance wrapping the original input stream.
* <p/>
* In case the original entity stream is already of type {@code EntityInputStream},
* the stream is returned without wrapping.
*
* @param inputStream input stream.
* @return entity input stream.
*/
public static EntityInputStream create(InputStream inputStream) {
if (inputStream instanceof EntityInputStream) {
return (EntityInputStream) inputStream;
}

return new EntityInputStream(inputStream);
}

/**
* Extension constructor.
*
* @param input underlying wrapped input stream.
*/
public EntityInputStream(InputStream input) {
this.input = input;
}

@Override
public int read() throws IOException {
return input.read();
}

@Override
public int read(byte[] b) throws IOException {
return input.read(b);
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return input.read(b, off, len);
}

@Override
public byte[] readAllBytes() throws IOException {
return input.readAllBytes();
}

@Override
public int readNBytes(byte[] b, int off, int len) throws IOException {
return input.readNBytes(b, off, len);
}
@Override
public long transferTo(OutputStream out) throws IOException {
return input.transferTo(out);
}

@Override
public long skip(long n) throws IOException {
return input.skip(n);
}

@Override
public int available() throws IOException {
return input.available();
}

@Override
public void mark(int readLimit) {
input.mark(readLimit);
}

@Override
public boolean markSupported() {
return input.markSupported();
}

/**
* {@inheritDoc}
* <p>
* The method is customized to not throw an {@link IOException} if the reset operation fails. Instead,
* a runtime {@link javax.ws.rs.ProcessingException} is thrown.
* </p>
*
* @throws javax.ws.rs.ProcessingException in case the reset operation on the underlying entity input stream failed.
*/
@Override
public void reset() {
try {
input.reset();
} catch (IOException ex) {
throw new ProcessingException(LocalizationMessages.MESSAGE_CONTENT_BUFFER_RESET_FAILED(), ex);
}
}

/**
* {@inheritDoc}
* <p>
* The method is customized to not throw an {@link IOException} if the close operation fails. Instead,
* a warning message is logged.
* </p>
*/
@Override
public void close() throws ProcessingException {
final InputStream in = input;
if (in == null) {
return;
}
if (!closed) {
try {
in.close();
} catch (IOException ex) {
// This e.g. means that the underlying socket stream got closed by other thread somehow...
throw new ProcessingException(LocalizationMessages.MESSAGE_CONTENT_INPUT_STREAM_CLOSE_FAILED(), ex);
} finally {
closed = true;
}
}
}

/**
* Check if the underlying entity stream is empty.
* <p>
* Note that the operation may need to block until a first byte (or EOF) is available in the stream.
* </p>
*
* @return {@code true} if the entity stream is empty, {@code false} otherwise.
*/
public boolean isEmpty() {
ensureNotClosed();

final InputStream in = input;
if (in == null) {
return true;
}

try {
// Try #markSupported first - #available on WLS waits until socked timeout is reached when chunked encoding is used.
if (in.markSupported()) {
in.mark(1);
int i = in.read();
in.reset();
return i == -1;
} else {
try {
if (in.available() > 0) {
return false;
}
} catch (IOException ioe) {
// NOOP. Try other approaches as this can fail on WLS.
}

int b = in.read();
if (b == -1) {
return true;
}

PushbackInputStream pbis;
if (in instanceof PushbackInputStream) {
pbis = (PushbackInputStream) in;
} else {
pbis = new PushbackInputStream(in, 1);
input = pbis;
}
pbis.unread(b);

return false;
}
} catch (IOException ex) {
throw new ProcessingException(ex);
}
}

/**
* Check that the entity input stream has not been closed yet.
*
* @throws IllegalStateException in case the entity input stream has been closed.
*/
public void ensureNotClosed() throws IllegalStateException {
if (closed) {
throw new IllegalStateException(LocalizationMessages.ERROR_ENTITY_STREAM_CLOSED());
}
}

/**
* Get the closed status of this input stream.
*
* @return {@code true} if the stream has been closed, {@code false} otherwise.
*/
public boolean isClosed() {
return closed;
}

/**
* Get the wrapped input stream instance.
*
* @return wrapped input stream instance.
*/
public final InputStream getWrappedStream() {
return input;
}

/**
* Set the wrapped input stream instance.
*
* @param wrapped new input stream instance to be wrapped.
*/
public final void setWrappedStream(InputStream wrapped) {
input = wrapped;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down

0 comments on commit 0de97f4

Please sign in to comment.