<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2013-2014, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"

#include "IECorePython/ScopedGILRelease.h"

#include "Gaffer/Context.h"
#include "Gaffer/Dispatcher.h"
#include "Gaffer/CompoundPlug.h"

#include "GafferBindings/DispatcherBinding.h"
#include "GafferBindings/NodeBinding.h"
#include "GafferBindings/SignalBinding.h"

using namespace boost::python;
using namespace IECore;
using namespace IECorePython;
using namespace Gaffer;
using namespace GafferBindings;

namespace
{

class DispatcherWrapper : public NodeWrapper<Dispatcher>
{
	public :

		DispatcherWrapper( PyObject *self, const std::string &name )
			: NodeWrapper<Dispatcher>( self, name )
		{
		}

		virtual ~DispatcherWrapper()
		{
		}

		void dispatch( list nodeList ) const
		{
			ScopedGILLock gilLock;
			size_t len = boost::python::len( nodeList );
			std::vector<NodePtr> nodes;
			nodes.reserve( len );
			for ( size_t i = 0; i < len; i++ )
			{
				nodes.push_back( extract<NodePtr>( nodeList[i] ) );
			}
			Dispatcher::dispatch( nodes );
		}

		void doDispatch( const TaskBatch *batch ) const
		{
			ScopedGILLock gilLock;

			boost::python::object f = this->methodOverride( "_doDispatch" );
			if( f )
			{
				try
				{
					f( boost::const_pointer_cast<Dispatcher::TaskBatch>( ConstTaskBatchPtr( batch ) ) );
				}
				catch( const boost::python::error_already_set &e )
				{
					PyErr_PrintEx(0);
					throw Exception( "doDispatch() failed" );
				}
			}
			else
			{
				throw Exception( "doDispatch() python method not defined" );
			}
		}

		void doSetupPlugs( CompoundPlug *parentPlug ) const
		{
			ScopedGILLock gilLock;
			boost::python::object f = this->methodOverride( "_doSetupPlugs" );
			if( f )
			{
				CompoundPlugPtr tmpPointer = parentPlug;
				try
				{
					f( tmpPointer );
				}
				catch( const boost::python::error_already_set &e )
				{
					PyErr_PrintEx(0);
					throw Exception( "doSetupPlugs() failed" );
				}

			}
		}

		static list dispatcherNames()
		{
			std::vector<std::string> names;
			Dispatcher::dispatcherNames( names );
			list result;
			for ( std::vector<std::string>::const_iterator nIt = names.begin(); nIt != names.end(); nIt++ )
			{
				result.append( *nIt );
			}
			return result;
		}

		static void registerDispatcher( std::string name, Dispatcher *dispatcher )
		{
			Dispatcher::registerDispatcher( name, dispatcher );
		}

		static DispatcherPtr dispatcher( std::string name )
		{
			const Dispatcher *d = Dispatcher::dispatcher( name );
			return const_cast< Dispatcher *>(d);
		}

		static void taskBatchExecute( const Dispatcher::TaskBatch &batch )
		{
			ScopedGILRelease gilRelease;
			batch.execute();
		}

		static ExecutableNodePtr taskBatchGetNode( const Dispatcher::TaskBatchPtr &batch )
		{
			if ( ConstExecutableNodePtr node = batch->node() )
			{
				return boost::const_pointer_cast<ExecutableNode>( node );
			}

			return 0;
		}

		static ContextPtr taskBatchGetContext( const Dispatcher::TaskBatchPtr &batch, bool copy = true )
		{
			if ( ConstContextPtr context = batch->context() )
			{
				if ( copy )
				{
					return new Context( *context );
				}

				return boost::const_pointer_cast<Context>( context );
			}

			return 0;
		}

		static boost::python::list taskBatchGetFrames( const Dispatcher::TaskBatchPtr &batch )
		{
			boost::python::list result;
			for ( std::vector<float>::const_iterator it = batch->frames().begin(); it != batch->frames().end(); ++it )
			{
				result.append( *it );
			}
			return result;
		}

		static boost::python::list taskBatchGetRequirements( const Dispatcher::TaskBatchPtr &batch )
		{
			boost::python::list result;
			for ( std::vector<TaskBatchPtr>::const_iterator it = batch->requirements().begin(); it != batch->requirements().end(); ++it )
			{
				result.append( *it );
			}
			return result;
		}

		static CompoundDataPtr taskBatchGetBlindData( Dispatcher::TaskBatch &batch )
		{
			return batch.blindData();
		}

};

struct PreDispatchSlotCaller
{
	bool operator()( boost::python::object slot, const Dispatcher *d, const std::vector<ExecutableNodePtr> &nodes )
	{
		try
		{
			list nodeList;
			for( std::vector<ExecutableNodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++ )
			{
				nodeList.append( *nIt );
			}
			DispatcherPtr dd = const_cast<Dispatcher*>(d);
			return slot( dd, nodeList );
		}
		catch( const error_already_set &e )
		{
			PyErr_PrintEx( 0 ); // clears the error status
		}
		return false;
	}
};

struct PostDispatchSlotCaller
{
	boost::signals::detail::unusable operator()( boost::python::object slot, const Dispatcher *d, const std::vector<ExecutableNodePtr> &nodes, bool success )
	{
		try
		{
			list nodeList;
			for( std::vector<ExecutableNodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++ )
			{
				nodeList.append( *nIt );
			}
			DispatcherPtr dd = const_cast<Dispatcher*>(d);
			slot( dd, nodeList, success );
		}
		catch( const error_already_set &e )
		{
			PyErr_PrintEx( 0 ); // clears the error status
		}
		return boost::signals::detail::unusable();
	}
};

} // namespace

void GafferBindings::bindDispatcher()
{
	scope s = NodeClass<Dispatcher, DispatcherWrapper>()
		.def( "dispatch", &DispatcherWrapper::dispatch )
		.def( "jobDirectory", &Dispatcher::jobDirectory )
		.def( "dispatcher", &DispatcherWrapper::dispatcher ).staticmethod( "dispatcher" )
		.def( "dispatcherNames", &DispatcherWrapper::dispatcherNames ).staticmethod( "dispatcherNames" )
		.def( "registerDispatcher", &DispatcherWrapper::registerDispatcher ).staticmethod( "registerDispatcher" )
		.def( "preDispatchSignal", &Dispatcher::preDispatchSignal, return_value_policy<reference_existing_object>() ).staticmethod( "preDispatchSignal" )
		.def( "postDispatchSignal", &Dispatcher::postDispatchSignal, return_value_policy<reference_existing_object>() ).staticmethod( "postDispatchSignal" )
	;

	enum_<Dispatcher::FramesMode>( "FramesMode" )
		.value( "CurrentFrame", Dispatcher::CurrentFrame )
		.value( "FullRange", Dispatcher::FullRange )
		.value( "CustomRange", Dispatcher::CustomRange )
	;

	RefCountedClass<Dispatcher::TaskBatch, RefCounted>( "_TaskBatch" )
		.def( "execute", &DispatcherWrapper::taskBatchExecute )
		.def( "node", &DispatcherWrapper::taskBatchGetNode )
		.def( "context", &DispatcherWrapper::taskBatchGetContext, ( boost::python::arg_( "_copy" ) = true ) )
		.def( "frames", &DispatcherWrapper::taskBatchGetFrames )
		.def( "requirements", &DispatcherWrapper::taskBatchGetRequirements )
		.def( "blindData", &DispatcherWrapper::taskBatchGetBlindData )
	;

	SignalBinder<Dispatcher::PreDispatchSignal, DefaultSignalCaller<Dispatcher::PreDispatchSignal>, PreDispatchSlotCaller >::bind( "PreDispatchSignal" );
	SignalBinder<Dispatcher::PostDispatchSignal, DefaultSignalCaller<Dispatcher::PostDispatchSignal>, PostDispatchSlotCaller >::bind( "PostDispatchSignal" );
}
<commit_msg>using translatePythonException instead<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2013-2014, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"

#include "IECorePython/ScopedGILRelease.h"

#include "Gaffer/Context.h"
#include "Gaffer/Dispatcher.h"
#include "Gaffer/CompoundPlug.h"

#include "GafferBindings/DispatcherBinding.h"
#include "GafferBindings/NodeBinding.h"
#include "GafferBindings/SignalBinding.h"
#include "GafferBindings/ExceptionAlgo.h"

using namespace boost::python;
using namespace IECore;
using namespace IECorePython;
using namespace Gaffer;
using namespace GafferBindings;

