/**
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.protocol.server;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Set;
import java.util.logging.Level;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.delcyon.capo.CapoApplication;
import com.delcyon.capo.controller.elements.GroupElement.Attributes;
import com.delcyon.capo.server.CapoServer;
import com.delcyon.capo.xml.XMLProcessor;
import com.delcyon.capo.xml.XMLProcessorProvider;
import com.delcyon.capo.xml.XMLStreamProcessor;
import com.delcyon.capo.xml.XPath;
/**
* @author jeremiah
*
*/
@SuppressWarnings("unchecked")
@XMLProcessorProvider(documentElementNames={"request"},namespaceURIs={"http://www.delcyon.com/capo-client","http://www.delcyon.com/capo-server"})
public class ClientRequestXMLProcessor implements XMLProcessor
{
private static HashMap<String, Class<? extends ClientRequestProcessor>> clientRequestProcessorHashMap = new HashMap<String, Class<? extends ClientRequestProcessor>>();
static
{
Set<String> clientRequestProcessorProviderSet = CapoApplication.getAnnotationMap().get(ClientRequestProcessorProvider.class.getCanonicalName());
for (String className : clientRequestProcessorProviderSet)
{
try
{
Class<? extends ClientRequestProcessor> clientRequestProcessorClass = (Class<? extends ClientRequestProcessor>) Class.forName(className);
ClientRequestProcessorProvider clientRequestProcessorProvider = clientRequestProcessorClass.getAnnotation(ClientRequestProcessorProvider.class);
clientRequestProcessorHashMap.put(clientRequestProcessorProvider.name(), clientRequestProcessorClass);
CapoApplication.logger.log(Level.CONFIG, "Loaded ClientRequestProcessor '"+clientRequestProcessorProvider.name()+"' from "+clientRequestProcessorClass.getSimpleName());
} catch (Exception e)
{
CapoApplication.logger.log(Level.WARNING, "Couldn't load "+className+" as an ClientRequestProcessor", e);
}
}
}
public static ClientRequestProcessor getClientRequestProcessor(String clientRequestProcessorName) throws Exception
{
Class<? extends ClientRequestProcessor> clientRequestProcessorClass = clientRequestProcessorHashMap.get(clientRequestProcessorName);
if (clientRequestProcessorClass != null)
{
return clientRequestProcessorClass.newInstance();
}
else
{
return null;
}
}
private Document requestDocument;
private XMLStreamProcessor xmlStreamProcessor;
private OutputStream outputStream;
private String sessionId;
private HashMap<String, String> sessionHashMap;
private ClientRequestProcessor clientRequestProcessor;
private ClientRequest clientRequest;
private boolean isRegisteredSession = false;
@Override
public OutputStream getOutputStream()
{
return outputStream;
}
@Override
public Document getDocument()
{
return requestDocument;
}
@Override
public XMLStreamProcessor getXmlStreamProcessor()
{
return xmlStreamProcessor;
}
@Override
public void init(Document requestDocument, XMLStreamProcessor xmlStreamProcessor, OutputStream outputStream,HashMap<String, String> sessionHashMap) throws Exception
{
this.outputStream = outputStream;
this.xmlStreamProcessor = xmlStreamProcessor;
this.requestDocument = requestDocument;
this.sessionHashMap = sessionHashMap;
if (requestDocument.getDocumentElement().hasAttribute(ClientRequest.SESSION_ID_ATTRIBUTE_NAME) == true)
{
sessionId = requestDocument.getDocumentElement().getAttribute(ClientRequest.SESSION_ID_ATTRIBUTE_NAME);
if (sessionId.trim().isEmpty())
{
sessionId = ClientRequestProcessorSessionManager.generateSessionID();
}
}
else
{
sessionId = ClientRequestProcessorSessionManager.generateSessionID();
}
//see if we already have a session, and if we do, and there is a request handler, then pass us off to it.
clientRequest = new ClientRequest(this,requestDocument, xmlStreamProcessor, outputStream);
clientRequestProcessor = ClientRequestProcessorSessionManager.getClientRequestProcessor(clientRequest.getSessionID());
if (clientRequestProcessor != null)
{
isRegisteredSession = true;
clientRequestProcessor.setNewSession(false);
clientRequestProcessor.init(this, sessionId, sessionHashMap, null);
}
else
{
Element documentElement = XPath.unwrapDocument(requestDocument,false).getDocumentElement();
String requestName = null;
if (documentElement.hasAttribute("type"))
{
requestName = documentElement.getAttribute("type");
}
String documentElementName = documentElement.getLocalName();
clientRequestProcessor = ClientRequestXMLProcessor.getClientRequestProcessor(documentElementName);
if (clientRequestProcessor != null)
{
String sessionID = ClientRequestProcessorSessionManager.generateSessionID();
clientRequest.setSessionID(sessionID);
clientRequestProcessor.setNewSession(true);
clientRequestProcessor.init(this,sessionID,sessionHashMap,requestName);
ClientRequestProcessorSessionManager.registerClientRequestProcessor(clientRequestProcessor);
}
else
{
CapoApplication.logger.log(Level.SEVERE, "Couldn't find @ClientRequestProcessorProvider for: "+documentElementName);
}
}
}
@Override
public boolean isStreamProcessor()
{
return clientRequestProcessor.isStreamProcessor();
}
@Override
public void run()
{
try
{
clientRequestProcessor.process(clientRequest);
if(isRegisteredSession == false)
{
//because once a control main request processor runs, we no longer need to have a link reference to it, remove it.
ClientRequestProcessorSessionManager.removeClientRequestProcessor(clientRequestProcessor);
//send finished indicator
clientRequest.finish();
//send finished indicator
}
} catch (Exception exception)
{
CapoApplication.logger.log(Level.SEVERE, "Exception in session:"+sessionId,exception);
xmlStreamProcessor.throwException(exception);
}
}
public XMLResponse createResponse() throws Exception
{
XMLResponse xmlResponse = new XMLResponse();
xmlResponse.setSessionID(getSessionId());
return xmlResponse;
}
public void writeResponse(Response response) throws Exception
{
XMLResponse clientRequestResponse = createResponse();
clientRequestResponse.setSessionID(response.getSessionID());
clientRequestResponse.setResponseElement(response.getResponseDocument().getDocumentElement());
xmlStreamProcessor.writeDocument(clientRequestResponse.getResponseDocument());
}
@Override
public Document readNextDocument() throws Exception
{
//unwrap document
Document requestDocument = xmlStreamProcessor.readNextDocument();
return requestDocument;
}
@Override
public void writeDocument(Document document) throws Exception
{
Document responseDocument = XPath.wrapDocument(CapoServer.getDefaultDocument("default_response.xml"),document);
if (responseDocument.getDocumentElement().hasAttribute(ClientRequest.SESSION_ID_ATTRIBUTE_NAME) == false)
{
responseDocument.getDocumentElement().setAttribute(Attributes.sessionId.toString(), getSessionId());
}
xmlStreamProcessor.writeDocument(responseDocument);
}
public String getSessionId()
{
return sessionId;
}
}