XMLRequestParser.cc 9.55 KB
/*
 * XMLRequestParser.cc
 *
 *  Created on: Nov 23, 2012
 *      Author: f.casimir
 */

//Common module include
#include "DicError.hh"

// DD_Client_r_lib module includes
#include "TimeUtil.hh"

//Parameters module include
#include "ServicesServer.hh"

//XMLConfigurator module include
#include "NodeCfg.hh"
#include "Constant.hh"

//XMLRequest module include
#include "Config.hh"
#include "XMLRequestParser.hh"

#include "TimeInterval.hh"
#include "TimeTableCatalogFactory.hh"
#include "TimeTable.hh"
#include "Catalog.hh"

#include <boost/filesystem.hpp>

// Using namespace
using namespace log4cxx;
using namespace AMDA::Parameters;
using namespace AMDA::XMLConfigurator;
using namespace TimeTableCatalog;

namespace AMDA {
namespace XMLRequest {

class ParamNode : public NodeCfg
{
public:
  void proceed(xmlNodePtr pNode,const AMDA::Parameters::CfgContext& pContext) {
		ParameterManager* lParameterManager =  pContext.get<ParameterManager*>();
		xmlChar* lParamName = NULL;

		try {
			if (!(lParamName = xmlGetProp(pNode, (const xmlChar *) "id"))) {
				ERROR_EXCEPTION( ERROR_MANDATORY_ATTRIBUTE_MISSING << pNode->name << "@" << PARAMNAME)
			}
			lParameterManager->createParameter(std::string((char*)lParamName));
		} catch (...) {
			//This parameter is ignored, continue
//			if (lParamName) {
//				xmlFree(lParamName);
//			}
//			throw;
		}
		if (lParamName) {
			xmlFree(lParamName);
		}
  }
};

class IntervalNode : public NodeGrpCfg {
public:
	class StartTimeNode : public NodeCfg {
	public:
	  void proceed(xmlNodePtr pNode,const AMDA::Parameters::CfgContext& pContext) {
		  IntervalNode* lIntervalNode =  pContext.get<IntervalNode*>();

		  double lStartTime = DD_Time2Double((const char*)pNode->children->content);

		  lIntervalNode->_startTime = lStartTime;
	  }
	};

	class TimeIntervalNode : public NodeCfg
	{
	public:
	  void proceed(xmlNodePtr pNode, const AMDA::Parameters::CfgContext& pContext) {
		  IntervalNode* lIntervalNode =  pContext.get<IntervalNode*>();

		  double lTimeInt = DD_Time2Double((const char*)pNode->children->content);

		  lIntervalNode->_timeInt = lTimeInt;

	  }
	};

	IntervalNode () : NodeGrpCfg(), _startTime(0), _timeInt(0) {
		getChildList()["startTime"] = NodeCfgSPtr(new StartTimeNode);
		getChildList()["timeInterval"] = NodeCfgSPtr(new TimeIntervalNode);
	}

	void proceed(xmlNodePtr pNode,
						const AMDA::Parameters::CfgContext& pContext) {
		LOG4CXX_DEBUG(gLogger, "IntervalNode::proceed");

		// Create new context
		CfgContext lContext;
		lContext.push<IntervalNode*>(this);

		// Go to next node
		NodeGrpCfg::proceed(pNode, lContext);

		// Get manager of the new output parameter for this node
		ParameterManager* lParameterManager = pContext.get<ParameterManager*>();

		lParameterManager->addInputInterval(_startTime, _startTime + _timeInt, 0);
	}