namespace
{

class DispatcherWrapper : public NodeWrapper<Dispatcher>
{
	public :

		DispatcherWrapper( PyObject *self, const std::string &name )
			: NodeWrapper<Dispatcher>( self, name )
		{
		}

		virtual ~DispatcherWrapper()
		{
		}

		void dispatch( list nodeList ) const
		{
			ScopedGILLock gilLock;
			size_t len = boost::python::len( nodeList );
			std::vector<NodePtr> nodes;
			nodes.reserve( len );
			for ( size_t i = 0; i < len; i++ )
			{
				nodes.push_back( extract<NodePtr>( nodeList[i] ) );
			}
			Dispatcher::dispatch( nodes );
		}

		void doDispatch( const TaskBatch *batch ) const
		{
			ScopedGILLock gilLock;

			boost::python::object f = this->methodOverride( "_doDispatch" );
			if( f )
			{
				try
				{
					f( boost::const_pointer_cast<Dispatcher::TaskBatch>( ConstTaskBatchPtr( batch ) ) );
				}
				catch( const boost::python::error_already_set &e )
				{
					translatePythonException();
				}
			}
			else
			{
				throw Exception( "doDispatch() python method not defined" );
			}
		}

		void doSetupPlugs( CompoundPlug *parentPlug ) const
		{
			ScopedGILLock gilLock;
			boost::python::object f = this->methodOverride( "_doSetupPlugs" );
			if( f )
			{
				CompoundPlugPtr tmpPointer = parentPlug;
				try
				{
					f( tmpPointer );
				}
				catch( const boost::python::error_already_set &e )
				{
					translatePythonException();
				}

			}
		}

		static list dispatcherNames()
		{
			std::vector<std::string> names;
			Dispatcher::dispatcherNames( names );
			list result;
			for ( std::vector<std::string>::const_iterator nIt = names.begin(); nIt != names.end(); nIt++ )
			{
				result.append( *nIt );
			}
			return result;
		}

		static void registerDispatcher( std::string name, Dispatcher *dispatcher )
		{
			Dispatcher::registerDispatcher( name, dispatcher );
		}

		static DispatcherPtr dispatcher( std::string name )
		{
			const Dispatcher *d = Dispatcher::dispatcher( name );
			return const_cast< Dispatcher *>(d);
		}

		static void taskBatchExecute( const Dispatcher::TaskBatch &batch )
		{
			ScopedGILRelease gilRelease;
			batch.execute();
		}

		static ExecutableNodePtr taskBatchGetNode( const Dispatcher::TaskBatchPtr &batch )
		{
			if ( ConstExecutableNodePtr node = batch->node() )
			{
				return boost::const_pointer_cast<ExecutableNode>( node );
			}

			return 0;
		}

		static ContextPtr taskBatchGetContext( const Dispatcher::TaskBatchPtr &batch, bool copy = true )
		{
			if ( ConstContextPtr context = batch->context() )
			{
				if ( copy )
				{
					return new Context( *context );
				}

				return boost::const_pointer_cast<Context>( context );
			}

			return 0;
		}

		static boost::python::list taskBatchGetFrames( const Dispatcher::TaskBatchPtr &batch )
		{
			boost::python::list result;
			for ( std::vector<float>::const_iterator it = batch->frames().begin(); it != batch->frames().end(); ++it )
			{
				result.append( *it );
			}
			return result;
		}

		static boost::python::list taskBatchGetRequirements( const Dispatcher::TaskBatchPtr &batch )
		{
			boost::python::list result;
			for ( std::vector<TaskBatchPtr>::const_iterator it = batch->requirements().begin(); it != batch->requirements().end(); ++it )
			{
				result.append( *it );
			}
			return result;
		}

		static CompoundDataPtr taskBatchGetBlindData( Dispatcher::TaskBatch &batch )
		{
			return batch.blindData();
		}

};

struct PreDispatchSlotCaller
{
	bool operator()( boost::python::object slot, const Dispatcher *d, const std::vector<ExecutableNodePtr> &nodes )
	{
		try
		{
			list nodeList;
			for( std::vector<ExecutableNodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++ )
			{
				nodeList.append( *nIt );
			}
			DispatcherPtr dd = const_cast<Dispatcher*>(d);
			return slot( dd, nodeList );
		}
		catch( const error_already_set &e )
		{
			PyErr_PrintEx( 0 ); // clears the error status
		}
		return false;
	}
};

struct PostDispatchSlotCaller
{
	boost::signals::detail::unusable operator()( boost::python::object slot, const Dispatcher *d, const std::vector<ExecutableNodePtr> &nodes, bool success )
	{
		try
		{
			list nodeList;
			for( std::vector<ExecutableNodePtr>::const_iterator nIt = nodes.begin(); nIt != nodes.end(); nIt++ )
			{
				nodeList.append( *nIt );
			}
			DispatcherPtr dd = const_cast<Dispatcher*>(d);
			slot( dd, nodeList, success );
		}
		catch( const error_already_set &e )
		{
			PyErr_PrintEx( 0 ); // clears the error status
		}
		return boost::signals::detail::unusable();
	}
};

} // namespace

void GafferBindings::bindDispatcher()
{
	scope s = NodeClass<Dispatcher, DispatcherWrapper>()
		.def( "dispatch", &DispatcherWrapper::dispatch )
		.def( "jobDirectory", &Dispatcher::jobDirectory )
		.def( "dispatcher", &DispatcherWrapper::dispatcher ).staticmethod( "dispatcher" )
		.def( "dispatcherNames", &DispatcherWrapper::dispatcherNames ).staticmethod( "dispatcherNames" )
		.def( "registerDispatcher", &DispatcherWrapper::registerDispatcher ).staticmethod( "registerDispatcher" )
		.def( "preDispatchSignal", &Dispatcher::preDispatchSignal, return_value_policy<reference_existing_object>() ).staticmethod( "preDispatchSignal" )
		.def( "postDispatchSignal", &Dispatcher::postDispatchSignal, return_value_policy<reference_existing_object>() ).staticmethod( "postDispatchSignal" )
	;

	enum_<Dispatcher::FramesMode>( "FramesMode" )
		.value( "CurrentFrame", Dispatcher::CurrentFrame )
		.value( "FullRange", Dispatcher::FullRange )
		.value( "CustomRange", Dispatcher::CustomRange )
	;

	RefCountedClass<Dispatcher::TaskBatch, RefCounted>( "_TaskBatch" )
		.def( "execute", &DispatcherWrapper::taskBatchExecute )
		.def( "node", &DispatcherWrapper::taskBatchGetNode )
		.def( "context", &DispatcherWrapper::taskBatchGetContext, ( boost::python::arg_( "_copy" ) = true ) )
		.def( "frames", &DispatcherWrapper::taskBatchGetFrames )
		.def( "requirements", &DispatcherWrapper::taskBatchGetRequirements )
		.def( "blindData", &DispatcherWrapper::taskBatchGetBlindData )
	;

	SignalBinder<Dispatcher::PreDispatchSignal, DefaultSignalCaller<Dispatcher::PreDispatchSignal>, PreDispatchSlotCaller >::bind( "PreDispatchSignal" );
	SignalBinder<Dispatcher::PostDispatchSignal, DefaultSignalCaller<Dispatcher::PostDispatchSignal>, PostDispatchSlotCaller >::bind( "PostDispatchSignal" );
}
<|endoftext|>


<commit_before>/*
 Basic Server code for CMPT 276, Spring 2016.
 */

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "TableCache.h"
#include "config.h"
#include "make_unique.h"

#include "azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34568";

const string create_table {"CreateTable"};
const string delete_table {"DeleteTable"};
const string update_entity {"UpdateEntity"};
const string delete_entity {"DeleteEntity"};

/*
  Cache of opened tables
 */
TableCache table_cache {};

/*
  Convert properties represented in Azure Storage type
  to prop_vals_t type.
 */
