org.apache.james.imap.functional.ImapHostSystem Maven / Gradle / Ivy
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.imap.functional;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.HashSet;
import java.util.Set;
import org.apache.james.imap.api.process.ImapProcessor;
import org.apache.james.imap.decode.ImapDecoder;
import org.apache.james.imap.encode.ImapEncoder;
import org.apache.james.imap.main.ImapRequestStreamHandler;
import org.apache.james.imap.main.ImapSessionImpl;
import org.apache.james.mailbox.MailboxSession.User;
import org.apache.james.test.functional.HostSystem;
public abstract class ImapHostSystem implements HostSystem {
private ImapDecoder decoder;
private ImapEncoder encoder;
private ImapProcessor processor;
private final Set users;
public ImapHostSystem() {
super();
users = new HashSet();
}
public void configure(final ImapDecoder decoder, final ImapEncoder encoder,
final ImapProcessor processor) {
this.decoder = decoder;
this.encoder = encoder;
this.processor = processor;
}
public HostSystem.Session newSession(Continuation continuation)
throws Exception {
return new Session(continuation);
}
public final void reset() throws Exception {
users.clear();
resetData();
}
protected abstract void resetData() throws Exception;
public String getHelloName() {
return "JAMES";
}
public ImapDecoder getImapDecoder() {
return decoder;
}
public ImapEncoder getImapEncoder() {
return encoder;
}
public ImapProcessor getImapProcessor() {
return processor;
}
public int getResetLength() {
return Integer.MAX_VALUE;
}
public int countUsers() {
return users.size();
}
public String getRealName(String name) {
return name;
}
class Session implements HostSystem.Session {
ByteBufferOutputStream out;
ByteBufferInputStream in;
ImapRequestStreamHandler handler;
ImapSessionImpl session;
boolean isReadLast = true;
public Session(Continuation continuation) {
out = new ByteBufferOutputStream(continuation);
in = new ByteBufferInputStream();
handler = new ImapRequestStreamHandler(decoder, processor, encoder);
session = new ImapSessionImpl();
session.setLog(new SilentLog());
}
public String readLine() throws Exception {
if (!isReadLast) {
handler.handleRequest(in, out, session);
isReadLast = true;
}
final String result = out.nextLine();
return result;
}
public void start() throws Exception {
// Welcome message handled in the server
out.write("* OK IMAP4rev1 Server ready\r\n");
}
public void stop() throws Exception {
}
public void writeLine(String line) throws Exception {
isReadLast = false;
in.nextLine(line);
}
public void forceConnectionClose(String byeMessage) {
try {
out.write(byeMessage);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
static class ByteBufferInputStream extends InputStream {
ByteBuffer buffer = ByteBuffer.allocate(16384);
CharsetEncoder encoder = Charset.forName("ASCII").newEncoder();
boolean readLast = true;
public int read() throws IOException {
if (!readLast) {
readLast = true;
buffer.flip();
}
int result = -1;
if (buffer.hasRemaining()) {
result = buffer.get();
}
return result;
}
public void nextLine(String line) {
if (buffer.position() > 0 && readLast) {
buffer.compact();
}
encoder.encode(CharBuffer.wrap(line), buffer, true);
buffer.put((byte) '\r');
buffer.put((byte) '\n');
readLast = false;
}
}
static class ByteBufferOutputStream extends OutputStream {
ByteBuffer buffer = ByteBuffer.allocate(65536);
Charset ascii = Charset.forName("ASCII");
Continuation continuation;
boolean matchPlus = false;
boolean matchCR = false;
boolean matchLF = false;
public ByteBufferOutputStream(Continuation continuation) {
this.continuation = continuation;
}
public void write(String message) throws IOException {
ascii.newEncoder().encode(CharBuffer.wrap(message), buffer, true);
}
public void write(int b) throws IOException {
buffer.put((byte) b);
if (b == '\n' && matchPlus && matchCR && matchLF) {
matchPlus = false;
matchCR = false;
matchLF = false;
continuation.doContinue();
} else if (b == '\n') {
matchLF = true;
matchPlus = false;
matchCR = false;
} else if (b == '+' && matchLF) {
matchPlus = true;
matchCR = false;
} else if (b == '\r' && matchPlus && matchLF) {
matchCR = true;
} else {
matchPlus = false;
matchCR = false;
matchLF = false;
}
}
public String nextLine() throws Exception {
buffer.flip();
byte last = 0;
while (buffer.hasRemaining()) {
byte next = buffer.get();
if (last == '\r' && next == '\n') {
break;
}
last = next;
}
final ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
readOnlyBuffer.flip();
int limit = readOnlyBuffer.limit() - 2;
if (limit < 0) {
limit = 0;
}
readOnlyBuffer.limit(limit);
String result = ascii.decode(readOnlyBuffer).toString();
buffer.compact();
return result;
}
}
public void afterTests() throws Exception {
// default do nothing
}
public void beforeTests() throws Exception {
// default do nothing
}
}