I have a Gateway implementation, which redirects requests, but also I'm adding a capability to decrypt the body of the received request. The thing is that I've found a lot of answers here on SO with instructions to implement it, wrapping the original request, but in some point, I do not know why, the request get lost before reaching the target and throws an IOException (the decryption works perfectly).
This is my implementation:
public class MyRequestWraper extends HttpServletRequestWrapper {
public MyRequestWraper(HttpServletRequest request) {
super(request);
}
#Override
public ServletInputStream getInputStream() throws IOException {
try {
String decryptedPayload = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decryptedPayload.getBytes(getRequest().getCharacterEncoding()));
return new ServletInputStream(){
#SuppressWarnings("unused")
private ReadListener readListener = null;
#Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
#Override
public void close() throws IOException {
byteArrayInputStream.close();
}
#Override
public int read(byte[] b, int off, int len) throws IOException {
return byteArrayInputStream.read(b, off, len);
}
#Override
public boolean isFinished() {
return byteArrayInputStream.available() > 0;
}
#Override
public boolean isReady() {
return isFinished();
}
#Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
};
} catch (Exception e) {
e.printStackTrace();
return super.getInputStream();
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
And this is the exception I get:
org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: UT000128: Remote peer closed connection before all data could be read
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:243)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:201)
The wrapper instance is used inside a Filter implementation, so I'm passing in it to the "chain.doFilter" (and as I said, I can see that the decryption is executed and successful). Any clue will be appreciated.
EDIT
Also tried to use a byte[] instead of ByteArrayInputStream for the getInputStream() implementation, based on this comment
Finally I made it work, the problem was with the content length of the request (keep in mind that my original request was encrypted, and the new input stream is decrypted, so the length differs). I have to overwrite the getContentLength method, and some other minor changes:
public class MyRequestWraper extends HttpServletRequestWrapper {
private byte[] content;
public MyRequestWraper(HttpServletRequest request) {
super(request);
content = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
}
#Override
public int getContentLength() {
if (content != null) {
return content.length;
}
return super.getContentLength();
}
#Override
public ServletInputStream getInputStream() throws IOException {
try {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
return new ServletInputStream(){
#SuppressWarnings("unused")
private ReadListener readListener = null;
#Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
#Override
public void close() throws IOException {
byteArrayInputStream.close();
}
#Override
public int read(byte[] b, int off, int len) throws IOException {
return byteArrayInputStream.read(b, off, len);
}
#Override
public boolean isFinished() {
return byteArrayInputStream.available() > 0;
}
#Override
public boolean isReady() {
return isFinished();
}
#Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
};
} catch (Exception e) {
e.printStackTrace();
return super.getInputStream();
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
Related
My application is currently running on java 1.6_45 and OSGI 3.2.
I should adapt TLSv1.2, because the server supports only TLSv1.2 from now.
I still get bad_record_mac error.
Can anyone help me?
I tried the following****
// Installiere Bouncy Castle und TLS 1.2
if (Security.getProvider(BouncyCastleJsseProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleJsseProvider());
}
....
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
System.out.println("TLSv1.2 ist vorhanden.");
......
sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[] { defaultTrustManager }, null);
// Create SSLConnectionSocketFactory with TLSv1.2
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
// Create clients
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
// Set UnirestClient
Unirest.setHttpClient(httpClient);
....
// Unirest Httpclient get request
HttpResponse<String> response = Unirest.get(url.toString()).basicAuth(<username>, <pass>).header("Accept-Language", "de").asString();
I get the following exception***
1559 [SpringOsgiExtenderThread-10] INFO org.bouncycastle.jsse.provider.ProvTlsClient - Client raised fatal(2) bad_record_mac(20) alert: Failed to read record
org.bouncycastle.tls.TlsFatalAlert: bad_record_mac(20)
at org.bouncycastle.tls.crypto.impl.TlsAEADCipher.decodeCiphertext(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.tls.RecordStream.decodeAndVerify(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396) [httpclient-4.5.3.jar:4.5.3]
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355) [httpclient-4.5.3.jar:4.5.3]
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) [httpclient-4.5.3.jar:4.5.3]
at
Caused by: java.lang.IllegalStateException: javax.crypto.BadPaddingException: mac check in GCM failed
at org.bouncycastle.tls.crypto.impl.jcajce.JceAEADCipherImpl.doFinal(Unknown Source) [bctls-jdk15on-160.jar:1.60.0.0]
... 51 common frames omitted
Caused by: javax.crypto.BadPaddingException: mac check in GCM failed
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source) [bcprov-jdk15on-160.jar:1.60.0]
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source) [bcprov-jdk15on-160.jar:1.60.0]
at javax.crypto.Cipher.doFinal(DashoA13*..) [na:1.6]
... 52 common frames omitted
I found a new Solution like the following
public class TLSSocketConnectionFactory extends SSLSocketFactory {
// ******************Adding Custom BouncyCastleProvider*********************//
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
Security.addProvider(new BouncyCastleProvider());
}
// ******************HANDSHAKE LISTENER*********************//
public class TLSHandshakeListener implements HandshakeCompletedListener {
#Override
public void handshakeCompleted(HandshakeCompletedEvent event) {
}
}
private SecureRandom _secureRandom = new SecureRandom();
// ******************Adding Custom BouncyCastleProvider*********************//
#Override
public Socket createSocket(Socket socket, final String host, int port, boolean arg3) throws IOException {
if (socket == null) {
socket = new Socket();
}
if (!socket.isConnected()) {
socket.connect(new InetSocketAddress(host, port));
}
final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom);
return _createSSLSocket(host, tlsClientProtocol);
}
// ******************SOCKET FACTORY METHODS*********************//
#Override
public String[] getDefaultCipherSuites() {
return null;
}
#Override
public String[] getSupportedCipherSuites() {
return null;
}
#Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return null;
}
#Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return null;
}
#Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return null;
}
#Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return null;
}
// ******************SOCKET CREATION*********************//
private SSLSocket _createSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) {
return new SSLSocket() {
private java.security.cert.Certificate[] peertCerts;
#Override
public InputStream getInputStream() throws IOException {
return tlsClientProtocol.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return tlsClientProtocol.getOutputStream();
}
#Override
public synchronized void close() throws IOException {
tlsClientProtocol.close();
}
#Override
public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public boolean getEnableSessionCreation() {
return false;
}
#Override
public String[] getEnabledCipherSuites() {
// return null;
return new String[] { "" };
}
#Override
public String[] getEnabledProtocols() {
// return null;
return new String[] { "" };
}
#Override
public boolean getNeedClientAuth() {
return false;
}
#Override
public SSLSession getSession() {
return new SSLSession() {
#Override
public int getApplicationBufferSize() {
return 0;
}
#Override
public String getCipherSuite() {
return "";
}
#Override
public long getCreationTime() {
throw new UnsupportedOperationException();
}
#Override
public byte[] getId() {
throw new UnsupportedOperationException();
}
#Override
public long getLastAccessedTime() {
throw new UnsupportedOperationException();
}
#Override
public java.security.cert.Certificate[] getLocalCertificates() {
throw new UnsupportedOperationException();
}
#Override
public Principal getLocalPrincipal() {
return null;
}
#Override
public int getPacketBufferSize() {
throw new UnsupportedOperationException();
}
#Override
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
return null;
}
#Override
public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
return peertCerts;
}
#Override
public String getPeerHost() {
throw new UnsupportedOperationException();
}
#Override
public int getPeerPort() {
return 0;
}
#Override
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
return null;
// throw new UnsupportedOperationException();
}
#Override
public String getProtocol() {
return "";
}
#Override
public SSLSessionContext getSessionContext() {
throw new UnsupportedOperationException();
}
#Override
public Object getValue(String arg0) {
throw new UnsupportedOperationException();
}
#Override
public String[] getValueNames() {
throw new UnsupportedOperationException();
}
#Override
public void invalidate() {
throw new UnsupportedOperationException();
}
#Override
public boolean isValid() {
throw new UnsupportedOperationException();
}
#Override
public void putValue(String arg0, Object arg1) {
throw new UnsupportedOperationException();
}
#Override
public void removeValue(String arg0) {
throw new UnsupportedOperationException();
}
};
}
#Override
public String[] getSupportedProtocols() {
return null;
}
#Override
public boolean getUseClientMode() {
return false;
}
#Override
public boolean getWantClientAuth() {
return false;
}
#Override
public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public void setEnableSessionCreation(boolean arg0) {
}
#Override
public void setEnabledCipherSuites(String[] arg0) {
}
#Override
public void setEnabledProtocols(String[] arg0) {
}
#Override
public void setNeedClientAuth(boolean arg0) {
}
#Override
public void setUseClientMode(boolean arg0) {
}
#Override
public void setWantClientAuth(boolean arg0) {
}
#Override
public String[] getSupportedCipherSuites() {
return null;
}
#Override
public void startHandshake() throws IOException {
tlsClientProtocol.connect(new DefaultTlsClient() {
#Override
public Hashtable<Integer, byte[]> getClientExtensions() throws IOException {
Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions();
if (clientExtensions == null) {
clientExtensions = new Hashtable<Integer, byte[]>();
}
// Add host_name
byte[] host_name = host.getBytes();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(host_name.length + 3); // entry size
dos.writeByte(0); // name type = hostname
dos.writeShort(host_name.length);
dos.write(host_name);
dos.close();
clientExtensions.put(ExtensionType.server_name, baos.toByteArray());
return clientExtensions;
}
#Override
public TlsAuthentication getAuthentication() throws IOException {
return new TlsAuthentication() {
#Override
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {
certs.add(cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())));
}
peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
} catch (CertificateException e) {
System.out.println("Failed to cache server certs" + e);
throw new IOException(e);
}
}
#Override
public TlsCredentials getClientCredentials(CertificateRequest arg0) throws IOException {
return null;
}
};
}
});
}
};// Socket
}
}
and create new http client like the following
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(new TLSSocketConnectionFactory(), new String[] { "TLSv1.2" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
// Create clients
HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(sf).build();
// Set UnirestClient
Unirest.setHttpClient(httpClient);
now works great :)
I have just read, that in Java the classes PrintStream and PrintWriter don't throw checked exceptions. Instead they are using a kind of an error flag which I can read invoking the method boolean checkError() (API link).
Now, I am asking myself how to find out the reason why the exception occurred. The information that there was an exception is sometimes maybe not enough, or?
Based on the source code, it looks like they discard the exception. All of the catch blocks look like this:
try {
...
}
catch (IOException x) {
trouble = true; // (x is ignored)
}
So the most straightforward solution is probably to not use PrintStream, if possible.
One workaround could be to extend PrintStream and wrap the output in another OutputStream which captures the exception before PrintStream catches (and discards) it. Something like this:
package mcve.util;
import java.io.*;
public class PrintStreamEx extends PrintStream {
public PrintStreamEx(OutputStream out) {
super(new HelperOutputStream(out));
}
/**
* #return the last IOException thrown by the output,
* or null if there isn't one
*/
public IOException getLastException() {
return ((HelperOutputStream) out).lastException;
}
#Override
protected void clearError() {
super.clearError();
((HelperOutputStream) out).setLastException(null);
}
private static class HelperOutputStream extends FilterOutputStream {
private IOException lastException;
private HelperOutputStream(OutputStream out) {
super(out);
}
private IOException setLastException(IOException e) {
return (lastException = e);
}
#Override
public void write(int b) throws IOException {
try {
super.write(b);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void write(byte[] b) throws IOException {
try {
super.write(b);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
try {
super.write(b, off, len);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void flush() throws IOException {
try {
super.flush();
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void close() throws IOException {
try {
super.close();
} catch (IOException e) {
throw setLastException(e);
}
}
}
}
I am currently working on a requirement where I need to get the XML (from POST request) in the servlet filter before the request reaches to the Spring controller and then I need to process the XML (cut off some empty nodes/elements) in the filter and then the call should proceed further.
I tried the below code (attached only snippet) and I was able to get the request body (XML) and able to set the modified response.
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (httpRequest.getMethod().equalsIgnoreCase("POST")) {
extractDataFromRequest(httpRequest);
httpResponse.getWriter().write("<root><root>");
}
chain.doFilter(request, wrappedResponse);
public static String extractDataFromRequest(HttpServletRequest request) throws IOException {
String line;
StringBuilder builder = new StringBuilder();
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
}
However, spring failed with the following exception.
Severe: java.lang.IllegalStateException: PWC3997: getReader() has already been called for this request
at org.apache.catalina.connector.Request.getInputStream(Request.java:1178)
at org.apache.catalina.connector.RequestFacade.getInputStream(RequestFacade.java:407)
at org.springframework.http.server.ServletServerHttpRequest.getBody(ServletServerHttpRequest.java:165)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:120)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:100)
I am looking for a concrete implementation for this requirement from experts.
You can't use the InputStream twice, you need to create a wrapper class which keeps a repeatable copy of the InputStream.
public class ReadTwiceHttpServletRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public ReadTwiceHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
IOUtils.copy(request.getInputStream(), outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray())));
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return new ServletInputStream() {
#Override
public int readLine(byte[] b, int off, int len) throws IOException {
return inputStream.read(b, off, len);
}
#Override
public boolean isFinished() {
return inputStream.available() > 0;
}
#Override
public boolean isReady() {
return true;
}
#Override
public void setReadListener(ReadListener arg0) {
// TODO Auto-generated method stub
}
#Override
public int read() throws IOException {
return inputStream.read();
}
};
}
public void setBody(String body) {
outputStream = new ByteArrayOutputStream();
try {
outputStream.write(body.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getBody() {
return new String(outputStream.toByteArray());
}
}
Then you need to initialise that with a Filter which is first in the chain.
public class ReadTwiceFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ReadTwiceHttpServletRequestWrapper readTwiceHttpServletRequestWrapper = new ReadTwiceHttpServletRequestWrapper(
(HttpServletRequest) request);
String newBody = readTwiceHttpServletRequestWrapper.getBody().replace("<soap:studentId>1</soap:studentId>", "<soap:studentId>2</soap:studentId>");
readTwiceHttpServletRequestWrapper.setBody(newBody);
chain.doFilter(readTwiceHttpServletRequestWrapper, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
Change your implementation in the filter to use getInputStream instead of getReader method. This issue arises when the overall implementation invokes both getReader and getInputStream method on ServletRequest.
As mentioned in javadoc, only one of them can be called. Looking at the stacktrace; the controller(spring mvc) is invoking getInputStream on it and hence failing with a message getReader() has already been called...
While it is qute clear how to configure multi-threaded jBehave run,
it is not qute clear for me how to deal with logging mess.
What are the options here?
Rederect application's output to std out (JBehave's one is already there). Notice follow=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.follow=true
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %-64.64C %4L | %m%n
log4j.rootLogger=error, stdout
log4j.logger.com.company.app.interesting.module=debug
...
Per thread file output
#SuppressWarnings("resource")
public class ThreadFileOutput extends PrintStream {
private static ThreadLocal<FileOutputStream> threadOutput = new ThreadLocal<>();
private static PrintStream stdout = System.out;
private static PrintStream stderr = System.err;
static {
System.setOut(new ThreadFileOutput(stdout));
System.setErr(new ThreadFileOutput(stderr));
}
public ThreadFileOutput(OutputStream out) {
super(out);
}
public static void startThreadOutputRedirect(FileOutputStream stream) {
threadOutput.set(stream);
}
public static void stopThreadOutputRedirect() {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
threadOutput.set(null);
try {
stream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void forceOut(String line) {
stdout.println(line);
}
public static void forceErr(String line) {
stderr.println(line);
}
#Override
public void write(byte[] b) throws IOException {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(b);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(b);
}
}
#Override
public void write(int b) {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(b);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(b);
}
}
#Override
public void write(byte[] buf, int off, int len) {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.write(buf, off, len);
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.write(buf, off, len);
}
}
#Override
public void flush() {
FileOutputStream stream = threadOutput.get();
if (stream != null) {
try {
stream.flush();
} catch (IOException e) {
threadOutput.set(null);
throw new RuntimeException(e);
}
} else {
super.flush();
}
}
}
Start redirecting thread output to the file befor the test and stop it after the test
startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath()))));
stopThreadOutputRedirect();
in
/**
* JBehave to TC integration.
*/
public class TeamCityReporter extends NullStoryReporter {
private static final LookupTranslator ESCAPE_TABLE = new LookupTranslator(new String[][] {
{ "'", "|'" },
{ "\n", "|n" },
{ "\r", "|r" },
{ "\\u", "|0x" },
{ "|", "||" },
{ "[", "|[" },
{ "]", "|]" }
});
private ThreadLocal<Story> story = new ThreadLocal<>();
private ThreadLocal<String> scenario = new ThreadLocal<>();
#Override
#SuppressWarnings("resource")
public void beforeStory(Story story, boolean givenStory) {
this.story.set(story);
this.scenario.set(null);
try {
startThreadOutputRedirect(new FileOutputStream(new File(workDirRelative(story.getPath()))));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
forceOut(format("##teamcity[testSuiteStarted name='%s']", escape(story.getPath())));
out.println(story.getPath());
super.beforeStory(story, givenStory);
}
#Override
public void afterStory(boolean givenStory) {
forceOut(format("##teamcity[testSuiteFinished name='%s']", escape(story.get().getPath())));
stopThreadOutputRedirect();
super.afterStory(givenStory);
}
#Override
public void beforeScenario(String scenario) {
this.scenario.set(scenario);
forceOut(format("##teamcity[testStarted name='%s']", escape(scenario)));
out.println(scenario);
super.beforeScenario(scenario);
}
#Override
public void afterScenario() {
forceOut(format("##teamcity[testFinished name='%s']", escape(scenario.get())));
this.scenario.set(null);
super.afterScenario();
}
#Override
public void beforeStep(String step) {
out.println(format("\n%s\n", step));
super.beforeStep(step);
}
#Override
public void storyNotAllowed(Story story, String filter) {
forceOut(format("##teamcity[message text='story not allowed %s' status='WARNING']", escape(story.getName())));
out.println(format("\n(Not allowed) %s\n", story.getPath()));
super.storyNotAllowed(story, filter);
}
#Override
public void failed(String step, Throwable cause) {
forceOut(format("##teamcity[testFailed name='%s' message='%s' details='%s']", new String[] { escape(scenario.get()), escape(getRootCauseMessage(cause)), escape(getStackTrace(cause)) }));
out.println(format("\n(Failed) %s\n", step));
cause.printStackTrace();
super.failed(step, cause);
}
#Override
public void pending(String step) {
forceOut(format("##teamcity[testFailed name='%s' message='Step in PENDING state: %s']", escape(scenario.get()), escape(step)));
out.println(format("\n(Pending) %s\n", step));
super.pending(step);
}
#Override
public void notPerformed(String step) {
out.println(format("\n(Not performed) %s\n", step));
super.notPerformed(step);
}
private static String escape(String string) {
return ESCAPE_TABLE.translate(string);
}
}
Turn on parallel JBehave execution
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
...
})
public class Stories extends JUnitStories {
#Before
public void setUp() throws Exception {
configuredEmbedder()
// turn on parallel test execution
.useExecutorService(newFixedThreadPool(30, new ThreadFactoryBuilder()
.setDaemon(true)
.build()));
configuredEmbedder()
.embedderControls()
...
// don't use it this way not to produce multiThreading = true and delayed StoryReporter callbacks
// and you will see your application logging 'for each jbehave step'
// .useThreads(30);
}
#Override
public Configuration configuration() {
return new MostUsefulConfiguration()
...
.useStoryReporterBuilder(new StoryReporterBuilder()
...
.withFormats(HTML)
.withReporters(teamCityReporter));
}
}
As a result, there will be a log file for each parallel test having both test output and application output (only the code being executed by test runner thread).
Bonus - TeamCityReporter (JBehave to TC integration) will successfully count running parallel tests in real time and report any test failures on TC GUI. Configure test output directory as TC artifact path to access each test output.
First i run serveur_final.java,creating thread for clients,getting login and password from client and in the second thread verify them in database and after sending "ok" to client and initialize communication
public class Serveur_final {
private ServerSocket sock_serv=null;
private Socket client_entrant=null;
private static Vector<String> nom_client=null;
private static Vector<connect_serveur> list_client=null;
private int port=1991;
public Serveur_final() throws IOException{
initialisation();
}
public void initialisation() throws IOException {
sock_serv=new ServerSocket(port);
System.out.println("ecoute au"+port);
list_client=new Vector<connect_serveur>();
nom_client=new Vector<String>();
while(true){
client_entrant=sock_serv.accept();
connect_serveur con=new connect_serveur(client_entrant);
list_client.add(con) ;
}
}
public static void ajouter_list(String nom_cli){
nom_client.add(nom_cli);
diffusion_list(nom_client);
}
public static void supprimer_nom_client(String con){
for(String nom: nom_client){
if(nom.equals(con)){
nom_client.remove(nom);
}
}
}
public static void supprimer_client(connect_serveur con){
for(connect_serveur nom: list_client){
if(nom.equals(con)){
list_client.remove(nom);}
}
}
public static Vector<connect_serveur> getList_client(){
return list_client;
}
public static void diffusion_list(Vector<String> client) {
for(connect_serveur cl: list_client){
for(int i=0;i<client.size();i++){
cl.diffuser(nom_client.get(i));
}
}
}
public static void diffusion_message(String client,String message) {
for(connect_serveur cl: list_client){
/*for(int i=0;i<nom_client.size();i++){*/
cl.getThead_client().getEnvoi_msg().diffusion(client, message);
/*}*/
}
}
public static void deconnection(String pseudo) {
for(connect_serveur cl: list_client){
if(cl.getPseudo().equals(pseudo)){
list_client.remove(cl);
}
for(int i=0;i<nom_client.size();i++){
if(pseudo.equals(nom_client.get(i))){
nom_client.remove(i);
}
}
}
}
}
/
///class connect-serveur
public class connect_serveur extends Thread {
private Socket client;
private BufferedReader reception;
private static PrintWriter envoi;
private String pseudo,passwd;
/* private static Vector<String> list_nom_client;*/
initialisation_communication thread_client;
private boolean verif=false, autorisation=false;
public connect_serveur(Socket client_entrant) throws IOException {
this.client=client_entrant;
envoi=new PrintWriter(client.getOutputStream());
reception=new BufferedReader(new InputStreamReader(client.getInputStream()));
pseudo=reception.readLine();
passwd=reception.readLine();
verif=verifier_info(pseudo, passwd);
setPseudo(pseudo);
start();
}
#Override
public void run() {
try {
if(!verif){
envoi.println("bye4");
envoi.flush();
Serveur_final.supprimer_client(this);
reception.close();
envoi.close();
client.close();
Serveur_final.deconnection(pseudo);
}
envoi.println("ok");
envoi.flush();
Serveur_final.ajouter_list(pseudo);
thread_client=new initialisation_communication(pseudo, envoi,reception);
setThead_client(thread_client);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setPseudo(String pseudo2) {
this.pseudo=pseudo2;
}
public String getPseudo() {
return this.pseudo;
}
public initialisation_communication getThead_client(){
return thread_client;
}
public void setThead_client(initialisation_communication com ){
thread_client=com;
}
/*public static void diffuser_list(Vector<String>client){
list_nom_client=client;
for(int i=0;i<list_nom_client.size();i++){
diffuser(list_nom_client.get(i));
Serveur_final.diffusion_list();
}
}*/
public static void diffuser(String client) {
System.out.println("en diffusion");
envoi.println("0>>:"+client);
envoi.flush();
}
boolean verifier_info(String pseudo, String passwd) {
autorisation=connexion_bdd.getInstance().verification_log(pseudo, passwd);
System.out.println("AUTORISER"+autorisation);
if(autorisation)
{
envoi.println("ok");
envoi.flush();
System.out.println("adding user");
}
else {
envoi.println("no");
envoi.flush();
}
return autorisation;
}
}
//initialisation-comm class
public class initialisation_communication extends Thread {
private String pseudo;
private BufferedReader reception;
private PrintWriter envoi;
private envoyer_message envoi_msg;
private recevoir_message recoi_msg;
public initialisation_communication(String pseudo,PrintWriter envoi,BufferedReader reception) {
// TODO Auto-generated constructor stub
this.envoi=envoi;
this.reception=reception;
this.pseudo=pseudo;
start();
}
#Override
public void run() {
/*envoi=new PrintWriter(socket_client.getOutputStream());
BufferedReader reception = new BufferedReader(new InputStreamReader(socket_client.getInputStream()));*/
System.out.println("initialiser");
envoi_msg=new envoyer_message(pseudo,envoi,reception);
recoi_msg=new recevoir_message(reception);
setEnvoi_msg(envoi_msg);
}
public envoyer_message getEnvoi_msg(){
return envoi_msg;
}
public void setEnvoi_msg(envoyer_message com ){
this.envoi_msg=com;
}
}
//envoyer_msg class:from which i'm getting errors
public class envoyer_message extends Thread {
private PrintWriter emettre;
private BufferedReader reception;
private String pseudo;
public envoyer_message(String pseudo, PrintWriter envoi, BufferedReader reception) {
this.emettre=envoi;
this.reception=reception;
this.pseudo=pseudo;
System.out.println("dans envoyer dja");
start();
}
public void run(){
String message;
emettre.println("bien connectee");
try {
while (true) {
message = reception.readLine();
if(message=="!!>>fin<<!!"){
Serveur_final.deconnection(pseudo);
}
Serveur_final.diffusion_message(pseudo, message);
} // end of while
} // try
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
public void diffusion(String pseudo2, String message) {
emettre.println(">>:"+pseudo2+"dit :"+message);
}
}
and finally my client
public class client_chat {
private Socket socket_client;
private String connected="",passwd,login,adress_server="localhost";
private int Port=1991;
private BufferedReader entrer=null;
private PrintWriter sortie=null;
private static client_chat client;
private boolean connecte=false;
private BufferedReader clavier ;
private String message;
private boolean fermer;
public client_chat(){
try {
this.socket_client=new Socket(adress_server,Port);
connecte=getConnection("nao", "nao");
init(connecte);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.getMessage();
}
}
public static client_chat getIntance(){
if(client==null){
client=new client_chat();
}
return client;
}
public boolean getConnection(String pseudo,String passwd){
this.login=pseudo;
this.passwd=passwd;
if(socket_client!=null){
try {
entrer=new BufferedReader(new InputStreamReader(socket_client.getInputStream()));
sortie=new PrintWriter(socket_client.getOutputStream());
sortie.println(pseudo);
sortie.flush();
sortie.println(passwd);
sortie.flush();
connected=entrer.readLine();
System.out.println(connected);
if(connected=="ok"){
connecte=true;
System.out.println(connected);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return connecte;
}
public void init(Boolean con) throws IOException{
if(con ){
new ThreadLecture().start();
while(!fermer){
clavier=new BufferedReader(new InputStreamReader(System.in));
sortie.println(clavier.readLine());
}
entrer.close();
sortie.close();
socket_client.close();
}
}
public void setLogin(String ps){
this.login=ps;
}
public String getLogin(){
return this.login;
}
public void setPasswd(String ps){
this.passwd=ps;
}
public String getPasswd(){
return this.passwd;
}
class ThreadLecture extends Thread{
public void run() {
try {
System.out.println("dans runcli");
while(true){
message=entrer.readLine();
System.out.println(message);
if(message.indexOf("bye4")!=-1 ||message.indexOf ("!!>>fin<<!!")!=-1)
break;
enter code here
}
fermer=true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
error message after running client_chat.java
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at modeles.envoyer_message.run(envoyer_message.java:30)
sorry for my english, I need your help please!
I have tried all the tips
"All the tips" say the same thing, or they should. You have written to a connection that had already been closed by the other end. An application protocol error.
There isn't nearly enough EOS-checking in your code either. For example you are just assuming you receive both the username and the password.
I don't know if this will fix this, but i noticed your check:
if(message=="!!>>fin<<!!"){
in envoyer_msg.run() is wrong.
message is a String, string comparison is done by equals()/compareTo().
Cheers