/*
* Copyright 2009 Joubin Houshyar
*
* 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 org.jredis.ri.alphazero.protocol.wip;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;
import java.util.List;
import org.jredis.ClientRuntimeException;
import org.jredis.ProviderException;
import org.jredis.protocol.BulkResponse;
import org.jredis.protocol.Command;
import org.jredis.protocol.MultiBulkResponse;
import org.jredis.protocol.Protocol;
import org.jredis.protocol.Request;
import org.jredis.protocol.Response;
import org.jredis.protocol.ResponseStatus;
import org.jredis.protocol.StatusResponse;
import org.jredis.protocol.ValueResponse;
import org.jredis.protocol.Response.Type;
import org.jredis.ri.alphazero.connection.ConnectionResetException;
import org.jredis.ri.alphazero.connection.UnexpectedEOFException;
import org.jredis.ri.alphazero.protocol.ProtocolBase;
import org.jredis.ri.alphazero.protocol.ResponseSupport;
import org.jredis.ri.alphazero.support.Log;
public class WipProtocol extends ProtocolBase {
// ------------------------------------------------------------------------
// Properties and Attributes
// ------------------------------------------------------------------------
/** Preferred size of request data buffer */
protected static final int PREFERRED_REQUEST_BUFFER_SIZE = 1024 * 48;
/** Initial size of the shared line buffer */
protected static final int PREFERRED_LINE_BUFFER_SIZE = 128;
/** Shared by <b>all</b> {@link Request} instances of this <b>non-thread-safe</b> {@link Protocol} implementation. */
private final ByteArrayOutputStream sharedRequestBuffer;
/** Shared {@link Request} instance of this <b>non-thread-safe</b> {@link Protocol} implementation. */
private final StreamBufferRequest sharedRequestObject;
public WipProtocol() {
sharedRequestBuffer = new ByteArrayOutputStream (PREFERRED_REQUEST_BUFFER_SIZE);
sharedRequestObject = new StreamBufferRequest (sharedRequestBuffer);
}
// ------------------------------------------------------------------------
// Super Extensions
// ------------------------------------------------------------------------
@Override
protected ByteArrayOutputStream createRequestBufffer(Command cmd) {
sharedRequestBuffer.reset();
return sharedRequestBuffer;
}
@Override
protected Request createRequest (ByteArrayOutputStream buffer) {
return sharedRequestObject;
}
@Override
protected Response createStatusResponse(Command cmd) {
return new ResponseImpl(cmd, Type.Status, ValueType.STATUS);
}
@Override
protected Response createBooleanResponse(Command cmd) {
return new ResponseImpl (cmd, Type.Value, ValueType.BOOLEAN);
}
@Override
protected Response createStringResponse(Command cmd) {
return new ResponseImpl (cmd, Type.Value, ValueType.STRING);
}
@Override
protected Response createNumberResponse(Command cmd /*, boolean isBigNum*/) {
return new ResponseImpl (cmd, Type.Value, ValueType.NUMBER64);
}
@Override
protected Response createBulkResponse(Command cmd) {
return new ResponseImpl (cmd, Type.Bulk);
}
@Override
protected Response createMultiBulkResponse(Command cmd) {
return new ResponseImpl (cmd, Type.MultiBulk);
}
protected enum ValueType {
STATUS,
BOOLEAN,
NUMBER64,
STRING
}
// ------------------------------------------------------------------------
// Inner Type
// ============================================================ Response(s)
// ------------------------------------------------------------------------
/**
* [TODO: document me!]
*
* @author Joubin (alphazero@sensesay.net)
* @version alpha.0, Sep 2, 2009
* @since alpha.0
*
*/
class ResponseImpl extends ResponseSupport implements StatusResponse, ValueResponse, BulkResponse, MultiBulkResponse{
/** */
protected final ValueType valueType;
/** */
// byte[] buffer = WipProtocol.this.sharedResponseBuffer;
byte[] buffer = new byte [128];
/** */
int offset;
// --------------------------------------------------------------------
// Constructor(s)
// --------------------------------------------------------------------
/**
* Constructor for responses of type {@link Type#Bulk} and {@link Type#MultiBulk}
* @param cmd
* @param type
*/
protected ResponseImpl (Command cmd, Type type) {
this (cmd, type, null);
}
/**
* Constructor for responses of type {@link Type#Status} and {@link Type#Value}
* @param cmd
* @param type
* @param valueType
*/
protected ResponseImpl (Command cmd, Type type, ValueType valueType) {
super(cmd, type);
if(type != Type.Bulk && type != Type.MultiBulk && valueType == null)
throw new ProviderException("have null valueType for Response.Type " + type.name());
this.valueType = valueType;
}
// --------------------------------------------------------------------
// Inner ops
// --------------------------------------------------------------------
// @Override
public void read (InputStream in)
throws ClientRuntimeException, ProviderException
{
if(didRead())
return;
switch(getType()){
case Status:
case Value:
readSingleLineResponse(in);
break;
case Bulk:
readBulkResponse(in);
break;
case MultiBulk:
readMultiBulkResponse(in);
break;
}
}
private void readSingleLineResponse (InputStream in) {
offset = 0;
int c = -1;
int available = buffer.length;
try {
while ((c = in.read(buffer, offset, available)) != -1) {
offset += c;
available -= c;
if(offset > 2 && buffer[offset-2]==(byte)13 && buffer[offset-1]==(byte)10){
break; // we're done
}
if(available == 0) {
byte[] newbuff = new byte[buffer.length * 2];
System.arraycopy(buffer, 0, newbuff, 0, buffer.length);
buffer = newbuff;
available = buffer.length - offset;
}
}
if(c == -1) {
Log.error("-1 read count in readLine() while reading response line.");
throw new UnexpectedEOFException ("Unexpected EOF (read -1) in readLine. Command: " + cmd.code);
}
if((this.isError = buffer[0] == ProtocolBase.ERR_BYTE) == true)
status = new ResponseStatus(ResponseStatus.Code.ERROR, new String(buffer, 1, offset-3));
else
status = ResponseStatus.STATUS_OK;
}
catch (SocketException e) {
// on connection reset
throw new ConnectionResetException("SocketException in readLine. Command: " + cmd.code, e);
}
catch (IOException e) {
e.printStackTrace();
throw new ClientRuntimeException ("IOException in readLine. Command: " + cmd.code, e);
}
}
private void readBulkResponse (InputStream in) {
}
private void readMultiBulkResponse (InputStream in) {
}
// @Override
public boolean getBooleanValue () throws IllegalStateException {
// TODO Auto-generated method stub
return false;
}
// @Override
public long getLongValue () throws IllegalStateException {
// TODO Auto-generated method stub
return 0;
}
// @Override
public String getStringValue () throws IllegalStateException {
// TODO Auto-generated method stub
return null;
}
// @Override
public byte[] getBulkData () {
// TODO Auto-generated method stub
return null;
}
// @Override
public List<byte[]> getMultiBulkData () throws ClientRuntimeException, ProviderException {
// TODO Auto-generated method stub
return null;
}
}
}