Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ protected AsteriskVersion determineVersion() throws IOException, TimeoutExceptio
if (Asterisk14outputPresent)
{
List<String> outputList = Arrays
.asList(showVersionFilesResponse.getOutput().split(SocketConnectionFacadeImpl.NL_PATTERN.pattern()));
.asList(showVersionFilesResponse.getOutput().split(Pattern.quote(SocketConnectionFacadeImpl.NL_PATTERN)));
showVersionFilesResult = outputList;
}
else
Expand Down
161 changes: 161 additions & 0 deletions src/main/java/org/asteriskjava/util/internal/LineReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package org.asteriskjava.util.internal;

import java.io.IOException;
import java.io.Reader;

public class LineReader extends Reader
{
private Reader in;
private char[] pattern;
private char[] cbuf;
private int off, len;

/**
* @param pattern the pattern used as delimiter for line breaks in {@link #readLine()}
*/
public LineReader(Reader in, String pattern)
{
if (pattern.isEmpty())
{
throw new IllegalArgumentException("pattern must not be empty");
}
this.in = in;
this.pattern = pattern.toCharArray();
cbuf = new char[8192 + pattern.length()];
}

@Override
public void close() throws IOException
{
synchronized (lock)
{
if (in == null)
{
return;
}
try
{
in.close();
}
finally
{
// free memory
in = null;
pattern = null;
cbuf = null;

// disable reading
len = -1;
}
}
}

@Override
public int read(char[] cbuf, int off, int len) throws IOException
{
if (len <= 0)
{
return 0;
}
if (off < 0 || off + len >= cbuf.length)
{
throw new ArrayIndexOutOfBoundsException();
}
synchronized (lock)
{
// fill buffer from stream
if (this.len == 0)
{
this.off = 0;
this.len = in.read(this.cbuf);
}

// end of stream?
if (this.len < 0)
{
// free memory
pattern = null;
this.cbuf = null;
return -1;
}

// copy buffer to result
len = Math.min(len, this.len);
System.arraycopy(this.cbuf, this.off, cbuf, off, len);
this.off += len;
this.len -= len;
return len;
}
}

/**
* Reads a line of text.
* A line is considered to be terminated by {@link #pattern}.
*
* @return A String containing the contents of the line, not including the pattern {@link #pattern}, or null if the end of the stream has been reached
* @exception IOException If an I/O error occurs
* @see java.io.BufferedReader#readLine()
*/
public String readLine() throws IOException
{
synchronized (lock)
{
if (len < 0)
{
return null;
}

StringBuilder result = new StringBuilder(80);
while (true)
{
// search pattern in buffer
int matches = 0;
int limit = len - off;
for (int i = off; i < limit; )
{
if (cbuf[i++] == pattern[matches])
{
matches++;
if (matches == pattern.length)
{
int size = i - off;
result.append(cbuf, off, size - matches);
off += size;
len -= size;
return result.toString();
}
}
else
{
// backtrack
i -= matches;
matches = 0;
}
}

// copy buffer to result except for matched suffix
result.append(cbuf, off, len - matches);

// fill buffer from stream
// (leaving some space to prepend matched suffix later)
len = in.read(cbuf, matches, cbuf.length - matches);

// end of stream?
if (len < 0)
{
// append matched suffix
result.append(pattern, 0, matches);
// free memory
pattern = null;
cbuf = null;
return result.length() > 0 ? result.toString() : null;
}

// prepend previously matched suffix as new prefix (for search during next iteration)
System.arraycopy(pattern, 0, cbuf, 0, matches);
off = 0;
len += matches; // chars from stream + previously matched suffix
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/
package org.asteriskjava.util.internal;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -28,8 +27,6 @@
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.regex.Pattern;

import javax.net.SocketFactory;
Expand All @@ -45,10 +42,10 @@
*/
public class SocketConnectionFacadeImpl implements SocketConnectionFacade
{
public static final Pattern CRNL_PATTERN = Pattern.compile("\r\n");
public static final Pattern NL_PATTERN = Pattern.compile("\n");
public static final String CRNL_PATTERN = "\r\n";
public static final String NL_PATTERN = "\n";
private Socket socket;
private Scanner scanner;
private LineReader reader;
private BufferedWriter writer;
private Trace trace;

Expand Down Expand Up @@ -103,7 +100,7 @@ public SocketConnectionFacadeImpl(String host, int port, boolean ssl, int timeou
* @throws IOException if the connection cannot be established.
*/
public SocketConnectionFacadeImpl(String host, int port, boolean ssl, int timeout, int readTimeout,
Pattern lineDelimiter) throws IOException
String lineDelimiter) throws IOException
{
this(host, port, ssl, timeout, readTimeout, StandardCharsets.UTF_8, lineDelimiter);
}
Expand All @@ -124,7 +121,7 @@ public SocketConnectionFacadeImpl(String host, int port, boolean ssl, int timeou
* @throws IOException if the connection cannot be established.
*/
public SocketConnectionFacadeImpl(String host, int port, boolean ssl, int timeout, int readTimeout, Charset encoding,
Pattern lineDelimiter) throws IOException
String lineDelimiter) throws IOException
{
Socket socket;

Expand Down Expand Up @@ -162,45 +159,21 @@ public SocketConnectionFacadeImpl(String host, int port, boolean ssl, int timeou
/** 70 mi = 70 * 60 * 1000 */
private static final int MAX_SOCKET_READ_TIMEOUT_MILLIS = 4200000;

private void initialize(Socket socket, Charset encoding, Pattern pattern) throws IOException
private void initialize(Socket socket, Charset encoding, String pattern) throws IOException
{
this.socket = socket;

InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, encoding));

this.scanner = new Scanner(reader);
this.scanner.useDelimiter(pattern);
this.reader = new LineReader(new InputStreamReader(inputStream, encoding), pattern);
this.writer = new BufferedWriter(new OutputStreamWriter(outputStream, encoding));
}

@Override
public String readLine() throws IOException
{
String line;
try
{
line = scanner.next();
}
catch (IllegalStateException e)
{
if (scanner.ioException() != null)
{
throw scanner.ioException();
}
// throw new IOException("No more lines available", e); // JDK6
throw new IOException("No more lines available: " + e.getMessage());
}
catch (NoSuchElementException e)
{
if (scanner.ioException() != null)
{
throw scanner.ioException();
}
// throw new IOException("No more lines available", e); // JDK6
throw new IOException("No more lines available: " + e.getMessage());
}
line = reader.readLine();

if (trace != null)
{
Expand All @@ -226,7 +199,7 @@ public void flush() throws IOException
public void close() throws IOException
{
socket.close();
scanner.close();
reader.close();
// close the trace only if it was activated (the object is not null)
if (trace != null)
{
Expand Down
91 changes: 91 additions & 0 deletions src/test/java/org/asteriskjava/util/internal/LineReaderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.asteriskjava.util.internal;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.regex.Pattern;

/**
* @author sere
* @since 2018-01-30
*/
public class LineReaderTest {
public static void main(String[] args) throws Exception {
final byte[] bytes = new byte[1000_000_000];
byte[] str = "Hallo hello: one line with text!\r\n".getBytes(StandardCharsets.US_ASCII);
for (int i = 0; i < bytes.length; i += str.length) {
System.arraycopy(str, 0, bytes, i, str.length);
}

for (int i = 10; i-- > 0; ) {
System.out.print(i + ":\t");

InputStream inputStream = new ByteArrayInputStream(bytes);

LineReader reader = new LineReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), "\r\n");
Scanner scanner = new Scanner(reader);
scanner.useDelimiter(Pattern.compile("\r\n"));

long start = System.currentTimeMillis();
try {
while (reader.readLine() != null) {
}
} catch (NoSuchElementException e) {
}
System.out.println((System.currentTimeMillis() - start));
}
}

public static void main2(String[] args) throws IOException {
Charset charset = StandardCharsets.UTF_8;
PipedOutputStream out = new PipedOutputStream();
final BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out, charset));
LineReader r = new LineReader(new InputStreamReader(new PipedInputStream(out), charset), "123");

new Thread() {
@Override
public void run() {
try {
write("ab");
write("12");
write("3");
write("ab");
write("12");
write("ab");
write("121");
write("2");
write("3");
write("321");
write("2312");

System.out.println("--");
w.close();
} catch (Exception e) {
e.printStackTrace();
}
}

private void write(String s) throws Exception {
System.out.println("<< " + s);
w.write(s);
w.flush();
Thread.sleep(1000);
}
}.start();

System.out.println("1: " + r.readLine());
System.out.println("2: " + r.readLine());
System.out.println("3: " + r.readLine());
System.out.println("4: " + r.readLine());
System.out.println("5: " + r.readLine());
}
}