prop_vals_t get_properties (const table_entity::properties_type& properties, prop_vals_t values = prop_vals_t {}) {
  for (const auto v : properties) {
    if (v.second.property_type() == edm_type::string) {
      values.push_back(make_pair(v.first, value::string(v.second.string_value())));
    }
    else if (v.second.property_type() == edm_type::datetime) {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
    else if(v.second.property_type() == edm_type::int32) {
      values.push_back(make_pair(v.first, value::number(v.second.int32_value())));
    }
    else if(v.second.property_type() == edm_type::int64) {
      values.push_back(make_pair(v.first, value::number(v.second.int64_value())));
    }
    else if(v.second.property_type() == edm_type::double_floating_point) {
      values.push_back(make_pair(v.first, value::number(v.second.double_value())));
    }
    else if(v.second.property_type() == edm_type::boolean) {
      values.push_back(make_pair(v.first, value::boolean(v.second.boolean_value())));
    }
    else {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
  }
  return values;
}

/*
  Return true if an HTTP request has a JSON body
 */
bool has_json_body (http_request message) {
  return message.headers()["Content-type"] == "application/json";
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.

  If the message has no JSON body, return an empty map.

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
	  {
            json = v;
	    return true;
	  })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
	results[v.first] = v.second.as_string();
      }
      else {
	results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

/*
  Top-level routine for processing all HTTP GET requests.

  GET is the only request that has no command. All
  operands specify the value(s) to be retrieved.
 */
void handle_get(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** GET " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least a table name
  if (paths.size() < 1) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[0])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  // GET all entries in table
  if (paths.size() == 1) {
    table_query query {};
    table_query_iterator end;
    table_query_iterator it = table.execute_query(query);
    vector<value> key_vec;
    while (it != end) {
      cout << "Key: " << it->partition_key() << " / " << it->row_key() << endl;
      prop_vals_t keys {
	make_pair("Partition",value::string(it->partition_key())),
	make_pair("Row", value::string(it->row_key()))};
      keys = get_properties(it->properties(), keys);
      key_vec.push_back(value::object(keys));
      ++it;
    }
    message.reply(status_codes::OK, value::array(key_vec));
    return;
  }

  // GET specific entry: Partition == paths[1], Row == paths[2]
  table_operation retrieve_operation {table_operation::retrieve_entity(paths[1], paths[2])};
  table_result retrieve_result {table.execute(retrieve_operation)};
  cout << "HTTP code: " << retrieve_result.http_status_code() << endl;
  if (retrieve_result.http_status_code() == status_codes::NotFound) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {retrieve_result.entity()};
  table_entity::properties_type properties {entity.properties()};

  // If the entity has any properties, return them as JSON
  prop_vals_t values (get_properties(properties));
  if (values.size() > 0)
    message.reply(status_codes::OK, value::object(values));
  else
    message.reply(status_codes::OK);
}

/*
  Top-level routine for processing all HTTP POST requests.
 */
void handle_post(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and a table name
  if (paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Create table (idempotent if table exists)
  if (paths[0] == create_table) {
    cout << "Create " << table_name << endl;
    bool created {table.create_if_not_exists()};
    cout << "Administrative table URI " << table.uri().primary_uri().to_string() << endl;
    if (created)
      message.reply(status_codes::Created);
    else
      message.reply(status_codes::Accepted);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP PUT requests.
 */
void handle_put(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** PUT " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation, table name, partition, and row
  if (paths.size() < 4) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[1])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {paths[2], paths[3]};

  // Update entity
  if (paths[0] == update_entity) {
    cout << "Update " << entity.partition_key() << " / " << entity.row_key() << endl;
    table_entity::properties_type& properties = entity.properties();
    for (const auto v : get_json_body(message)) {
      properties[v.first] = entity_property {v.second};
    }

    table_operation operation {table_operation::insert_or_merge_entity(entity)};
    table_result op_result {table.execute(operation)};

    message.reply(status_codes::OK);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP DELETE requests.
 */
void handle_delete(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** DELETE " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and table name
  if (paths.size() < 2) {
	message.reply(status_codes::BadRequest);
	return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Delete table
  if (paths[0] == delete_table) {
    cout << "Delete " << table_name << endl;
    if ( ! table.exists()) {
      message.reply(status_codes::NotFound);
    }
    table.delete_table();
    table_cache.delete_entry(table_name);
    message.reply(status_codes::OK);
  }
  // Delete entity
  else if (paths[0] == delete_entity) {
    // For delete entity, also need partition and row
    if (paths.size() < 4) {
	message.reply(status_codes::BadRequest);
	return;
    }
    table_entity entity {paths[2], paths[3]};
    cout << "Delete " << entity.partition_key() << " / " << entity.row_key()<< endl;

    table_operation operation {table_operation::delete_entity(entity)};
    table_result op_result {table.execute(operation)};

    int code {op_result.http_status_code()};
    if (code == status_codes::OK ||
	code == status_codes::NoContent)
      message.reply(status_codes::OK);
    else
      message.reply(code);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Main server routine

  Install handlers for the HTTP requests and open the listener,
  which processes each request asynchronously.

  Wait for a carriage return, then shut the server down.
 */
int main (int argc, char const * argv[]) {
  cout << "Parsing connection string" << endl;
  table_cache.init (storage_connection_string);

  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get);
  listener.support(methods::POST, &handle_post);
  listener.support(methods::PUT, &handle_put);
  listener.support(methods::DEL, &handle_delete);
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<commit_msg>Add check for BadRequest on GET<commit_after>/*
 Basic Server code for CMPT 276, Spring 2016.
 */

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "TableCache.h"
#include "config.h"
#include "make_unique.h"

#include "azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34568";

const string create_table {"CreateTable"};
const string delete_table {"DeleteTable"};
const string update_entity {"UpdateEntity"};
const string delete_entity {"DeleteEntity"};

/*
  Cache of opened tables
 */
TableCache table_cache {};

/*
  Convert properties represented in Azure Storage type
  to prop_vals_t type.
 */
prop_vals_t get_properties (const table_entity::properties_type& properties, prop_vals_t values = prop_vals_t {}) {
  for (const auto v : properties) {
    if (v.second.property_type() == edm_type::string) {
      values.push_back(make_pair(v.first, value::string(v.second.string_value())));
    }
    else if (v.second.property_type() == edm_type::datetime) {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
    else if(v.second.property_type() == edm_type::int32) {
      values.push_back(make_pair(v.first, value::number(v.second.int32_value())));
    }
    else if(v.second.property_type() == edm_type::int64) {
      values.push_back(make_pair(v.first, value::number(v.second.int64_value())));
    }
    else if(v.second.property_type() == edm_type::double_floating_point) {
      values.push_back(make_pair(v.first, value::number(v.second.double_value())));
    }
    else if(v.second.property_type() == edm_type::boolean) {
      values.push_back(make_pair(v.first, value::boolean(v.second.boolean_value())));
    }
    else {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
  }
  return values;
}

/*
  Return true if an HTTP request has a JSON body
 */
bool has_json_body (http_request message) {
  return message.headers()["Content-type"] == "application/json";
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.

  If the message has no JSON body, return an empty map.

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
	  {
            json = v;
	    return true;
	  })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
	results[v.first] = v.second.as_string();
      }
      else {
	results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

/*
  Top-level routine for processing all HTTP GET requests.

  GET is the only request that has no command. All
  operands specify the value(s) to be retrieved.
 */
void handle_get(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** GET " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least a table name
  if (paths.size() < 1) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[0])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  // GET all entries in table
  if (paths.size() == 1) {
    table_query query {};
    table_query_iterator end;
    table_query_iterator it = table.execute_query(query);
    vector<value> key_vec;
    while (it != end) {
      cout << "Key: " << it->partition_key() << " / " << it->row_key() << endl;
      prop_vals_t keys {
	make_pair("Partition",value::string(it->partition_key())),
	make_pair("Row", value::string(it->row_key()))};
      keys = get_properties(it->properties(), keys);
      key_vec.push_back(value::object(keys));
      ++it;
    }
    message.reply(status_codes::OK, value::array(key_vec));
    return;
  }

  if (paths.size() != 3) {
    message.reply (status_codes::BadRequest);
    return;
  }

  // GET specific entry: Partition == paths[1], Row == paths[2]
  table_operation retrieve_operation {table_operation::retrieve_entity(paths[1], paths[2])};
  table_result retrieve_result {table.execute(retrieve_operation)};
  cout << "HTTP code: " << retrieve_result.http_status_code() << endl;
  if (retrieve_result.http_status_code() == status_codes::NotFound) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {retrieve_result.entity()};
  table_entity::properties_type properties {entity.properties()};

  // If the entity has any properties, return them as JSON
  prop_vals_t values (get_properties(properties));
  if (values.size() > 0)
    message.reply(status_codes::OK, value::object(values));
  else
    message.reply(status_codes::OK);
}

/*
  Top-level routine for processing all HTTP POST requests.
 */
void handle_post(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and a table name
  if (paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Create table (idempotent if table exists)
  if (paths[0] == create_table) {
    cout << "Create " << table_name << endl;
    bool created {table.create_if_not_exists()};
    cout << "Administrative table URI " << table.uri().primary_uri().to_string() << endl;
    if (created)
      message.reply(status_codes::Created);
    else
      message.reply(status_codes::Accepted);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP PUT requests.
 */
void handle_put(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** PUT " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation, table name, partition, and row
  if (paths.size() < 4) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[1])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {paths[2], paths[3]};

  // Update entity
  if (paths[0] == update_entity) {
    cout << "Update " << entity.partition_key() << " / " << entity.row_key() << endl;
    table_entity::properties_type& properties = entity.properties();
    for (const auto v : get_json_body(message)) {
      properties[v.first] = entity_property {v.second};
    }

    table_operation operation {table_operation::insert_or_merge_entity(entity)};
    table_result op_result {table.execute(operation)};

    message.reply(status_codes::OK);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP DELETE requests.
 */
void handle_delete(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** DELETE " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and table name
  if (paths.size() < 2) {
	message.reply(status_codes::BadRequest);
	return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Delete table
  if (paths[0] == delete_table) {
    cout << "Delete " << table_name << endl;
    if ( ! table.exists()) {
      message.reply(status_codes::NotFound);
    }
    table.delete_table();
    table_cache.delete_entry(table_name);
    message.reply(status_codes::OK);
  }
  // Delete entity
  else if (paths[0] == delete_entity) {
    // For delete entity, also need partition and row
    if (paths.size() < 4) {
	message.reply(status_codes::BadRequest);
	return;
    }
    table_entity entity {paths[2], paths[3]};
    cout << "Delete " << entity.partition_key() << " / " << entity.row_key()<< endl;

    table_operation operation {table_operation::delete_entity(entity)};
    table_result op_result {table.execute(operation)};

    int code {op_result.http_status_code()};
    if (code == status_codes::OK ||
	code == status_codes::NoContent)
      message.reply(status_codes::OK);
    else
      message.reply(code);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Main server routine

  Install handlers for the HTTP requests and open the listener,
  which processes each request asynchronously.

  Wait for a carriage return, then shut the server down.
 */
int main (int argc, char const * argv[]) {
  cout << "Parsing connection string" << endl;
  table_cache.init (storage_connection_string);

  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get);
  listener.support(methods::POST, &handle_post);
  listener.support(methods::PUT, &handle_put);
  listener.support(methods::DEL, &handle_delete);
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<|endoftext|>


<commit_before>#include "KEngine/Core/ResourceManager.hpp"

#include "KEngine/Resources/ImageResource.hpp"
#include "KEngine/Resources/Loaders/ImageResourceLoader.hpp"

#include "KEngine/Log/Log.hpp"
#include "KEngine/Common/Json.hpp"

#include <filesystem>
#include <fstream>

namespace ke
{

    ResourceManager::ResourceManager()
        : threadPool(2)
    {
        this->registerResourceLoader(ke::ImageResource::TYPE, ke::makeResourceLoader<ke::ImageResourceLoader>());
    }

    void ResourceManager::update()
    {
        // TODO
    }

    bool ResourceManager::isLoading() const
    {
        return !threadedInProgressLoadingFutures.empty();
    }

    void ResourceManager::releaseResource(ResourceSptr resource)
    {
        this->allResources.erase(resource->getName());
    }

    void ResourceManager::releaseResource(const ke::String & resourceName)
    {
        this->allResources.erase(resourceName);
    }

    void ResourceManager::registerResource(ResourceSptr resource)
    {
        this->allResources.insert_or_assign(resource->getName(), resource);
    }

    IResource * ResourceManager::getResource(const ke::String & name)
    {
        return
            this->allResources.find(name) != this->allResources.end() ?
            this->allResources[name].get() :
            nullptr;
    }

    void ResourceManager::loadFromManifest(ke::String manifestPath)
    {
        // filesystem safety checks.
        namespace fs = std::experimental::filesystem;
        if (!fs::exists(manifestPath))
        {
            ke::Log::instance()->error("Manifest path does not exist at: '{}'.", manifestPath);
            return;
        }
        if (!fs::is_regular_file(manifestPath))
        {
            ke::Log::instance()->error("Manifest path is not a file. Path: '{}'.", manifestPath);
            return;
        }

        // read the JSON content.
        std::ifstream ifs{ manifestPath.c_str() };
        std::string content( std::istreambuf_iterator<char> { ifs }, std::istreambuf_iterator<char>{} );
        auto manifestJson = ke::Json::parse(content.begin(), content.end());

        // type check JSON for manifest
        if (!this->validateManifestJson(manifestJson, manifestPath))
        {
            return;
        }

        //  check if there are resources to load.
        auto resourcesItr = manifestJson.find("resources");
        if (resourcesItr == manifestJson.end())
        {
            ke::Log::instance()->warn("Resource manifest at {} does not have a 'resources' object.");
            return;
        }

        // load all resources.
        for (const auto & resourceJson : *resourcesItr)
        {
            if (!this->validateResourceJson(resourceJson))
            {
                continue;
            }

            auto resourceType = resourceJson["resource_type"].get<std::string>();
            auto resourceLoaderItr = this->resourceLoaders.find(resourceType);
            if (resourceLoaderItr == this->resourceLoaders.end())
            {
                ke::Log::instance()->error("No resource loader available for resource of type '{}'.", resourceType);
                continue;
            }

            auto resourceName = resourceJson["resource_name"].get<std::string>();
            auto newResource = resourceLoaderItr->second->load(resourceJson);
            if (nullptr == newResource)
            {
                ke::Log::instance()->error("Resource loader failed to load resource named '{}'. JSON content: {}",
                    resourceName, resourceJson.dump(2));
                continue;
            }

            if (this->allResources.find(resourceName) != this->allResources.end())
            {
                ke::Log::instance()->warn("Overwriting resource named '{}'.", resourceName);
            }

            this->allResources[resourceName] = resourceLoaderItr->second->load(resourceJson);
        }
    }

    bool ResourceManager::validateManifestJson(const ke::Json & manifestJson, const ke::String & manifestPath)
    {
        auto manifestTypeItr = manifestJson.find("type");
        if (manifestTypeItr == manifestJson.end())
        {
            ke::Log::instance()->error("Manifest JSON missing 'type' object.");
            return false;
        }
        if (manifestTypeItr->get<std::string>() != "manifest")
        {
            ke::Log::instance()->error("The JSON at '{}' is not an engine resource manifest.", manifestPath);
            return false;
        }

        return true;
    }

    bool ResourceManager::validateResourceJson(const ke::Json & resourceJson)
    {
        auto typeItr = resourceJson.find("type");
        if (typeItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'type'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto typeValue = typeItr->get<std::string>();
        if (typeValue != "resource")
        {
            ke::Log::instance()->error("Engine resource JSON containts unexpected 'type' value: {}", typeValue);
            return false;
        }

        auto resourceTypeItr = resourceJson.find("resource_type");
        if (resourceTypeItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'resource_type'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto resourceType = resourceTypeItr->get<std::string>();

        auto resourceNameItr = resourceJson.find("resource_name");
        if (resourceNameItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'resource_name'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto resourceName = resourceNameItr->get<std::string>();

        return true;
    }

    void ResourceManager::registerResourceLoader(ke::ResourceType resourceType, ke::ResourceLoaderSptr loader)
    {
        auto resourceLoaderItr = this->resourceLoaders.find(resourceType);
        if (resourceLoaderItr != this->resourceLoaders.end() &&
            resourceLoaderItr->second != loader)
        {
            ke::Log::instance()->info("Current resource loader for type '{}' resources is being replaced.", resourceType);
        }
        this->resourceLoaders[resourceType] = loader;
    }

}<commit_msg>replace use of std::experimental::filesystem<commit_after>#include "KEngine/Core/ResourceManager.hpp"

#include "KEngine/Resources/ImageResource.hpp"
#include "KEngine/Resources/Loaders/ImageResourceLoader.hpp"

#include "KEngine/Log/Log.hpp"
#include "KEngine/Common/Json.hpp"

#include <filesystem>
#include <fstream>

namespace ke
{

    ResourceManager::ResourceManager()
        : threadPool(2)
    {
        this->registerResourceLoader(ke::ImageResource::TYPE, ke::makeResourceLoader<ke::ImageResourceLoader>());
    }

    void ResourceManager::update()
    {
        // TODO
    }

    bool ResourceManager::isLoading() const
    {
        return !threadedInProgressLoadingFutures.empty();
    }

    void ResourceManager::releaseResource(ResourceSptr resource)
    {
        this->allResources.erase(resource->getName());
    }

    void ResourceManager::releaseResource(const ke::String & resourceName)
    {
        this->allResources.erase(resourceName);
    }

    void ResourceManager::registerResource(ResourceSptr resource)
    {
        this->allResources.insert_or_assign(resource->getName(), resource);
    }

    IResource * ResourceManager::getResource(const ke::String & name)
    {
        return
            this->allResources.find(name) != this->allResources.end() ?
            this->allResources[name].get() :
            nullptr;
    }

    void ResourceManager::loadFromManifest(ke::String manifestPath)
    {
        // filesystem safety checks.
        namespace fs = std::filesystem;
        if (!fs::exists(manifestPath))
        {
            ke::Log::instance()->error("Manifest path does not exist at: '{}'.", manifestPath);
            return;
        }
        if (!fs::is_regular_file(manifestPath))
        {
            ke::Log::instance()->error("Manifest path is not a file. Path: '{}'.", manifestPath);
            return;
        }

        // read the JSON content.
        std::ifstream ifs{ manifestPath.c_str() };
        std::string content( std::istreambuf_iterator<char> { ifs }, std::istreambuf_iterator<char>{} );
        auto manifestJson = ke::Json::parse(content.begin(), content.end());

        // type check JSON for manifest
        if (!this->validateManifestJson(manifestJson, manifestPath))
        {
            return;
        }

        //  check if there are resources to load.
        auto resourcesItr = manifestJson.find("resources");
        if (resourcesItr == manifestJson.end())
        {
            ke::Log::instance()->warn("Resource manifest at {} does not have a 'resources' object.");
            return;
        }

        // load all resources.
        for (const auto & resourceJson : *resourcesItr)
        {
            if (!this->validateResourceJson(resourceJson))
            {
                continue;
            }

            auto resourceType = resourceJson["resource_type"].get<std::string>();
            auto resourceLoaderItr = this->resourceLoaders.find(resourceType);
            if (resourceLoaderItr == this->resourceLoaders.end())
            {
                ke::Log::instance()->error("No resource loader available for resource of type '{}'.", resourceType);
                continue;
            }

            auto resourceName = resourceJson["resource_name"].get<std::string>();
            auto newResource = resourceLoaderItr->second->load(resourceJson);
            if (nullptr == newResource)
            {
                ke::Log::instance()->error("Resource loader failed to load resource named '{}'. JSON content: {}",
                    resourceName, resourceJson.dump(2));
                continue;
            }

            if (this->allResources.find(resourceName) != this->allResources.end())
            {
                ke::Log::instance()->warn("Overwriting resource named '{}'.", resourceName);
            }

            this->allResources[resourceName] = resourceLoaderItr->second->load(resourceJson);
        }
    }

    bool ResourceManager::validateManifestJson(const ke::Json & manifestJson, const ke::String & manifestPath)
    {
        auto manifestTypeItr = manifestJson.find("type");
        if (manifestTypeItr == manifestJson.end())
        {
            ke::Log::instance()->error("Manifest JSON missing 'type' object.");
            return false;
        }
        if (manifestTypeItr->get<std::string>() != "manifest")
        {
            ke::Log::instance()->error("The JSON at '{}' is not an engine resource manifest.", manifestPath);
            return false;
        }

        return true;
    }

    bool ResourceManager::validateResourceJson(const ke::Json & resourceJson)
    {
        auto typeItr = resourceJson.find("type");
        if (typeItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'type'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto typeValue = typeItr->get<std::string>();
        if (typeValue != "resource")
        {
            ke::Log::instance()->error("Engine resource JSON containts unexpected 'type' value: {}", typeValue);
            return false;
        }

        auto resourceTypeItr = resourceJson.find("resource_type");
        if (resourceTypeItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'resource_type'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto resourceType = resourceTypeItr->get<std::string>();

        auto resourceNameItr = resourceJson.find("resource_name");
        if (resourceNameItr == resourceJson.end())
        {
            ke::Log::instance()->error("Engine resource JSON missing 'resource_name'. Content: {}", resourceJson.dump(2));
            return false;
        }
        auto resourceName = resourceNameItr->get<std::string>();

        return true;
    }

    void ResourceManager::registerResourceLoader(ke::ResourceType resourceType, ke::ResourceLoaderSptr loader)
    {
        auto resourceLoaderItr = this->resourceLoaders.find(resourceType);
        if (resourceLoaderItr != this->resourceLoaders.end() &&
            resourceLoaderItr->second != loader)
        {
            ke::Log::instance()->info("Current resource loader for type '{}' resources is being replaced.", resourceType);
        }
        this->resourceLoaders[resourceType] = loader;
    }

}<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXMLPStructuredDataReader.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkXMLPStructuredDataReader.h"

#include "vtkDataArray.h"
#include "vtkDataSet.h"
#include "vtkExtentSplitter.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"
//#include "vtkTableExtentTranslator.h"
#include "vtkXMLDataElement.h"
#include "vtkXMLStructuredDataReader.h"

#include <vtksys/ios/sstream>

vtkCxxRevisionMacro(vtkXMLPStructuredDataReader, "1.27");

//----------------------------------------------------------------------------
vtkXMLPStructuredDataReader::vtkXMLPStructuredDataReader()
{
  //this->ExtentTranslator = vtkTableExtentTranslator::New();
  this->ExtentSplitter = vtkExtentSplitter::New();
  this->PieceExtents = 0;
}

//----------------------------------------------------------------------------
vtkXMLPStructuredDataReader::~vtkXMLPStructuredDataReader()
{
  if(this->NumberOfPieces) { this->DestroyPieces(); }
  this->ExtentSplitter->Delete();
  //this->ExtentTranslator->Delete();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//----------------------------------------------------------------------------
vtkExtentTranslator* vtkXMLPStructuredDataReader::GetExtentTranslator()
{
  return 0;
  //return this->ExtentTranslator;
}

//----------------------------------------------------------------------------
vtkIdType vtkXMLPStructuredDataReader::GetNumberOfPoints()
{
  return (this->PointDimensions[0]*
          this->PointDimensions[1]*
          this->PointDimensions[2]);
}

//----------------------------------------------------------------------------
vtkIdType vtkXMLPStructuredDataReader::GetNumberOfCells()
{
  return (this->CellDimensions[0]*
          this->CellDimensions[1]*
          this->CellDimensions[2]);
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::ReadXMLData()
{
  // Get the requested Update Extent.
  vtkInformation* outInfo = this->GetCurrentOutputInformation();
  outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
      this->UpdateExtent);

  vtkDebugMacro("Updating extent "
                << this->UpdateExtent[0] << " " << this->UpdateExtent[1] << " "
                << this->UpdateExtent[2] << " " << this->UpdateExtent[3] << " "
                << this->UpdateExtent[4] << " " << this->UpdateExtent[5]
                << "\n");

  // Prepare increments for the update extent.
  this->ComputePointDimensions(this->UpdateExtent, this->PointDimensions);
  this->ComputePointIncrements(this->UpdateExtent, this->PointIncrements);
  this->ComputeCellDimensions(this->UpdateExtent, this->CellDimensions);
  this->ComputeCellIncrements(this->UpdateExtent, this->CellIncrements);

  // Let superclasses read data.  This also allocates output data.
  this->Superclass::ReadXMLData();

  // Use the ExtentSplitter to split the update extent into
  // sub-extents read by each piece.
  if(!this->ComputePieceSubExtents())
    {
    // Not all needed data are available.
    this->DataError = 1;
    return;
    }

  // Split current progress range based on fraction contributed by
  // each sub-extent.
  float progressRange[2] = {0,0};
  this->GetProgressRange(progressRange);

  // Calculate the cumulative fraction of data contributed by each
  // sub-extent (for progress).
  int n = this->ExtentSplitter->GetNumberOfSubExtents();
  float* fractions = new float[n+1];
  int i;
  fractions[0] = 0;
  for(i=0;i < n;++i)
    {
    // Get this sub-extent.
    this->ExtentSplitter->GetSubExtent(i, this->SubExtent);

    // Add this sub-extent's volume to the cumulative volume.
    int pieceDims[3] = {0,0,0};
    this->ComputePointDimensions(this->SubExtent, pieceDims);
    fractions[i+1] = fractions[i] + pieceDims[0]*pieceDims[1]*pieceDims[2];
    }
  if(fractions[n] == 0)
    {
    fractions[n] = 1;
    }
  for(i=1;i <= n;++i)
    {
    fractions[i] = fractions[i] / fractions[n];
    }

  // Read the data needed from each sub-extent.
  for(i=0;(i < n && !this->AbortExecute && !this->DataError);++i)
    {
    // Set the range of progress for this sub-extent.
    this->SetProgressRange(progressRange, i, fractions);

    // Get this sub-extent and the piece from which to read it.
    int piece = this->ExtentSplitter->GetSubExtentSource(i);
    this->ExtentSplitter->GetSubExtent(i, this->SubExtent);

    vtkDebugMacro("Reading extent "
                  << this->SubExtent[0] << " " << this->SubExtent[1] << " "
                  << this->SubExtent[2] << " " << this->SubExtent[3] << " "
                  << this->SubExtent[4] << " " << this->SubExtent[5]
                  << " from piece " << piece);

    this->ComputePointDimensions(this->SubExtent, this->SubPointDimensions);
    this->ComputeCellDimensions(this->SubExtent, this->SubCellDimensions);

    // Read the data from this piece.
    if(!this->Superclass::ReadPieceData(piece))
      {
      // An error occurred while reading the piece.
      this->DataError = 1;
      }
    }

  delete [] fractions;

  // We filled the exact update extent in the output.
  this->SetOutputExtent(this->UpdateExtent);
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::RequestInformation(vtkInformation *request,
    vtkInformationVector **inputVector,
    vtkInformationVector *outputVector)
{

  // Tell the output to use the table extent translator to provide the
  // correct piece breakdown for the file layout.
  /*
  outputVector->GetInformationObject(0)->Set(
      vtkStreamingDemandDrivenPipeline::EXTENT_TRANSLATOR(),
      this->ExtentTranslator);
   */

  return this->Superclass::RequestInformation(
      request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int
vtkXMLPStructuredDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
{
  if(!this->Superclass::ReadPrimaryElement(ePrimary)) { return 0; }

  // Get the whole extent attribute.
  int extent[6];
  if(ePrimary->GetVectorAttribute("WholeExtent", 6, extent) == 6)
    {
    // Set the output's whole extent.
    vtkInformation* outInfo = this->GetCurrentOutputInformation();
    outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
        extent, 6);

    // Check each axis to see if it has cells.
    for(int a=0; a < 3; ++a)
      {
      this->AxesEmpty[a] = (extent[2*a+1] > extent[2*a])? 0 : 1;
      }
    }
  else
    {
    vtkErrorMacro(<< this->GetDataSetName() << " element has no WholeExtent.");
    return 0;
    }

  return 1;
}

//----------------------------------------------------------------------------
void
vtkXMLPStructuredDataReader::CopyOutputInformation(vtkInformation* outInfo,
                                                   int port)
{
  // Let the superclass copy information first.
  this->Superclass::CopyOutputInformation(outInfo, port);

  // All structured data has a whole extent.
  vtkInformation *localInfo =
    this->GetExecutive()->GetOutputInformation( port );
  if(localInfo->Has(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()))
    {
    outInfo->CopyEntry(localInfo,
                       vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
    }
}

void vtkXMLPStructuredDataReader::SetupOutputData()
{
  this->Superclass::SetupOutputData();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::SetupPieces(int numPieces)
{
  this->Superclass::SetupPieces(numPieces);
  //this->ExtentTranslator->SetNumberOfPiecesInTable(this->NumberOfPieces);
  //this->ExtentTranslator->SetMaximumGhostLevel(this->GhostLevel);
  this->PieceExtents = new int[6*this->NumberOfPieces];
  int i;
  for(i=0;i < this->NumberOfPieces;++i)
    {
    int* extent = this->PieceExtents+i*6;
    extent[0] = 0; extent[1] = -1;
    extent[2] = 0; extent[3] = -1;
    extent[4] = 0; extent[5] = -1;
    }
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::DestroyPieces()
{
  delete [] this->PieceExtents;
  this->PieceExtents = 0;
  this->Superclass::DestroyPieces();
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ReadPiece(vtkXMLDataElement* ePiece)
{
  // Superclass will create a reader for the piece's file.
  if(!this->Superclass::ReadPiece(ePiece)) { return 0; }

  // Get the extent of the piece.
  int* pieceExtent = this->PieceExtents+this->Piece*6;
  if(ePiece->GetVectorAttribute("Extent", 6, pieceExtent) < 6)
    {
    vtkErrorMacro("Piece " << this->Piece << " has invalid Extent.");
    return 0;
    }

  // Set this table entry in the extent translator.
  //this->ExtentTranslator->SetExtentForPiece(this->Piece, pieceExtent);
  //this->ExtentTranslator->SetPieceAvailable(this->Piece,
  //                                          this->CanReadPiece(this->Piece));

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ReadPieceData()
{
  // Use the internal reader to read the piece.
  vtkDataSet* input = this->GetPieceInputAsDataSet(this->Piece);
  input->SetUpdateExtent(this->SubExtent);
  input->Update();

  // Skip rest of read if aborting.
  if(this->AbortExecute)
    {
    return 0;
    }

  // Get the actual portion of the piece that was read.
  this->GetPieceInputExtent(this->Piece, this->SubPieceExtent);
  this->ComputePointDimensions(this->SubPieceExtent,
                               this->SubPiecePointDimensions);
  this->ComputePointIncrements(this->SubPieceExtent,
                               this->SubPiecePointIncrements);
  this->ComputeCellDimensions(this->SubPieceExtent,
                              this->SubPieceCellDimensions);
  this->ComputeCellIncrements(this->SubPieceExtent,
                              this->SubPieceCellIncrements);

  // Let the superclass read the data it wants.
  return this->Superclass::ReadPieceData();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::CopyArrayForPoints(vtkDataArray* inArray,
                                                     vtkDataArray* outArray)
{
  if(!inArray || !outArray)
    {
    return;
    }
  this->CopySubExtent(this->SubPieceExtent,
                      this->SubPiecePointDimensions,
                      this->SubPiecePointIncrements,
                      this->UpdateExtent, this->PointDimensions,
                      this->PointIncrements, this->SubExtent,
                      this->SubPointDimensions, inArray, outArray);
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::CopyArrayForCells(vtkDataArray* inArray,
                                                    vtkDataArray* outArray)
{
  if(!inArray || !outArray)
    {
    return;
    }
  this->CopySubExtent(this->SubPieceExtent,
                      this->SubPieceCellDimensions,
                      this->SubPieceCellIncrements,
                      this->UpdateExtent, this->CellDimensions,
                      this->CellIncrements, this->SubExtent,
                      this->SubCellDimensions, inArray, outArray);
}

//----------------------------------------------------------------------------
void
vtkXMLPStructuredDataReader
::CopySubExtent(int* inExtent, int* inDimensions, vtkIdType* inIncrements,
                int* outExtent, int* outDimensions, vtkIdType* outIncrements,
                int* subExtent, int* subDimensions,
                vtkDataArray* inArray, vtkDataArray* outArray)
{
  unsigned int components = inArray->GetNumberOfComponents();
  unsigned int tupleSize = inArray->GetDataTypeSize()*components;

  if((inDimensions[0] == outDimensions[0]) &&
     (inDimensions[1] == outDimensions[1]))
    {
    if(inDimensions[2] == outDimensions[2])
      {
      // Copy the whole volume at once.
      unsigned int volumeTuples = (inDimensions[0]*
                                   inDimensions[1]*
                                   inDimensions[2]);
      memcpy(outArray->GetVoidPointer(0), inArray->GetVoidPointer(0),
             volumeTuples*tupleSize);
      }
    else
      {
      // Copy an entire slice at a time.
      vtkIdType sliceTuples = inDimensions[0]*inDimensions[1];
      int k;
      for(k=0;k < subDimensions[2];++k)
        {
        vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements,
                                                    subExtent[0],
                                                    subExtent[2],
                                                    subExtent[4]+k);
        vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements,
                                                  subExtent[0],
                                                  subExtent[2],
                                                  subExtent[4]+k);
        memcpy(outArray->GetVoidPointer(destTuple*components),
               inArray->GetVoidPointer(sourceTuple*components),
               sliceTuples*tupleSize);
        }
      }
    }
  else
    {
    // Copy a row at a time.
    vtkIdType rowTuples = subDimensions[0];
    int j,k;
    for(k=0;k < subDimensions[2];++k)
      {
      for(j=0;j < subDimensions[1];++j)
        {
        vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements,
                                                    subExtent[0],
                                                    subExtent[2]+j,
                                                    subExtent[4]+k);
        vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements,
                                                  subExtent[0],
                                                  subExtent[2]+j,
                                                  subExtent[4]+k);
        memcpy(outArray->GetVoidPointer(destTuple*components),
               inArray->GetVoidPointer(sourceTuple*components),
               rowTuples*tupleSize);
        }
      }
    }
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ComputePieceSubExtents()
{
  // Reset the extent splitter.
  this->ExtentSplitter->RemoveAllExtentSources();

  // Add each readable piece as an extent source.
  int i;
  for(i=0;i < this->NumberOfPieces;++i)
    {
    //if(this->CanReadPiece(i))
      {
      // Add the exact extent provided by the piece to the splitter.
      int extent[6];
      this->PieceReaders[i]->UpdateInformation();
      this->PieceReaders[i]->GetOutputAsDataSet()->GetWholeExtent(extent);
      this->ExtentSplitter->AddExtentSource(i, 0, extent);
      }
    }

  // We want to split the entire update extent across the pieces.
  this->ExtentSplitter->AddExtent(this->UpdateExtent);

  // Compute the sub-extents.
  if(!this->ExtentSplitter->ComputeSubExtents())
    {
    // A portion of the extent is not available.
    vtksys_ios::ostringstream e_with_warning_C4701;
    e_with_warning_C4701
      << "No available piece provides data for the following extents:\n";
    for(i=0; i < this->ExtentSplitter->GetNumberOfSubExtents(); ++i)
      {
      if(this->ExtentSplitter->GetSubExtentSource(i) < 0)
        {
        int extent[6];
        this->ExtentSplitter->GetSubExtent(i, extent);
        e_with_warning_C4701
          << "    "
          << extent[0] << " " << extent[1] << "  "
          << extent[2] << " " << extent[3] << "  "
          << extent[4] << " " << extent[5] << "\n";
        }
      }
    e_with_warning_C4701 << "The UpdateExtent cannot be filled.";
    vtkErrorMacro(<< e_with_warning_C4701.str().c_str());
    return 0;
    }

  return 1;
}

<commit_msg>BUG: pvti reader (and possibly other structured readers) were reading all pieces on all processes to determine the piece extents. That was unnecessary since the pvti file has all the piece extent information in it. Fixed the vtkXMLPStructuredDataReader to use that information for determining extent related information.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkXMLPStructuredDataReader.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkXMLPStructuredDataReader.h"

#include "vtkDataArray.h"
#include "vtkDataSet.h"
#include "vtkExtentSplitter.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"
//#include "vtkTableExtentTranslator.h"
#include "vtkXMLDataElement.h"
#include "vtkXMLStructuredDataReader.h"

#include <vtksys/ios/sstream>

vtkCxxRevisionMacro(vtkXMLPStructuredDataReader, "1.28");

//----------------------------------------------------------------------------
vtkXMLPStructuredDataReader::vtkXMLPStructuredDataReader()
{
  //this->ExtentTranslator = vtkTableExtentTranslator::New();
  this->ExtentSplitter = vtkExtentSplitter::New();
  this->PieceExtents = 0;
}

//----------------------------------------------------------------------------
vtkXMLPStructuredDataReader::~vtkXMLPStructuredDataReader()
{
  if(this->NumberOfPieces) { this->DestroyPieces(); }
  this->ExtentSplitter->Delete();
  //this->ExtentTranslator->Delete();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//----------------------------------------------------------------------------
vtkExtentTranslator* vtkXMLPStructuredDataReader::GetExtentTranslator()
{
  return 0;
  //return this->ExtentTranslator;
}

//----------------------------------------------------------------------------
vtkIdType vtkXMLPStructuredDataReader::GetNumberOfPoints()
{
  return (this->PointDimensions[0]*
          this->PointDimensions[1]*
          this->PointDimensions[2]);
}

//----------------------------------------------------------------------------
vtkIdType vtkXMLPStructuredDataReader::GetNumberOfCells()
{
  return (this->CellDimensions[0]*
          this->CellDimensions[1]*
          this->CellDimensions[2]);
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::ReadXMLData()
{
  // Get the requested Update Extent.
  vtkInformation* outInfo = this->GetCurrentOutputInformation();
  outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
      this->UpdateExtent);

  vtkDebugMacro("Updating extent "
                << this->UpdateExtent[0] << " " << this->UpdateExtent[1] << " "
                << this->UpdateExtent[2] << " " << this->UpdateExtent[3] << " "
                << this->UpdateExtent[4] << " " << this->UpdateExtent[5]);

  // Prepare increments for the update extent.
  this->ComputePointDimensions(this->UpdateExtent, this->PointDimensions);
  this->ComputePointIncrements(this->UpdateExtent, this->PointIncrements);
  this->ComputeCellDimensions(this->UpdateExtent, this->CellDimensions);
  this->ComputeCellIncrements(this->UpdateExtent, this->CellIncrements);

  // Let superclasses read data.  This also allocates output data.
  this->Superclass::ReadXMLData();

  // Use the ExtentSplitter to split the update extent into
  // sub-extents read by each piece.
  if(!this->ComputePieceSubExtents())
    {
    // Not all needed data are available.
    this->DataError = 1;
    return;
    }

  // Split current progress range based on fraction contributed by
  // each sub-extent.
  float progressRange[2] = {0,0};
  this->GetProgressRange(progressRange);

  // Calculate the cumulative fraction of data contributed by each
  // sub-extent (for progress).
  int n = this->ExtentSplitter->GetNumberOfSubExtents();
  float* fractions = new float[n+1];
  int i;
  fractions[0] = 0;
  for(i=0;i < n;++i)
    {
    // Get this sub-extent.
    this->ExtentSplitter->GetSubExtent(i, this->SubExtent);

    // Add this sub-extent's volume to the cumulative volume.
    int pieceDims[3] = {0,0,0};
    this->ComputePointDimensions(this->SubExtent, pieceDims);
    fractions[i+1] = fractions[i] + pieceDims[0]*pieceDims[1]*pieceDims[2];
    }
  if(fractions[n] == 0)
    {
    fractions[n] = 1;
    }
  for(i=1;i <= n;++i)
    {
    fractions[i] = fractions[i] / fractions[n];
    }

  // Read the data needed from each sub-extent.
  for(i=0;(i < n && !this->AbortExecute && !this->DataError);++i)
    {
    // Set the range of progress for this sub-extent.
    this->SetProgressRange(progressRange, i, fractions);

    // Get this sub-extent and the piece from which to read it.
    int piece = this->ExtentSplitter->GetSubExtentSource(i);
    this->ExtentSplitter->GetSubExtent(i, this->SubExtent);

    vtkDebugMacro("Reading extent "
                  << this->SubExtent[0] << " " << this->SubExtent[1] << " "
                  << this->SubExtent[2] << " " << this->SubExtent[3] << " "
                  << this->SubExtent[4] << " " << this->SubExtent[5]
                  << " from piece " << piece);

    this->ComputePointDimensions(this->SubExtent, this->SubPointDimensions);
    this->ComputeCellDimensions(this->SubExtent, this->SubCellDimensions);

    // Read the data from this piece.
    if(!this->Superclass::ReadPieceData(piece))
      {
      // An error occurred while reading the piece.
      this->DataError = 1;
      }
    }

  delete [] fractions;

  // We filled the exact update extent in the output.
  this->SetOutputExtent(this->UpdateExtent);
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::RequestInformation(vtkInformation *request,
    vtkInformationVector **inputVector,
    vtkInformationVector *outputVector)
{

  // Tell the output to use the table extent translator to provide the
  // correct piece breakdown for the file layout.
  /*
  outputVector->GetInformationObject(0)->Set(
      vtkStreamingDemandDrivenPipeline::EXTENT_TRANSLATOR(),
      this->ExtentTranslator);
   */

  return this->Superclass::RequestInformation(
      request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int
vtkXMLPStructuredDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
{
  if(!this->Superclass::ReadPrimaryElement(ePrimary)) { return 0; }

  // Get the whole extent attribute.
  int extent[6];
  if(ePrimary->GetVectorAttribute("WholeExtent", 6, extent) == 6)
    {
    // Set the output's whole extent.
    vtkInformation* outInfo = this->GetCurrentOutputInformation();
    outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
        extent, 6);

    // Check each axis to see if it has cells.
    for(int a=0; a < 3; ++a)
      {
      this->AxesEmpty[a] = (extent[2*a+1] > extent[2*a])? 0 : 1;
      }
    }
  else
    {
    vtkErrorMacro(<< this->GetDataSetName() << " element has no WholeExtent.");
    return 0;
    }

  return 1;
}

//----------------------------------------------------------------------------
void
vtkXMLPStructuredDataReader::CopyOutputInformation(vtkInformation* outInfo,
                                                   int port)
{
  // Let the superclass copy information first.
  this->Superclass::CopyOutputInformation(outInfo, port);

  // All structured data has a whole extent.
  vtkInformation *localInfo =
    this->GetExecutive()->GetOutputInformation( port );
  if(localInfo->Has(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()))
    {
    outInfo->CopyEntry(localInfo,
                       vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
    }
}

void vtkXMLPStructuredDataReader::SetupOutputData()
{
  this->Superclass::SetupOutputData();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::SetupPieces(int numPieces)
{
  this->Superclass::SetupPieces(numPieces);
  //this->ExtentTranslator->SetNumberOfPiecesInTable(this->NumberOfPieces);
  //this->ExtentTranslator->SetMaximumGhostLevel(this->GhostLevel);
  this->PieceExtents = new int[6*this->NumberOfPieces];
  int i;
  for(i=0;i < this->NumberOfPieces;++i)
    {
    int* extent = this->PieceExtents+i*6;
    extent[0] = 0; extent[1] = -1;
    extent[2] = 0; extent[3] = -1;
    extent[4] = 0; extent[5] = -1;
    }
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::DestroyPieces()
{
  delete [] this->PieceExtents;
  this->PieceExtents = 0;
  this->Superclass::DestroyPieces();
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ReadPiece(vtkXMLDataElement* ePiece)
{
  // Superclass will create a reader for the piece's file.
  if(!this->Superclass::ReadPiece(ePiece)) { return 0; }

  // Get the extent of the piece.
  int* pieceExtent = this->PieceExtents+this->Piece*6;
  if(ePiece->GetVectorAttribute("Extent", 6, pieceExtent) < 6)
    {
    vtkErrorMacro("Piece " << this->Piece << " has invalid Extent.");
    return 0;
    }

  // Set this table entry in the extent translator.
  //this->ExtentTranslator->SetExtentForPiece(this->Piece, pieceExtent);
  //this->ExtentTranslator->SetPieceAvailable(this->Piece,
  //                                          this->CanReadPiece(this->Piece));

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ReadPieceData()
{
  // Use the internal reader to read the piece.
  vtkDataSet* input = this->GetPieceInputAsDataSet(this->Piece);
  input->SetUpdateExtent(this->SubExtent);
  input->Update();

  // Skip rest of read if aborting.
  if(this->AbortExecute)
    {
    return 0;
    }

  // Get the actual portion of the piece that was read.
  this->GetPieceInputExtent(this->Piece, this->SubPieceExtent);
  this->ComputePointDimensions(this->SubPieceExtent,
                               this->SubPiecePointDimensions);
  this->ComputePointIncrements(this->SubPieceExtent,
                               this->SubPiecePointIncrements);
  this->ComputeCellDimensions(this->SubPieceExtent,
                              this->SubPieceCellDimensions);
  this->ComputeCellIncrements(this->SubPieceExtent,
                              this->SubPieceCellIncrements);

  // Let the superclass read the data it wants.
  return this->Superclass::ReadPieceData();
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::CopyArrayForPoints(vtkDataArray* inArray,
                                                     vtkDataArray* outArray)
{
  if(!inArray || !outArray)
    {
    return;
    }
  this->CopySubExtent(this->SubPieceExtent,
                      this->SubPiecePointDimensions,
                      this->SubPiecePointIncrements,
                      this->UpdateExtent, this->PointDimensions,
                      this->PointIncrements, this->SubExtent,
                      this->SubPointDimensions, inArray, outArray);
}

//----------------------------------------------------------------------------
void vtkXMLPStructuredDataReader::CopyArrayForCells(vtkDataArray* inArray,
                                                    vtkDataArray* outArray)
{
  if(!inArray || !outArray)
    {
    return;
    }
  this->CopySubExtent(this->SubPieceExtent,
                      this->SubPieceCellDimensions,
                      this->SubPieceCellIncrements,
                      this->UpdateExtent, this->CellDimensions,
                      this->CellIncrements, this->SubExtent,
                      this->SubCellDimensions, inArray, outArray);
}

//----------------------------------------------------------------------------
void
vtkXMLPStructuredDataReader
::CopySubExtent(int* inExtent, int* inDimensions, vtkIdType* inIncrements,
                int* outExtent, int* outDimensions, vtkIdType* outIncrements,
                int* subExtent, int* subDimensions,
                vtkDataArray* inArray, vtkDataArray* outArray)
{
  unsigned int components = inArray->GetNumberOfComponents();
  unsigned int tupleSize = inArray->GetDataTypeSize()*components;

  if((inDimensions[0] == outDimensions[0]) &&
     (inDimensions[1] == outDimensions[1]))
    {
    if(inDimensions[2] == outDimensions[2])
      {
      // Copy the whole volume at once.
      unsigned int volumeTuples = (inDimensions[0]*
                                   inDimensions[1]*
                                   inDimensions[2]);
      memcpy(outArray->GetVoidPointer(0), inArray->GetVoidPointer(0),
             volumeTuples*tupleSize);
      }
    else
      {
      // Copy an entire slice at a time.
      vtkIdType sliceTuples = inDimensions[0]*inDimensions[1];
      int k;
      for(k=0;k < subDimensions[2];++k)
        {
        vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements,
                                                    subExtent[0],
                                                    subExtent[2],
                                                    subExtent[4]+k);
        vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements,
                                                  subExtent[0],
                                                  subExtent[2],
                                                  subExtent[4]+k);
        memcpy(outArray->GetVoidPointer(destTuple*components),
               inArray->GetVoidPointer(sourceTuple*components),
               sliceTuples*tupleSize);
        }
      }
    }
  else
    {
    // Copy a row at a time.
    vtkIdType rowTuples = subDimensions[0];
    int j,k;
    for(k=0;k < subDimensions[2];++k)
      {
      for(j=0;j < subDimensions[1];++j)
        {
        vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements,
                                                    subExtent[0],
                                                    subExtent[2]+j,
                                                    subExtent[4]+k);
        vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements,
                                                  subExtent[0],
                                                  subExtent[2]+j,
                                                  subExtent[4]+k);
        memcpy(outArray->GetVoidPointer(destTuple*components),
               inArray->GetVoidPointer(sourceTuple*components),
               rowTuples*tupleSize);
        }
      }
    }
}

//----------------------------------------------------------------------------
int vtkXMLPStructuredDataReader::ComputePieceSubExtents()
{
  // Reset the extent splitter.
  this->ExtentSplitter->RemoveAllExtentSources();

  // Add each readable piece as an extent source.
  int i;
  for(i=0;i < this->NumberOfPieces;++i)
    {
    //if(this->CanReadPiece(i))
      {
      // Add the exact extent provided by the piece to the splitter.
      // BUG: This was causing all processes to read the meta-data for all
      // pieces which is a nightmare!!! Using the this->PieceExtents information
      // which we had already collected while reading the pvti file for
      // determining the piece extents.
      // int extent[6];
      //this->PieceReaders[i]->UpdateInformation();
      //this->PieceReaders[i]->GetOutputAsDataSet()->GetWholeExtent(extent);
      int *extent = this->PieceExtents + 6*i;
      this->ExtentSplitter->AddExtentSource(i, 0, extent);
      }
    }

  // We want to split the entire update extent across the pieces.
  this->ExtentSplitter->AddExtent(this->UpdateExtent);

  // Compute the sub-extents.
  if(!this->ExtentSplitter->ComputeSubExtents())
    {
    // A portion of the extent is not available.
    vtksys_ios::ostringstream e_with_warning_C4701;
    e_with_warning_C4701
      << "No available piece provides data for the following extents:\n";
    for(i=0; i < this->ExtentSplitter->GetNumberOfSubExtents(); ++i)
      {
      if(this->ExtentSplitter->GetSubExtentSource(i) < 0)
        {
        int extent[6];
        this->ExtentSplitter->GetSubExtent(i, extent);
        e_with_warning_C4701
          << "    "
          << extent[0] << " " << extent[1] << "  "
          << extent[2] << " " << extent[3] << "  "
          << extent[4] << " " << extent[5] << "\n";
        }
      }
    e_with_warning_C4701 << "The UpdateExtent cannot be filled.";
    vtkErrorMacro(<< e_with_warning_C4701.str().c_str());
    return 0;
    }

  return 1;
}

<|endoftext|>