blob: d8f17643b851375a8eb194870a8a58fa6192065b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
#include "stdafx.h"
#include "CrossfireProcessor.h"
/* initialize constants */
const wchar_t* CrossfireProcessor::HEADER_CONTENTLENGTH = L"Content-Length:";
const wchar_t* CrossfireProcessor::LINEBREAK = L"\r\n";
const size_t CrossfireProcessor::LINEBREAK_LENGTH = 2;
const wchar_t* CrossfireProcessor::NAME_ARGUMENTS = L"arguments";
const wchar_t* CrossfireProcessor::NAME_BODY = L"body";
const wchar_t* CrossfireProcessor::NAME_CODE = L"code";
const wchar_t* CrossfireProcessor::NAME_COMMAND = L"command";
const wchar_t* CrossfireProcessor::NAME_CONTEXTID = L"contextId";
const wchar_t* CrossfireProcessor::NAME_EVENT = L"event";
const wchar_t* CrossfireProcessor::NAME_MESSAGE = L"message";
const wchar_t* CrossfireProcessor::NAME_REQUESTSEQ = L"requestSeq";
const wchar_t* CrossfireProcessor::NAME_RUNNING = L"running";
const wchar_t* CrossfireProcessor::NAME_SEQ = L"seq";
const wchar_t* CrossfireProcessor::NAME_STATUS = L"status";
const wchar_t* CrossfireProcessor::NAME_TYPE = L"type";
const wchar_t* CrossfireProcessor::VALUE_EVENT = L"event";
const wchar_t* CrossfireProcessor::VALUE_REQUEST = L"request";
const wchar_t* CrossfireProcessor::VALUE_RESPONSE = L"response";
CrossfireProcessor::CrossfireProcessor() {
m_jsonParser = new JSONParser();
m_nextEventSeq = 0;
}
CrossfireProcessor::~CrossfireProcessor() {
delete m_jsonParser;
}
bool CrossfireProcessor::createEventPacket(CrossfireEvent* eventObj, std::wstring** _value) {
*_value = NULL;
Value value_packet;
/* packet type */
value_packet.addObjectValue(NAME_TYPE, &Value(VALUE_EVENT));
/* event type */
if (!eventObj->getName()) {
Logger::error("CrossfireProcessor.createEventPacket(): event does not have a name");
return false;
}
value_packet.addObjectValue(NAME_EVENT, &Value(eventObj->getName()));
/* context id */
if (eventObj->getContextId()) {
value_packet.addObjectValue(NAME_CONTEXTID, &Value(eventObj->getContextId()));
} else {
Value value_null;
value_null.setType(TYPE_NULL);
value_packet.addObjectValue(NAME_CONTEXTID, &value_null);
}
/* body */
Value* bodyValue = eventObj->getBody();
if (bodyValue) {
if (bodyValue->getType() != TYPE_OBJECT) {
Logger::error("CrossfireProcessor.createEventPacket(): event has body object of wrong type");
return false;
}
value_packet.addObjectValue(NAME_BODY, bodyValue);
}
/* seq */
value_packet.setObjectValue(NAME_SEQ, &Value((double)m_nextEventSeq++));
std::wstring* content = NULL;
m_jsonParser->stringify(&value_packet, &content);
wchar_t length[9];
_ltow_s((unsigned int)content->length() + LINEBREAK_LENGTH, length, 9, 10); /* trailing linebreak */
std::wstring* eventString = new std::wstring;
eventString->append(HEADER_CONTENTLENGTH);
eventString->append(length);
eventString->append(LINEBREAK);
eventString->append(LINEBREAK);
eventString->append(*content);
eventString->append(LINEBREAK);
delete content;
*_value = eventString;
return true;
}
bool CrossfireProcessor::createResponsePacket(CrossfireResponse *response, std::wstring **_value) {
static unsigned int s_nextResponseSeq = 0;
*_value = NULL;
Value value_packet;
/* packet type */
value_packet.addObjectValue(NAME_TYPE, &Value(VALUE_RESPONSE));
/* command */
if (!response->getName()) {
Logger::error("CrossfireProcessor.createResponsePacket(): response does not have a name");
return false;
}
value_packet.addObjectValue(NAME_COMMAND, &Value(response->getName()));
/* contextId */
if (response->getContextId()) {
value_packet.addObjectValue(NAME_CONTEXTID, &Value(response->getContextId()));
} else {
Value value_null;
value_null.setType(TYPE_NULL);
value_packet.addObjectValue(NAME_CONTEXTID, &value_null);
}
/* request seq */
if (response->getRequestSeq() < 0) {
Logger::error("CrossfireProcessor.createResponsePacket(): response does not have a request seq value");
return false;
}
value_packet.addObjectValue(NAME_REQUESTSEQ, &Value((double)response->getRequestSeq()));
/* status */
Value status;
status.addObjectValue(NAME_CODE, &Value((double)response->getCode()));
status.addObjectValue(NAME_RUNNING, &Value(response->getRunning()));
wchar_t* message = response->getMessage();
if (message) {
status.addObjectValue(NAME_MESSAGE, &Value(message));
}
value_packet.addObjectValue(NAME_STATUS, &status);
/* body */
Value* bodyValue = response->getBody();
if (!bodyValue || bodyValue->getType() != TYPE_OBJECT) {
Logger::error("CrossfireProcessor.createResponsePacket(): response does not have a body value of type object");
return false;
}
value_packet.addObjectValue(NAME_BODY, bodyValue);
/* seq */
value_packet.setObjectValue(NAME_SEQ, &Value((double)s_nextResponseSeq++));
std::wstring* content = NULL;
m_jsonParser->stringify(&value_packet, &content);
wchar_t length[9];
_ltow_s((unsigned int)content->length() + LINEBREAK_LENGTH, length, 9, 10); /* trailing linebreak */
std::wstring* responseString = new std::wstring;
responseString->append(HEADER_CONTENTLENGTH);
responseString->append(length);
responseString->append(LINEBREAK);
responseString->append(LINEBREAK);
responseString->append(*content);
responseString->append(LINEBREAK);
delete content;
*_value = responseString;
return true;
}
int CrossfireProcessor::parseRequestPacket(std::wstring* msg, CrossfireRequest** _value, wchar_t** _message) {
*_value = NULL;
*_message = NULL;
size_t startIndex = msg->find(L"\r\n\r\n") + 2 * LINEBREAK_LENGTH; /* header linebreak */
size_t msgLength = msg->length();
if (msg->at(msgLength - 2) != wchar_t('\r')) {
*_message = _wcsdup(L"Request packet does not contain terminating '\\r'");
return CODE_MALFORMED_PACKET;
}
if (msg->at(msgLength - 1) != wchar_t('\n')) {
*_message = _wcsdup(L"Request packet does not contain terminating '\\n'");
return CODE_MALFORMED_PACKET;
}
std::wstring content = msg->substr(startIndex, msgLength - startIndex - LINEBREAK_LENGTH); /* trailing linebreak */
Value* value_request = NULL;
m_jsonParser->parse(&content, &value_request);
if (!value_request) {
*_message = _wcsdup(L"Failure occurred while parsing Request packet content");
return CODE_MALFORMED_PACKET;
}
Value* value_type = value_request->getObjectValue(NAME_TYPE);
if (!value_type || value_type->getType() != TYPE_STRING || value_type->getStringValue()->compare(VALUE_REQUEST) != 0) {
*_message = _wcsdup(L"Request packet does not contain a 'type' value of \"request\"");
delete value_request;
return CODE_MALFORMED_REQUEST;
}
Value* value_seq = value_request->getObjectValue(NAME_SEQ);
if (!value_seq || value_seq->getType() != TYPE_NUMBER || value_seq->getNumberValue() < 0) {
*_message = _wcsdup(L"Request packet does not contain a 'seq' Number value >= 0");
delete value_request;
return CODE_MALFORMED_REQUEST;
}
Value* value_command = value_request->getObjectValue(NAME_COMMAND);
if (!value_command || value_command->getType() != TYPE_STRING) {
*_message = _wcsdup(L"Request packet does not contain a String 'command' value");
delete value_request;
return CODE_MALFORMED_REQUEST;
}
Value* value_contextId = value_request->getObjectValue(NAME_CONTEXTID);
if (value_contextId && value_contextId->getType() != TYPE_STRING) {
*_message = _wcsdup(L"Request packet contains a non-string 'context_id' value");
delete value_request;
return CODE_MALFORMED_REQUEST;
}
Value* value_arguments = value_request->getObjectValue(NAME_ARGUMENTS);
if (value_arguments && value_arguments->getType() != TYPE_OBJECT) {
*_message = _wcsdup(L"Request packet contains a non-object 'arguments' value");
delete value_request;
return CODE_MALFORMED_REQUEST;
}
CrossfireRequest* result = new CrossfireRequest();
result->setName((wchar_t*)value_command->getStringValue()->c_str());
result->setSeq((unsigned int)value_seq->getNumberValue());
if (value_contextId) {
result->setContextId(value_contextId->getStringValue());
}
if (value_arguments) {
result->setArguments(value_arguments);
} else {
Value value_empty;
value_empty.setType(TYPE_OBJECT);
result->setArguments(&value_empty);
}
*_value = result;
delete value_request;
return CODE_OK;
}