	double _startTime;
	double _timeInt;
};

class TimeTableNode : public NodeCfg
{
public:
  void proceed(xmlNodePtr pNode, const AMDA::Parameters::CfgContext& pContext) {
	  xmlChar* lTTName = NULL;

	  ParameterManager* lParameterManager =  pContext.get<ParameterManager*>();
	  if (!(lTTName = xmlGetProp(pNode, (const xmlChar *) "id"))) {
		  ERROR_EXCEPTION(
				 AMDA::XMLConfigurator::ERROR_MANDATORY_ATTRIBUTE_MISSING << pNode->name << "@" << AMDA::XMLConfigurator::TIMETABLENAME)
	  }
	  std::string lStrTTName((const char*)lTTName);

	  if(lTTName){
		  xmlFree(lTTName);
	  }

	  lParameterManager->setTimeTablePath(lStrTTName);

	  // check local file exists
	  // if distant file does not exist an error will be thrown in the next if
	  if((lStrTTName.find("http://")!=std::string::npos
			  && lStrTTName.find("https://")!=std::string::npos)
			  && !boost::filesystem::exists(lStrTTName)){
		  ERROR_EXCEPTION(
				 AMDA::XMLConfigurator::ERROR_FILE_NOT_EXIST << lStrTTName);
	  }

	  // Read file
	  std::string lReaderType = TimeTableCatalogFactory::getInstance().getReaderType(lStrTTName);
	  if(lReaderType.empty()){
		  ERROR_EXCEPTION(
				 "Unknown Timetable : " << lStrTTName);

	  }
	  TimeTableCatalog::TimeTable inputTT;
	  inputTT.read(lStrTTName, lReaderType);

	  const std::vector<TimeInterval> lTimeIntervalList = inputTT.getIntervals();

	  // Get interval index if exists
	  xmlChar* lTTIndex = xmlGetProp(pNode, (const xmlChar *) "index");
	  if (lTTIndex)
	  {
		  //Add only interval designate by index
		  size_t index = atoi( (const char*)lTTIndex );

		  xmlFree(lTTIndex);

		  if (index >= lTimeIntervalList.size())
		  {
			  ERROR_EXCEPTION(
			  				 "Cannot find index : " << index << " in TimeTable : " << lStrTTName);
		  }

		  lParameterManager->addInputInterval(
				  lTimeIntervalList[index]._startTime,
				  lTimeIntervalList[index]._stopTime,
				  lTimeIntervalList[index]._index);
	  }
	  else
	  {
		  //Add all intervals
		  for(std::vector<TimeInterval>::const_iterator it = lTimeIntervalList.begin(); it != lTimeIntervalList.end(); ++it) {
			  lParameterManager->addInputInterval(it->_startTime, it->_stopTime, it->_index);
		  }
	  }
  }
};

class CatalogNode : public NodeCfg
{
public:
  void proceed(xmlNodePtr pNode, const AMDA::Parameters::CfgContext& pContext) {
	  xmlChar* lCatalogName = NULL;

	  ParameterManager* lParameterManager =  pContext.get<ParameterManager*>();
	  if (!(lCatalogName = xmlGetProp(pNode, (const xmlChar *) "id"))) {
		  ERROR_EXCEPTION(
				 AMDA::XMLConfigurator::ERROR_MANDATORY_ATTRIBUTE_MISSING << pNode->name << "@" << AMDA::XMLConfigurator::TIMETABLENAME)
	  }
	  std::string lStrCatalogName((const char*)lCatalogName);

	  if(lCatalogName){
		  xmlFree(lCatalogName);
	  }

	  lParameterManager->setTimeTablePath(lStrCatalogName);

	  // check local file exists
	  // if distant file does not exist an error will be thrown in the next if
	  if((lStrCatalogName.find("http://")!=std::string::npos
			  && lStrCatalogName.find("https://")!=std::string::npos)
			  && !boost::filesystem::exists(lStrCatalogName)){
		  ERROR_EXCEPTION(
				 AMDA::XMLConfigurator::ERROR_FILE_NOT_EXIST << lStrCatalogName);
	  }

	  // Read file
	  std::string lReaderType = TimeTableCatalogFactory::getInstance().getReaderType(lStrCatalogName);
	  if(lReaderType.empty()){
		  ERROR_EXCEPTION(
				 "Unknown Catalog : " << lStrCatalogName);

	  }
	  TimeTableCatalog::Catalog inputCatalog;
	  inputCatalog.read(lStrCatalogName, lReaderType);

	  std::vector<TimeInterval> lTimeIntervalList = inputCatalog.getIntervals();

	  // Get interval index if exists
	  xmlChar* lCatalogIndex = xmlGetProp(pNode, (const xmlChar *) "index");
	  if (lCatalogIndex)
	  {
		  //Add only interval designate by index
		  size_t index = atoi( (const char*)lCatalogIndex );

		  xmlFree(lCatalogIndex);

		  if (index >= lTimeIntervalList.size())
		  {
			  ERROR_EXCEPTION(
			  				 "Cannot find index : " << index << " in Catalog : " << lStrCatalogName);
		  }

		  lParameterManager->addInputInterval(
				  lTimeIntervalList[index]._startTime,
				  lTimeIntervalList[index]._stopTime,
				  lTimeIntervalList[index]._index);

		  for (auto &desc : inputCatalog.getParameterDescriptions())
		  {
			  lParameterManager->addInputIntervalDataList(index, desc.getId(), lTimeIntervalList[index].getParameterData(desc.getId()));
		  }
	  }
	  else
	  {
		  //Add all intervals
		  for(std::vector<TimeInterval>::const_iterator it = lTimeIntervalList.begin(); it != lTimeIntervalList.end(); ++it)
		  {
			  lParameterManager->addInputInterval(it->_startTime, it->_stopTime, it->_index);
			  for (auto &desc : inputCatalog.getParameterDescriptions())
				  lParameterManager->addInputIntervalDataList(it->_index, desc.getId(), lTimeIntervalList[it->_index].getParameterData(desc.getId()));
		  }
	  }
  }
};

XMLRequestParser::XMLRequestParser(const char* pXSDFile) : XMLConfigurator(pXSDFile,false) {
/*
	<request>
	  <params>
	    <param id='imf'/>
	    <param id='dst'/>
	  </params>
	  <times>
	  <interval>
	    <startTime>2008000000000000</startTime>
	    <timeInterval>0000000100000000</timeInterval>
	  <interval>
	  </times>
	  <outputs>
	  	<download>
	    	<timeFormat>ISO</timeFormat>
	    	<param id='imf'/>
	  	</download>
	  	<download>
	    	<timeFormat>ISO</timeFormat>
	    	<param id='dst'/>
	  	</download>
	  </outputs>
	</request>
	*/
	// Request root node
	NodeGrpCfg* lRequestNode = new NodeGrpCfg();
	getXmlConfiguratorMap()["request"] = RootNodeCfgSPtr(lRequestNode);
	{
		// Params group node
		NodeGrpCfg* lParamsNode = new NodeGrpCfg();
		lRequestNode->getChildList()["params"] = NodeCfgSPtr(lParamsNode);
		lParamsNode->getChildList()["param"] = NodeCfgSPtr(new ParamNode);
	}
	{
		// Times group node
		NodeGrpCfg* lTimeNode = new NodeGrpCfg();
		lRequestNode->getChildList()["times"] = NodeCfgSPtr(lTimeNode);
		{
			// Interval group node
			NodeGrpCfg* lIntervalNode = new IntervalNode();
			lTimeNode->getChildList()["interval"] = NodeCfgSPtr(lIntervalNode);
		}
		{
			// Timetable group node
			lTimeNode->getChildList()["timetable"] = NodeCfgSPtr(
					new TimeTableNode);
		}
		{
			// Catalog group node
			lTimeNode->getChildList()["catalog"] = NodeCfgSPtr(
					new CatalogNode);
		}
	}
	{
		// Output group node
		NodeGrpCfg* lOutputNode = new NodeGrpCfg();
		lRequestNode->getChildList()["outputs"] = NodeCfgSPtr(lOutputNode);
	}
}

XMLRequestParser::~XMLRequestParser() {
}


void XMLRequestParser::operator()( AMDA::Parameters::ParameterManager& lParameterManager, const std::string& requestFile)
{
	CfgContext ctx;
	ctx.push<ParameterManager*>(&lParameterManager);
	ctx.push<ServicesServer*>(ServicesServer::getInstance());
	try {
		XMLConfigurator::proceed(requestFile.c_str(), ctx);
	} catch (AMDA::AMDA_exception & e) {
		e << AMDA::errno_code(AMDA_INFORMATION_REQUEST_ERR);
		throw;
	}

}

} /* namespace XMLRequest */
} /* namespace AMDA */