/*
############################################################################
##
## Copyright (C) 2006-2009 University of Utah. All rights reserved.
##
## This file is part of DeepPeep.
##
## This file may be used under the terms of the GNU General Public
## License version 2.0 as published by the Free Software Foundation
## and appearing in the file LICENSE.GPL included in the packaging of
## this file. Please review the following to ensure GNU General Public
## Licensing requirements will be met:
## http://www.opensource.org/licenses/gpl-license.php
##
## If you are unsure which license is appropriate for your use (for
## instance, you are interested in developing a commercial derivative
## of DeepPeep), please contact us at deeppeep@sci.utah.edu.
##
## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
##
############################################################################
*/
package focusedCrawler.util.storage.socket;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import focusedCrawler.util.CommunicationException;
import focusedCrawler.util.DataNotFoundException;
import focusedCrawler.util.storage.Storage;
import focusedCrawler.util.storage.StorageException;
/**
*
*/
class ServerConnectionHandler extends Thread {
private static final Logger logger = LoggerFactory.getLogger(ServerConnectionHandler.class);
private Storage storage;
private Socket socket;
private long startTime;
private int inLength=0;
private int outLength= 0;
private ServerConnectionListener listener;
private int methodId=-1;
private DataInputStream din;
private DataOutputStream dout;
private byte[] buffer;
private Object param;
private int returnType=-1;
private Object result;
private ByteArrayOutputStream bout;
public ServerConnectionHandler(int number, String storage_name, Storage storage, Socket socket, ServerConnectionListener listener) {
super();
this.storage = storage;
this.socket = socket;
this.startTime = System.currentTimeMillis();
this.listener = listener;
setName("ServerConnectionHandler["+storage_name+"/"+number+"/"+listener.getConcurrentLevel()+"]-"+socket.getInetAddress()+":"+socket.getPort());
}
public String toString() {
return getName();
}
private void readRequestData() throws IOException {
// read request data
methodId = din.read();
inLength = din.readInt();
buffer = new byte[inLength];
din.readFully(buffer);
}
private void buildRequestObject() throws ClassNotFoundException, IOException {
// build serialized client request paramter object
ByteArrayInputStream bin = new ByteArrayInputStream(buffer);
ObjectInputStream oin = new ObjectInputStream(bin);
param = oin.readObject();
oin.close();
}
private void callStorage() throws StorageException, DataNotFoundException, CommunicationException {
// call storage method
switch(methodId) {
case CommunicationConstants.METHOD_PING:
result = storage.ping(param);
break;
case CommunicationConstants.METHOD_INSERT:
result = storage.insert(param);
break;
case CommunicationConstants.METHOD_INSERT_ARRAY:
result = storage.insertArray((Object[])param);
break;
case CommunicationConstants.METHOD_SELECT:
result = storage.select(param);
break;
case CommunicationConstants.METHOD_SELECT_ARRAY:
result = storage.selectArray((Object[])param);
break;
case CommunicationConstants.METHOD_SELECT_ENUMERATION:
result = storage.selectEnumeration(param);
break;
case CommunicationConstants.METHOD_UPDATE:
result = storage.update(param);
break;
case CommunicationConstants.METHOD_UPDATE_ARRAY:
result = storage.updateArray((Object[])param);
break;
case CommunicationConstants.METHOD_REMOVE:
result = storage.remove(param);
break;
case CommunicationConstants.METHOD_REMOVE_ARRAY:
result = storage.removeArray((Object[])param);
break;
case CommunicationConstants.METHOD_ADD_RESOURCE:
result = storage.addResource(param);
break;
case CommunicationConstants.METHOD_ADD_RESOURCE_ARRAY:
result = storage.addResourceArray((Object[])param);
break;
case CommunicationConstants.METHOD_REMOVE_RESOURCE:
result = storage.removeResource(param);
break;
case CommunicationConstants.METHOD_REMOVE_RESOURCE_ARRAY:
result = storage.removeResourceArray((Object[])param);
break;
case CommunicationConstants.METHOD_COMMIT:
result = storage.commit(param);
break;
case CommunicationConstants.METHOD_ROLLBACK:
result = storage.rollback(param);
break;
case CommunicationConstants.METHOD_FINALIZE:
result = storage.finalize(param);
break;
default:
throw new CommunicationException("protocol error: invalid method id " + methodId);
}
}
private void serializeObject(Object obj) throws IOException {
// serialize the result object or exception
bout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(bout);
oout.writeObject(obj);
oout.flush();
}
private void serializeException(Exception obj) throws IOException {
bout = new ByteArrayOutputStream();
PrintStream pstream = new PrintStream(bout);
obj.printStackTrace(pstream);
pstream.flush();
String exceptionString = bout.toString();
serializeObject(exceptionString);
}
private void sendResult() throws IOException {
// send data to client
outLength = bout.size();
dout.writeByte(returnType);
dout.writeInt(bout.size());
bout.writeTo(dout);
dout.flush();
}
public void run() {
long t1=0, t2=0, t3=0, t4=0, t5=0, t6=0;
try {
try {
din = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
dout = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
t1=System.currentTimeMillis();
readRequestData();
t2=System.currentTimeMillis();
try {
buildRequestObject();
t3=System.currentTimeMillis();
callStorage();
t4=System.currentTimeMillis();
serializeObject(result);
returnType = CommunicationConstants.RETURN_OK;
} catch(StorageException e) {
serializeException(e);
returnType = CommunicationConstants.RETURN_STORAGE_EXCEPTION;
} catch(DataNotFoundException e) {
serializeException(e);
returnType = CommunicationConstants.RETURN_DATA_NOT_FOUND;
} catch(CommunicationException e) {
serializeException(e);
returnType = CommunicationConstants.RETURN_COMMUNICATION_EXCEPTION;
} catch(ClassNotFoundException e) {
serializeException(e);
returnType = CommunicationConstants.RETURN_COMMUNICATION_EXCEPTION;
} catch(Exception e) {
serializeException(e);
returnType = CommunicationConstants.RETURN_COMMUNICATION_EXCEPTION;
}
t5=System.currentTimeMillis();
sendResult();
t6=System.currentTimeMillis();
} catch(IOException e) {
// ignore socket errors(closing and free client)
logger.error("["+storage.toString()+"] IO error:", e);
}
} finally {
try {
socket.close();
}
catch (IOException ioe) {
logger.info("["+storage.toString()+"] Socket close error:", ioe);
}
socket = null;
din= null;
dout = null;
buffer = null;
param = null;
result = null;
bout = null;
t6-=t5; t5-=t4; t4-=t3; t3-=t2; t2-=t1; t1-=startTime;
long tt = System.currentTimeMillis() - startTime;
listener.outgoingConnection();
if(logger.isTraceEnabled()) {
logger.trace("[" + getReturnType(returnType) + "] " + "time= " + tt +
" dataIn= " + inLength + " dataOut= " + outLength +
" init= " + t1 + " ,rr= " + t2 + " ,bro= " + t3 + " ,cs= "
+ t4 + " ,so= " + t5 + " ,sr= " + t6);
}
}
}
private String getReturnType(int t) {
switch(t) {
case CommunicationConstants.RETURN_OK:
return "ok";
case CommunicationConstants.RETURN_DATA_NOT_FOUND:
return "data_not_found";
case CommunicationConstants.RETURN_STORAGE_EXCEPTION:
return "storage_exception";
case CommunicationConstants.RETURN_COMMUNICATION_EXCEPTION:
return "communication_exception";
default:
return "unknown_return_type";
}
}
}