/*
* Copyright 2010 Richard Zschech.
*
* Licensed 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 net.zschech.gwt.comet.server.impl;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.zschech.gwt.comet.client.impl.HTTPRequestCometTransport;
import net.zschech.gwt.comet.server.CometServlet;
import com.google.gwt.rpc.server.ClientOracle;
import com.google.gwt.user.server.rpc.SerializationPolicy;
/**
* The CometServletResponse for the {@link HTTPRequestCometTransport}
*
* @author Richard Zschech
*/
public abstract class RawDataCometServletResponse extends ManagedStreamCometServletResponseImpl {
private static final int MAX_PADDING_REQUIRED = 256;
private static final String PADDING_STRING;
static {
char[] padding = new char[MAX_PADDING_REQUIRED];
for (int i = 0; i < padding.length - 1; i++) {
padding[i] = '*';
}
padding[padding.length - 1] = '\n';
PADDING_STRING = new String(padding);
}
public RawDataCometServletResponse(HttpServletRequest request, HttpServletResponse response, SerializationPolicy serializationPolicy, ClientOracle clientOracle, CometServlet servlet, AsyncServlet async, int heartbeat) {
super(request, response, serializationPolicy, clientOracle, servlet, async, heartbeat);
}
@Override
protected void appendMessageTrailer() throws IOException {
writer.append('\n');
}
@Override
protected int getPaddingRequired() {
return 0;
}
@Override
protected CharSequence getPadding(int padding) {
if (padding > PADDING_STRING.length()) {
StringBuilder result = new StringBuilder(padding);
for (int i = 0; i < padding - 2; i++) {
result.append('*');
}
return result;
}
else {
return PADDING_STRING.substring(padding);
}
}
@Override
protected void doInitiate(int heartbeat) throws IOException {
// send connection event to client
appendMessageHeader();
writer.append('!').append(String.valueOf(heartbeat));
appendMessageTrailer();
}
@Override
protected void doSendError(int statusCode, String message) throws IOException {
appendMessageHeader();
writer.append(String.valueOf(statusCode));
if (message != null) {
writer.append(' ').append(escape(message));
}
appendMessageTrailer();
}
@Override
protected void doWrite(List<? extends Serializable> messages) throws IOException {
for (Serializable message : messages) {
CharSequence string;
appendMessageHeader();
if (message instanceof CharSequence) {
string = escape((CharSequence) message);
if (string == message) {
writer.append('|');
}
else {
writer.append(']');
}
}
else {
string = serialize(message);
}
appendMessage(string);
appendMessageTrailer();
}
}
protected void appendMessage(CharSequence string) throws IOException {
writer.append(string);
}
@Override
protected void doHeartbeat() throws IOException {
appendMessageHeader();
writer.append('#');
appendMessageTrailer();
}
@Override
protected void doTerminate() throws IOException {
appendMessageHeader();
writer.append('?');
appendMessageTrailer();
}
@Override
protected void doRefresh() throws IOException {
appendMessageHeader();
writer.append('@');
appendMessageTrailer();
}
@Override
protected boolean isOverTerminateLength(int written) {
return false;
}
private CharSequence escape(CharSequence string) {
int length = string.length();
int i = 0;
loop: while (i < length) {
char ch = string.charAt(i);
switch (ch) {
case '\\':
case '\n':
case '\r':
break loop;
}
i++;
}
if (i == length) {
return string;
}
StringBuilder str = new StringBuilder(string.length() * 2);
str.append(string, 0, i);
while (i < length) {
char ch = string.charAt(i);
switch (ch) {
case '\\':
str.append("\\\\");
break;
case '\n':
str.append("\\n");
break;
case '\r':
str.append("\\r");
break;
default:
str.append(ch);
}
i++;
}
return str;
}
}