/**
Copyright (C) 2012 Delcyon, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.delcyon.capo.controller.elements;
import java.io.BufferedInputStream;
import java.net.SocketException;
import java.util.HashMap;
import java.util.logging.Level;
import com.delcyon.capo.CapoApplication;
import com.delcyon.capo.Configuration.PREFERENCE;
import com.delcyon.capo.controller.AbstractControl;
import com.delcyon.capo.controller.ControlElementProvider;
import com.delcyon.capo.controller.LocalRequestProcessor;
import com.delcyon.capo.controller.client.ControllerRequest;
import com.delcyon.capo.controller.server.ControllerClientRequestProcessor;
import com.delcyon.capo.datastream.StreamHandler;
import com.delcyon.capo.datastream.StreamProcessor;
import com.delcyon.capo.protocol.client.CapoConnection;
import com.delcyon.capo.protocol.client.Request;
import com.delcyon.capo.server.CapoServer;
/**
* @author jeremiah
* Appends a node to the XML
*/
@ControlElementProvider(name="request")
public class RequestElement extends AbstractControl
{
public enum Attributes
{
name
}
private static final String[] supportedNamespaces = {CapoApplication.SERVER_NAMESPACE_URI};
@Override
public Attributes[] getAttributes()
{
return Attributes.values();
}
@Override
public Attributes[] getRequiredAttributes()
{
return new Attributes[]{Attributes.name};
}
@Override
public String[] getSupportedNamespaces()
{
return supportedNamespaces;
}
@Override
public Object processServerSideElement() throws Exception
{
HashMap<String, String> sessionHashMap = new HashMap<String, String>();
if (CapoApplication.isServer())
{
throw new Exception("Server does not support client like request to itself yet. Don't do that!");
}
else
{
CapoConnection capoConnection = new CapoConnection();
ControllerRequest controllerRequest = new ControllerRequest(capoConnection.getOutputStream(),capoConnection.getInputStream());
controllerRequest.setType(getAttributeValue(Attributes.name));
controllerRequest.loadSystemVariables();
runRequest(capoConnection, controllerRequest,sessionHashMap);
capoConnection.close();
}
return null;
}
public void runRequest(CapoConnection capoConnection, Request request, HashMap<String, String> sessionHashMap) throws Exception
{
String initialRequestType = null;
if (request instanceof ControllerRequest)
{
initialRequestType = ((ControllerRequest) request).getRequestType();
if (initialRequestType == null)
{
initialRequestType = "default";
}
}
else
{
initialRequestType = request.getClass().getSimpleName();
}
//send request
try
{
request.send();
}
catch (SocketException socketException)
{
//do nothing, let any errors be processed later, since there might be a message in the buffer
}
boolean isFinished = false;
while(isFinished == false)
{
byte[] buffer = getBuffer(capoConnection.getInputStream());
//System.out.println(new String(buffer));
//figure out the kind of response
StreamProcessor streamProcessor = StreamHandler.getStreamProcessor(buffer);
if (streamProcessor != null)
{
streamProcessor.init(sessionHashMap);
streamProcessor.processStream(capoConnection.getInputStream(), capoConnection.getOutputStream());
}
else
{
//if we have no data, then we are finished, otherwise wait, then try again?
if (buffer.length == 0)
{
CapoApplication.logger.log(Level.INFO, "Nothing left to process, finishing up "+initialRequestType+" request.");
isFinished = true;
}
}
}
}
private byte[] getBuffer(BufferedInputStream inputStream) throws Exception
{
int bufferSize = CapoApplication.getConfiguration().getIntValue(PREFERENCE.BUFFER_SIZE);
byte[] buffer = new byte[bufferSize];
inputStream.mark(bufferSize);
int bytesRead = inputStream.read(buffer);
inputStream.reset();
//truncate the buffer so we can do accurate length checks on it
//totally pointless, but seems like a good idea at the time
if (bytesRead < 0)
{
return new byte[0];
}
else if (bytesRead < bufferSize)
{
byte[] shortenedBuffer = new byte[bytesRead];
System.arraycopy(buffer, 0, shortenedBuffer, 0, bytesRead);
return shortenedBuffer;
}
else
{
return buffer;
}
}
}