<commit_before>/*
 * Copyright 2009 <NAME>.
 * 
 * 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.ByteArrayOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.zschech.gwt.comet.server.CometServlet;
import net.zschech.gwt.comet.server.CometServletResponse;
import net.zschech.gwt.comet.server.CometSession;
import net.zschech.gwt.comet.server.deflate.DeflaterOutputStream;

import com.google.gwt.rpc.server.ClientOracle;
import com.google.gwt.rpc.server.RPC;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;

public abstract class CometServletResponseImpl implements CometServletResponse {
	
	private HttpServletRequest request;
	private final HttpServletResponse response;
	private CometSessionImpl session;
	
	private final SerializationPolicy serializationPolicy;
	private final ClientOracle clientOracle;
	private final CometServlet servlet;
	private final AsyncServlet async;
	private final int heartbeat;
	
	private Flushable flushable;
	private OutputStream asyncOutputStream;
	protected Writer writer;
	
	private boolean terminated;
	private boolean suspended;
	
	private Object suspendInfo;
	private volatile long lastWriteTime;
	private ScheduledFuture<?> heartbeatFuture;
	private ScheduledFuture<?> sessionKeepAliveFuture;
	
	protected CometServletResponseImpl(HttpServletRequest request, HttpServletResponse response, SerializationPolicy serializationPolicy, ClientOracle clientOracle, CometServlet servlet, AsyncServlet async, int heartbeat) {
		this.request = request;
		this.response = response;
		this.serializationPolicy = serializationPolicy;
		this.clientOracle = clientOracle;
		this.servlet = servlet;
		this.async = async;
		this.heartbeat = heartbeat;
	}
	
	@Override
	public int getHeartbeat() {
		return heartbeat;
	}
	
	@Override
	public synchronized boolean isTerminated() {
		return terminated;
	}
	
	protected OutputStream getOutputStream(OutputStream outputStream) {
		return outputStream;
	}
	
	public OutputStream getAsyncOutputStream() {
		return asyncOutputStream;
	}
	
	protected boolean isDeRPC() {
		return clientOracle != null;
	}
	
	@Override
	public synchronized HttpServletRequest getRequest() {
		if (suspended) {
			throw new IllegalStateException("HttpServletRequest can not be accessed after the CometServletResponse has been suspended.");
		}
		return request;
	}
	
	@Override
	public HttpServletResponse getResponse() {
		return response;
	}
	
	@Override
	public CometSession getSession() {
		return getSession(true);
	}
	
	@Override
	public synchronized CometSession getSession(boolean create) {
		if (suspended) {
			throw new IllegalStateException("CometSession can not be accessed after the CometServletResponse has been suspended.");
		}
		if (session != null) {
			return session;
		}
		HttpSession httpSession = getRequest().getSession(create);
		if (httpSession == null) {
			return null;
		}
		
		session = (CometSessionImpl) CometServlet.getCometSession(httpSession, create, create ? new ConcurrentLinkedQueue<Serializable>() : null);
		if (create) {
			session.setLastAccessedTime(System.currentTimeMillis());
			scheduleSessionKeepAlive();
			session.setResponse(this);
		}
		return session;
	}
	
	synchronized void scheduleSessionKeepAlive() {
		if (sessionKeepAliveFuture != null) {
			sessionKeepAliveFuture.cancel(false);
		}
		sessionKeepAliveFuture = async.scheduleSessionKeepAlive(this, session);
	}
	
	void scheduleHeartbeat() {
		assert Thread.holdsLock(this);
		lastWriteTime = System.currentTimeMillis();
		if (heartbeatFuture != null) {
			heartbeatFuture.cancel(false);
		}
		heartbeatFuture = async.scheduleHeartbeat(this, session);
	}
	
	@Override
	public void sendError(int statusCode) throws IOException {
		sendError(statusCode, null);
	}
	
	@Override
	public synchronized void sendError(int statusCode, String message) throws IOException {
		if (suspended) {
			throw new IllegalStateException("sendError can not be accessed after the CometServletResponse has been suspended.");
		}
		try {
			getResponse().reset();
			response.setHeader("Cache-Control", "no-cache");
			response.setCharacterEncoding("UTF-8");
			
			OutputStream outputStream = response.getOutputStream();
			writer = new OutputStreamWriter(outputStream, "UTF-8");
			
			doSendError(statusCode, message);
		}
		finally {
			setTerminated(true);
		}
	}
	
	public synchronized void initiate() throws IOException {
		response.setHeader("Cache-Control", "no-cache");
		response.setCharacterEncoding("UTF-8");
		
		flushable = async.getFlushable(this);<commit_msg>Nicer error handling of reset response<commit_after>/*
 * Copyright 2009 <NAME>.
 * 
 * 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.ByteArrayOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.zschech.gwt.comet.server.CometServlet;
import net.zschech.gwt.comet.server.CometServletResponse;
import net.zschech.gwt.comet.server.CometSession;
import net.zschech.gwt.comet.server.deflate.DeflaterOutputStream;

import com.google.gwt.rpc.server.ClientOracle;
import com.google.gwt.rpc.server.RPC;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;

public abstract class CometServletResponseImpl implements CometServletResponse {
	
	private HttpServletRequest request;
	private final HttpServletResponse response;
	private CometSessionImpl session;
	
	private final SerializationPolicy serializationPolicy;
	private final ClientOracle clientOracle;
	private final CometServlet servlet;
	private final AsyncServlet async;
	private final int heartbeat;
	
	private Flushable flushable;
	private OutputStream asyncOutputStream;
	protected Writer writer;
	
	private boolean terminated;
	private boolean suspended;
	
	private Object suspendInfo;
	private volatile long lastWriteTime;
	private ScheduledFuture<?> heartbeatFuture;
	private ScheduledFuture<?> sessionKeepAliveFuture;
	
	protected CometServletResponseImpl(HttpServletRequest request, HttpServletResponse response, SerializationPolicy serializationPolicy, ClientOracle clientOracle, CometServlet servlet, AsyncServlet async, int heartbeat) {
		this.request = request;
		this.response = response;
		this.serializationPolicy = serializationPolicy;
		this.clientOracle = clientOracle;
		this.servlet = servlet;
		this.async = async;
		this.heartbeat = heartbeat;
	}
	
	@Override
	public int getHeartbeat() {
		return heartbeat;
	}
	
	@Override
	public synchronized boolean isTerminated() {
		return terminated;
	}
	
	protected OutputStream getOutputStream(OutputStream outputStream) {
		return outputStream;
	}
	
	public OutputStream getAsyncOutputStream() {
		return asyncOutputStream;
	}
	
	protected boolean isDeRPC() {
		return clientOracle != null;
	}
	
	@Override
	public synchronized HttpServletRequest getRequest() {
		if (suspended) {
			throw new IllegalStateException("HttpServletRequest can not be accessed after the CometServletResponse has been suspended.");
		}
		return request;
	}
	
	@Override
	public HttpServletResponse getResponse() {
		return response;
	}
	
	@Override
	public CometSession getSession() {
		return getSession(true);
	}
	
	@Override
	public synchronized CometSession getSession(boolean create) {
		if (suspended) {
			throw new IllegalStateException("CometSession can not be accessed after the CometServletResponse has been suspended.");
		}
		if (session != null) {
			return session;
		}
		HttpSession httpSession = getRequest().getSession(create);
		if (httpSession == null) {
			return null;
		}
		
		session = (CometSessionImpl) CometServlet.getCometSession(httpSession, create, create ? new ConcurrentLinkedQueue<Serializable>() : null);
		if (create) {
			session.setLastAccessedTime(System.currentTimeMillis());
			scheduleSessionKeepAlive();
			session.setResponse(this);
		}
		return session;
	}
	
	synchronized void scheduleSessionKeepAlive() {
		if (sessionKeepAliveFuture != null) {
			sessionKeepAliveFuture.cancel(false);
		}
		sessionKeepAliveFuture = async.scheduleSessionKeepAlive(this, session);
	}
	
	void scheduleHeartbeat() {
		assert Thread.holdsLock(this);
		lastWriteTime = System.currentTimeMillis();
		if (heartbeatFuture != null) {
			heartbeatFuture.cancel(false);
		}
		heartbeatFuture = async.scheduleHeartbeat(this, session);
	}
	
	@Override
	public void sendError(int statusCode) throws IOException {
		sendError(statusCode, null);
	}
	
	@Override
	public synchronized void sendError(int statusCode, String message) throws IOException {
		if (suspended) {
			throw new IllegalStateException("sendError can not be accessed after the CometServletResponse has been suspended.");
		}
		try {
			getResponse().reset();
			response.setHeader("Cache-Control", "no-cache");
			response.setCharacterEncoding("UTF-8");
			
			OutputStream outputStream = response.getOutputStream();
			writer = new OutputStreamWriter(outputStream, "UTF-8");
			
			doSendError(statusCode, message);
		}
		catch (IllegalStateException e) {
			servlet.log("Error resetting response to send error: " + e.getMessage());
		}
		finally {
			setTerminated(true);
		}
	}
	
	public synchronized void initiate() throws IOException {
		response.setHeader("Cache-Control", "no-cache");
		response.setCharacterEncoding("UTF-8");
		
		flushable = async.getFlushable(this);
{'fraction_non_alphanumeric': 0.08717554644808743, 'fraction_numerical': 0.001878415300546448, 'mean_word_length': 5.187533016376123, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7392253', 'n_tokens_mistral': 3507, 'n_tokens_neox': 3223, 'n_words': 870}