You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2016/10/13 15:07:19 UTC

[01/18] nifi-minifi-cpp git commit: MINIFI-34 - Adjust CMake files to complete under Travis CI CMake utilize system libuuid instead of third party Add missing include directories Add dummy.cpp

Repository: nifi-minifi-cpp
Updated Branches:
  refs/heads/master 8beb3772d -> 6f8269606


MINIFI-34 - Adjust CMake files to complete under Travis CI
	CMake utilize system libuuid instead of third party
	Add missing include directories
	Add dummy.cpp

Move commit ExecuteProcess to the CMake based file structure

This closes #14 and closes #18.

Signed-off-by: Aldrin Piri <al...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/commit/6f826960
Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/6f826960
Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/6f826960

Branch: refs/heads/master
Commit: 6f8269606de9a12cd0f50be4204545702f276f5d
Parents: b02af54
Author: Andre F de Miranda <tr...@users.noreply.github.com>
Authored: Fri Oct 7 15:40:20 2016 +1100
Committer: Aldrin Piri <al...@apache.org>
Committed: Thu Oct 13 11:06:55 2016 -0400

----------------------------------------------------------------------
 .travis.yml                        |   7 +-
 CMakeLists.txt                     |  26 +++-
 inc/ExecuteProcess.h               | 112 ---------------
 include/spdlog/dummy.cpp           |  22 +++
 libminifi/CMakeLists.txt           |  23 +--
 libminifi/include/ExecuteProcess.h | 112 +++++++++++++++
 libminifi/src/ExecuteProcess.cpp   | 244 ++++++++++++++++++++++++++++++++
 main/CMakeLists.txt                |  10 +-
 src/ExecuteProcess.cpp             | 244 --------------------------------
 9 files changed, 425 insertions(+), 375 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index eb2baa5..3866739 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,8 @@
 # limitations under the License.
 sudo: required
 
+dist: trusty
+
 language: cpp
 
 script:
@@ -26,9 +28,10 @@ addons:
   apt:
     sources:
     - ubuntu-toolchain-r-test
-    - boost-latest
+#    - boost-latest
     packages:
     - gcc-4.8
     - g++-4.8
-    - libboost1.55-all-dev
+    - libboost-all-dev
+    - uuid-dev
     - libxml2-dev

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1cc95c2..082e994 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,20 +19,36 @@
 
 cmake_minimum_required(VERSION 2.6)
 
-set(PROJECT "nifi-minifi-cpp")
-set(VERSION "0.1.0")
+project(nifi-minifi-cpp)
+set(PROJECT_NAME "nifi-minifi-cpp")
+set(PROJECT_VERSION_MAJOR 0)
+set(PROJECT_VERSION_MINOR 1)
+set(PROJECT_VERSION_PATCH 0)
 
 #### Establish Project Configuration ####
 # Enable usage of the VERSION specifier
 # https://cmake.org/cmake/help/v3.0/policy/CMP0048.html#policy:CMP0048
-cmake_policy(SET CMP0048 NEW)
+IF(POLICY CMP0048)
+  CMAKE_POLICY(SET CMP0048 OLD)
+ENDIF(POLICY CMP0048)
 
-project(${PROJECT}
-        VERSION ${VERSION})
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
+if(COMPILER_SUPPORTS_CXX11)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+elseif(COMPILER_SUPPORTS_CXX0X)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+else()
+        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
+endif()
 
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
+# Search for threads
+find_package(Threads REQUIRED)
+
 # Provide custom modules for the project
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
 

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/inc/ExecuteProcess.h
----------------------------------------------------------------------
diff --git a/inc/ExecuteProcess.h b/inc/ExecuteProcess.h
deleted file mode 100644
index dce287a..0000000
--- a/inc/ExecuteProcess.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * @file ExecuteProcess.h
- * ExecuteProcess class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __EXECUTE_PROCESS_H__
-#define __EXECUTE_PROCESS_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string>
-#include <errno.h>
-#include <chrono>
-#include <thread>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <iostream>
-#include <sys/types.h>
-#include <signal.h>
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! ExecuteProcess Class
-class ExecuteProcess : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	ExecuteProcess(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-		_redirectErrorStream = false;
-		_batchDuration = 0;
-		_workingDir = ".";
-		_processRunning = false;
-		_pid = 0;
-	}
-	//! Destructor
-	virtual ~ExecuteProcess()
-	{
-		if (_processRunning && _pid > 0)
-			kill(_pid, SIGTERM);
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property Command;
-	static Property CommandArguments;
-	static Property WorkingDir;
-	static Property BatchDuration;
-	static Property RedirectErrorStream;
-	//! Supported Relationships
-	static Relationship Success;
-
-	//! Nest Callback Class for write stream
-	class WriteCallback : public OutputStreamCallback
-	{
-		public:
-		WriteCallback(char *data, uint64_t size)
-		: _data(data), _dataSize(size) {}
-		char *_data;
-		uint64_t _dataSize;
-		void process(std::ofstream *stream) {
-			if (_data && _dataSize > 0)
-				stream->write(_data, _dataSize);
-		}
-	};
-
-public:
-	//! OnTrigger method, implemented by NiFi ExecuteProcess
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi ExecuteProcess
-	virtual void initialize(void);
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-	//! Property
-	std::string _command;
-	std::string _commandArgument;
-	std::string _workingDir;
-	int64_t _batchDuration;
-	bool _redirectErrorStream;
-	//! Full command
-	std::string _fullCommand;
-	//! whether the process is running
-	bool _processRunning;
-	int _pipefd[2];
-	pid_t _pid;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/include/spdlog/dummy.cpp
----------------------------------------------------------------------
diff --git a/include/spdlog/dummy.cpp b/include/spdlog/dummy.cpp
new file mode 100644
index 0000000..6b2d4ab
--- /dev/null
+++ b/include/spdlog/dummy.cpp
@@ -0,0 +1,22 @@
+/**
+ * @file dummy.cpp 
+ * MiNiFiMain implementation 
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Dummy CPP file to work around Cmake limitation on header only libraries
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/libminifi/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt
index 571b73d..2d6b84b 100644
--- a/libminifi/CMakeLists.txt
+++ b/libminifi/CMakeLists.txt
@@ -19,26 +19,33 @@
 
 cmake_minimum_required (VERSION 2.6)
 
-set(PROJECT "apache-nifi-minifi-cpp")
-set(VERSION "0.1.0")
+project(nifi-libminifi)
+set(PROJECT_NAME "nifi-libminifi")
+set(PROJECT_VERSION_MAJOR 0)
+set(PROJECT_VERSION_MINOR 1)
+set(PROJECT_VERSION_PATCH 0)
+
 
 #### Establish Project Configuration ####
 # Enable usage of the VERSION specifier
 # https://cmake.org/cmake/help/v3.0/policy/CMP0048.html#policy:CMP0048
-cmake_policy(SET CMP0048 NEW)
-
-project(${PROJECT}
-        VERSION ${VERSION})
+IF(POLICY CMP0048)
+  CMAKE_POLICY(SET CMP0048 OLD)
+ENDIF(POLICY CMP0048)
 
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 include_directories(../include)
+include_directories(../thirdparty/yaml-cpp-yaml-cpp-0.5.3/include)
 include_directories(include)
 
 file(GLOB SOURCES "src/*.cpp")
+file(GLOB SPD_SOURCES "../include/spdlog/*")
 
-add_library(spdlog INTERFACE)
+# Workaround the limitations of having a
+# header only library
+add_library(spdlog STATIC ${SPD_SOURCES})
 add_library(minifi STATIC ${SOURCES})
 
 # Include libxml2
@@ -48,4 +55,4 @@ if (LIBXML2_FOUND)
     target_link_libraries (minifi ${LIBXML2_LIBRARIES})
 else ()
     # Build from our local version
-endif (LIBXML2_FOUND)
\ No newline at end of file
+endif (LIBXML2_FOUND)

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/libminifi/include/ExecuteProcess.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ExecuteProcess.h b/libminifi/include/ExecuteProcess.h
new file mode 100644
index 0000000..dce287a
--- /dev/null
+++ b/libminifi/include/ExecuteProcess.h
@@ -0,0 +1,112 @@
+/**
+ * @file ExecuteProcess.h
+ * ExecuteProcess class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __EXECUTE_PROCESS_H__
+#define __EXECUTE_PROCESS_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string>
+#include <errno.h>
+#include <chrono>
+#include <thread>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <sys/types.h>
+#include <signal.h>
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! ExecuteProcess Class
+class ExecuteProcess : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	ExecuteProcess(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+		_redirectErrorStream = false;
+		_batchDuration = 0;
+		_workingDir = ".";
+		_processRunning = false;
+		_pid = 0;
+	}
+	//! Destructor
+	virtual ~ExecuteProcess()
+	{
+		if (_processRunning && _pid > 0)
+			kill(_pid, SIGTERM);
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property Command;
+	static Property CommandArguments;
+	static Property WorkingDir;
+	static Property BatchDuration;
+	static Property RedirectErrorStream;
+	//! Supported Relationships
+	static Relationship Success;
+
+	//! Nest Callback Class for write stream
+	class WriteCallback : public OutputStreamCallback
+	{
+		public:
+		WriteCallback(char *data, uint64_t size)
+		: _data(data), _dataSize(size) {}
+		char *_data;
+		uint64_t _dataSize;
+		void process(std::ofstream *stream) {
+			if (_data && _dataSize > 0)
+				stream->write(_data, _dataSize);
+		}
+	};
+
+public:
+	//! OnTrigger method, implemented by NiFi ExecuteProcess
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi ExecuteProcess
+	virtual void initialize(void);
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+	//! Property
+	std::string _command;
+	std::string _commandArgument;
+	std::string _workingDir;
+	int64_t _batchDuration;
+	bool _redirectErrorStream;
+	//! Full command
+	std::string _fullCommand;
+	//! whether the process is running
+	bool _processRunning;
+	int _pipefd[2];
+	pid_t _pid;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/libminifi/src/ExecuteProcess.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/ExecuteProcess.cpp b/libminifi/src/ExecuteProcess.cpp
new file mode 100644
index 0000000..16d9457
--- /dev/null
+++ b/libminifi/src/ExecuteProcess.cpp
@@ -0,0 +1,244 @@
+/**
+ * @file ExecuteProcess.cpp
+ * ExecuteProcess class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TimeUtil.h"
+#include "ExecuteProcess.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+#include <cstring>
+
+const std::string ExecuteProcess::ProcessorName("ExecuteProcess");
+Property ExecuteProcess::Command("Command", "Specifies the command to be executed; if just the name of an executable is provided, it must be in the user's environment PATH.", "");
+Property ExecuteProcess::CommandArguments("Command Arguments",
+		"The arguments to supply to the executable delimited by white space. White space can be escaped by enclosing it in double-quotes.", "");
+Property ExecuteProcess::WorkingDir("Working Directory",
+		"The directory to use as the current working directory when executing the command", "");
+Property ExecuteProcess::BatchDuration("Batch Duration",
+		"If the process is expected to be long-running and produce textual output, a batch duration can be specified.", "0");
+Property ExecuteProcess::RedirectErrorStream("Redirect Error Stream",
+		"If true will redirect any error stream output of the process to the output stream.", "false");
+Relationship ExecuteProcess::Success("success", "All created FlowFiles are routed to this relationship.");
+
+void ExecuteProcess::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(Command);
+	properties.insert(CommandArguments);
+	properties.insert(WorkingDir);
+	properties.insert(BatchDuration);
+	properties.insert(RedirectErrorStream);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+}
+
+
+void ExecuteProcess::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string value;
+	if (context->getProperty(Command.getName(), value))
+	{
+		this->_command = value;
+	}
+	if (context->getProperty(CommandArguments.getName(), value))
+	{
+		this->_commandArgument = value;
+	}
+	if (context->getProperty(WorkingDir.getName(), value))
+	{
+		this->_workingDir = value;
+	}
+	if (context->getProperty(BatchDuration.getName(), value))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(value, _batchDuration, unit) &&
+			Property::ConvertTimeUnitToMS(_batchDuration, unit, _batchDuration))
+		{
+
+		}
+	}
+	if (context->getProperty(RedirectErrorStream.getName(), value))
+	{
+		Property::StringToBool(value, _redirectErrorStream);
+	}
+	this->_fullCommand = _command + " " + _commandArgument;
+	if (_fullCommand.length() == 0)
+	{
+		yield();
+		return;
+	}
+	if (_workingDir.length() > 0 && _workingDir != ".")
+	{
+		// change to working directory
+		if (chdir(_workingDir.c_str()) != 0)
+		{
+			_logger->log_error("Execute Command can not chdir %s", _workingDir.c_str());
+			yield();
+			return;
+		}
+	}
+	_logger->log_info("Execute Command %s", _fullCommand.c_str());
+	// split the command into array
+	char cstr[_fullCommand.length()+1];
+	std::strcpy(cstr, _fullCommand.c_str());
+	char *p = std::strtok (cstr, " ");
+	int argc = 0;
+	char *argv[64];
+	while (p != 0 && argc < 64)
+	{
+		argv[argc] = p;
+		p = std::strtok(NULL, " ");
+		argc++;
+	}
+	argv[argc] = NULL;
+	int status, died;
+	if (!_processRunning)
+	{
+		_processRunning = true;
+		// if the process has not launched yet
+		// create the pipe
+		if (pipe(_pipefd) == -1)
+		{
+			_processRunning = false;
+			yield();
+			return;
+		}
+		switch (_pid = fork())
+		{
+		case -1:
+			_logger->log_error("Execute Process fork failed");
+			_processRunning = false;
+			close(_pipefd[0]);
+			close(_pipefd[1]);
+			yield();
+			break;
+		case 0 : // this is the code the child runs
+			close(1);      // close stdout
+			dup(_pipefd[1]); // points pipefd at file descriptor
+			if (_redirectErrorStream)
+				// redirect stderr
+				dup2(_pipefd[1], 2);
+			close(_pipefd[0]);
+			execvp(argv[0], argv);
+			exit(1);
+			break;
+		default: // this is the code the parent runs
+			// the parent isn't going to write to the pipe
+			close(_pipefd[1]);
+			if (_batchDuration > 0)
+			{
+				while (1)
+				{
+					std::this_thread::sleep_for(std::chrono::milliseconds(_batchDuration));
+					char buffer[4096];
+					int numRead = read(_pipefd[0], buffer, sizeof(buffer));
+					if (numRead <= 0)
+						break;
+					_logger->log_info("Execute Command Respond %d", numRead);
+					ExecuteProcess::WriteCallback callback(buffer, numRead);
+					FlowFileRecord *flowFile = session->create();
+					if (!flowFile)
+						continue;
+					session->write(flowFile, &callback);
+					session->transfer(flowFile, Success);
+					session->commit();
+				}
+			}
+			else
+			{
+				char buffer[4096];
+				char *bufPtr = buffer;
+				int totalRead = 0;
+				FlowFileRecord *flowFile = NULL;
+				while (1)
+				{
+					int numRead = read(_pipefd[0], bufPtr, (sizeof(buffer) - totalRead));
+					if (numRead <= 0)
+					{
+						if (totalRead > 0)
+						{
+							_logger->log_info("Execute Command Respond %d", totalRead);
+							// child exits and close the pipe
+							ExecuteProcess::WriteCallback callback(buffer, totalRead);
+							if (!flowFile)
+							{
+								flowFile = session->create();
+								if (!flowFile)
+									break;
+								session->write(flowFile, &callback);
+							}
+							else
+							{
+								session->append(flowFile, &callback);
+							}
+							session->transfer(flowFile, Success);
+						}
+						break;
+					}
+					else
+					{
+						if (numRead == (sizeof(buffer) - totalRead))
+						{
+							// we reach the max buffer size
+							_logger->log_info("Execute Command Max Respond %d", sizeof(buffer));
+							ExecuteProcess::WriteCallback callback(buffer, sizeof(buffer));
+							if (!flowFile)
+							{
+								flowFile = session->create();
+								if (!flowFile)
+									continue;
+								session->write(flowFile, &callback);
+							}
+							else
+							{
+								session->append(flowFile, &callback);
+							}
+							// Rewind
+							totalRead = 0;
+							bufPtr = buffer;
+						}
+						else
+						{
+							totalRead += numRead;
+							bufPtr += numRead;
+						}
+					}
+				}
+			}
+
+			died= wait(&status);
+			if (WIFEXITED(status))
+			{
+				_logger->log_info("Execute Command Complete %s status %d pid %d", _fullCommand.c_str(), WEXITSTATUS(status), _pid);
+			}
+			else
+			{
+				_logger->log_info("Execute Command Complete %s status %d pid %d", _fullCommand.c_str(), WTERMSIG(status), _pid);
+			}
+
+			close(_pipefd[0]);
+			_processRunning = false;
+			break;
+		}
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/main/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 2f470a5..e740955 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -19,9 +19,11 @@
 
 cmake_minimum_required(VERSION 2.6)
 
-cmake_policy(SET CMP0048 NEW)
+IF(POLICY CMP0048)
+  CMAKE_POLICY(SET CMP0048 OLD)
+ENDIF(POLICY CMP0048)
 
-include_directories(../include ../libminifi/include ../thirdparty/yaml-cpp-yaml-cpp-0.5.3/include)
+include_directories(../include ../libminifi/include ../thirdparty/yaml-cpp-yaml-cpp-0.5.3/include ../thirdparty)
 
 # Include libxml2
 find_package(LibXml2)
@@ -33,8 +35,8 @@ endif (LIBXML2_FOUND)
 
 add_executable(minifiexe MiNiFiMain.cpp)
 
-# Link against minifi and yaml-cpp
-target_link_libraries(minifiexe minifi yaml-cpp)
+# Link against minifi, yaml-cpp and uuid
+target_link_libraries(minifiexe minifi yaml-cpp uuid)
 set_target_properties(minifiexe
         PROPERTIES OUTPUT_NAME minifi)
 

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/6f826960/src/ExecuteProcess.cpp
----------------------------------------------------------------------
diff --git a/src/ExecuteProcess.cpp b/src/ExecuteProcess.cpp
deleted file mode 100644
index 16d9457..0000000
--- a/src/ExecuteProcess.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * @file ExecuteProcess.cpp
- * ExecuteProcess class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "TimeUtil.h"
-#include "ExecuteProcess.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-#include <cstring>
-
-const std::string ExecuteProcess::ProcessorName("ExecuteProcess");
-Property ExecuteProcess::Command("Command", "Specifies the command to be executed; if just the name of an executable is provided, it must be in the user's environment PATH.", "");
-Property ExecuteProcess::CommandArguments("Command Arguments",
-		"The arguments to supply to the executable delimited by white space. White space can be escaped by enclosing it in double-quotes.", "");
-Property ExecuteProcess::WorkingDir("Working Directory",
-		"The directory to use as the current working directory when executing the command", "");
-Property ExecuteProcess::BatchDuration("Batch Duration",
-		"If the process is expected to be long-running and produce textual output, a batch duration can be specified.", "0");
-Property ExecuteProcess::RedirectErrorStream("Redirect Error Stream",
-		"If true will redirect any error stream output of the process to the output stream.", "false");
-Relationship ExecuteProcess::Success("success", "All created FlowFiles are routed to this relationship.");
-
-void ExecuteProcess::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(Command);
-	properties.insert(CommandArguments);
-	properties.insert(WorkingDir);
-	properties.insert(BatchDuration);
-	properties.insert(RedirectErrorStream);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-}
-
-
-void ExecuteProcess::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string value;
-	if (context->getProperty(Command.getName(), value))
-	{
-		this->_command = value;
-	}
-	if (context->getProperty(CommandArguments.getName(), value))
-	{
-		this->_commandArgument = value;
-	}
-	if (context->getProperty(WorkingDir.getName(), value))
-	{
-		this->_workingDir = value;
-	}
-	if (context->getProperty(BatchDuration.getName(), value))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(value, _batchDuration, unit) &&
-			Property::ConvertTimeUnitToMS(_batchDuration, unit, _batchDuration))
-		{
-
-		}
-	}
-	if (context->getProperty(RedirectErrorStream.getName(), value))
-	{
-		Property::StringToBool(value, _redirectErrorStream);
-	}
-	this->_fullCommand = _command + " " + _commandArgument;
-	if (_fullCommand.length() == 0)
-	{
-		yield();
-		return;
-	}
-	if (_workingDir.length() > 0 && _workingDir != ".")
-	{
-		// change to working directory
-		if (chdir(_workingDir.c_str()) != 0)
-		{
-			_logger->log_error("Execute Command can not chdir %s", _workingDir.c_str());
-			yield();
-			return;
-		}
-	}
-	_logger->log_info("Execute Command %s", _fullCommand.c_str());
-	// split the command into array
-	char cstr[_fullCommand.length()+1];
-	std::strcpy(cstr, _fullCommand.c_str());
-	char *p = std::strtok (cstr, " ");
-	int argc = 0;
-	char *argv[64];
-	while (p != 0 && argc < 64)
-	{
-		argv[argc] = p;
-		p = std::strtok(NULL, " ");
-		argc++;
-	}
-	argv[argc] = NULL;
-	int status, died;
-	if (!_processRunning)
-	{
-		_processRunning = true;
-		// if the process has not launched yet
-		// create the pipe
-		if (pipe(_pipefd) == -1)
-		{
-			_processRunning = false;
-			yield();
-			return;
-		}
-		switch (_pid = fork())
-		{
-		case -1:
-			_logger->log_error("Execute Process fork failed");
-			_processRunning = false;
-			close(_pipefd[0]);
-			close(_pipefd[1]);
-			yield();
-			break;
-		case 0 : // this is the code the child runs
-			close(1);      // close stdout
-			dup(_pipefd[1]); // points pipefd at file descriptor
-			if (_redirectErrorStream)
-				// redirect stderr
-				dup2(_pipefd[1], 2);
-			close(_pipefd[0]);
-			execvp(argv[0], argv);
-			exit(1);
-			break;
-		default: // this is the code the parent runs
-			// the parent isn't going to write to the pipe
-			close(_pipefd[1]);
-			if (_batchDuration > 0)
-			{
-				while (1)
-				{
-					std::this_thread::sleep_for(std::chrono::milliseconds(_batchDuration));
-					char buffer[4096];
-					int numRead = read(_pipefd[0], buffer, sizeof(buffer));
-					if (numRead <= 0)
-						break;
-					_logger->log_info("Execute Command Respond %d", numRead);
-					ExecuteProcess::WriteCallback callback(buffer, numRead);
-					FlowFileRecord *flowFile = session->create();
-					if (!flowFile)
-						continue;
-					session->write(flowFile, &callback);
-					session->transfer(flowFile, Success);
-					session->commit();
-				}
-			}
-			else
-			{
-				char buffer[4096];
-				char *bufPtr = buffer;
-				int totalRead = 0;
-				FlowFileRecord *flowFile = NULL;
-				while (1)
-				{
-					int numRead = read(_pipefd[0], bufPtr, (sizeof(buffer) - totalRead));
-					if (numRead <= 0)
-					{
-						if (totalRead > 0)
-						{
-							_logger->log_info("Execute Command Respond %d", totalRead);
-							// child exits and close the pipe
-							ExecuteProcess::WriteCallback callback(buffer, totalRead);
-							if (!flowFile)
-							{
-								flowFile = session->create();
-								if (!flowFile)
-									break;
-								session->write(flowFile, &callback);
-							}
-							else
-							{
-								session->append(flowFile, &callback);
-							}
-							session->transfer(flowFile, Success);
-						}
-						break;
-					}
-					else
-					{
-						if (numRead == (sizeof(buffer) - totalRead))
-						{
-							// we reach the max buffer size
-							_logger->log_info("Execute Command Max Respond %d", sizeof(buffer));
-							ExecuteProcess::WriteCallback callback(buffer, sizeof(buffer));
-							if (!flowFile)
-							{
-								flowFile = session->create();
-								if (!flowFile)
-									continue;
-								session->write(flowFile, &callback);
-							}
-							else
-							{
-								session->append(flowFile, &callback);
-							}
-							// Rewind
-							totalRead = 0;
-							bufPtr = buffer;
-						}
-						else
-						{
-							totalRead += numRead;
-							bufPtr += numRead;
-						}
-					}
-				}
-			}
-
-			died= wait(&status);
-			if (WIFEXITED(status))
-			{
-				_logger->log_info("Execute Command Complete %s status %d pid %d", _fullCommand.c_str(), WEXITSTATUS(status), _pid);
-			}
-			else
-			{
-				_logger->log_info("Execute Command Complete %s status %d pid %d", _fullCommand.c_str(), WTERMSIG(status), _pid);
-			}
-
-			close(_pipefd[0]);
-			_processRunning = false;
-			break;
-		}
-	}
-}
-


[12/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/format.cc
----------------------------------------------------------------------
diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc
new file mode 100644
index 0000000..fb0ef9e
--- /dev/null
+++ b/include/spdlog/details/format.cc
@@ -0,0 +1,1353 @@
+/*
+Formatting library for C++
+
+Copyright (c) 2012 - 2015, Victor Zverovich
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. 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.
+
+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 "format.h"
+
+#include <string.h>
+
+#include <cctype>
+#include <cerrno>
+#include <climits>
+#include <cmath>
+#include <cstdarg>
+
+#if defined(_WIN32) && defined(__MINGW32__)
+# include <cstring>
+#endif
+
+#if FMT_USE_WINDOWS_H
+# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
+#  include <windows.h>
+# else
+#  define NOMINMAX
+#  include <windows.h>
+#  undef NOMINMAX
+# endif
+#endif
+
+using fmt::internal::Arg;
+
+// Check if exceptions are disabled.
+#if __GNUC__ && !__EXCEPTIONS
+# define FMT_EXCEPTIONS 0
+#endif
+#if _MSC_VER && !_HAS_EXCEPTIONS
+# define FMT_EXCEPTIONS 0
+#endif
+#ifndef FMT_EXCEPTIONS
+# define FMT_EXCEPTIONS 1
+#endif
+
+#if FMT_EXCEPTIONS
+# define FMT_TRY try
+# define FMT_CATCH(x) catch (x)
+#else
+# define FMT_TRY if (true)
+# define FMT_CATCH(x) if (false)
+#endif
+
+#ifndef FMT_THROW
+# if FMT_EXCEPTIONS
+#  define FMT_THROW(x) throw x
+# else
+#  define FMT_THROW(x) assert(false)
+# endif
+#endif
+
+#ifdef FMT_HEADER_ONLY
+# define FMT_FUNC inline
+#else
+# define FMT_FUNC
+#endif
+
+#if _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4127)  // conditional expression is constant
+# pragma warning(disable: 4702)  // unreachable code
+// Disable deprecation warning for strerror. The latter is not called but
+// MSVC fails to detect it.
+# pragma warning(disable: 4996)
+#endif
+
+// Dummy implementations of strerror_r and strerror_s called if corresponding
+// system functions are not available.
+static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
+    return fmt::internal::Null<>();
+}
+static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
+    return fmt::internal::Null<>();
+}
+
+namespace fmt {
+namespace {
+
+#ifndef _MSC_VER
+# define FMT_SNPRINTF snprintf
+#else  // _MSC_VER
+inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
+    va_list args;
+    va_start(args, format);
+    int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
+    va_end(args);
+    return result;
+}
+# define FMT_SNPRINTF fmt_snprintf
+#endif  // _MSC_VER
+
+#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
+# define FMT_SWPRINTF snwprintf
+#else
+# define FMT_SWPRINTF swprintf
+#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
+
+// Checks if a value fits in int - used to avoid warnings about comparing
+// signed and unsigned integers.
+template <bool IsSigned>
+struct IntChecker {
+    template <typename T>
+    static bool fits_in_int(T value) {
+        unsigned max = INT_MAX;
+        return value <= max;
+    }
+    static bool fits_in_int(bool) {
+        return true;
+    }
+};
+
+template <>
+struct IntChecker<true> {
+    template <typename T>
+    static bool fits_in_int(T value) {
+        return value >= INT_MIN && value <= INT_MAX;
+    }
+};
+
+const char RESET_COLOR[] = "\x1b[0m";
+
+typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
+
+// Portable thread-safe version of strerror.
+// Sets buffer to point to a string describing the error code.
+// This can be either a pointer to a string stored in buffer,
+// or a pointer to some static immutable string.
+// Returns one of the following values:
+//   0      - success
+//   ERANGE - buffer is not large enough to store the error message
+//   other  - failure
+// Buffer should be at least of size 1.
+int safe_strerror(
+    int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
+    FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
+
+    class StrError {
+    private:
+        int error_code_;
+        char *&buffer_;
+        std::size_t buffer_size_;
+
+        // A noop assignment operator to avoid bogus warnings.
+        void operator=(const StrError &) {}
+
+        // Handle the result of XSI-compliant version of strerror_r.
+        int handle(int result) {
+            // glibc versions before 2.13 return result in errno.
+            return result == -1 ? errno : result;
+        }
+
+        // Handle the result of GNU-specific version of strerror_r.
+        int handle(char *message) {
+            // If the buffer is full then the message is probably truncated.
+            if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
+                return ERANGE;
+            buffer_ = message;
+            return 0;
+        }
+
+        // Handle the case when strerror_r is not available.
+        int handle(fmt::internal::Null<>) {
+            return fallback(strerror_s(buffer_, buffer_size_, error_code_));
+        }
+
+        // Fallback to strerror_s when strerror_r is not available.
+        int fallback(int result) {
+            // If the buffer is full then the message is probably truncated.
+            return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
+            ERANGE : result;
+        }
+
+        // Fallback to strerror if strerror_r and strerror_s are not available.
+        int fallback(fmt::internal::Null<>) {
+            errno = 0;
+            buffer_ = strerror(error_code_);
+            return errno;
+        }
+
+    public:
+        StrError(int error_code, char *&buffer, std::size_t buffer_size)
+            : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
+
+        int run() {
+            strerror_r(0, 0, "");  // Suppress a warning about unused strerror_r.
+            return handle(strerror_r(error_code_, buffer_, buffer_size_));
+        }
+    };
+    return StrError(error_code, buffer, buffer_size).run();
+}
+
+void format_error_code(fmt::Writer &out, int error_code,
+                       fmt::StringRef message) FMT_NOEXCEPT{
+    // Report error code making sure that the output fits into
+    // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
+    // bad_alloc.
+    out.clear();
+    static const char SEP[] = ": ";
+    static const char ERROR_STR[] = "error ";
+    fmt::internal::IntTraits<int>::MainType ec_value = error_code;
+    // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
+    std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
+    error_code_size += fmt::internal::count_digits(ec_value);
+    if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
+        out << message << SEP;
+    out << ERROR_STR << error_code;
+    assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
+}
+
+void report_error(FormatFunc func,
+                  int error_code, fmt::StringRef message) FMT_NOEXCEPT{
+    fmt::MemoryWriter full_message;
+    func(full_message, error_code, message);
+    // Use Writer::data instead of Writer::c_str to avoid potential memory
+    // allocation.
+    std::fwrite(full_message.data(), full_message.size(), 1, stderr);
+    std::fputc('\n', stderr);
+}
+
+// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
+class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
+public:
+    template <typename T>
+    bool visit_any_int(T value) {
+        return value == 0;
+    }
+};
+
+// Parses an unsigned integer advancing s to the end of the parsed input.
+// This function assumes that the first character of s is a digit.
+template <typename Char>
+int parse_nonnegative_int(const Char *&s) {
+    assert('0' <= *s && *s <= '9');
+    unsigned value = 0;
+    do {
+        unsigned new_value = value * 10 + (*s++ - '0');
+        // Check if value wrapped around.
+        if (new_value < value) {
+            value = UINT_MAX;
+            break;
+        }
+        value = new_value;
+    } while ('0' <= *s && *s <= '9');
+    if (value > INT_MAX)
+        FMT_THROW(fmt::FormatError("number is too big"));
+    return value;
+}
+
+template <typename Char>
+inline bool is_name_start(Char c) {
+    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
+}
+
+inline void require_numeric_argument(const Arg &arg, char spec) {
+    if (arg.type > Arg::LAST_NUMERIC_TYPE) {
+        std::string message =
+            fmt::format("format specifier '{}' requires numeric argument", spec);
+        FMT_THROW(fmt::FormatError(message));
+    }
+}
+
+template <typename Char>
+void check_sign(const Char *&s, const Arg &arg) {
+    char sign = static_cast<char>(*s);
+    require_numeric_argument(arg, sign);
+    if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
+        FMT_THROW(fmt::FormatError(fmt::format(
+                                       "format specifier '{}' requires signed argument", sign)));
+    }
+    ++s;
+}
+
+// Checks if an argument is a valid printf width specifier and sets
+// left alignment if it is negative.
+class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
+private:
+    fmt::FormatSpec &spec_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
+
+public:
+    explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
+
+    void report_unhandled_arg() {
+        FMT_THROW(fmt::FormatError("width is not integer"));
+    }
+
+    template <typename T>
+    unsigned visit_any_int(T value) {
+        typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
+        UnsignedType width = value;
+        if (fmt::internal::is_negative(value)) {
+            spec_.align_ = fmt::ALIGN_LEFT;
+            width = 0 - width;
+        }
+        if (width > INT_MAX)
+            FMT_THROW(fmt::FormatError("number is too big"));
+        return static_cast<unsigned>(width);
+    }
+};
+
+class PrecisionHandler :
+    public fmt::internal::ArgVisitor<PrecisionHandler, int> {
+public:
+    void report_unhandled_arg() {
+        FMT_THROW(fmt::FormatError("precision is not integer"));
+    }
+
+    template <typename T>
+    int visit_any_int(T value) {
+        if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
+            FMT_THROW(fmt::FormatError("number is too big"));
+        return static_cast<int>(value);
+    }
+};
+
+// Converts an integer argument to an integral type T for printf.
+template <typename T>
+class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
+private:
+    fmt::internal::Arg &arg_;
+    wchar_t type_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
+
+public:
+    ArgConverter(fmt::internal::Arg &arg, wchar_t type)
+        : arg_(arg), type_(type) {}
+
+    template <typename U>
+    void visit_any_int(U value) {
+        bool is_signed = type_ == 'd' || type_ == 'i';
+        using fmt::internal::Arg;
+        if (sizeof(T) <= sizeof(int)) {
+            // Extra casts are used to silence warnings.
+            if (is_signed) {
+                arg_.type = Arg::INT;
+                arg_.int_value = static_cast<int>(static_cast<T>(value));
+            }
+            else {
+                arg_.type = Arg::UINT;
+                arg_.uint_value = static_cast<unsigned>(
+                                      static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
+            }
+        }
+        else {
+            if (is_signed) {
+                arg_.type = Arg::LONG_LONG;
+                arg_.long_long_value =
+                    static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
+            }
+            else {
+                arg_.type = Arg::ULONG_LONG;
+                arg_.ulong_long_value =
+                    static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
+            }
+        }
+    }
+};
+
+// Converts an integer argument to char for printf.
+class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
+private:
+    fmt::internal::Arg &arg_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
+
+public:
+    explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
+
+    template <typename T>
+    void visit_any_int(T value) {
+        arg_.type = Arg::CHAR;
+        arg_.int_value = static_cast<char>(value);
+    }
+};
+}  // namespace
+
+namespace internal {
+
+template <typename Impl, typename Char>
+class BasicArgFormatter : public ArgVisitor<Impl, void> {
+private:
+    BasicWriter<Char> &writer_;
+    FormatSpec &spec_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
+
+protected:
+    BasicWriter<Char> &writer() {
+        return writer_;
+    }
+    const FormatSpec &spec() const {
+        return spec_;
+    }
+
+public:
+    BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
+        : writer_(w), spec_(s) {}
+
+    template <typename T>
+    void visit_any_int(T value) {
+        writer_.write_int(value, spec_);
+    }
+
+    template <typename T>
+    void visit_any_double(T value) {
+        writer_.write_double(value, spec_);
+    }
+
+    void visit_bool(bool value) {
+        if (spec_.type_) {
+            writer_.write_int(value, spec_);
+            return;
+        }
+        const char *str_value = value ? "true" : "false";
+        Arg::StringValue<char> str = { str_value, strlen(str_value) };
+        writer_.write_str(str, spec_);
+    }
+
+    void visit_char(int value) {
+        if (spec_.type_ && spec_.type_ != 'c') {
+            spec_.flags_ |= CHAR_FLAG;
+            writer_.write_int(value, spec_);
+            return;
+        }
+        if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
+            FMT_THROW(FormatError("invalid format specifier for char"));
+        typedef typename BasicWriter<Char>::CharPtr CharPtr;
+        Char fill = internal::CharTraits<Char>::cast(spec_.fill());
+        CharPtr out = CharPtr();
+        if (spec_.width_ > 1) {
+            out = writer_.grow_buffer(spec_.width_);
+            if (spec_.align_ == ALIGN_RIGHT) {
+                std::fill_n(out, spec_.width_ - 1, fill);
+                out += spec_.width_ - 1;
+            }
+            else if (spec_.align_ == ALIGN_CENTER) {
+                out = writer_.fill_padding(out, spec_.width_, 1, fill);
+            }
+            else {
+                std::fill_n(out + 1, spec_.width_ - 1, fill);
+            }
+        }
+        else {
+            out = writer_.grow_buffer(1);
+        }
+        *out = internal::CharTraits<Char>::cast(value);
+    }
+
+    void visit_string(Arg::StringValue<char> value) {
+        writer_.write_str(value, spec_);
+    }
+
+    using ArgVisitor<Impl, void>::visit_wstring;
+
+    void visit_wstring(Arg::StringValue<Char> value) {
+        writer_.write_str(value, spec_);
+    }
+
+    void visit_pointer(const void *value) {
+        if (spec_.type_ && spec_.type_ != 'p')
+            report_unknown_type(spec_.type_, "pointer");
+        spec_.flags_ = HASH_FLAG;
+        spec_.type_ = 'x';
+        writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
+    }
+};
+
+// An argument formatter.
+template <typename Char>
+class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
+private:
+    BasicFormatter<Char> &formatter_;
+    const Char *format_;
+
+public:
+    ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
+        : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
+          formatter_(f), format_(fmt) {}
+
+    void visit_custom(Arg::CustomValue c) {
+        c.format(&formatter_, c.value, &format_);
+    }
+};
+
+template <typename Char>
+class PrintfArgFormatter :
+    public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
+public:
+    PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
+        : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
+
+    void visit_char(int value) {
+        const FormatSpec &spec = this->spec();
+        BasicWriter<Char> &writer = this->writer();
+        if (spec.type_ && spec.type_ != 'c')
+            writer.write_int(value, spec);
+        typedef typename BasicWriter<Char>::CharPtr CharPtr;
+        CharPtr out = CharPtr();
+        if (spec.width_ > 1) {
+            Char fill = ' ';
+            out = writer.grow_buffer(spec.width_);
+            if (spec.align_ != ALIGN_LEFT) {
+                std::fill_n(out, spec.width_ - 1, fill);
+                out += spec.width_ - 1;
+            }
+            else {
+                std::fill_n(out + 1, spec.width_ - 1, fill);
+            }
+        }
+        else {
+            out = writer.grow_buffer(1);
+        }
+        *out = static_cast<Char>(value);
+    }
+};
+}  // namespace internal
+}  // namespace fmt
+
+FMT_FUNC void fmt::SystemError::init(
+    int err_code, CStringRef format_str, ArgList args) {
+    error_code_ = err_code;
+    MemoryWriter w;
+    internal::format_system_error(w, err_code, format(format_str, args));
+    std::runtime_error &base = *this;
+    base = std::runtime_error(w.str());
+}
+
+template <typename T>
+int fmt::internal::CharTraits<char>::format_float(
+    char *buffer, std::size_t size, const char *format,
+    unsigned width, int precision, T value) {
+    if (width == 0) {
+        return precision < 0 ?
+               FMT_SNPRINTF(buffer, size, format, value) :
+               FMT_SNPRINTF(buffer, size, format, precision, value);
+    }
+    return precision < 0 ?
+           FMT_SNPRINTF(buffer, size, format, width, value) :
+           FMT_SNPRINTF(buffer, size, format, width, precision, value);
+}
+
+template <typename T>
+int fmt::internal::CharTraits<wchar_t>::format_float(
+    wchar_t *buffer, std::size_t size, const wchar_t *format,
+    unsigned width, int precision, T value) {
+    if (width == 0) {
+        return precision < 0 ?
+               FMT_SWPRINTF(buffer, size, format, value) :
+               FMT_SWPRINTF(buffer, size, format, precision, value);
+    }
+    return precision < 0 ?
+           FMT_SWPRINTF(buffer, size, format, width, value) :
+           FMT_SWPRINTF(buffer, size, format, width, precision, value);
+}
+
+template <typename T>
+const char fmt::internal::BasicData<T>::DIGITS[] =
+    "0001020304050607080910111213141516171819"
+    "2021222324252627282930313233343536373839"
+    "4041424344454647484950515253545556575859"
+    "6061626364656667686970717273747576777879"
+    "8081828384858687888990919293949596979899";
+
+#define FMT_POWERS_OF_10(factor) \
+  factor * 10, \
+  factor * 100, \
+  factor * 1000, \
+  factor * 10000, \
+  factor * 100000, \
+  factor * 1000000, \
+  factor * 10000000, \
+  factor * 100000000, \
+  factor * 1000000000
+
+template <typename T>
+const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
+    0, FMT_POWERS_OF_10(1)
+};
+
+template <typename T>
+const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
+    0,
+    FMT_POWERS_OF_10(1),
+    FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
+    // Multiply several constants instead of using a single long long constant
+    // to avoid warnings about C++98 not supporting long long.
+    fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
+};
+
+FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
+    (void)type;
+    if (std::isprint(static_cast<unsigned char>(code))) {
+        FMT_THROW(fmt::FormatError(
+                      fmt::format("unknown format code '{}' for {}", code, type)));
+    }
+    FMT_THROW(fmt::FormatError(
+                  fmt::format("unknown format code '\\x{:02x}' for {}",
+                              static_cast<unsigned>(code), type)));
+}
+
+#if FMT_USE_WINDOWS_H
+
+FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
+    int length = MultiByteToWideChar(
+                     CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
+    static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
+    if (length == 0)
+        FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
+    buffer_.resize(length + 1);
+    length = MultiByteToWideChar(
+                 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
+    if (length == 0)
+        FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
+    buffer_[length] = 0;
+}
+
+FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
+    if (int error_code = convert(s)) {
+        FMT_THROW(WindowsError(error_code,
+                               "cannot convert string from UTF-16 to UTF-8"));
+    }
+}
+
+FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
+    int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
+    if (length == 0)
+        return GetLastError();
+    buffer_.resize(length + 1);
+    length = WideCharToMultiByte(
+                 CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
+    if (length == 0)
+        return GetLastError();
+    buffer_[length] = 0;
+    return 0;
+}
+
+FMT_FUNC void fmt::WindowsError::init(
+    int err_code, CStringRef format_str, ArgList args) {
+    error_code_ = err_code;
+    MemoryWriter w;
+    internal::format_windows_error(w, err_code, format(format_str, args));
+    std::runtime_error &base = *this;
+    base = std::runtime_error(w.str());
+}
+
+FMT_FUNC void fmt::internal::format_windows_error(
+    fmt::Writer &out, int error_code,
+    fmt::StringRef message) FMT_NOEXCEPT{
+    class String {
+    private:
+        LPWSTR str_;
+
+    public:
+        String() : str_() {}
+        ~String() {
+            LocalFree(str_);
+        }
+        LPWSTR *ptr() {
+            return &str_;
+        }
+        LPCWSTR c_str() const { return str_; }
+    };
+    FMT_TRY{
+        String system_message;
+        if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
+        error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
+            UTF16ToUTF8 utf8_message;
+            if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
+                out << message << ": " << utf8_message;
+                return;
+            }
+        }
+    } FMT_CATCH(...) {}
+    format_error_code(out, error_code, message);
+}
+
+#endif  // FMT_USE_WINDOWS_H
+
+FMT_FUNC void fmt::internal::format_system_error(
+    fmt::Writer &out, int error_code,
+    fmt::StringRef message) FMT_NOEXCEPT{
+    FMT_TRY{
+        MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
+        buffer.resize(INLINE_BUFFER_SIZE);
+        for (;;) {
+            char *system_message = &buffer[0];
+            int result = safe_strerror(error_code, system_message, buffer.size());
+            if (result == 0) {
+                out << message << ": " << system_message;
+                return;
+            }
+            if (result != ERANGE)
+                break;  // Can't get error message, report error code instead.
+            buffer.resize(buffer.size() * 2);
+        }
+    } FMT_CATCH(...) {}
+    format_error_code(out, error_code, message);
+}
+
+template <typename Char>
+void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
+    if (!map_.empty())
+        return;
+    typedef internal::NamedArg<Char> NamedArg;
+    const NamedArg *named_arg = 0;
+    bool use_values =
+        args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
+    if (use_values) {
+        for (unsigned i = 0;/*nothing*/; ++i) {
+            internal::Arg::Type arg_type = args.type(i);
+            switch (arg_type) {
+            case internal::Arg::NONE:
+                return;
+            case internal::Arg::NAMED_ARG:
+                named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
+                map_.insert(Pair(named_arg->name, *named_arg));
+                break;
+            default:
+                /*nothing*/
+                ;
+            }
+        }
+        return;
+    }
+    for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
+        internal::Arg::Type arg_type = args.type(i);
+        if (arg_type == internal::Arg::NAMED_ARG) {
+            named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
+            map_.insert(Pair(named_arg->name, *named_arg));
+        }
+    }
+    for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
+        switch (args.args_[i].type) {
+        case internal::Arg::NONE:
+            return;
+        case internal::Arg::NAMED_ARG:
+            named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
+            map_.insert(Pair(named_arg->name, *named_arg));
+            break;
+        default:
+            /*nothing*/
+            ;
+        }
+    }
+}
+
+template <typename Char>
+void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
+    FMT_THROW(std::runtime_error("buffer overflow"));
+}
+
+template <typename Char>
+template <typename StrChar>
+void fmt::BasicWriter<Char>::write_str(
+    const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
+    // Check if StrChar is convertible to Char.
+    internal::CharTraits<Char>::convert(StrChar());
+    if (spec.type_ && spec.type_ != 's')
+        internal::report_unknown_type(spec.type_, "string");
+    const StrChar *str_value = s.value;
+    std::size_t str_size = s.size;
+    if (str_size == 0) {
+        if (!str_value)
+            FMT_THROW(FormatError("string pointer is null"));
+        if (*str_value)
+            str_size = std::char_traits<StrChar>::length(str_value);
+    }
+    std::size_t precision = spec.precision_;
+    if (spec.precision_ >= 0 && precision < str_size)
+        str_size = spec.precision_;
+    write_str(str_value, str_size, spec);
+}
+
+template <typename Char>
+inline Arg fmt::BasicFormatter<Char>::get_arg(
+    BasicStringRef<Char> arg_name, const char *&error) {
+    if (check_no_auto_index(error)) {
+        map_.init(args());
+        const Arg *arg = map_.find(arg_name);
+        if (arg)
+            return *arg;
+        error = "argument not found";
+    }
+    return Arg();
+}
+
+template <typename Char>
+inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
+    const char *error = 0;
+    Arg arg = *s < '0' || *s > '9' ?
+              next_arg(error) : get_arg(parse_nonnegative_int(s), error);
+    if (error) {
+        FMT_THROW(FormatError(
+                      *s != '}' && *s != ':' ? "invalid format string" : error));
+    }
+    return arg;
+}
+
+template <typename Char>
+inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
+    assert(is_name_start(*s));
+    const Char *start = s;
+    Char c;
+    do {
+        c = *++s;
+    } while (is_name_start(c) || ('0' <= c && c <= '9'));
+    const char *error = 0;
+    Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
+    if (error)
+        FMT_THROW(fmt::FormatError(error));
+    return arg;
+}
+
+FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
+    unsigned arg_index, const char *&error) {
+    Arg arg = args_[arg_index];
+    switch (arg.type) {
+    case Arg::NONE:
+        error = "argument index out of range";
+        break;
+    case Arg::NAMED_ARG:
+        arg = *static_cast<const internal::Arg*>(arg.pointer);
+    default:
+        /*nothing*/
+        ;
+    }
+    return arg;
+}
+
+inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
+    if (next_arg_index_ >= 0)
+        return do_get_arg(next_arg_index_++, error);
+    error = "cannot switch from manual to automatic argument indexing";
+    return Arg();
+}
+
+inline bool fmt::internal::FormatterBase::check_no_auto_index(
+    const char *&error) {
+    if (next_arg_index_ > 0) {
+        error = "cannot switch from automatic to manual argument indexing";
+        return false;
+    }
+    next_arg_index_ = -1;
+    return true;
+}
+
+inline Arg fmt::internal::FormatterBase::get_arg(
+    unsigned arg_index, const char *&error) {
+    return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
+}
+
+template <typename Char>
+void fmt::internal::PrintfFormatter<Char>::parse_flags(
+    FormatSpec &spec, const Char *&s) {
+    for (;;) {
+        switch (*s++) {
+        case '-':
+            spec.align_ = ALIGN_LEFT;
+            break;
+        case '+':
+            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
+            break;
+        case '0':
+            spec.fill_ = '0';
+            break;
+        case ' ':
+            spec.flags_ |= SIGN_FLAG;
+            break;
+        case '#':
+            spec.flags_ |= HASH_FLAG;
+            break;
+        default:
+            --s;
+            return;
+        }
+    }
+}
+
+template <typename Char>
+Arg fmt::internal::PrintfFormatter<Char>::get_arg(
+    const Char *s, unsigned arg_index) {
+    (void)s;
+    const char *error = 0;
+    Arg arg = arg_index == UINT_MAX ?
+              next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
+    if (error)
+        FMT_THROW(FormatError(!*s ? "invalid format string" : error));
+    return arg;
+}
+
+template <typename Char>
+unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
+    const Char *&s, FormatSpec &spec) {
+    unsigned arg_index = UINT_MAX;
+    Char c = *s;
+    if (c >= '0' && c <= '9') {
+        // Parse an argument index (if followed by '$') or a width possibly
+        // preceded with '0' flag(s).
+        unsigned value = parse_nonnegative_int(s);
+        if (*s == '$') {  // value is an argument index
+            ++s;
+            arg_index = value;
+        }
+        else {
+            if (c == '0')
+                spec.fill_ = '0';
+            if (value != 0) {
+                // Nonzero value means that we parsed width and don't need to
+                // parse it or flags again, so return now.
+                spec.width_ = value;
+                return arg_index;
+            }
+        }
+    }
+    parse_flags(spec, s);
+    // Parse width.
+    if (*s >= '0' && *s <= '9') {
+        spec.width_ = parse_nonnegative_int(s);
+    }
+    else if (*s == '*') {
+        ++s;
+        spec.width_ = WidthHandler(spec).visit(get_arg(s));
+    }
+    return arg_index;
+}
+
+template <typename Char>
+void fmt::internal::PrintfFormatter<Char>::format(
+    BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
+    const ArgList &args) {
+    const Char *start = format_str.c_str();
+    set_args(args);
+    const Char *s = start;
+    while (*s) {
+        Char c = *s++;
+        if (c != '%') continue;
+        if (*s == c) {
+            write(writer, start, s);
+            start = ++s;
+            continue;
+        }
+        write(writer, start, s - 1);
+
+        FormatSpec spec;
+        spec.align_ = ALIGN_RIGHT;
+
+        // Parse argument index, flags and width.
+        unsigned arg_index = parse_header(s, spec);
+
+        // Parse precision.
+        if (*s == '.') {
+            ++s;
+            if ('0' <= *s && *s <= '9') {
+                spec.precision_ = parse_nonnegative_int(s);
+            }
+            else if (*s == '*') {
+                ++s;
+                spec.precision_ = PrecisionHandler().visit(get_arg(s));
+            }
+        }
+
+        Arg arg = get_arg(s, arg_index);
+        if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
+            spec.flags_ &= ~HASH_FLAG;
+        if (spec.fill_ == '0') {
+            if (arg.type <= Arg::LAST_NUMERIC_TYPE)
+                spec.align_ = ALIGN_NUMERIC;
+            else
+                spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
+        }
+
+        // Parse length and convert the argument to the required type.
+        switch (*s++) {
+        case 'h':
+            if (*s == 'h')
+                ArgConverter<signed char>(arg, *++s).visit(arg);
+            else
+                ArgConverter<short>(arg, *s).visit(arg);
+            break;
+        case 'l':
+            if (*s == 'l')
+                ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
+            else
+                ArgConverter<long>(arg, *s).visit(arg);
+            break;
+        case 'j':
+            ArgConverter<intmax_t>(arg, *s).visit(arg);
+            break;
+        case 'z':
+            ArgConverter<size_t>(arg, *s).visit(arg);
+            break;
+        case 't':
+            ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
+            break;
+        case 'L':
+            // printf produces garbage when 'L' is omitted for long double, no
+            // need to do the same.
+            break;
+        default:
+            --s;
+            ArgConverter<int>(arg, *s).visit(arg);
+        }
+
+        // Parse type.
+        if (!*s)
+            FMT_THROW(FormatError("invalid format string"));
+        spec.type_ = static_cast<char>(*s++);
+        if (arg.type <= Arg::LAST_INTEGER_TYPE) {
+            // Normalize type.
+            switch (spec.type_) {
+            case 'i':
+            case 'u':
+                spec.type_ = 'd';
+                break;
+            case 'c':
+                // TODO: handle wchar_t
+                CharConverter(arg).visit(arg);
+                break;
+            }
+        }
+
+        start = s;
+
+        // Format argument.
+        internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
+    }
+    write(writer, start, s);
+}
+
+template <typename Char>
+const Char *fmt::BasicFormatter<Char>::format(
+    const Char *&format_str, const Arg &arg) {
+    const Char *s = format_str;
+    FormatSpec spec;
+    if (*s == ':') {
+        if (arg.type == Arg::CUSTOM) {
+            arg.custom.format(this, arg.custom.value, &s);
+            return s;
+        }
+        ++s;
+        // Parse fill and alignment.
+        if (Char c = *s) {
+            const Char *p = s + 1;
+            spec.align_ = ALIGN_DEFAULT;
+            do {
+                switch (*p) {
+                case '<':
+                    spec.align_ = ALIGN_LEFT;
+                    break;
+                case '>':
+                    spec.align_ = ALIGN_RIGHT;
+                    break;
+                case '=':
+                    spec.align_ = ALIGN_NUMERIC;
+                    break;
+                case '^':
+                    spec.align_ = ALIGN_CENTER;
+                    break;
+                }
+                if (spec.align_ != ALIGN_DEFAULT) {
+                    if (p != s) {
+                        if (c == '}') break;
+                        if (c == '{')
+                            FMT_THROW(FormatError("invalid fill character '{'"));
+                        s += 2;
+                        spec.fill_ = c;
+                    }
+                    else ++s;
+                    if (spec.align_ == ALIGN_NUMERIC)
+                        require_numeric_argument(arg, '=');
+                    break;
+                }
+            } while (--p >= s);
+        }
+
+        // Parse sign.
+        switch (*s) {
+        case '+':
+            check_sign(s, arg);
+            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
+            break;
+        case '-':
+            check_sign(s, arg);
+            spec.flags_ |= MINUS_FLAG;
+            break;
+        case ' ':
+            check_sign(s, arg);
+            spec.flags_ |= SIGN_FLAG;
+            break;
+        }
+
+        if (*s == '#') {
+            require_numeric_argument(arg, '#');
+            spec.flags_ |= HASH_FLAG;
+            ++s;
+        }
+
+        // Parse zero flag.
+        if (*s == '0') {
+            require_numeric_argument(arg, '0');
+            spec.align_ = ALIGN_NUMERIC;
+            spec.fill_ = '0';
+            ++s;
+        }
+
+        // Parse width.
+        if ('0' <= *s && *s <= '9') {
+            spec.width_ = parse_nonnegative_int(s);
+        }
+        else if (*s == '{') {
+            ++s;
+            Arg width_arg = is_name_start(*s) ?
+                            parse_arg_name(s) : parse_arg_index(s);
+            if (*s++ != '}')
+                FMT_THROW(FormatError("invalid format string"));
+            ULongLong value = 0;
+            switch (width_arg.type) {
+            case Arg::INT:
+                if (width_arg.int_value < 0)
+                    FMT_THROW(FormatError("negative width"));
+                value = width_arg.int_value;
+                break;
+            case Arg::UINT:
+                value = width_arg.uint_value;
+                break;
+            case Arg::LONG_LONG:
+                if (width_arg.long_long_value < 0)
+                    FMT_THROW(FormatError("negative width"));
+                value = width_arg.long_long_value;
+                break;
+            case Arg::ULONG_LONG:
+                value = width_arg.ulong_long_value;
+                break;
+            default:
+                FMT_THROW(FormatError("width is not integer"));
+            }
+            if (value > INT_MAX)
+                FMT_THROW(FormatError("number is too big"));
+            spec.width_ = static_cast<int>(value);
+        }
+
+        // Parse precision.
+        if (*s == '.') {
+            ++s;
+            spec.precision_ = 0;
+            if ('0' <= *s && *s <= '9') {
+                spec.precision_ = parse_nonnegative_int(s);
+            }
+            else if (*s == '{') {
+                ++s;
+                Arg precision_arg =
+                    is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
+                if (*s++ != '}')
+                    FMT_THROW(FormatError("invalid format string"));
+                ULongLong value = 0;
+                switch (precision_arg.type) {
+                case Arg::INT:
+                    if (precision_arg.int_value < 0)
+                        FMT_THROW(FormatError("negative precision"));
+                    value = precision_arg.int_value;
+                    break;
+                case Arg::UINT:
+                    value = precision_arg.uint_value;
+                    break;
+                case Arg::LONG_LONG:
+                    if (precision_arg.long_long_value < 0)
+                        FMT_THROW(FormatError("negative precision"));
+                    value = precision_arg.long_long_value;
+                    break;
+                case Arg::ULONG_LONG:
+                    value = precision_arg.ulong_long_value;
+                    break;
+                default:
+                    FMT_THROW(FormatError("precision is not integer"));
+                }
+                if (value > INT_MAX)
+                    FMT_THROW(FormatError("number is too big"));
+                spec.precision_ = static_cast<int>(value);
+            }
+            else {
+                FMT_THROW(FormatError("missing precision specifier"));
+            }
+            if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
+                FMT_THROW(FormatError(
+                              fmt::format("precision not allowed in {} format specifier",
+                                          arg.type == Arg::POINTER ? "pointer" : "integer")));
+            }
+        }
+
+        // Parse type.
+        if (*s != '}' && *s)
+            spec.type_ = static_cast<char>(*s++);
+    }
+
+    if (*s++ != '}')
+        FMT_THROW(FormatError("missing '}' in format string"));
+    start_ = s;
+
+    // Format argument.
+    internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
+    return s;
+}
+
+template <typename Char>
+void fmt::BasicFormatter<Char>::format(
+    BasicCStringRef<Char> format_str, const ArgList &args) {
+    const Char *s = start_ = format_str.c_str();
+    set_args(args);
+    while (*s) {
+        Char c = *s++;
+        if (c != '{' && c != '}') continue;
+        if (*s == c) {
+            write(writer_, start_, s);
+            start_ = ++s;
+            continue;
+        }
+        if (c == '}')
+            FMT_THROW(FormatError("unmatched '}' in format string"));
+        write(writer_, start_, s - 1);
+        Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
+        s = format(s, arg);
+    }
+    write(writer_, start_, s);
+}
+
+FMT_FUNC void fmt::report_system_error(
+    int error_code, fmt::StringRef message) FMT_NOEXCEPT{
+    report_error(internal::format_system_error, error_code, message);
+}
+
+#if FMT_USE_WINDOWS_H
+FMT_FUNC void fmt::report_windows_error(
+    int error_code, fmt::StringRef message) FMT_NOEXCEPT{
+    report_error(internal::format_windows_error, error_code, message);
+}
+#endif
+
+FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
+    MemoryWriter w;
+    w.write(format_str, args);
+    std::fwrite(w.data(), 1, w.size(), f);
+}
+
+FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
+    print(stdout, format_str, args);
+}
+
+FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
+    MemoryWriter w;
+    w.write(format_str, args);
+    os.write(w.data(), w.size());
+}
+
+FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
+    char escape[] = "\x1b[30m";
+    escape[3] = '0' + static_cast<char>(c);
+    std::fputs(escape, stdout);
+    print(format, args);
+    std::fputs(RESET_COLOR, stdout);
+}
+
+FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
+    MemoryWriter w;
+    printf(w, format, args);
+    std::size_t size = w.size();
+    return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
+}
+
+#ifndef FMT_HEADER_ONLY
+
+template struct fmt::internal::BasicData<void>;
+
+// Explicit instantiations for char.
+
+template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
+
+template const char *fmt::BasicFormatter<char>::format(
+    const char *&format_str, const fmt::internal::Arg &arg);
+
+template void fmt::BasicFormatter<char>::format(
+    CStringRef format, const ArgList &args);
+
+template void fmt::internal::PrintfFormatter<char>::format(
+    BasicWriter<char> &writer, CStringRef format, const ArgList &args);
+
+template int fmt::internal::CharTraits<char>::format_float(
+    char *buffer, std::size_t size, const char *format,
+    unsigned width, int precision, double value);
+
+template int fmt::internal::CharTraits<char>::format_float(
+    char *buffer, std::size_t size, const char *format,
+    unsigned width, int precision, long double value);
+
+// Explicit instantiations for wchar_t.
+
+template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
+
+template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
+    const wchar_t *&format_str, const fmt::internal::Arg &arg);
+
+template void fmt::BasicFormatter<wchar_t>::format(
+    BasicCStringRef<wchar_t> format, const ArgList &args);
+
+template void fmt::internal::PrintfFormatter<wchar_t>::format(
+    BasicWriter<wchar_t> &writer, WCStringRef format,
+    const ArgList &args);
+
+template int fmt::internal::CharTraits<wchar_t>::format_float(
+    wchar_t *buffer, std::size_t size, const wchar_t *format,
+    unsigned width, int precision, double value);
+
+template int fmt::internal::CharTraits<wchar_t>::format_float(
+    wchar_t *buffer, std::size_t size, const wchar_t *format,
+    unsigned width, int precision, long double value);
+
+#endif  // FMT_HEADER_ONLY
+
+#if _MSC_VER
+# pragma warning(pop)
+#endif
\ No newline at end of file


[02/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Site2SiteClientProtocol.cpp
----------------------------------------------------------------------
diff --git a/src/Site2SiteClientProtocol.cpp b/src/Site2SiteClientProtocol.cpp
deleted file mode 100644
index 88ea78a..0000000
--- a/src/Site2SiteClientProtocol.cpp
+++ /dev/null
@@ -1,1313 +0,0 @@
-/**
- * @file Site2SiteProtocol.cpp
- * Site2SiteProtocol class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <sys/time.h>
-#include <stdio.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <random>
-#include <netinet/tcp.h>
-#include <iostream>
-#include "Site2SitePeer.h"
-#include "Site2SiteClientProtocol.h"
-
-bool Site2SiteClientProtocol::establish()
-{
-	if (_peerState != IDLE)
-	{
-		_logger->log_error("Site2Site peer state is not idle while try to establish");
-		return false;
-	}
-
-	bool ret = _peer->Open();
-
-	if (!ret)
-	{
-		_logger->log_error("Site2Site peer socket open failed");
-		return false;
-	}
-
-	// Negotiate the version
-	ret = initiateResourceNegotiation();
-
-	if (!ret)
-	{
-		_logger->log_error("Site2Site Protocol Version Negotiation failed");
-		/*
-		_peer->yield();
-		tearDown(); */
-		return false;
-	}
-
-	_logger->log_info("Site2Site socket established");
-	_peerState = ESTABLISHED;
-
-	return true;
-}
-
-bool Site2SiteClientProtocol::initiateResourceNegotiation()
-{
-	// Negotiate the version
-	if (_peerState != IDLE)
-	{
-		_logger->log_error("Site2Site peer state is not idle while initiateResourceNegotiation");
-		return false;
-	}
-
-	_logger->log_info("Negotiate protocol version with destination port %s current version %d", _portIdStr.c_str(), _currentVersion);
-
-	int ret = _peer->writeUTF(this->getResourceName());
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	ret = _peer->write(_currentVersion);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	uint8_t statusCode;
-	ret = _peer->read(statusCode);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	switch (statusCode)
-	{
-	case RESOURCE_OK:
-		_logger->log_info("Site2Site Protocol Negotiate protocol version OK");
-		return true;
-	case DIFFERENT_RESOURCE_VERSION:
-		uint32_t serverVersion;
-		ret = _peer->read(serverVersion);
-		if (ret <= 0)
-		{
-			// tearDown();
-			return false;
-		}
-		_logger->log_info("Site2Site Server Response asked for a different protocol version %d", serverVersion);
-		for (unsigned int i = (_currentVersionIndex + 1); i < sizeof(_supportedVersion)/sizeof(uint32_t); i++)
-		{
-			if (serverVersion >= _supportedVersion[i])
-			{
-				_currentVersion = _supportedVersion[i];
-				_currentVersionIndex = i;
-				return initiateResourceNegotiation();
-			}
-		}
-		ret = -1;
-		// tearDown();
-		return false;
-	case NEGOTIATED_ABORT:
-		_logger->log_info("Site2Site Negotiate protocol response ABORT");
-		ret = -1;
-		// tearDown();
-		return false;
-	default:
-		_logger->log_info("Negotiate protocol response unknown code %d", statusCode);
-		return true;
-	}
-
-	return true;
-}
-
-bool Site2SiteClientProtocol::initiateCodecResourceNegotiation()
-{
-	// Negotiate the version
-	if (_peerState != HANDSHAKED)
-	{
-		_logger->log_error("Site2Site peer state is not handshaked while initiateCodecResourceNegotiation");
-		return false;
-	}
-
-	_logger->log_info("Negotiate Codec version with destination port %s current version %d", _portIdStr.c_str(), _currentCodecVersion);
-
-	int ret = _peer->writeUTF(this->getCodecResourceName());
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	ret = _peer->write(_currentCodecVersion);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	uint8_t statusCode;
-	ret = _peer->read(statusCode);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	switch (statusCode)
-	{
-	case RESOURCE_OK:
-		_logger->log_info("Site2Site Codec Negotiate version OK");
-		return true;
-	case DIFFERENT_RESOURCE_VERSION:
-		uint32_t serverVersion;
-		ret = _peer->read(serverVersion);
-		if (ret <= 0)
-		{
-			// tearDown();
-			return false;
-		}
-		_logger->log_info("Site2Site Server Response asked for a different codec version %d", serverVersion);
-		for (unsigned int i = (_currentCodecVersionIndex + 1); i < sizeof(_supportedCodecVersion)/sizeof(uint32_t); i++)
-		{
-			if (serverVersion >= _supportedCodecVersion[i])
-			{
-				_currentCodecVersion = _supportedCodecVersion[i];
-				_currentCodecVersionIndex = i;
-				return initiateCodecResourceNegotiation();
-			}
-		}
-		ret = -1;
-		// tearDown();
-		return false;
-	case NEGOTIATED_ABORT:
-		_logger->log_info("Site2Site Codec Negotiate response ABORT");
-		ret = -1;
-		// tearDown();
-		return false;
-	default:
-		_logger->log_info("Negotiate Codec response unknown code %d", statusCode);
-		return true;
-	}
-
-	return true;
-}
-
-bool Site2SiteClientProtocol::handShake()
-{
-	if (_peerState != ESTABLISHED)
-	{
-		_logger->log_error("Site2Site peer state is not established while handshake");
-		return false;
-	}
-	_logger->log_info("Site2Site Protocol Perform hand shake with destination port %s", _portIdStr.c_str());
-	uuid_t uuid;
-	// Generate the global UUID for the com identify
-	uuid_generate(uuid);
-	char uuidStr[37];
-	uuid_unparse(uuid, uuidStr);
-	_commsIdentifier = uuidStr;
-
-	int ret = _peer->writeUTF(_commsIdentifier);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	std::map<std::string, std::string> properties;
-	properties[HandShakePropertyStr[GZIP]] = "false";
-	properties[HandShakePropertyStr[PORT_IDENTIFIER]] = _portIdStr;
-	properties[HandShakePropertyStr[REQUEST_EXPIRATION_MILLIS]] = std::to_string(this->_timeOut);
-	if (this->_currentVersion >= 5)
-	{
-		if (this->_batchCount > 0)
-			properties[HandShakePropertyStr[BATCH_COUNT]] = std::to_string(this->_batchCount);
-		if (this->_batchSize > 0)
-			properties[HandShakePropertyStr[BATCH_SIZE]] = std::to_string(this->_batchSize);
-		if (this->_batchDuration > 0)
-			properties[HandShakePropertyStr[BATCH_DURATION]] = std::to_string(this->_batchDuration);
-	}
-
-	if (_currentVersion >= 3)
-	{
-		ret = _peer->writeUTF(_peer->getURL());
-		if (ret <= 0)
-		{
-			// tearDown();
-			return false;
-		}
-	}
-
-	uint32_t size = properties.size();
-	ret = _peer->write(size);
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	std::map<std::string, std::string>::iterator it;
-	for (it = properties.begin(); it!= properties.end(); it++)
-	{
-		ret = _peer->writeUTF(it->first);
-		if (ret <= 0)
-		{
-			// tearDown();
-			return false;
-		}
-		ret = _peer->writeUTF(it->second);
-		if (ret <= 0)
-		{
-			// tearDown();
-			return false;
-		}
-		_logger->log_info("Site2Site Protocol Send handshake properties %s %s", it->first.c_str(), it->second.c_str());
-	}
-
-	RespondCode code;
-	std::string message;
-
-	ret = this->readRespond(code, message);
-
-	if (ret <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	switch (code)
-	{
-	case PROPERTIES_OK:
-		_logger->log_info("Site2Site HandShake Completed");
-		_peerState = HANDSHAKED;
-		return true;
-	case PORT_NOT_IN_VALID_STATE:
-    case UNKNOWN_PORT:
-    case PORTS_DESTINATION_FULL:
-    	_logger->log_error("Site2Site HandShake Failed because destination port is either invalid or full");
-		ret = -1;
-		/*
-		_peer->yield();
-		tearDown(); */
-		return false;
-	default:
-		_logger->log_info("HandShake Failed because of unknown respond code %d", code);
-		ret = -1;
-		/*
-		_peer->yield();
-		tearDown(); */
-		return false;
-	}
-
-	return false;
-}
-
-void Site2SiteClientProtocol::tearDown()
-{
-	if (_peerState >= ESTABLISHED)
-	{
-		_logger->log_info("Site2Site Protocol tearDown");
-		// need to write shutdown request
-		writeRequestType(SHUTDOWN);
-	}
-
-	std::map<std::string, Transaction *>::iterator it;
-	for (it = _transactionMap.begin(); it!= _transactionMap.end(); it++)
-	{
-		delete it->second;
-	}
-	_transactionMap.clear();
-	_peer->Close();
-	_peerState = IDLE;
-}
-
-int Site2SiteClientProtocol::writeRequestType(RequestType type)
-{
-	if (type >= MAX_REQUEST_TYPE)
-		return -1;
-
-	return _peer->writeUTF(RequestTypeStr[type]);
-}
-
-int Site2SiteClientProtocol::readRequestType(RequestType &type)
-{
-	std::string requestTypeStr;
-
-	int ret = _peer->readUTF(requestTypeStr);
-
-	if (ret <= 0)
-		return ret;
-
-	for (int i = (int) NEGOTIATE_FLOWFILE_CODEC; i <= (int) SHUTDOWN; i++)
-	{
-		if (RequestTypeStr[i] == requestTypeStr)
-		{
-			type = (RequestType) i;
-			return ret;
-		}
-	}
-
-	return -1;
-}
-
-int Site2SiteClientProtocol::readRespond(RespondCode &code, std::string &message)
-{
-	uint8_t firstByte;
-
-	int ret = _peer->read(firstByte);
-
-	if (ret <= 0 || firstByte != CODE_SEQUENCE_VALUE_1)
-		return -1;
-
-	uint8_t secondByte;
-
-	ret = _peer->read(secondByte);
-
-	if (ret <= 0 || secondByte != CODE_SEQUENCE_VALUE_2)
-		return -1;
-
-	uint8_t thirdByte;
-
-	ret = _peer->read(thirdByte);
-
-	if (ret <= 0)
-		return ret;
-
-	code = (RespondCode) thirdByte;
-
-	RespondCodeContext *resCode = this->getRespondCodeContext(code);
-
-	if ( resCode == NULL)
-	{
-		// Not a valid respond code
-		return -1;
-	}
-	if (resCode->hasDescription)
-	{
-		ret = _peer->readUTF(message);
-		if (ret <= 0)
-			return -1;
-	}
-	return 3 + message.size();
-}
-
-int Site2SiteClientProtocol::writeRespond(RespondCode code, std::string message)
-{
-	RespondCodeContext *resCode = this->getRespondCodeContext(code);
-
-	if (resCode == NULL)
-	{
-		// Not a valid respond code
-		return -1;
-	}
-
-	uint8_t codeSeq[3];
-	codeSeq[0] = CODE_SEQUENCE_VALUE_1;
-	codeSeq[1] = CODE_SEQUENCE_VALUE_2;
-	codeSeq[2] = (uint8_t) code;
-
-	int ret = _peer->write(codeSeq, 3);
-
-	if (ret != 3)
-		return -1;
-
-	if (resCode->hasDescription)
-	{
-		ret = _peer->writeUTF(message);
-		if (ret > 0)
-			return (3 + ret);
-		else
-			return ret;
-	}
-	else
-		return 3;
-}
-
-bool Site2SiteClientProtocol::negotiateCodec()
-{
-	if (_peerState != HANDSHAKED)
-	{
-		_logger->log_error("Site2Site peer state is not handshaked while negotiate codec");
-		return false;
-	}
-
-	_logger->log_info("Site2Site Protocol Negotiate Codec with destination port %s", _portIdStr.c_str());
-
-	int status = this->writeRequestType(NEGOTIATE_FLOWFILE_CODEC);
-
-	if (status <= 0)
-	{
-		// tearDown();
-		return false;
-	}
-
-	// Negotiate the codec version
-	bool ret = initiateCodecResourceNegotiation();
-
-	if (!ret)
-	{
-		_logger->log_error("Site2Site Codec Version Negotiation failed");
-		/*
-		_peer->yield();
-		tearDown(); */
-		return false;
-	}
-
-	_logger->log_info("Site2Site Codec Completed and move to READY state for data transfer");
-	_peerState = READY;
-
-	return true;
-}
-
-bool Site2SiteClientProtocol::bootstrap()
-{
-	if (_peerState == READY)
-		return true;
-
-	tearDown();
-
-	if (establish() && handShake() && negotiateCodec())
-	{
-		_logger->log_info("Site2Site Ready For data transaction");
-		return true;
-	}
-	else
-	{
-		_peer->yield();
-		tearDown();
-		return false;
-	}
-}
-
-Transaction* Site2SiteClientProtocol::createTransaction(std::string &transactionID, TransferDirection direction)
-{
-	int ret;
-	bool dataAvailable;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		return NULL;
-	}
-
-	if (direction == RECEIVE)
-	{
-		ret = writeRequestType(RECEIVE_FLOWFILES);
-
-		if (ret <= 0)
-		{
-			// tearDown();
-			return NULL;
-		}
-
-		RespondCode code;
-		std::string message;
-
-		ret = readRespond(code, message);
-
-		if (ret <= 0)
-		{
-			// tearDown();
-			return NULL;
-		}
-
-		switch (code)
-		{
-		case MORE_DATA:
-			dataAvailable = true;
-			_logger->log_info("Site2Site peer indicates that data is available");
-			transaction = new Transaction(direction);
-			_transactionMap[transaction->getUUIDStr()] = transaction;
-			transactionID = transaction->getUUIDStr();
-			transaction->setDataAvailable(dataAvailable);
-			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
-			return transaction;
-		case NO_MORE_DATA:
-			dataAvailable = false;
-			_logger->log_info("Site2Site peer indicates that no data is available");
-			transaction = new Transaction(direction);
-			_transactionMap[transaction->getUUIDStr()] = transaction;
-			transactionID = transaction->getUUIDStr();
-			transaction->setDataAvailable(dataAvailable);
-			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
-			return transaction;
-		default:
-			_logger->log_info("Site2Site got unexpected response %d when asking for data", code);
-			// tearDown();
-			return NULL;
-		}
-	}
-	else
-	{
-		ret = writeRequestType(SEND_FLOWFILES);
-
-		if (ret <= 0)
-		{
-			// tearDown();
-			return NULL;
-		}
-		else
-		{
-			transaction = new Transaction(direction);
-			_transactionMap[transaction->getUUIDStr()] = transaction;
-			transactionID = transaction->getUUIDStr();
-			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
-			return transaction;
-		}
-	}
-}
-
-bool Site2SiteClientProtocol::receive(std::string transactionID, DataPacket *packet, bool &eof)
-{
-	int ret;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		return false;
-	}
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return false;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	if (transaction->getState() != TRANSACTION_STARTED && transaction->getState() != DATA_EXCHANGED)
-	{
-		_logger->log_info("Site2Site transaction %s is not at started or exchanged state", transactionID.c_str());
-		return false;
-	}
-
-	if (transaction->getDirection() != RECEIVE)
-	{
-		_logger->log_info("Site2Site transaction %s direction is wrong", transactionID.c_str());
-		return false;
-	}
-
-	if (!transaction->isDataAvailable())
-	{
-		eof = true;
-		return true;
-	}
-
-	if (transaction->_transfers > 0)
-	{
-		// if we already has transfer before, check to see whether another one is available
-		RespondCode code;
-		std::string message;
-
-		ret = readRespond(code, message);
-
-		if (ret <= 0)
-		{
-			return false;
-		}
-		if (code == CONTINUE_TRANSACTION)
-		{
-			_logger->log_info("Site2Site transaction %s peer indicate continue transaction", transactionID.c_str());
-			transaction->_dataAvailable = true;
-		}
-		else if (code == FINISH_TRANSACTION)
-		{
-			_logger->log_info("Site2Site transaction %s peer indicate finish transaction", transactionID.c_str());
-			transaction->_dataAvailable = false;
-		}
-		else
-		{
-			_logger->log_info("Site2Site transaction %s peer indicate wrong respond code %d", transactionID.c_str(), code);
-			return false;
-		}
-	}
-
-	if (!transaction->isDataAvailable())
-	{
-		eof = true;
-		return true;
-	}
-
-	// start to read the packet
-	uint32_t numAttributes;
-	ret = _peer->read(numAttributes, &transaction->_crc);
-	if (ret <= 0 || numAttributes > MAX_NUM_ATTRIBUTES)
-	{
-		return false;
-	}
-
-	// read the attributes
-	for (unsigned int i = 0; i < numAttributes; i++)
-	{
-		std::string key;
-		std::string value;
-		ret = _peer->readUTF(key, true, &transaction->_crc);
-		if (ret <= 0)
-		{
-			return false;
-		}
-		ret = _peer->readUTF(value, true, &transaction->_crc);
-		if (ret <= 0)
-		{
-			return false;
-		}
-		packet->_attributes[key] = value;
-		_logger->log_info("Site2Site transaction %s receives attribute key %s value %s", transactionID.c_str(), key.c_str(), value.c_str());
-	}
-
-	uint64_t len;
-	ret = _peer->read(len, &transaction->_crc);
-	if (ret <= 0)
-	{
-		return false;
-	}
-
-	packet->_size = len;
-	transaction->_transfers++;
-	transaction->_state = DATA_EXCHANGED;
-	transaction->_bytes += len;
-	_logger->log_info("Site2Site transaction %s receives flow record %d, total length %d", transactionID.c_str(),
-			transaction->_transfers, transaction->_bytes);
-
-	return true;
-}
-
-bool Site2SiteClientProtocol::send(std::string transactionID, DataPacket *packet, FlowFileRecord *flowFile, ProcessSession *session)
-{
-	int ret;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		return false;
-	}
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return false;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	if (transaction->getState() != TRANSACTION_STARTED && transaction->getState() != DATA_EXCHANGED)
-	{
-		_logger->log_info("Site2Site transaction %s is not at started or exchanged state", transactionID.c_str());
-		return false;
-	}
-
-	if (transaction->getDirection() != SEND)
-	{
-		_logger->log_info("Site2Site transaction %s direction is wrong", transactionID.c_str());
-		return false;
-	}
-
-	if (transaction->_transfers > 0)
-	{
-		ret = writeRespond(CONTINUE_TRANSACTION, "CONTINUE_TRANSACTION");
-		if (ret <= 0)
-		{
-			return false;
-		}
-	}
-
-	// start to read the packet
-	uint32_t numAttributes = packet->_attributes.size();
-	ret = _peer->write(numAttributes, &transaction->_crc);
-	if (ret != 4)
-	{
-		return false;
-	}
-
-	std::map<std::string, std::string>::iterator itAttribute;
-	for (itAttribute = packet->_attributes.begin(); itAttribute!= packet->_attributes.end(); itAttribute++)
-	{
-		ret = _peer->writeUTF(itAttribute->first, true, &transaction->_crc);
-		if (ret <= 0)
-		{
-			return false;
-		}
-		ret = _peer->writeUTF(itAttribute->second, true, &transaction->_crc);
-		if (ret <= 0)
-		{
-			return false;
-		}
-		_logger->log_info("Site2Site transaction %s send attribute key %s value %s", transactionID.c_str(),
-				itAttribute->first.c_str(), itAttribute->second.c_str());
-	}
-
-	uint64_t len = flowFile->getSize() ;
-	ret = _peer->write(len, &transaction->_crc);
-	if (ret != 8)
-	{
-		return false;
-	}
-
-	if (flowFile->getSize())
-	{
-		Site2SiteClientProtocol::ReadCallback callback(packet);
-		session->read(flowFile, &callback);
-		if (flowFile->getSize() != packet->_size)
-		{
-			return false;
-		}
-	}
-
-	transaction->_transfers++;
-	transaction->_state = DATA_EXCHANGED;
-	transaction->_bytes += len;
-	_logger->log_info("Site2Site transaction %s send flow record %d, total length %d", transactionID.c_str(),
-				transaction->_transfers, transaction->_bytes);
-
-	return true;
-}
-
-void Site2SiteClientProtocol::receiveFlowFiles(ProcessContext *context, ProcessSession *session)
-{
-	uint64_t bytes = 0;
-	int transfers = 0;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		context->yield();
-		tearDown();
-		throw Exception(SITE2SITE_EXCEPTION, "Can not establish handshake with peer");
-		return;
-	}
-
-	// Create the transaction
-	std::string transactionID;
-	transaction = createTransaction(transactionID, RECEIVE);
-
-	if (transaction == NULL)
-	{
-		context->yield();
-		tearDown();
-		throw Exception(SITE2SITE_EXCEPTION, "Can not create transaction");
-		return;
-	}
-
-	try
-	{
-		while (true)
-		{
-			std::map<std::string, std::string> empty;
-			DataPacket packet(this, transaction, empty);
-			bool eof = false;
-
-			if (!receive(transactionID, &packet, eof))
-			{
-				throw Exception(SITE2SITE_EXCEPTION, "Receive Failed");
-				return;
-			}
-			if (eof)
-			{
-				// transaction done
-				break;
-			}
-			FlowFileRecord *flowFile = session->create();
-			if (!flowFile)
-			{
-				throw Exception(SITE2SITE_EXCEPTION, "Flow File Creation Failed");
-				return;
-			}
-			std::map<std::string, std::string>::iterator it;
-			for (it = packet._attributes.begin(); it!= packet._attributes.end(); it++)
-			{
-				flowFile->addAttribute(it->first, it->second);
-			}
-
-			if (packet._size > 0)
-			{
-				Site2SiteClientProtocol::WriteCallback callback(&packet);
-				session->write(flowFile, &callback);
-				if (flowFile->getSize() != packet._size)
-				{
-					throw Exception(SITE2SITE_EXCEPTION, "Receive Size Not Right");
-					return;
-				}
-			}
-			Relationship relation; // undefined relationship
-			session->transfer(flowFile, relation);
-			// receive the transfer for the flow record
-			bytes += packet._size;
-			transfers++;
-		} // while true
-
-		if (!confirm(transactionID))
-		{
-			throw Exception(SITE2SITE_EXCEPTION, "Confirm Transaction Failed");
-			return;
-		}
-		if (!complete(transactionID))
-		{
-			throw Exception(SITE2SITE_EXCEPTION, "Complete Transaction Failed");
-			return;
-		}
-		_logger->log_info("Site2Site transaction %s successfully receive flow record %d, content bytes %d",
-				transactionID.c_str(), transfers, bytes);
-		// we yield the receive if we did not get anything
-		if (transfers == 0)
-			context->yield();
-	}
-	catch (std::exception &exception)
-	{
-		if (transaction)
-			deleteTransaction(transactionID);
-		context->yield();
-		tearDown();
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		if (transaction)
-			deleteTransaction(transactionID);
-		context->yield();
-		tearDown();
-		_logger->log_debug("Caught Exception during Site2SiteClientProtocol::receiveFlowFiles");
-		throw;
-	}
-
-	deleteTransaction(transactionID);
-
-	return;
-}
-
-bool Site2SiteClientProtocol::confirm(std::string transactionID)
-{
-	int ret;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		return false;
-	}
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return false;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	if (transaction->getState() == TRANSACTION_STARTED && !transaction->isDataAvailable() &&
-			transaction->getDirection() == RECEIVE)
-	{
-		transaction->_state = TRANSACTION_CONFIRMED;
-		return true;
-	}
-
-	if (transaction->getState() != DATA_EXCHANGED)
-		return false;
-
-	if (transaction->getDirection() == RECEIVE)
-	{
-		if (transaction->isDataAvailable())
-			return false;
-		// we received a FINISH_TRANSACTION indicator. Send back a CONFIRM_TRANSACTION message
-		// to peer so that we can verify that the connection is still open. This is a two-phase commit,
-		// which helps to prevent the chances of data duplication. Without doing this, we may commit the
-		// session and then when we send the response back to the peer, the peer may have timed out and may not
-		// be listening. As a result, it will re-send the data. By doing this two-phase commit, we narrow the
-		// Critical Section involved in this transaction so that rather than the Critical Section being the
-		// time window involved in the entire transaction, it is reduced to a simple round-trip conversation.
-		long crcValue = transaction->getCRC();
-		std::string crc = std::to_string(crcValue);
-		_logger->log_info("Site2Site Send confirm with CRC %d to transaction %s", transaction->getCRC(),
-						transactionID.c_str());
-		ret = writeRespond(CONFIRM_TRANSACTION, crc);
-		if (ret <= 0)
-			return false;
-		RespondCode code;
-		std::string message;
-		readRespond(code, message);
-		if (ret <= 0)
-			return false;
-
-		if (code == CONFIRM_TRANSACTION)
-		{
-			_logger->log_info("Site2Site transaction %s peer confirm transaction", transactionID.c_str());
-			transaction->_state = TRANSACTION_CONFIRMED;
-			return true;
-		}
-		else if (code == BAD_CHECKSUM)
-		{
-			_logger->log_info("Site2Site transaction %s peer indicate bad checksum", transactionID.c_str());
-			/*
-			transaction->_state = TRANSACTION_CONFIRMED;
-			return true; */
-			return false;
-		}
-		else
-		{
-			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
-					transactionID.c_str(), code);
-			return false;
-		}
-	}
-	else
-	{
-		_logger->log_info("Site2Site Send FINISH TRANSACTION for transaction %s",
-								transactionID.c_str());
-		ret = writeRespond(FINISH_TRANSACTION, "FINISH_TRANSACTION");
-		if (ret <= 0)
-			return false;
-		RespondCode code;
-		std::string message;
-		readRespond(code, message);
-		if (ret <= 0)
-			return false;
-
-		// we've sent a FINISH_TRANSACTION. Now we'll wait for the peer to send a 'Confirm Transaction' response
-		if (code == CONFIRM_TRANSACTION)
-		{
-			_logger->log_info("Site2Site transaction %s peer confirm transaction with CRC %s", transactionID.c_str(), message.c_str());
-			if (this->_currentVersion > 3)
-			{
-				long crcValue = transaction->getCRC();
-				std::string crc = std::to_string(crcValue);
-				if (message == crc)
-				{
-					_logger->log_info("Site2Site transaction %s CRC matched", transactionID.c_str());
-					ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
-					if (ret <= 0)
-						return false;
-					transaction->_state = TRANSACTION_CONFIRMED;
-					return true;
-				}
-				else
-				{
-					_logger->log_info("Site2Site transaction %s CRC not matched %s", transactionID.c_str(), crc.c_str());
-					ret = writeRespond(BAD_CHECKSUM, "BAD_CHECKSUM");
-					/*
-					ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
-										if (ret <= 0)
-											return false;
-										transaction->_state = TRANSACTION_CONFIRMED;
-					return true; */
-					return false;
-				}
-			}
-			ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
-			if (ret <= 0)
-				return false;
-			transaction->_state = TRANSACTION_CONFIRMED;
-			return true;
-		}
-		else
-		{
-			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
-					transactionID.c_str(), code);
-			return false;
-		}
-		return false;
-	}
-}
-
-void Site2SiteClientProtocol::cancel(std::string transactionID)
-{
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		return;
-	}
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	if (transaction->getState() == TRANSACTION_CANCELED || transaction->getState() == TRANSACTION_COMPLETED
-			|| transaction->getState() == TRANSACTION_ERROR)
-	{
-		return;
-	}
-
-	this->writeRespond(CANCEL_TRANSACTION, "Cancel");
-	transaction->_state = TRANSACTION_CANCELED;
-
-	tearDown();
-	return;
-}
-
-void Site2SiteClientProtocol::deleteTransaction(std::string transactionID)
-{
-	Transaction *transaction = NULL;
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	_logger->log_info("Site2Site delete transaction %s", transaction->getUUIDStr().c_str());
-	delete transaction;
-	_transactionMap.erase(transactionID);
-}
-
-void Site2SiteClientProtocol::error(std::string transactionID)
-{
-	Transaction *transaction = NULL;
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	transaction->_state = TRANSACTION_ERROR;
-	tearDown();
-	return;
-}
-
-//! Complete the transaction
-bool Site2SiteClientProtocol::complete(std::string transactionID)
-{
-	int ret;
-	Transaction *transaction = NULL;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		return false;
-	}
-
-	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
-
-	if (it == _transactionMap.end())
-	{
-		return false;
-	}
-	else
-	{
-		transaction = it->second;
-	}
-
-	if (transaction->getState() != TRANSACTION_CONFIRMED)
-	{
-		return false;
-	}
-
-	if (transaction->getDirection() == RECEIVE)
-	{
-		if (transaction->_transfers == 0)
-		{
-			transaction->_state = TRANSACTION_COMPLETED;
-			return true;
-		}
-		else
-		{
-			_logger->log_info("Site2Site transaction %s send finished", transactionID.c_str());
-			ret = this->writeRespond(TRANSACTION_FINISHED, "Finished");
-			if (ret <= 0)
-				return false;
-			else
-			{
-				transaction->_state = TRANSACTION_COMPLETED;
-				return true;
-			}
-		}
-	}
-	else
-	{
-		RespondCode code;
-		std::string message;
-		int ret;
-
-		ret = readRespond(code, message);
-
-		if (ret <= 0)
-			return false;
-
-		if (code == TRANSACTION_FINISHED)
-		{
-			_logger->log_info("Site2Site transaction %s peer finished transaction", transactionID.c_str());
-			transaction->_state = TRANSACTION_COMPLETED;
-			return true;
-		}
-		else
-		{
-			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
-					transactionID.c_str(), code);
-			return false;
-		}
-	}
-}
-
-void Site2SiteClientProtocol::transferFlowFiles(ProcessContext *context, ProcessSession *session)
-{
-	FlowFileRecord *flow = session->get();
-	Transaction *transaction = NULL;
-
-	if (!flow)
-		return;
-
-	if (_peerState != READY)
-	{
-		bootstrap();
-	}
-
-	if (_peerState != READY)
-	{
-		context->yield();
-		tearDown();
-		throw Exception(SITE2SITE_EXCEPTION, "Can not establish handshake with peer");
-		return;
-	}
-
-	// Create the transaction
-	std::string transactionID;
-	transaction = createTransaction(transactionID, SEND);
-
-	if (transaction == NULL)
-	{
-		context->yield();
-		tearDown();
-		throw Exception(SITE2SITE_EXCEPTION, "Can not create transaction");
-		return;
-	}
-
-	bool continueTransaction = true;
-	uint64_t startSendingNanos = getTimeNano();
-
-	try
-	{
-		while (continueTransaction)
-		{
-			DataPacket packet(this, transaction, flow->getAttributes());
-
-			if (!send(transactionID, &packet, flow, session))
-			{
-				throw Exception(SITE2SITE_EXCEPTION, "Send Failed");
-				return;
-			}
-			_logger->log_info("Site2Site transaction %s send flow record %s",
-							transactionID.c_str(), flow->getUUIDStr().c_str());
-			session->remove(flow);
-
-			uint64_t transferNanos = getTimeNano() - startSendingNanos;
-			if (transferNanos > _batchSendNanos)
-				break;
-
-			flow = session->get();
-			if (!flow)
-			{
-				continueTransaction = false;
-			}
-		} // while true
-
-		if (!confirm(transactionID))
-		{
-			throw Exception(SITE2SITE_EXCEPTION, "Confirm Failed");
-			return;
-		}
-		if (!complete(transactionID))
-		{
-			throw Exception(SITE2SITE_EXCEPTION, "Complete Failed");
-			return;
-		}
-		_logger->log_info("Site2Site transaction %s successfully send flow record %d, content bytes %d",
-				transactionID.c_str(), transaction->_transfers, transaction->_bytes);
-	}
-	catch (std::exception &exception)
-	{
-		if (transaction)
-			deleteTransaction(transactionID);
-		context->yield();
-		tearDown();
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		if (transaction)
-			deleteTransaction(transactionID);
-		context->yield();
-		tearDown();
-		_logger->log_debug("Caught Exception during Site2SiteClientProtocol::transferFlowFiles");
-		throw;
-	}
-
-	deleteTransaction(transactionID);
-
-	return;
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Site2SitePeer.cpp
----------------------------------------------------------------------
diff --git a/src/Site2SitePeer.cpp b/src/Site2SitePeer.cpp
deleted file mode 100644
index 48e19d0..0000000
--- a/src/Site2SitePeer.cpp
+++ /dev/null
@@ -1,435 +0,0 @@
-/**
- * @file Site2SitePeer.cpp
- * Site2SitePeer class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <sys/time.h>
-#include <stdio.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <random>
-#include <netinet/tcp.h>
-#include <iostream>
-#include "Site2SitePeer.h"
-
-//! CRC tables
-std::atomic<bool> CRC32::tableInit(false);
-unsigned int CRC32::table[256];
-
-bool Site2SitePeer::Open()
-{
-	in_addr_t addr;
-	int sock = 0;
-	struct hostent *h;
-	const char *host;
-	uint16_t port;
-
-	host = this->_host.c_str();
-	port = this->_port;
-
-	if (strlen(host) == 0)
-		return false;
-
-#ifdef __MACH__
-	h = gethostbyname(host);
-#else
-	char buf[1024];
-	struct hostent he;
-	int hh_errno;
-	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
-#endif
-	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0)
-	{
-		_logger->log_error("Could not create socket to hostName %s", host);
-		this->yield();
-		return false;
-	}
-
-#ifndef __MACH__
-	int opt = 1;
-	bool nagle_off = true;
-
-	if (nagle_off)
-	{
-		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() TCP_NODELAY failed");
-			close(sock);
-			this->yield();
-			return false;
-		}
-		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-				(char *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() SO_REUSEADDR failed");
-			close(sock);
-			this->yield();
-			return false;
-		}
-	}
-
-	int sndsize = 256*1024;
-	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
-	{
-		_logger->log_error("setsockopt() SO_SNDBUF failed");
-		close(sock);
-		this->yield();
-		return false;
-	}
-	int rcvsize = 256*1024;
-	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcvsize, (int)sizeof(rcvsize)) < 0)
-	{
-		_logger->log_error("setsockopt() SO_RCVBUF failed");
-		close(sock);
-		this->yield();
-		return false;
-	}
-#endif
-
-	struct sockaddr_in sa;
-	socklen_t socklen;
-	int status;
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = htonl(INADDR_ANY);
-	sa.sin_port = htons(0);
-	socklen = sizeof(sa);
-	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
-	{
-		_logger->log_error("socket bind failed");
-		close(sock);
-		this->yield();
-		return false;
-	}
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = addr;
-	sa.sin_port = htons(port);
-	socklen = sizeof(sa);
-
-	status = connect(sock, (struct sockaddr *)&sa, socklen);
-
-	if (status < 0)
-	{
-		_logger->log_error("socket connect failed to %s %d", host, port);
-		close(sock);
-		this->yield();
-		return false;
-	}
-
-	_logger->log_info("Site2Site Peer socket %d connect to server %s port %d success", sock, host, port);
-
-	_socket = sock;
-
-	status = sendData((uint8_t *) MAGIC_BYTES, sizeof(MAGIC_BYTES));
-
-	if (status <= 0)
-	{
-		Close();
-		return false;
-	}
-
-	return true;
-}
-
-void Site2SitePeer::Close()
-{
-	if (_socket)
-	{
-		_logger->log_info("Site2Site Peer socket %d close", _socket);
-		close(_socket);
-		_socket = 0;
-	}
-}
-
-int Site2SitePeer::sendData(uint8_t *buf, int buflen, CRC32 *crc)
-{
-	int ret = 0, bytes = 0;
-
-	if (_socket <= 0)
-	{
-		// this->yield();
-		return -1;
-	}
-
-	while (bytes < buflen)
-	{
-		ret = send(_socket, buf+bytes, buflen-bytes, 0);
-		//check for errors
-		if (ret == -1)
-		{
-			_logger->log_error("Site2Site Peer socket %d send failed %s", _socket, strerror(errno));
-			Close();
-			// this->yield();
-			return ret;
-		}
-		bytes+=ret;
-	}
-
-	if (crc)
-		crc->update(buf, buflen);
-
-	return bytes;
-}
-
-int Site2SitePeer::Select(int msec)
-{
-	fd_set fds;
-	struct timeval tv;
-    int retval;
-    int fd = _socket;
-
-    FD_ZERO(&fds);
-    FD_SET(fd, &fds);
-
-    tv.tv_sec = msec/1000;
-    tv.tv_usec = (msec % 1000) * 1000;
-
-    if (msec > 0)
-       retval = select(fd+1, &fds, NULL, NULL, &tv);
-    else
-       retval = select(fd+1, &fds, NULL, NULL, NULL);
-
-    if (retval <= 0)
-      return retval;
-    if (FD_ISSET(fd, &fds))
-      return retval;
-    else
-      return 0;
-}
-
-int Site2SitePeer::readData(uint8_t *buf, int buflen, CRC32 *crc)
-{
-	int sendSize = buflen;
-	uint8_t *start = buf;
-
-	if (_socket <= 0)
-	{
-		// this->yield();
-		return -1;
-	}
-
-	while (buflen)
-	{
-		int status;
-		status = Select((int) _timeOut);
-		if (status <= 0)
-		{
-			Close();
-			return status;
-		}
-		status = recv(_socket, buf, buflen, 0);
-		if (status <= 0)
-		{
-			Close();
-			// this->yield();
-			return status;
-		}
-		buflen -= status;
-		buf += status;
-	}
-
-	if (crc)
-		crc->update(start, sendSize);
-
-	return sendSize;
-}
-
-int Site2SitePeer::writeUTF(std::string str, bool widen, CRC32 *crc)
-{
-	int strlen = str.length();
-	int utflen = 0;
-	int c, count = 0;
-
-	/* use charAt instead of copying String to char array */
-	for (int i = 0; i < strlen; i++) {
-		c = str.at(i);
-		if ((c >= 0x0001) && (c <= 0x007F)) {
-			utflen++;
-		} else if (c > 0x07FF) {
-			utflen += 3;
-		} else {
-			utflen += 2;
-		}
-	}
-
-	if (utflen > 65535)
-		return -1;
-
-	uint8_t *bytearr = NULL;
-	if (!widen)
-	{
-		bytearr = new uint8_t[utflen+2];
-		bytearr[count++] = (uint8_t) ((utflen >> 8) & 0xFF);
-		bytearr[count++] = (uint8_t) ((utflen >> 0) & 0xFF);
-	}
-	else
-	{
-		bytearr = new uint8_t[utflen+4];
-		bytearr[count++] = (uint8_t) ((utflen >> 24) & 0xFF);
-		bytearr[count++] = (uint8_t) ((utflen >> 16) & 0xFF);
-		bytearr[count++] = (uint8_t) ((utflen >> 8) & 0xFF);
-		bytearr[count++] = (uint8_t) ((utflen >> 0) & 0xFF);
-	}
-
-	int i=0;
-	for (i=0; i<strlen; i++) {
-		c = str.at(i);
-		if (!((c >= 0x0001) && (c <= 0x007F))) break;
-		bytearr[count++] = (uint8_t) c;
-	}
-
-	for (;i < strlen; i++){
-		c = str.at(i);
-		if ((c >= 0x0001) && (c <= 0x007F)) {
-			bytearr[count++] = (uint8_t) c;
-		} else if (c > 0x07FF) {
-			bytearr[count++] = (uint8_t) (0xE0 | ((c >> 12) & 0x0F));
-			bytearr[count++] = (uint8_t) (0x80 | ((c >>  6) & 0x3F));
-			bytearr[count++] = (uint8_t) (0x80 | ((c >>  0) & 0x3F));
-		} else {
-			bytearr[count++] = (uint8_t) (0xC0 | ((c >>  6) & 0x1F));
-			bytearr[count++] = (uint8_t) (0x80 | ((c >>  0) & 0x3F));
-		}
-	}
-	int ret;
-	if (!widen)
-	{
-		ret = sendData(bytearr, utflen+2, crc);
-	}
-	else
-	{
-		ret = sendData(bytearr, utflen+4, crc);
-	}
-	delete[] bytearr;
-	return ret;
-}
-
-int Site2SitePeer::readUTF(std::string &str, bool widen, CRC32 *crc)
-{
-    uint16_t utflen;
-    int ret;
-
-    if (!widen)
-    {
-    	ret = read(utflen, crc);
-    	if (ret <= 0)
-    		return ret;
-    }
-    else
-    {
-    	uint32_t len;
-       	ret = read(len, crc);
-        if (ret <= 0)
-        	return ret;
-        utflen = len;
-    }
-
-    uint8_t *bytearr = NULL;
-    char *chararr = NULL;
-    bytearr = new uint8_t[utflen];
-    chararr = new char[utflen];
-    memset(chararr, 0, utflen);
-
-    int c, char2, char3;
-    int count = 0;
-    int chararr_count=0;
-
-    ret = read(bytearr, utflen, crc);
-    if (ret <= 0)
-    {
-    	delete[] bytearr;
-    	delete[] chararr;
-    	return ret;
-    }
-
-    while (count < utflen) {
-        c = (int) bytearr[count] & 0xff;
-        if (c > 127) break;
-        count++;
-        chararr[chararr_count++]=(char)c;
-    }
-
-    while (count < utflen) {
-        c = (int) bytearr[count] & 0xff;
-        switch (c >> 4) {
-            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
-                /* 0xxxxxxx*/
-                count++;
-                chararr[chararr_count++]=(char)c;
-                break;
-            case 12: case 13:
-                /* 110x xxxx   10xx xxxx*/
-                count += 2;
-                if (count > utflen)
-                {
-                	delete[] bytearr;
-                	delete[] chararr;
-                	return -1;
-                }
-                char2 = (int) bytearr[count-1];
-                if ((char2 & 0xC0) != 0x80)
-                {
-                	delete[] bytearr;
-                	delete[] chararr;
-                	return -1;
-                }
-                chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
-                                                (char2 & 0x3F));
-                break;
-            case 14:
-                /* 1110 xxxx  10xx xxxx  10xx xxxx */
-                count += 3;
-                if (count > utflen)
-                {
-                	delete[] bytearr;
-                	delete[] chararr;
-                	return -1;
-                }
-                char2 = (int) bytearr[count-2];
-                char3 = (int) bytearr[count-1];
-                if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-                {
-                	delete[] bytearr;
-                	delete[] chararr;
-                	return -1;
-                }
-                chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
-                                                ((char2 & 0x3F) << 6)  |
-                                                ((char3 & 0x3F) << 0));
-                break;
-            default:
-            	delete[] bytearr;
-            	delete[] chararr;
-            	return -1;
-        }
-    }
-    // The number of chars produced may be less than utflen
-    std::string value(chararr, chararr_count);
-    str = value;
-    delete[] bytearr;
-    delete[] chararr;
-    if (!widen)
-    	return (2 + utflen);
-    else
-    	return (4 + utflen);
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/TailFile.cpp
----------------------------------------------------------------------
diff --git a/src/TailFile.cpp b/src/TailFile.cpp
deleted file mode 100644
index 445255b..0000000
--- a/src/TailFile.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * @file TailFile.cpp
- * TailFile class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <sstream>
-#include <stdio.h>
-#include <string>
-#include <iostream>
-#include <dirent.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include "TimeUtil.h"
-#include "TailFile.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string TailFile::ProcessorName("TailFile");
-Property TailFile::FileName("File to Tail", "Fully-qualified filename of the file that should be tailed", "");
-Property TailFile::StateFile("State File",
-		"Specifies the file that should be used for storing state about what data has been ingested so that upon restart NiFi can resume from where it left off", "");
-Relationship TailFile::Success("success", "All files are routed to success");
-
-void TailFile::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(FileName);
-	properties.insert(StateFile);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-}
-
-std::string TailFile::trimLeft(const std::string& s)
-{
-	const char *WHITESPACE = " \n\r\t";
-    size_t startpos = s.find_first_not_of(WHITESPACE);
-    return (startpos == std::string::npos) ? "" : s.substr(startpos);
-}
-
-std::string TailFile::trimRight(const std::string& s)
-{
-	const char *WHITESPACE = " \n\r\t";
-    size_t endpos = s.find_last_not_of(WHITESPACE);
-    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
-}
-
-void TailFile::parseStateFileLine(char *buf)
-{
-	char *line = buf;
-
-    while ((line[0] == ' ') || (line[0] =='\t'))
-    	++line;
-
-    char first = line[0];
-    if ((first == '\0') || (first == '#')  || (first == '\r') || (first == '\n') || (first == '='))
-    {
-    	return;
-    }
-
-    char *equal = strchr(line, '=');
-    if (equal == NULL)
-    {
-    	return;
-    }
-
-    equal[0] = '\0';
-    std::string key = line;
-
-    equal++;
-    while ((equal[0] == ' ') || (equal[0] == '\t'))
-    	++equal;
-
-    first = equal[0];
-    if ((first == '\0') || (first == '\r') || (first== '\n'))
-    {
-    	return;
-    }
-
-    std::string value = equal;
-    key = trimRight(key);
-    value = trimRight(value);
-
-    if (key == "FILENAME")
-    	this->_currentTailFileName = value;
-    if (key == "POSITION")
-    	this->_currentTailFilePosition = std::stoi(value);
-
-    return;
-}
-
-void TailFile::recoverState()
-{
-	std::ifstream file(_stateFile.c_str(), std::ifstream::in);
-	if (!file.good())
-	{
-		_logger->log_error("load state file failed %s", _stateFile.c_str());
-		return;
-	}
-	const unsigned int bufSize = 512;
-	char buf[bufSize];
-	for (file.getline(buf,bufSize); file.good(); file.getline(buf,bufSize))
-	{
-		parseStateFileLine(buf);
-	}
-}
-
-void TailFile::storeState()
-{
-	std::ofstream file(_stateFile.c_str());
-	if (!file.is_open())
-	{
-		_logger->log_error("store state file failed %s", _stateFile.c_str());
-		return;
-	}
-	file << "FILENAME=" << this->_currentTailFileName << "\n";
-	file << "POSITION=" << this->_currentTailFilePosition << "\n";
-	file.close();
-}
-
-static bool sortTailMatchedFileItem(TailMatchedFileItem i, TailMatchedFileItem j)
-{
-	return (i.modifiedTime < j.modifiedTime);
-}
-void TailFile::checkRollOver()
-{
-	struct stat statbuf;
-	std::vector<TailMatchedFileItem> matchedFiles;
-	std::string fullPath = this->_fileLocation + "/" + _currentTailFileName;
-
-	if (stat(fullPath.c_str(), &statbuf) == 0)
-	{
-		if (statbuf.st_size > this->_currentTailFilePosition)
-			// there are new input for the current tail file
-			return;
-
-		uint64_t modifiedTimeCurrentTailFile = ((uint64_t) (statbuf.st_mtime) * 1000);
-		std::string pattern = _fileName;
-		std::size_t found = _fileName.find_last_of(".");
-		if (found != std::string::npos)
-			pattern = _fileName.substr(0,found);
-		DIR *d;
-		d = opendir(this->_fileLocation.c_str());
-		if (!d)
-			return;
-		while (1)
-		{
-			struct dirent *entry;
-			entry = readdir(d);
-			if (!entry)
-				break;
-			std::string d_name = entry->d_name;
-			if (!(entry->d_type & DT_DIR))
-			{
-				std::string fileName = d_name;
-				std::string fileFullName = this->_fileLocation + "/" + d_name;
-				if (fileFullName.find(pattern) != std::string::npos && stat(fileFullName.c_str(), &statbuf) == 0)
-				{
-					if (((uint64_t) (statbuf.st_mtime) * 1000) >= modifiedTimeCurrentTailFile)
-					{
-						TailMatchedFileItem item;
-						item.fileName = fileName;
-						item.modifiedTime = ((uint64_t) (statbuf.st_mtime) * 1000);
-						matchedFiles.push_back(item);
-					}
-				}
-			}
-		}
-		closedir(d);
-
-		// Sort the list based on modified time
-		std::sort(matchedFiles.begin(), matchedFiles.end(), sortTailMatchedFileItem);
-		for (std::vector<TailMatchedFileItem>::iterator it = matchedFiles.begin(); it!=matchedFiles.end(); ++it)
-		{
-			TailMatchedFileItem item = *it;
-			if (item.fileName == _currentTailFileName)
-			{
-				++it;
-				if (it!=matchedFiles.end())
-				{
-					TailMatchedFileItem nextItem = *it;
-					_logger->log_info("TailFile File Roll Over from %s to %s", _currentTailFileName.c_str(), nextItem.fileName.c_str());
-					_currentTailFileName = nextItem.fileName;
-					_currentTailFilePosition = 0;
-					storeState();
-				}
-				break;
-			}
-		}
-	}
-	else
-		return;
-}
-
-
-void TailFile::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string value;
-	if (context->getProperty(FileName.getName(), value))
-	{
-		std::size_t found = value.find_last_of("/\\");
-		this->_fileLocation = value.substr(0,found);
-		this->_fileName = value.substr(found+1);
-	}
-	if (context->getProperty(StateFile.getName(), value))
-	{
-		_stateFile = value;
-	}
-	if (!this->_stateRecovered)
-	{
-		_stateRecovered = true;
-		this->_currentTailFileName = _fileName;
-		this->_currentTailFilePosition = 0;
-		// recover the state if we have not done so
-		this->recoverState();
-	}
-	checkRollOver();
-	std::string fullPath = this->_fileLocation + "/" + _currentTailFileName;
-	struct stat statbuf;
-	if (stat(fullPath.c_str(), &statbuf) == 0)
-	{
-		if (statbuf.st_size <= this->_currentTailFilePosition)
-			// there are no new input for the current tail file
-		{
-			context->yield();
-			return;
-		}
-		FlowFileRecord *flowFile = session->create();
-		if (!flowFile)
-			return;
-		std::size_t found = _currentTailFileName.find_last_of(".");
-		std::string baseName = _currentTailFileName.substr(0,found);
-		std::string extension = _currentTailFileName.substr(found+1);
-		flowFile->updateAttribute(PATH, _fileLocation);
-		flowFile->addAttribute(ABSOLUTE_PATH, fullPath);
-		session->import(fullPath, flowFile, true, this->_currentTailFilePosition);
-		session->transfer(flowFile, Success);
-		_logger->log_info("TailFile %s for %d bytes", _currentTailFileName.c_str(), flowFile->getSize());
-		std::string logName = baseName + "." + std::to_string(_currentTailFilePosition) + "-" +
-				std::to_string(_currentTailFilePosition + flowFile->getSize()) + "." + extension;
-		flowFile->updateAttribute(FILENAME, logName);
-		this->_currentTailFilePosition += flowFile->getSize();
-		storeState();
-	}
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/TimerDrivenSchedulingAgent.cpp
----------------------------------------------------------------------
diff --git a/src/TimerDrivenSchedulingAgent.cpp b/src/TimerDrivenSchedulingAgent.cpp
deleted file mode 100644
index 3ce57ae..0000000
--- a/src/TimerDrivenSchedulingAgent.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @file TimerDrivenSchedulingAgent.cpp
- * TimerDrivenSchedulingAgent class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <chrono>
-#include <thread>
-#include <iostream>
-#include "Property.h"
-#include "TimerDrivenSchedulingAgent.h"
-
-void TimerDrivenSchedulingAgent::schedule(Processor *processor)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_administrativeYieldDuration = 0;
-	std::string yieldValue;
-
-	if (_configure->get(Configure::nifi_administrative_yield_duration, yieldValue))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(yieldValue, _administrativeYieldDuration, unit) &&
-					Property::ConvertTimeUnitToMS(_administrativeYieldDuration, unit, _administrativeYieldDuration))
-		{
-			_logger->log_debug("nifi_administrative_yield_duration: [%d] ms", _administrativeYieldDuration);
-		}
-	}
-
-	_boredYieldDuration = 0;
-	if (_configure->get(Configure::nifi_bored_yield_duration, yieldValue))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(yieldValue, _boredYieldDuration, unit) &&
-					Property::ConvertTimeUnitToMS(_boredYieldDuration, unit, _boredYieldDuration))
-		{
-			_logger->log_debug("nifi_bored_yield_duration: [%d] ms", _boredYieldDuration);
-		}
-	}
-
-	if (processor->getScheduledState() != RUNNING)
-	{
-		_logger->log_info("Can not schedule threads for processor %s because it is not running", processor->getName().c_str());
-		return;
-	}
-
-	std::map<std::string, std::vector<std::thread *>>::iterator it =
-			_threads.find(processor->getUUIDStr());
-	if (it != _threads.end())
-	{
-		_logger->log_info("Can not schedule threads for processor %s because there are existed thread running");
-		return;
-	}
-
-	std::vector<std::thread *> threads;
-	for (int i = 0; i < processor->getMaxConcurrentTasks(); i++)
-	{
-		std::thread *thread = new std::thread(run, this, processor);
-		thread->detach();
-		threads.push_back(thread);
-		_logger->log_info("Scheduled Time Driven thread %d running for process %s", thread->get_id(),
-				processor->getName().c_str());
-	}
-	_threads[processor->getUUIDStr().c_str()] = threads;
-
-	return;
-}
-
-void TimerDrivenSchedulingAgent::unschedule(Processor *processor)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (processor->getScheduledState() != RUNNING)
-	{
-		_logger->log_info("Can not unschedule threads for processor %s because it is not running", processor->getName().c_str());
-		return;
-	}
-
-	std::map<std::string, std::vector<std::thread *>>::iterator it =
-			_threads.find(processor->getUUIDStr());
-
-	if (it == _threads.end())
-	{
-		_logger->log_info("Can not unschedule threads for processor %s because there are no existed thread running");
-		return;
-	}
-	for (std::vector<std::thread *>::iterator itThread = it->second.begin(); itThread != it->second.end(); ++itThread)
-	{
-		std::thread *thread = *itThread;
-		_logger->log_info("Scheduled Time Driven thread %d deleted for process %s", thread->get_id(),
-				processor->getName().c_str());
-		delete thread;
-	}
-	_threads.erase(processor->getUUIDStr());
-	processor->clearActiveTask();
-
-	return;
-}
-
-void TimerDrivenSchedulingAgent::run(TimerDrivenSchedulingAgent *agent, Processor *processor)
-{
-	while (agent->_running)
-	{
-		bool shouldYield = agent->onTrigger(processor);
-
-		if (processor->isYield())
-		{
-			// Honor the yield
-			std::this_thread::sleep_for(std::chrono::milliseconds(processor->getYieldTime()));
-		}
-		else if (shouldYield && agent->_boredYieldDuration > 0)
-		{
-			// No work to do or need to apply back pressure
-			std::this_thread::sleep_for(std::chrono::milliseconds(agent->_boredYieldDuration));
-		}
-		std::this_thread::sleep_for(std::chrono::nanoseconds(processor->getSchedulingPeriodNano()));
-	}
-	return;
-}
-
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/test/FlowFileRecordTest.cpp
----------------------------------------------------------------------
diff --git a/test/FlowFileRecordTest.cpp b/test/FlowFileRecordTest.cpp
deleted file mode 100644
index 09a3d33..0000000
--- a/test/FlowFileRecordTest.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @file MiNiFiMain.cpp 
- * MiNiFiMain implementation 
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-
-#include "FlowFileRecord.h"
-
-int main(int argc, char **argv)
-{
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/test/Server.cpp
----------------------------------------------------------------------
diff --git a/test/Server.cpp b/test/Server.cpp
deleted file mode 100644
index e7b3452..0000000
--- a/test/Server.cpp
+++ /dev/null
@@ -1,607 +0,0 @@
-/* A simple server in the internet domain using TCP
-   The port number is passed as an argument */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h> 
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <errno.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <string>
-#include <errno.h>
-#include <chrono>
-#include <thread>
-#include <iostream>     // std::cout
-#include <fstream>      // std::ifstream
-#include <signal.h>
-
-#define DEFAULT_NIFI_SERVER_PORT 9000
-#define DEFAULT_REPORT_INTERVAL 1000 // 1 sec
-#define MAX_READ_TIMEOUT 30000 // 30 seconds
-
-//! FlowControl Protocol Msg Type
-typedef enum {
-	REGISTER_REQ, // Device Register Request from device to server which contain device serial number, current running flow xml version
-	REGISTER_RESP, // Device Register Respond from server to device, may contain new flow.xml from server ask device to apply and also device report interval
-	REPORT_REQ, // Period Device Report from device to server which contain device serial number, current running flow xml name/version and other period report info
-	REPORT_RESP, // Report Respond from server to device, may ask device to update flow xml or processor property
-	MAX_FLOW_CONTROL_MSG_TYPE
-} FlowControlMsgType;
-
-//! FlowControl Protocol Msg Type String
-static const char *FlowControlMsgTypeStr[MAX_FLOW_CONTROL_MSG_TYPE] =
-{
-		"REGISTER_REQ",
-		"REGISTER_RESP",
-		"REPORT_REQ",
-		"REPORT_RESP"
-};
-
-//! Flow Control Msg Type to String
-inline const char *FlowControlMsgTypeToStr(FlowControlMsgType type)
-{
-	if (type < MAX_FLOW_CONTROL_MSG_TYPE)
-		return FlowControlMsgTypeStr[type];
-	else
-		return NULL;
-}
-
-//! FlowControll Protocol Msg ID (Some Messages are fix length, Some are variable length (TLV)
-typedef enum {
-	//Fix length 8 bytes: client to server in register request, required field
-	FLOW_SERIAL_NUMBER,
-	// Flow XML name TLV: client to server in register request and report request, required field
-	FLOW_XML_NAME,
-	// Flow XML content, TLV: server to client in register respond, option field in case server want to ask client to load xml from server
-	FLOW_XML_CONTENT,
-	// Fix length, 4 bytes Report interval in msec: server to client in register respond, option field
-	REPORT_INTERVAL,
-	// Processor Name TLV:  server to client in report respond, option field in case server want to ask client to update processor property
-	PROCESSOR_NAME,
-	// Processor Property Name TLV: server to client in report respond, option field in case server want to ask client to update processor property
-	PROPERTY_NAME,
-	// Processor Property Value TLV: server to client in report respond, option field in case server want to ask client to update processor property
-	PROPERTY_VALUE,
-	// Report Blob TLV: client to server in report request, option field in case client want to pickyback the report blob in report request to server
-	REPORT_BLOB,
-	MAX_FLOW_MSG_ID
-} FlowControlMsgID;
-
-//! FlowControl Protocol Msg ID String
-static const char *FlowControlMsgIDStr[MAX_FLOW_MSG_ID] =
-{
-		"FLOW_SERIAL_NUMBER",
-		"FLOW_XML_NAME",
-		"FLOW_XML_CONTENT",
-		"REPORT_INTERVAL",
-		"PROCESSOR_NAME"
-		"PROPERTY_NAME",
-		"PROPERTY_VALUE",
-		"REPORT_BLOB"
-};
-
-#define TYPE_HDR_LEN 4 // Fix Hdr Type
-#define TLV_HDR_LEN 8 // Type 4 bytes and Len 4 bytes
-
-//! FlowControl Protocol Msg Len
-inline int FlowControlMsgIDEncodingLen(FlowControlMsgID id, int payLoadLen)
-{
-	if (id == FLOW_SERIAL_NUMBER)
-		return (TYPE_HDR_LEN + 8);
-	else if (id == REPORT_INTERVAL)
-		return (TYPE_HDR_LEN + 4);
-	else if (id < MAX_FLOW_MSG_ID)
-		return (TLV_HDR_LEN + payLoadLen);
-	else
-		return -1;
-}
-
-//! Flow Control Msg Id to String
-inline const char *FlowControlMsgIdToStr(FlowControlMsgID id)
-{
-	if (id < MAX_FLOW_MSG_ID)
-		return FlowControlMsgIDStr[id];
-	else
-		return NULL;
-}
-
-//! Flow Control Respond status code
-typedef enum {
-	RESP_SUCCESS,
-	RESP_TRIGGER_REGISTER, // Server respond to client report to re trigger register
-	RESP_START_FLOW_CONTROLLER, // Server respond to client to start flow controller
-	RESP_STOP_FLOW_CONTROLLER, // Server respond to client to stop flow controller
-	RESP_FAILURE,
-	MAX_RESP_CODE
-} FlowControlRespCode;
-
-//! FlowControl Resp Code str
-static const char *FlowControlRespCodeStr[MAX_RESP_CODE] =
-{
-		"RESP_SUCCESS",
-		"RESP_TRIGGER_REGISTER",
-		"RESP_START_FLOW_CONTROLLER",
-		"RESP_STOP_FLOW_CONTROLLER",
-		"RESP_FAILURE"
-};
-
-//! Flow Control Resp Code to String
-inline const char *FlowControlRespCodeToStr(FlowControlRespCode code)
-{
-	if (code < MAX_RESP_CODE)
-		return FlowControlRespCodeStr[code];
-	else
-		return NULL;
-}
-
-//! Common FlowControlProtocol Header
-typedef struct {
-	uint32_t msgType; //! Msg Type
-	uint32_t seqNumber; //! Seq Number to match Req with Resp
-	uint32_t status; //! Resp Code, see FlowControlRespCode
-	uint32_t payloadLen; //! Msg Payload length
-} FlowControlProtocolHeader;
-
-
-//! encode uint32_t
-uint8_t *encode(uint8_t *buf, uint32_t value)
-{
-		*buf++ = (value & 0xFF000000) >> 24;
-		*buf++ = (value & 0x00FF0000) >> 16;
-		*buf++ = (value & 0x0000FF00) >> 8;
-		*buf++ = (value & 0x000000FF);
-		return buf;
-}
-
-//! encode uint32_t
-uint8_t *decode(uint8_t *buf, uint32_t &value)
-{
-		value = ((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3]));
-		return (buf + 4);
-}
-
-//! encode byte array
-uint8_t *encode(uint8_t *buf, uint8_t *bufArray, int size)
-{
-		memcpy(buf, bufArray, size);
-		buf += size;
-		return buf;
-}
-
-//! encode std::string
-uint8_t *encode(uint8_t *buf, std::string value)
-{
-		// add the \0 for size
-		buf = encode(buf, value.size()+1);
-		buf = encode(buf, (uint8_t *) value.c_str(), value.size()+1);
-		return buf;
-}
-
-int sendData(int socket, uint8_t *buf, int buflen)
-{
-	int ret = 0, bytes = 0;
-
-	while (bytes < buflen)
-	{
-		ret = send(socket, buf+bytes, buflen-bytes, 0);
-		//check for errors
-		if (ret == -1)
-		{
-			return ret;
-		}
-		bytes+=ret;
-	}
-
-	return bytes;
-}
-
-void error(const char *msg)
-{
-    perror(msg);
-    exit(1);
-}
-
-/* readline - read a '\n' terminated line from socket fd 
-              into buffer bufptr of size len. The line in the
-              buffer is terminated with '\0'.
-              It returns -1 in case of error or if
-              the capacity of the buffer is exceeded.
-	      It returns 0 if EOF is encountered before reading '\n'.
- */
-int readline( int fd, char *bufptr, size_t len )
-{
-  /* Note that this function is very tricky.  It uses the
-     static variables bp, cnt, and b to establish a local buffer.
-     The recv call requests large chunks of data (the size of the buffer).
-     Then if the recv call reads more than one line, the overflow
-     remains in the buffer and it is made available to the next call
-     to readline. 
-     Notice also that this routine reads up to '\n' and overwrites
-     it with '\0'. Thus if the line is really terminated with
-     "\r\n", the '\r' will remain unchanged.
-  */
-  char *bufx = bufptr;
-  static char *bp;
-  static int cnt = 0;
-  static char b[ 4096 ];
-  char c;
-  
-  while ( --len > 0 )
-    {
-      if ( --cnt <= 0 )
-	{
-	  cnt = recv( fd, b, sizeof( b ), 0 );
-	  if ( cnt < 0 )
-	    {
-	      if ( errno == EINTR )
-		{
-		  len++;		/* the while will decrement */
-		  continue;
-		}
-	      return -1;
-	    }
-	  if ( cnt == 0 )
-	    return 0;
-	  bp = b;
-	}
-      c = *bp++;
-      *bufptr++ = c;
-      if ( c == '\n' )
-	{
-	  *bufptr = '\0';
-	  return bufptr - bufx;
-	}
-    }
-  return -1;
-}
-
-int readData(int socket, uint8_t *buf, int buflen)
-{
-	int sendSize = buflen;
-	int status;
-
-	while (buflen)
-	{
-#ifndef __MACH__
-		status = read(socket, buf, buflen);
-#else
-		status = recv(socket, buf, buflen, 0);
-#endif
-		if (status <= 0)
-		{
-			return status;
-		}
-		buflen -= status;
-		buf += status;
-	}
-
-	return sendSize;
-}
-
-int readHdr(int socket, FlowControlProtocolHeader *hdr)
-{
-	uint8_t buffer[sizeof(FlowControlProtocolHeader)];
-
-	uint8_t *data = buffer;
-
-	int status = readData(socket, buffer, sizeof(FlowControlProtocolHeader));
-	if (status <= 0)
-		return status;
-
-	uint32_t value;
-	data = decode(data, value);
-	hdr->msgType = value;
-
-	data = decode(data, value);
-	hdr->seqNumber = value;
-
-	data = decode(data, value);
-	hdr->status = value;
-
-	data = decode(data, value);
-	hdr->payloadLen = value;
-
-	return sizeof(FlowControlProtocolHeader);
-}
-
-int readXML(char **xmlContent)
-{
-	  std::ifstream is ("conf/flowServer.xml", std::ifstream::binary);
-	  if (is) {
-	    // get length of file:
-	    is.seekg (0, is.end);
-	    int length = is.tellg();
-	    is.seekg (0, is.beg);
-
-	    char * buffer = new char [length];
-
-	    printf("Reading %s len %d\n", "conf/flowServer.xml", length);
-	    // read data as a block:
-	    is.read (buffer,length);
-
-	    is.close();
-
-	    // ...buffer contains the entire file...
-	    *xmlContent = buffer;
-
-	    return length;
-	  }
-	  return 0;
-}
-
-static int sockfd = 0, newsockfd = 0;
-void sigHandler(int signal)
-{
-	if (signal == SIGINT || signal == SIGTERM)
-	{
-		close(newsockfd);
-		close(sockfd);
-		exit(1);
-	}
-}
-
-int main(int argc, char *argv[])
-{
-     int portno;
-     socklen_t clilen;
-     struct sockaddr_in serv_addr, cli_addr;
-     char buffer[4096];
-     int flag = 0;
-     int number = 0;
-     
-     int n;
-     if (argc < 2) {
-         fprintf(stderr,"ERROR, no port provided\n");
-         exit(1);
-     }
-
- 	 if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) == SIG_ERR)
- 	 {
-
- 		return -1;
- 	 }
-     sockfd = socket(AF_INET, SOCK_STREAM, 0);
-     if (sockfd < 0) 
-        error("ERROR opening socket");
-     bzero((char *) &serv_addr, sizeof(serv_addr));
-     portno = atoi(argv[1]);
-     serv_addr.sin_family = AF_INET;
-     serv_addr.sin_addr.s_addr = INADDR_ANY;
-     serv_addr.sin_port = htons(portno);
-     if (bind(sockfd, (struct sockaddr *) &serv_addr,
-              sizeof(serv_addr)) < 0) 
-              error("ERROR on binding");
-     listen(sockfd,5);
-     if (portno == DEFAULT_NIFI_SERVER_PORT)
-     {
-    	 while (true)
-    	 {
-    		 clilen = sizeof(cli_addr);
-    		 newsockfd = accept(sockfd,
-                 (struct sockaddr *) &cli_addr, 
-                 &clilen);
-    		 if (newsockfd < 0)
-    		 {
-    			 error("ERROR on accept");
-    			 break;
-    		 }
-    		 // process request
-    		 FlowControlProtocolHeader hdr;
-    		 int status = readHdr(newsockfd, &hdr);
-    		 if (status > 0)
-    		 {
-    			 printf("Flow Control Protocol receive MsgType %s\n", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
-    		     printf("Flow Control Protocol receive Seq Num %d\n", hdr.seqNumber);
-    		     printf("Flow Control Protocol receive Resp Code %s\n", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
-    		     printf("Flow Control Protocol receive Payload len %d\n", hdr.payloadLen);
-    		 	 if (((FlowControlMsgType) hdr.msgType) == REGISTER_REQ)
-    		 	 {
-    		 		printf("Flow Control Protocol Register Req receive\n");
-    		 		uint8_t *payload = new uint8_t[hdr.payloadLen];
-    		 		uint8_t *payloadPtr = payload;
-    		 		status = readData(newsockfd, payload, hdr.payloadLen);
-    		 		while (status > 0 && payloadPtr < (payload + hdr.payloadLen))
-    		 		{
-    		 			uint32_t msgID = 0xFFFFFFFF;
-    		 			payloadPtr = decode(payloadPtr, msgID);
-    		 			if (((FlowControlMsgID) msgID) == FLOW_SERIAL_NUMBER)
-    		 			{
-    		 				// Fixed 8 bytes
-    		 				uint8_t seqNum[8];
-    		 				memcpy(seqNum, payloadPtr, 8);
-    		 				printf("Flow Control Protocol Register Req receive serial num\n");
-    		 				payloadPtr += 8;
-    		 			}
-    		 			else if (((FlowControlMsgID) msgID) == FLOW_XML_NAME)
-    		 			{
-    		 				uint32_t len;
-    		 				payloadPtr = decode(payloadPtr, len);
-    		 				printf("Flow Control Protocol receive XML name length %d\n", len);
-    		 				std::string flowName = (const char *) payloadPtr;
-    		 				payloadPtr += len;
-    		 				printf("Flow Control Protocol receive XML name %s\n", flowName.c_str());
-    		 			}
-    		 			else
-    		 			{
-    		 				break;
-    		 			}
-    		 		}
-    		 		delete[] payload;
-    		 		// Send Register Respond
-    		 		// Calculate the total payload msg size
-    		 		char *xmlContent;
-    		 		uint32_t xmlLen = readXML(&xmlContent);
-    		 		uint32_t payloadSize = FlowControlMsgIDEncodingLen(REPORT_INTERVAL, 0);
-    		 		if (xmlLen > 0)
-    		 			payloadSize += FlowControlMsgIDEncodingLen(FLOW_XML_CONTENT, xmlLen);
-
-    		 		uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
-    		 		uint8_t *data = new uint8_t[size];
-    		 		uint8_t *start = data;
-
-    		 		// encode the HDR
-    		 		hdr.msgType = REGISTER_RESP;
-    		 		hdr.payloadLen = payloadSize;
-    		 		hdr.status = RESP_SUCCESS;
-    		 		data = encode(data, hdr.msgType);
-    		 		data = encode(data, hdr.seqNumber);
-    		 		data = encode(data, hdr.status);
-    		 		data = encode(data, hdr.payloadLen);
-
-    		 		// encode the report interval
-    		 		data = encode(data, REPORT_INTERVAL);
-    		 		data = encode(data, DEFAULT_REPORT_INTERVAL);
-
-    		 		// encode the XML content
-    		 		if (xmlLen > 0)
-    		 		{
-    		 			data = encode(data, FLOW_XML_CONTENT);
-    		 			data = encode(data, xmlLen);
-    		 			data = encode(data, (uint8_t *) xmlContent, xmlLen);
-    		 			delete[] xmlContent;
-    		 		}
-
-    		 		// send it
-    		 		status = sendData(newsockfd, start, size);
-    		 		delete[] start;
-    		 	 }
-    		 	 else if (((FlowControlMsgType) hdr.msgType) == REPORT_REQ)
-        		 {
-        		 		printf("Flow Control Protocol Report Req receive\n");
-        		 		uint8_t *payload = new uint8_t[hdr.payloadLen];
-        		 		uint8_t *payloadPtr = payload;
-        		 		status = readData(newsockfd, payload, hdr.payloadLen);
-        		 		while (status > 0 && payloadPtr < (payload + hdr.payloadLen))
-        		 		{
-        		 			uint32_t msgID = 0xFFFFFFFF;
-        		 			payloadPtr = decode(payloadPtr, msgID);
-        		 			if (((FlowControlMsgID) msgID) == FLOW_XML_NAME)
-        		 			{
-        		 				uint32_t len;
-        		 				payloadPtr = decode(payloadPtr, len);
-        		 				printf("Flow Control Protocol receive XML name length %d\n", len);
-        		 				std::string flowName = (const char *) payloadPtr;
-        		 				payloadPtr += len;
-        		 				printf("Flow Control Protocol receive XML name %s\n", flowName.c_str());
-        		 			}
-        		 			else
-        		 			{
-        		 				break;
-        		 			}
-        		 		}
-        		 		delete[] payload;
-        		 		// Send Register Respond
-        		 		// Calculate the total payload msg size
-        		 		std::string processor = "RealTimeDataCollector";
-        		 		std::string propertyName1 = "real Time Message ID";
-        		 		std::string propertyValue1 = "41";
-        		 		std::string propertyName2 = "Batch Message ID";
-        		 		std::string propertyValue2 = "172,30,48";
-        		 		if (flag == 0)
-        		 		{
-              		 		propertyName1 = "Real Time Message ID";
-              		 		propertyValue1 = "41";
-                		    propertyName2 = "Batch Message ID";
-                		    propertyValue2 = "172,48";
-        		 			flag = 1;
-        		 		}
-        		 		else if (flag == 1)
-        		 		{
-        		 			propertyName1 = "Real Time Message ID";
-        		 			propertyValue1 = "172,48";
-        		 			propertyName2 = "Batch Message ID";
-        		 			propertyValue2 = "41";
-        		 			flag = 0;
-        		 		}
-        		 		uint32_t payloadSize = FlowControlMsgIDEncodingLen(PROCESSOR_NAME, processor.size()+1);
-        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_NAME, propertyName1.size()+1);
-        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_VALUE, propertyValue1.size()+1);
-        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_NAME, propertyName2.size()+1);
-        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_VALUE, propertyValue2.size()+1);
-
-        		 		uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
-        		 		uint8_t *data = new uint8_t[size];
-        		 		uint8_t *start = data;
-
-        		 		// encode the HDR
-        		 		hdr.msgType = REPORT_RESP;
-        		 		hdr.payloadLen = payloadSize;
-        		 		hdr.status = RESP_SUCCESS;
-
-        		 		if (number >= 10 && number < 20)
-        		 	    {
-        		 	        // After 10 second report, stop the flow controller for 10 second
-        		 	       hdr.status = RESP_STOP_FLOW_CONTROLLER;
-        		 	    }
-        		 		else if (number == 20)
-        		 		{
-        		 			// restart the flow controller after 10 second
-        		 			hdr.status = RESP_START_FLOW_CONTROLLER;
-        		 		}
-        		 		else if (number == 30)
-        		 		{
-        		 			// retrigger register
-        		 			hdr.status = RESP_TRIGGER_REGISTER;
-        		 			number = 0;
-        		 		}
-
-        		 	    number++;
-
-        		 		data = encode(data, hdr.msgType);
-        		 		data = encode(data, hdr.seqNumber);
-        		 		data = encode(data, hdr.status);
-        		 		data = encode(data, hdr.payloadLen);
-
-        		 		// encode the processorName
-        		 		data = encode(data, PROCESSOR_NAME);
-        		 		data = encode(data, processor);
-
-        		 		// encode the propertyName and value TLV
-        		 		data = encode(data, PROPERTY_NAME);
-            		 	data = encode(data, propertyName1);
-            		 	data = encode(data, PROPERTY_VALUE);
-            		 	data = encode(data, propertyValue1);
-            		 	data = encode(data, PROPERTY_NAME);
-            		 	data = encode(data, propertyName2);
-            		 	data = encode(data, PROPERTY_VALUE);
-            		 	data = encode(data, propertyValue2);
-        		 		// send it
-        		 		status = sendData(newsockfd, start, size);
-        		 		delete[] start;
-        		 	 }
-    		 }
-    		 close(newsockfd);
-    	 }
-    	 close(sockfd);
-     }
-     else
-     {
-    	 clilen = sizeof(cli_addr);
-    	 newsockfd = accept(sockfd,
-    	                (struct sockaddr *) &cli_addr,
-    	                 &clilen);
-    	 if (newsockfd < 0)
-    	    	error("ERROR on accept");
-    	 while (1)
-    	 {
-    	    	bzero(buffer,4096);
-    	    	n = readline(newsockfd,buffer,4095);
-    	    	if (n <= 0 )
-    	        {
-    	    		close(newsockfd);
-    	    		newsockfd = accept(sockfd,
-    	    		    	                (struct sockaddr *) &cli_addr,
-    	    		    	                 &clilen);
-    	    		continue;
-    	    	}
-    	    	printf("%s",buffer);
-    	  }
-    	  close(newsockfd);
-    	  close(sockfd);
-     }
-     return 0; 
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/thirdparty/yaml-cpp-yaml-cpp-0.5.3/Makefile
----------------------------------------------------------------------
diff --git a/thirdparty/yaml-cpp-yaml-cpp-0.5.3/Makefile b/thirdparty/yaml-cpp-yaml-cpp-0.5.3/Makefile
deleted file mode 100644
index f23f477..0000000
--- a/thirdparty/yaml-cpp-yaml-cpp-0.5.3/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-CFLAGS = -Wall
-INCLUDES = -I./include
-
-CPP_FILES := $(wildcard src/*.cpp)
-OBJ_FILES := $(addprefix build/,$(notdir $(CPP_FILES:.cpp=.o)))
-
-all: lib/libyaml-cpp.a
-
-lib:
-	mkdir -p ./lib
-
-build:
-	mkdir -p ./build
-
-lib/libyaml-cpp.a: $(OBJ_FILES)
-	mkdir -p ./lib
-	ar crs $@ $^
-
-build/%.o: src/%.cpp
-	mkdir -p ./build
-	g++ -Os $(INCLUDES) $(CC_FLAGS) -c -o $@ $<
-
-clean:
-	rm -rf ./lib ./build


[03/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/LogAttribute.cpp
----------------------------------------------------------------------
diff --git a/src/LogAttribute.cpp b/src/LogAttribute.cpp
deleted file mode 100644
index 82130f8..0000000
--- a/src/LogAttribute.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * @file LogAttribute.cpp
- * LogAttribute class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <sstream>
-#include <string.h>
-#include <iostream>
-
-#include "TimeUtil.h"
-#include "LogAttribute.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string LogAttribute::ProcessorName("LogAttribute");
-Property LogAttribute::LogLevel("Log Level", "The Log Level to use when logging the Attributes", "info");
-Property LogAttribute::AttributesToLog("Attributes to Log", "A comma-separated list of Attributes to Log. If not specified, all attributes will be logged.", "");
-Property LogAttribute::AttributesToIgnore("Attributes to Ignore", "A comma-separated list of Attributes to ignore. If not specified, no attributes will be ignored.", "");
-Property LogAttribute::LogPayload("Log Payload",
-		"If true, the FlowFile's payload will be logged, in addition to its attributes; otherwise, just the Attributes will be logged.", "false");
-Property LogAttribute::LogPrefix("Log prefix",
-		"Log prefix appended to the log lines. It helps to distinguish the output of multiple LogAttribute processors.", "");
-Relationship LogAttribute::Success("success", "success operational on the flow record");
-
-void LogAttribute::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(LogLevel);
-	properties.insert(AttributesToLog);
-	properties.insert(AttributesToIgnore);
-	properties.insert(LogPayload);
-	properties.insert(LogPrefix);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-}
-
-void LogAttribute::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string dashLine = "--------------------------------------------------";
-	LogAttrLevel level = LogAttrLevelInfo;
-	bool logPayload = false;
-	std::ostringstream message;
-
-	FlowFileRecord *flow = session->get();
-
-	if (!flow)
-		return;
-
-	std::string value;
-	if (context->getProperty(LogLevel.getName(), value))
-	{
-		logLevelStringToEnum(value, level);
-	}
-	if (context->getProperty(LogPrefix.getName(), value))
-	{
-		dashLine = "-----" + value + "-----";
-	}
-	if (context->getProperty(LogPayload.getName(), value))
-	{
-		Property::StringToBool(value, logPayload);
-	}
-
-	message << "Logging for flow file " << "\n";
-	message << dashLine;
-	message << "\nStandard FlowFile Attributes";
-	message << "\n" << "UUID:" << flow->getUUIDStr();
-	message << "\n" << "EntryDate:" << getTimeStr(flow->getEntryDate());
-	message << "\n" << "lineageStartDate:" << getTimeStr(flow->getlineageStartDate());
-	message << "\n" << "Size:" << flow->getSize() << " Offset:" << flow->getOffset();
-	message << "\nFlowFile Attributes Map Content";
-	std::map<std::string, std::string> attrs = flow->getAttributes();
-    std::map<std::string, std::string>::iterator it;
-    for (it = attrs.begin(); it!= attrs.end(); it++)
-    {
-    	message << "\n" << "key:" << it->first << " value:" << it->second;
-    }
-    message << "\nFlowFile Resource Claim Content";
-    ResourceClaim *claim = flow->getResourceClaim();
-    if (claim)
-    {
-    	message << "\n" << "Content Claim:" << claim->getContentFullPath();
-    }
-    if (logPayload && flow->getSize() <= 1024*1024)
-    {
-    	message << "\n" << "Payload:" << "\n";
-    	ReadCallback callback(flow->getSize());
-    	session->read(flow, &callback);
-    	for (unsigned int i = 0, j = 0; i < callback._readSize; i++)
-    	{
-    		char temp[8];
-    		sprintf(temp, "%02x ", (unsigned char) (callback._buffer[i]));
-    		message << temp;
-    		j++;
-    		if (j == 16)
-    		{
-    			message << '\n';
-    			j = 0;
-    		}
-    	}
-    }
-    message << "\n" << dashLine << std::ends;
-    std::string output = message.str();
-
-    switch (level)
-    {
-    case LogAttrLevelInfo:
-    	_logger->log_info("%s", output.c_str());
-		break;
-    case LogAttrLevelDebug:
-    	_logger->log_debug("%s", output.c_str());
-		break;
-    case LogAttrLevelError:
-    	_logger->log_error("%s", output.c_str());
-		break;
-    case LogAttrLevelTrace:
-    	_logger->log_trace("%s", output.c_str());
-    	break;
-    case LogAttrLevelWarn:
-    	_logger->log_warn("%s", output.c_str());
-    	break;
-    default:
-    	break;
-    }
-
-    // Test Import
-    /*
-    FlowFileRecord *importRecord = session->create();
-    session->import(claim->getContentFullPath(), importRecord);
-    session->transfer(importRecord, Success); */
-
-
-    // Transfer to the relationship
-    session->transfer(flow, Success);
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Logger.cpp
----------------------------------------------------------------------
diff --git a/src/Logger.cpp b/src/Logger.cpp
deleted file mode 100644
index 984f609..0000000
--- a/src/Logger.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * @file Logger.cpp
- * Logger class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-
-#include "Logger.h"
-
-Logger *Logger::_logger(NULL);
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/ProcessGroup.cpp
----------------------------------------------------------------------
diff --git a/src/ProcessGroup.cpp b/src/ProcessGroup.cpp
deleted file mode 100644
index 70ee9d7..0000000
--- a/src/ProcessGroup.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/**
- * @file ProcessGroup.cpp
- * ProcessGroup class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-
-#include "ProcessGroup.h"
-#include "Processor.h"
-
-ProcessGroup::ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid, ProcessGroup *parent)
-: _name(name),
-  _type(type),
-  _parentProcessGroup(parent)
-{
-	if (!uuid)
-		// Generate the global UUID for the flow record
-		uuid_generate(_uuid);
-	else
-		uuid_copy(_uuid, uuid);
-
-	_yieldPeriodMsec = 0;
-	_transmitting = false;
-
-	_logger = Logger::getLogger();
-	_logger->log_info("ProcessGroup %s created", _name.c_str());
-}
-
-ProcessGroup::~ProcessGroup()
-{
-	for (std::set<Connection *>::iterator it = _connections.begin(); it != _connections.end(); ++it)
-	{
-		Connection *connection = *it;
-		connection->drain();
-		delete connection;
-	}
-
-	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-	{
-		ProcessGroup *processGroup(*it);
-		delete processGroup;
-	}
-
-	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-	{
-		Processor *processor(*it);
-		delete processor;
-	}
-}
-
-bool ProcessGroup::isRootProcessGroup()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-	return (_type == ROOT_PROCESS_GROUP);
-}
-
-void ProcessGroup::addProcessor(Processor *processor)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_processors.find(processor) == _processors.end())
-	{
-		// We do not have the same processor in this process group yet
-		_processors.insert(processor);
-		_logger->log_info("Add processor %s into process group %s",
-				processor->getName().c_str(), _name.c_str());
-	}
-}
-
-void ProcessGroup::removeProcessor(Processor *processor)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_processors.find(processor) != _processors.end())
-	{
-		// We do have the same processor in this process group yet
-		_processors.erase(processor);
-		_logger->log_info("Remove processor %s from process group %s",
-				processor->getName().c_str(), _name.c_str());
-	}
-}
-
-void ProcessGroup::addProcessGroup(ProcessGroup *child)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_childProcessGroups.find(child) == _childProcessGroups.end())
-	{
-		// We do not have the same child process group in this process group yet
-		_childProcessGroups.insert(child);
-		_logger->log_info("Add child process group %s into process group %s",
-				child->getName().c_str(), _name.c_str());
-	}
-}
-
-void ProcessGroup::removeProcessGroup(ProcessGroup *child)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_childProcessGroups.find(child) != _childProcessGroups.end())
-	{
-		// We do have the same child process group in this process group yet
-		_childProcessGroups.erase(child);
-		_logger->log_info("Remove child process group %s from process group %s",
-				child->getName().c_str(), _name.c_str());
-	}
-}
-
-void ProcessGroup::startProcessing(TimerDrivenSchedulingAgent *timeScheduler)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	try
-	{
-		// Start all the processor node, input and output ports
-		for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-		{
-			Processor *processor(*it);
-			if (!processor->isRunning() && processor->getScheduledState() != DISABLED)
-			{
-				if (processor->getSchedulingStrategy() == TIMER_DRIVEN)
-					timeScheduler->schedule(processor);
-			}
-		}
-
-		for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-		{
-			ProcessGroup *processGroup(*it);
-			processGroup->startProcessing(timeScheduler);
-		}
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process group start processing");
-		throw;
-	}
-}
-
-void ProcessGroup::stopProcessing(TimerDrivenSchedulingAgent *timeScheduler)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	try
-	{
-		// Stop all the processor node, input and output ports
-		for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-		{
-			Processor *processor(*it);
-			if (processor->getSchedulingStrategy() == TIMER_DRIVEN)
-					timeScheduler->unschedule(processor);
-		}
-
-		for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-		{
-			ProcessGroup *processGroup(*it);
-			processGroup->stopProcessing(timeScheduler);
-		}
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process group stop processing");
-		throw;
-	}
-}
-
-Processor *ProcessGroup::findProcessor(uuid_t uuid)
-{
-	Processor *ret = NULL;
-	// std::lock_guard<std::mutex> lock(_mtx);
-
-	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-	{
-		Processor *processor(*it);
-		uuid_t processorUUID;
-		if (processor->getUUID(processorUUID) && uuid_compare(processorUUID, uuid) == 0)
-			return processor;
-	}
-
-	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-	{
-		ProcessGroup *processGroup(*it);
-		Processor *processor = processGroup->findProcessor(uuid);
-		if (processor)
-			return processor;
-	}
-
-	return ret;
-}
-
-Processor *ProcessGroup::findProcessor(std::string processorName)
-{
-	Processor *ret = NULL;
-
-	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-	{
-		Processor *processor(*it);
-		_logger->log_debug("Current processor is %s", processor->getName().c_str());
-		if (processor->getName() == processorName)
-			return processor;
-	}
-
-	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-	{
-		ProcessGroup *processGroup(*it);
-		Processor *processor = processGroup->findProcessor(processorName);
-		if (processor)
-			return processor;
-	}
-
-	return ret;
-}
-
-void ProcessGroup::updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
-	{
-		Processor *processor(*it);
-		if (processor->getName() == processorName)
-		{
-			processor->setProperty(propertyName, propertyValue);
-		}
-	}
-
-	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
-	{
-		ProcessGroup *processGroup(*it);
-		processGroup->updatePropertyValue(processorName, propertyName, propertyValue);
-	}
-
-	return;
-}
-
-void ProcessGroup::addConnection(Connection *connection)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_connections.find(connection) == _connections.end())
-	{
-		// We do not have the same connection in this process group yet
-		_connections.insert(connection);
-		_logger->log_info("Add connection %s into process group %s",
-				connection->getName().c_str(), _name.c_str());
-		uuid_t sourceUUID;
-		Processor *source = NULL;
-		connection->getSourceProcessorUUID(sourceUUID);
-		source = this->findProcessor(sourceUUID);
-		if (source)
-			source->addConnection(connection);
-		Processor *destination = NULL;
-		uuid_t destinationUUID;
-		connection->getDestinationProcessorUUID(destinationUUID);
-		destination = this->findProcessor(destinationUUID);
-		if (destination && destination != source)
-			destination->addConnection(connection);
-	}
-}
-
-void ProcessGroup::removeConnection(Connection *connection)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_connections.find(connection) != _connections.end())
-	{
-		// We do not have the same connection in this process group yet
-		_connections.erase(connection);
-		_logger->log_info("Remove connection %s into process group %s",
-				connection->getName().c_str(), _name.c_str());
-		uuid_t sourceUUID;
-		Processor *source = NULL;
-		connection->getSourceProcessorUUID(sourceUUID);
-		source = this->findProcessor(sourceUUID);
-		if (source)
-			source->removeConnection(connection);
-		Processor *destination = NULL;
-		uuid_t destinationUUID;
-		connection->getDestinationProcessorUUID(destinationUUID);
-		destination = this->findProcessor(destinationUUID);
-		if (destination && destination != source)
-			destination->removeConnection(connection);
-	}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/ProcessSession.cpp
----------------------------------------------------------------------
diff --git a/src/ProcessSession.cpp b/src/ProcessSession.cpp
deleted file mode 100644
index 4f526c3..0000000
--- a/src/ProcessSession.cpp
+++ /dev/null
@@ -1,731 +0,0 @@
-/**
- * @file ProcessSession.cpp
- * ProcessSession class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <iostream>
-
-#include "ProcessSession.h"
-
-FlowFileRecord* ProcessSession::create()
-{
-	std::map<std::string, std::string> empty;
-	FlowFileRecord *record = new FlowFileRecord(empty);
-
-	if (record)
-	{
-		_addedFlowFiles[record->getUUIDStr()] = record;
-		_logger->log_debug("Create FlowFile with UUID %s", record->getUUIDStr().c_str());
-	}
-
-	return record;
-}
-
-FlowFileRecord* ProcessSession::create(FlowFileRecord *parent)
-{
-	FlowFileRecord *record = this->create();
-	if (record)
-	{
-		// Copy attributes
-		std::map<std::string, std::string> parentAttributes = parent->getAttributes();
-	    std::map<std::string, std::string>::iterator it;
-	    for (it = parentAttributes.begin(); it!= parentAttributes.end(); it++)
-	    {
-	    	if (it->first == FlowAttributeKey(ALTERNATE_IDENTIFIER) ||
-	    			it->first == FlowAttributeKey(DISCARD_REASON) ||
-					it->first == FlowAttributeKey(UUID))
-	    		// Do not copy special attributes from parent
-	    		continue;
-	    	record->setAttribute(it->first, it->second);
-	    }
-	    record->_lineageStartDate = parent->_lineageStartDate;
-	    record->_lineageIdentifiers = parent->_lineageIdentifiers;
-	    record->_lineageIdentifiers.insert(parent->_uuidStr);
-
-	}
-	return record;
-}
-
-FlowFileRecord* ProcessSession::clone(FlowFileRecord *parent)
-{
-	FlowFileRecord *record = this->create(parent);
-	if (record)
-	{
-		// Copy Resource Claim
-		record->_claim = parent->_claim;
-		if (record->_claim)
-		{
-			record->_offset = parent->_offset;
-			record->_size = parent->_size;
-			record->_claim->increaseFlowFileRecordOwnedCount();
-		}
-	}
-	return record;
-}
-
-FlowFileRecord* ProcessSession::cloneDuringTransfer(FlowFileRecord *parent)
-{
-	std::map<std::string, std::string> empty;
-	FlowFileRecord *record = new FlowFileRecord(empty);
-
-	if (record)
-	{
-		this->_clonedFlowFiles[record->getUUIDStr()] = record;
-		_logger->log_debug("Clone FlowFile with UUID %s during transfer", record->getUUIDStr().c_str());
-		// Copy attributes
-		std::map<std::string, std::string> parentAttributes = parent->getAttributes();
-		std::map<std::string, std::string>::iterator it;
-		for (it = parentAttributes.begin(); it!= parentAttributes.end(); it++)
-		{
-			if (it->first == FlowAttributeKey(ALTERNATE_IDENTIFIER) ||
-	    			it->first == FlowAttributeKey(DISCARD_REASON) ||
-					it->first == FlowAttributeKey(UUID))
-	    		// Do not copy special attributes from parent
-	    		continue;
-	    	record->setAttribute(it->first, it->second);
-	    }
-	    record->_lineageStartDate = parent->_lineageStartDate;
-	    record->_lineageIdentifiers = parent->_lineageIdentifiers;
-	    record->_lineageIdentifiers.insert(parent->_uuidStr);
-
-	    // Copy Resource Claim
-	    record->_claim = parent->_claim;
-	    if (record->_claim)
-	    {
-	    	record->_offset = parent->_offset;
-	    	record->_size = parent->_size;
-	    	record->_claim->increaseFlowFileRecordOwnedCount();
-	    }
-	}
-
-	return record;
-}
-
-FlowFileRecord* ProcessSession::clone(FlowFileRecord *parent, long offset, long size)
-{
-	FlowFileRecord *record = this->create(parent);
-	if (record)
-	{
-		if (parent->_claim)
-		{
-			if ((offset + size) > (long) parent->_size)
-			{
-				// Set offset and size
-				_logger->log_error("clone offset %d and size %d exceed parent size %d",
-						offset, size, parent->_size);
-				// Remove the Add FlowFile for the session
-				std::map<std::string, FlowFileRecord *>::iterator it =
-						this->_addedFlowFiles.find(record->getUUIDStr());
-				if (it != this->_addedFlowFiles.end())
-					this->_addedFlowFiles.erase(record->getUUIDStr());
-				delete record;
-				return NULL;
-			}
-			record->_offset = parent->_offset + parent->_offset;
-			record->_size = size;
-			// Copy Resource Claim
-			record->_claim = parent->_claim;
-			record->_claim->increaseFlowFileRecordOwnedCount();
-		}
-	}
-	return record;
-}
-
-void ProcessSession::remove(FlowFileRecord *flow)
-{
-	flow->_markedDelete = true;
-	_deletedFlowFiles[flow->getUUIDStr()] = flow;
-}
-
-void ProcessSession::putAttribute(FlowFileRecord *flow, std::string key, std::string value)
-{
-	flow->setAttribute(key, value);
-}
-
-void ProcessSession::removeAttribute(FlowFileRecord *flow, std::string key)
-{
-	flow->removeAttribute(key);
-}
-
-void ProcessSession::penalize(FlowFileRecord *flow)
-{
-	flow->_penaltyExpirationMs = getTimeMillis() + this->_processContext->getProcessor()->getPenalizationPeriodMsec();
-}
-
-void ProcessSession::transfer(FlowFileRecord *flow, Relationship relationship)
-{
-	_transferRelationship[flow->getUUIDStr()] = relationship;
-}
-
-void ProcessSession::write(FlowFileRecord *flow, OutputStreamCallback *callback)
-{
-	ResourceClaim *claim = NULL;
-
-	claim = new ResourceClaim(DEFAULT_CONTENT_DIRECTORY);
-
-	try
-	{
-		std::ofstream fs;
-		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
-		if (fs.is_open())
-		{
-			// Call the callback to write the content
-			callback->process(&fs);
-			if (fs.good() && fs.tellp() >= 0)
-			{
-				flow->_size = fs.tellp();
-				flow->_offset = 0;
-				if (flow->_claim)
-				{
-					// Remove the old claim
-					flow->_claim->decreaseFlowFileRecordOwnedCount();
-					flow->_claim = NULL;
-				}
-				flow->_claim = claim;
-				claim->increaseFlowFileRecordOwnedCount();
-				/*
-				_logger->log_debug("Write offset %d length %d into content %s for FlowFile UUID %s",
-						flow->_offset, flow->_size, flow->_claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
-				fs.close();
-			}
-			else
-			{
-				fs.close();
-				throw Exception(FILE_OPERATION_EXCEPTION, "File Write Error");
-			}
-		}
-		else
-		{
-			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
-		}
-	}
-	catch (std::exception &exception)
-	{
-		if (flow && flow->_claim == claim)
-		{
-			flow->_claim->decreaseFlowFileRecordOwnedCount();
-			flow->_claim = NULL;
-		}
-		if (claim)
-			delete claim;
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		if (flow && flow->_claim == claim)
-		{
-			flow->_claim->decreaseFlowFileRecordOwnedCount();
-			flow->_claim = NULL;
-		}
-		if (claim)
-			delete claim;
-		_logger->log_debug("Caught Exception during process session write");
-		throw;
-	}
-}
-
-void ProcessSession::append(FlowFileRecord *flow, OutputStreamCallback *callback)
-{
-	ResourceClaim *claim = NULL;
-
-	if (flow->_claim == NULL)
-	{
-		// No existed claim for append, we need to create new claim
-		return write(flow, callback);
-	}
-
-	claim = flow->_claim;
-
-	try
-	{
-		std::ofstream fs;
-		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::app);
-		if (fs.is_open())
-		{
-			// Call the callback to write the content
-			std::streampos oldPos = fs.tellp();
-			callback->process(&fs);
-			if (fs.good() && fs.tellp() >= 0)
-			{
-				uint64_t appendSize = fs.tellp() - oldPos;
-				flow->_size += appendSize;
-				/*
-				_logger->log_debug("Append offset %d extra length %d to new size %d into content %s for FlowFile UUID %s",
-						flow->_offset, appendSize, flow->_size, claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
-				fs.close();
-			}
-			else
-			{
-				fs.close();
-				throw Exception(FILE_OPERATION_EXCEPTION, "File Write Error");
-			}
-		}
-		else
-		{
-			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
-		}
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process session append");
-		throw;
-	}
-}
-
-void ProcessSession::read(FlowFileRecord *flow, InputStreamCallback *callback)
-{
-	try
-	{
-		ResourceClaim *claim = NULL;
-		if (flow->_claim == NULL)
-		{
-			// No existed claim for read, we throw exception
-			throw Exception(FILE_OPERATION_EXCEPTION, "No Content Claim existed for read");
-		}
-
-		claim = flow->_claim;
-		std::ifstream fs;
-		fs.open(claim->getContentFullPath().c_str(), std::fstream::in | std::fstream::binary);
-		if (fs.is_open())
-		{
-			fs.seekg(flow->_offset, fs.beg);
-
-			if (fs.good())
-			{
-				callback->process(&fs);
-				/*
-				_logger->log_debug("Read offset %d size %d content %s for FlowFile UUID %s",
-						flow->_offset, flow->_size, claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
-				fs.close();
-			}
-			else
-			{
-				fs.close();
-				throw Exception(FILE_OPERATION_EXCEPTION, "File Read Error");
-			}
-		}
-		else
-		{
-			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
-		}
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process session read");
-		throw;
-	}
-}
-
-void ProcessSession::import(std::string source, FlowFileRecord *flow, bool keepSource, uint64_t offset)
-{
-	ResourceClaim *claim = NULL;
-
-	claim = new ResourceClaim(DEFAULT_CONTENT_DIRECTORY);
-	char *buf = NULL;
-	int size = 4096;
-	buf = new char [size];
-
-	try
-	{
-		std::ofstream fs;
-		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
-		std::ifstream input;
-		input.open(source.c_str(), std::fstream::in | std::fstream::binary);
-
-		if (fs.is_open() && input.is_open())
-		{
-			// Open the source file and stream to the flow file
-			input.seekg(offset, fs.beg);
-			while (input.good())
-			{
-				input.read(buf, size);
-				if (input)
-					fs.write(buf, size);
-				else
-					fs.write(buf, input.gcount());
-			}
-
-			if (fs.good() && fs.tellp() >= 0)
-			{
-				flow->_size = fs.tellp();
-				flow->_offset = 0;
-				if (flow->_claim)
-				{
-					// Remove the old claim
-					flow->_claim->decreaseFlowFileRecordOwnedCount();
-					flow->_claim = NULL;
-				}
-				flow->_claim = claim;
-				claim->increaseFlowFileRecordOwnedCount();
-				/*
-				_logger->log_debug("Import offset %d length %d into content %s for FlowFile UUID %s",
-						flow->_offset, flow->_size, flow->_claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
-				fs.close();
-				input.close();
-				if (!keepSource)
-					std::remove(source.c_str());
-			}
-			else
-			{
-				fs.close();
-				input.close();
-				throw Exception(FILE_OPERATION_EXCEPTION, "File Import Error");
-			}
-		}
-		else
-		{
-			throw Exception(FILE_OPERATION_EXCEPTION, "File Import Error");
-		}
-
-		delete[] buf;
-	}
-	catch (std::exception &exception)
-	{
-		if (flow && flow->_claim == claim)
-		{
-			flow->_claim->decreaseFlowFileRecordOwnedCount();
-			flow->_claim = NULL;
-		}
-		if (claim)
-			delete claim;
-		_logger->log_debug("Caught Exception %s", exception.what());
-		delete[] buf;
-		throw;
-	}
-	catch (...)
-	{
-		if (flow && flow->_claim == claim)
-		{
-			flow->_claim->decreaseFlowFileRecordOwnedCount();
-			flow->_claim = NULL;
-		}
-		if (claim)
-			delete claim;
-		_logger->log_debug("Caught Exception during process session write");
-		delete[] buf;
-		throw;
-	}
-}
-
-void ProcessSession::commit()
-{
-	try
-	{
-		// First we clone the flow record based on the transfered relationship for updated flow record
-		std::map<std::string, FlowFileRecord *>::iterator it;
-		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_markedDelete)
-				continue;
-			std::map<std::string, Relationship>::iterator itRelationship =
-					this->_transferRelationship.find(record->getUUIDStr());
-			if (itRelationship != _transferRelationship.end())
-			{
-				Relationship relationship = itRelationship->second;
-				// Find the relationship, we need to find the connections for that relationship
-				std::set<Connection *> connections =
-						_processContext->getProcessor()->getOutGoingConnections(relationship.getName());
-				if (connections.empty())
-				{
-					// No connection
-					if (!_processContext->getProcessor()->isAutoTerminated(relationship))
-					{
-						// Not autoterminate, we should have the connect
-						std::string message = "Connect empty for non auto terminated relationship" + relationship.getName();
-						throw Exception(PROCESS_SESSION_EXCEPTION, message.c_str());
-					}
-					else
-					{
-						// Autoterminated
-						remove(record);
-					}
-				}
-				else
-				{
-					// We connections, clone the flow and assign the connection accordingly
-					for (std::set<Connection *>::iterator itConnection = connections.begin(); itConnection != connections.end(); ++itConnection)
-					{
-						Connection *connection(*itConnection);
-						if (itConnection == connections.begin())
-						{
-							// First connection which the flow need be routed to
-							record->_connection = connection;
-						}
-						else
-						{
-							// Clone the flow file and route to the connection
-							FlowFileRecord *cloneRecord;
-							cloneRecord = this->cloneDuringTransfer(record);
-							if (cloneRecord)
-								cloneRecord->_connection = connection;
-							else
-								throw Exception(PROCESS_SESSION_EXCEPTION, "Can not clone the flow for transfer");
-						}
-					}
-				}
-			}
-			else
-			{
-				// Can not find relationship for the flow
-				throw Exception(PROCESS_SESSION_EXCEPTION, "Can not find the transfer relationship for the flow");
-			}
-		}
-
-		// Do the samething for added flow file
-		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_markedDelete)
-				continue;
-			std::map<std::string, Relationship>::iterator itRelationship =
-					this->_transferRelationship.find(record->getUUIDStr());
-			if (itRelationship != _transferRelationship.end())
-			{
-				Relationship relationship = itRelationship->second;
-				// Find the relationship, we need to find the connections for that relationship
-				std::set<Connection *> connections =
-						_processContext->getProcessor()->getOutGoingConnections(relationship.getName());
-				if (connections.empty())
-				{
-					// No connection
-					if (!_processContext->getProcessor()->isAutoTerminated(relationship))
-					{
-						// Not autoterminate, we should have the connect
-						std::string message = "Connect empty for non auto terminated relationship " + relationship.getName();
-						throw Exception(PROCESS_SESSION_EXCEPTION, message.c_str());
-					}
-					else
-					{
-						// Autoterminated
-						remove(record);
-					}
-				}
-				else
-				{
-					// We connections, clone the flow and assign the connection accordingly
-					for (std::set<Connection *>::iterator itConnection = connections.begin(); itConnection != connections.end(); ++itConnection)
-					{
-						Connection *connection(*itConnection);
-						if (itConnection == connections.begin())
-						{
-							// First connection which the flow need be routed to
-							record->_connection = connection;
-						}
-						else
-						{
-							// Clone the flow file and route to the connection
-							FlowFileRecord *cloneRecord;
-							cloneRecord = this->cloneDuringTransfer(record);
-							if (cloneRecord)
-								cloneRecord->_connection = connection;
-							else
-								throw Exception(PROCESS_SESSION_EXCEPTION, "Can not clone the flow for transfer");
-						}
-					}
-				}
-			}
-			else
-			{
-				// Can not find relationship for the flow
-				throw Exception(PROCESS_SESSION_EXCEPTION, "Can not find the transfer relationship for the flow");
-			}
-		}
-
-		// Complete process the added and update flow files for the session, send the flow file to its queue
-		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_markedDelete)
-			{
-				continue;
-			}
-			if (record->_connection)
-				record->_connection->put(record);
-			else
-				delete record;
-		}
-		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_markedDelete)
-			{
-				continue;
-			}
-			if (record->_connection)
-				record->_connection->put(record);
-			else
-				delete record;
-		}
-		// Process the clone flow files
-		for (it = _clonedFlowFiles.begin(); it!= _clonedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_markedDelete)
-			{
-				continue;
-			}
-			if (record->_connection)
-				record->_connection->put(record);
-			else
-				delete record;
-		}
-		// Delete the deleted flow files
-		for (it = _deletedFlowFiles.begin(); it!= _deletedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			delete record;
-		}
-		// Delete the snapshot
-		for (it = _originalFlowFiles.begin(); it!= _originalFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			delete record;
-		}
-		// All done
-		_updatedFlowFiles.clear();
-		_addedFlowFiles.clear();
-		_clonedFlowFiles.clear();
-		_deletedFlowFiles.clear();
-		_originalFlowFiles.clear();
-		_logger->log_trace("ProcessSession committed for %s", _processContext->getProcessor()->getName().c_str());
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process session commit");
-		throw;
-	}
-}
-
-
-void ProcessSession::rollback()
-{
-	try
-	{
-		std::map<std::string, FlowFileRecord *>::iterator it;
-		// Requeue the snapshot of the flowfile back
-		for (it = _originalFlowFiles.begin(); it!= _originalFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			if (record->_orginalConnection)
-			{
-				record->_snapshot = false;
-				record->_orginalConnection->put(record);
-			}
-			else
-				delete record;
-		}
-		_originalFlowFiles.clear();
-		// Process the clone flow files
-		for (it = _clonedFlowFiles.begin(); it!= _clonedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			delete record;
-		}
-		_clonedFlowFiles.clear();
-		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			delete record;
-		}
-		_addedFlowFiles.clear();
-		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
-		{
-			FlowFileRecord *record = it->second;
-			delete record;
-		}
-		_updatedFlowFiles.clear();
-		_deletedFlowFiles.clear();
-		_logger->log_trace("ProcessSession rollback for %s", _processContext->getProcessor()->getName().c_str());
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during process session roll back");
-		throw;
-	}
-}
-
-FlowFileRecord *ProcessSession::get()
-{
-	Connection *first = _processContext->getProcessor()->getNextIncomingConnection();
-
-	if (first == NULL)
-		return NULL;
-
-	Connection *current = first;
-
-	do
-	{
-		std::set<FlowFileRecord *> expired;
-		FlowFileRecord *ret = current->poll(expired);
-		if (expired.size() > 0)
-		{
-			// Remove expired flow record
-			for (std::set<FlowFileRecord *>::iterator it = expired.begin(); it != expired.end(); ++it)
-			{
-				delete (*it);
-			}
-		}
-		if (ret)
-		{
-			// add the flow record to the current process session update map
-			ret->_markedDelete = false;
-			_updatedFlowFiles[ret->getUUIDStr()] = ret;
-			std::map<std::string, std::string> empty;
-			FlowFileRecord *snapshot = new FlowFileRecord(empty);
-			_logger->log_debug("Create Snapshot FlowFile with UUID %s", snapshot->getUUIDStr().c_str());
-			snapshot->duplicate(ret);
-			// save a snapshot
-			_originalFlowFiles[snapshot->getUUIDStr()] = snapshot;
-			return ret;
-		}
-		current = _processContext->getProcessor()->getNextIncomingConnection();
-	}
-	while (current != NULL && current != first);
-
-	return NULL;
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Processor.cpp
----------------------------------------------------------------------
diff --git a/src/Processor.cpp b/src/Processor.cpp
deleted file mode 100644
index cc136dc..0000000
--- a/src/Processor.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-/**
- * @file Processor.cpp
- * Processor class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-
-#include "Processor.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-Processor::Processor(std::string name, uuid_t uuid)
-: _name(name)
-{
-	if (!uuid)
-		// Generate the global UUID for the flow record
-		uuid_generate(_uuid);
-	else
-		uuid_copy(_uuid, uuid);
-
-	char uuidStr[37];
-	uuid_unparse(_uuid, uuidStr);
-	_uuidStr = uuidStr;
-
-	// Setup the default values
-	_state = DISABLED;
-	_strategy = TIMER_DRIVEN;
-	_lossTolerant = false;
-	_triggerWhenEmpty = false;
-	_schedulingPeriodNano = MINIMUM_SCHEDULING_NANOS;
-	_runDurantionNano = 0;
-	_yieldPeriodMsec = DEFAULT_YIELD_PERIOD_SECONDS * 1000;
-	_penalizationPeriodMsec = DEFAULT_PENALIZATION_PERIOD_SECONDS * 1000;
-	_maxConcurrentTasks = 1;
-	_activeTasks = 0;
-	_yieldExpiration = 0;
-	_incomingConnectionsIter = this->_incomingConnections.begin();
-	_logger = Logger::getLogger();
-
-	_logger->log_info("Processor %s created UUID %s", _name.c_str(), _uuidStr.c_str());
-}
-
-Processor::~Processor()
-{
-
-}
-
-bool Processor::isRunning()
-{
-	return (_state == RUNNING && _activeTasks > 0);
-}
-
-bool Processor::setSupportedProperties(std::set<Property> properties)
-{
-	if (isRunning())
-	{
-		_logger->log_info("Can not set processor property while the process %s is running",
-				_name.c_str());
-		return false;
-	}
-
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_properties.clear();
-	for (std::set<Property>::iterator it = properties.begin(); it != properties.end(); ++it)
-	{
-		Property item(*it);
-		_properties[item.getName()] = item;
-		_logger->log_info("Processor %s supported property name %s", _name.c_str(), item.getName().c_str());
-	}
-
-	return true;
-}
-
-bool Processor::setSupportedRelationships(std::set<Relationship> relationships)
-{
-	if (isRunning())
-	{
-		_logger->log_info("Can not set processor supported relationship while the process %s is running",
-				_name.c_str());
-		return false;
-	}
-
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_relationships.clear();
-	for (std::set<Relationship>::iterator it = relationships.begin(); it != relationships.end(); ++it)
-	{
-		Relationship item(*it);
-		_relationships[item.getName()] = item;
-		_logger->log_info("Processor %s supported relationship name %s", _name.c_str(), item.getName().c_str());
-	}
-
-	return true;
-}
-
-bool Processor::setAutoTerminatedRelationships(std::set<Relationship> relationships)
-{
-	if (isRunning())
-	{
-		_logger->log_info("Can not set processor auto terminated relationship while the process %s is running",
-				_name.c_str());
-		return false;
-	}
-
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_autoTerminatedRelationships.clear();
-	for (std::set<Relationship>::iterator it = relationships.begin(); it != relationships.end(); ++it)
-	{
-		Relationship item(*it);
-		_autoTerminatedRelationships[item.getName()] = item;
-		_logger->log_info("Processor %s auto terminated relationship name %s", _name.c_str(), item.getName().c_str());
-	}
-
-	return true;
-}
-
-bool Processor::isAutoTerminated(Relationship relationship)
-{
-	bool isRun = isRunning();
-
-	if (!isRun)
-		_mtx.lock();
-
-	std::map<std::string, Relationship>::iterator it = _autoTerminatedRelationships.find(relationship.getName());
-	if (it != _autoTerminatedRelationships.end())
-	{
-		if (!isRun)
-			_mtx.unlock();
-		return true;
-	}
-	else
-	{
-		if (!isRun)
-			_mtx.unlock();
-		return false;
-	}
-}
-
-bool Processor::isSupportedRelationship(Relationship relationship)
-{
-	bool isRun = isRunning();
-
-	if (!isRun)
-		_mtx.lock();
-
-	std::map<std::string, Relationship>::iterator it = _relationships.find(relationship.getName());
-	if (it != _relationships.end())
-	{
-		if (!isRun)
-			_mtx.unlock();
-		return true;
-	}
-	else
-	{
-		if (!isRun)
-			_mtx.unlock();
-		return false;
-	}
-}
-
-bool Processor::getProperty(std::string name, std::string &value)
-{
-	bool isRun = isRunning();
-
-	if (!isRun)
-		// Because set property only allowed in non running state, we need to obtain lock avoid rack condition
-		_mtx.lock();
-
-	std::map<std::string, Property>::iterator it = _properties.find(name);
-	if (it != _properties.end())
-	{
-		Property item = it->second;
-		value = item.getValue();
-		if (!isRun)
-			_mtx.unlock();
-		return true;
-	}
-	else
-	{
-		if (!isRun)
-			_mtx.unlock();
-		return false;
-	}
-}
-
-bool Processor::setProperty(std::string name, std::string value)
-{
-
-	std::lock_guard<std::mutex> lock(_mtx);
-	std::map<std::string, Property>::iterator it = _properties.find(name);
-
-	if (it != _properties.end())
-	{
-		Property item = it->second;
-		item.setValue(value);
-		_properties[item.getName()] = item;
-		_logger->log_info("Processor %s property name %s value %s", _name.c_str(), item.getName().c_str(), value.c_str());
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-std::set<Connection *> Processor::getOutGoingConnections(std::string relationship)
-{
-	std::set<Connection *> empty;
-
-	std::map<std::string, std::set<Connection *>>::iterator it = _outGoingConnections.find(relationship);
-	if (it != _outGoingConnections.end())
-	{
-		return _outGoingConnections[relationship];
-	}
-	else
-	{
-		return empty;
-	}
-}
-
-bool Processor::addConnection(Connection *connection)
-{
-	bool ret = false;
-
-	if (isRunning())
-	{
-		_logger->log_info("Can not add connection while the process %s is running",
-				_name.c_str());
-		return false;
-	}
-
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	uuid_t srcUUID;
-	uuid_t destUUID;
-
-	connection->getSourceProcessorUUID(srcUUID);
-	connection->getDestinationProcessorUUID(destUUID);
-
-	if (uuid_compare(_uuid, destUUID) == 0)
-	{
-		// Connection is destination to the current processor
-		if (_incomingConnections.find(connection) == _incomingConnections.end())
-		{
-			_incomingConnections.insert(connection);
-			connection->setDestinationProcessor(this);
-			_logger->log_info("Add connection %s into Processor %s incoming connection",
-					connection->getName().c_str(), _name.c_str());
-			_incomingConnectionsIter = this->_incomingConnections.begin();
-			ret = true;
-		}
-	}
-
-	if (uuid_compare(_uuid, srcUUID) == 0)
-	{
-		std::string relationship = connection->getRelationship().getName();
-		// Connection is source from the current processor
-		std::map<std::string, std::set<Connection *>>::iterator it =
-				_outGoingConnections.find(relationship);
-		if (it != _outGoingConnections.end())
-		{
-			// We already has connection for this relationship
-			std::set<Connection *> existedConnection = it->second;
-			if (existedConnection.find(connection) == existedConnection.end())
-			{
-				// We do not have the same connection for this relationship yet
-				existedConnection.insert(connection);
-				connection->setSourceProcessor(this);
-				_outGoingConnections[relationship] = existedConnection;
-				_logger->log_info("Add connection %s into Processor %s outgoing connection for relationship %s",
-												connection->getName().c_str(), _name.c_str(), relationship.c_str());
-				ret = true;
-			}
-		}
-		else
-		{
-			// We do not have any outgoing connection for this relationship yet
-			std::set<Connection *> newConnection;
-			newConnection.insert(connection);
-			connection->setSourceProcessor(this);
-			_outGoingConnections[relationship] = newConnection;
-			_logger->log_info("Add connection %s into Processor %s outgoing connection for relationship %s",
-								connection->getName().c_str(), _name.c_str(), relationship.c_str());
-			ret = true;
-		}
-	}
-
-	return ret;
-}
-
-void Processor::removeConnection(Connection *connection)
-{
-	if (isRunning())
-	{
-		_logger->log_info("Can not remove connection while the process %s is running",
-				_name.c_str());
-		return;
-	}
-
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	uuid_t srcUUID;
-	uuid_t destUUID;
-
-	connection->getSourceProcessorUUID(srcUUID);
-	connection->getDestinationProcessorUUID(destUUID);
-
-	if (uuid_compare(_uuid, destUUID) == 0)
-	{
-		// Connection is destination to the current processor
-		if (_incomingConnections.find(connection) != _incomingConnections.end())
-		{
-			_incomingConnections.erase(connection);
-			connection->setDestinationProcessor(NULL);
-			_logger->log_info("Remove connection %s into Processor %s incoming connection",
-					connection->getName().c_str(), _name.c_str());
-			_incomingConnectionsIter = this->_incomingConnections.begin();
-		}
-	}
-
-	if (uuid_compare(_uuid, srcUUID) == 0)
-	{
-		std::string relationship = connection->getRelationship().getName();
-		// Connection is source from the current processor
-		std::map<std::string, std::set<Connection *>>::iterator it =
-				_outGoingConnections.find(relationship);
-		if (it == _outGoingConnections.end())
-		{
-			return;
-		}
-		else
-		{
-			if (_outGoingConnections[relationship].find(connection) != _outGoingConnections[relationship].end())
-			{
-				_outGoingConnections[relationship].erase(connection);
-				connection->setSourceProcessor(NULL);
-				_logger->log_info("Remove connection %s into Processor %s outgoing connection for relationship %s",
-								connection->getName().c_str(), _name.c_str(), relationship.c_str());
-			}
-		}
-	}
-}
-
-Connection *Processor::getNextIncomingConnection()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_incomingConnections.size() == 0)
-		return NULL;
-
-	if (_incomingConnectionsIter == _incomingConnections.end())
-		_incomingConnectionsIter = _incomingConnections.begin();
-
-	Connection *ret = *_incomingConnectionsIter;
-	_incomingConnectionsIter++;
-
-	if (_incomingConnectionsIter == _incomingConnections.end())
-		_incomingConnectionsIter = _incomingConnections.begin();
-
-	return ret;
-}
-
-bool Processor::flowFilesQueued()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_incomingConnections.size() == 0)
-		return false;
-
-	for (std::set<Connection *>::iterator it = _incomingConnections.begin(); it != _incomingConnections.end(); ++it)
-	{
-		Connection *connection = *it;
-		if (connection->getQueueSize() > 0)
-			return true;
-	}
-
-	return false;
-}
-
-bool Processor::flowFilesOutGoingFull()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	std::map<std::string, std::set<Connection *>>::iterator it;
-
-	for (it = _outGoingConnections.begin(); it != _outGoingConnections.end(); ++it)
-	{
-		// We already has connection for this relationship
-		std::set<Connection *> existedConnection = it->second;
-		for (std::set<Connection *>::iterator itConnection = existedConnection.begin(); itConnection != existedConnection.end(); ++itConnection)
-		{
-			Connection *connection = *itConnection;
-			if (connection->isFull())
-				return true;
-		}
-	}
-
-	return false;
-}
-
-void Processor::onTrigger()
-{
-	ProcessContext *context = new ProcessContext(this);
-	ProcessSession *session = new ProcessSession(context);
-	try {
-		// Call the child onTrigger function
-		this->onTrigger(context, session);
-		session->commit();
-		delete session;
-		delete context;
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		session->rollback();
-		delete session;
-		delete context;
-		throw;
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception Processor::onTrigger");
-		session->rollback();
-		delete session;
-		delete context;
-		throw;
-	}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/RealTimeDataCollector.cpp
----------------------------------------------------------------------
diff --git a/src/RealTimeDataCollector.cpp b/src/RealTimeDataCollector.cpp
deleted file mode 100644
index c7118ff..0000000
--- a/src/RealTimeDataCollector.cpp
+++ /dev/null
@@ -1,482 +0,0 @@
-/**
- * @file RealTimeDataCollector.cpp
- * RealTimeDataCollector class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <random>
-#include <netinet/tcp.h>
-
-#include "RealTimeDataCollector.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string RealTimeDataCollector::ProcessorName("RealTimeDataCollector");
-Property RealTimeDataCollector::FILENAME("File Name", "File Name for the real time processor to process", "data.osp");
-Property RealTimeDataCollector::REALTIMESERVERNAME("Real Time Server Name", "Real Time Server Name", "localhost");
-Property RealTimeDataCollector::REALTIMESERVERPORT("Real Time Server Port", "Real Time Server Port", "10000");
-Property RealTimeDataCollector::BATCHSERVERNAME("Batch Server Name", "Batch Server Name", "localhost");
-Property RealTimeDataCollector::BATCHSERVERPORT("Batch Server Port", "Batch Server Port", "10001");
-Property RealTimeDataCollector::ITERATION("Iteration",
-		"If true, sample osp file will be iterated", "true");
-Property RealTimeDataCollector::REALTIMEMSGID("Real Time Message ID", "Real Time Message ID", "41");
-Property RealTimeDataCollector::BATCHMSGID("Batch Message ID", "Batch Message ID", "172, 30, 48");
-Property RealTimeDataCollector::REALTIMEINTERVAL("Real Time Interval", "Real Time Data Collection Interval in msec", "10 ms");
-Property RealTimeDataCollector::BATCHINTERVAL("Batch Time Interval", "Batch Processing Interval in msec", "100 ms");
-Property RealTimeDataCollector::BATCHMAXBUFFERSIZE("Batch Max Buffer Size", "Batch Buffer Maximum size in bytes", "262144");
-Relationship RealTimeDataCollector::Success("success", "success operational on the flow record");
-
-void RealTimeDataCollector::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(FILENAME);
-	properties.insert(REALTIMESERVERNAME);
-	properties.insert(REALTIMESERVERPORT);
-	properties.insert(BATCHSERVERNAME);
-	properties.insert(BATCHSERVERPORT);
-	properties.insert(ITERATION);
-	properties.insert(REALTIMEMSGID);
-	properties.insert(BATCHMSGID);
-	properties.insert(REALTIMEINTERVAL);
-	properties.insert(BATCHINTERVAL);
-	properties.insert(BATCHMAXBUFFERSIZE);
-
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-
-}
-
-int RealTimeDataCollector::connectServer(const char *host, uint16_t port)
-{
-	in_addr_t addr;
-	int sock = 0;
-	struct hostent *h;
-#ifdef __MACH__
-	h = gethostbyname(host);
-#else
-	char buf[1024];
-	struct hostent he;
-	int hh_errno;
-	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
-#endif
-	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0)
-	{
-		_logger->log_error("Could not create socket to hostName %s", host);
-		return 0;
-	}
-
-#ifndef __MACH__
-	int opt = 1;
-	bool nagle_off = true;
-
-	if (nagle_off)
-	{
-		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() TCP_NODELAY failed");
-			close(sock);
-			return 0;
-		}
-		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-				(char *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() SO_REUSEADDR failed");
-			close(sock);
-			return 0;
-		}
-	}
-
-	int sndsize = 256*1024;
-	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
-	{
-		_logger->log_error("setsockopt() SO_SNDBUF failed");
-		close(sock);
-		return 0;
-	}
-#endif
-
-	struct sockaddr_in sa;
-	socklen_t socklen;
-	int status;
-
-	//TODO bind socket to the interface
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = htonl(INADDR_ANY);
-	sa.sin_port = htons(0);
-	socklen = sizeof(sa);
-	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
-	{
-		_logger->log_error("socket bind failed");
-		close(sock);
-		return 0;
-	}
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = addr;
-	sa.sin_port = htons(port);
-	socklen = sizeof(sa);
-
-	status = connect(sock, (struct sockaddr *)&sa, socklen);
-
-	if (status < 0)
-	{
-		_logger->log_error("socket connect failed to %s %d", host, port);
-		close(sock);
-		return 0;
-	}
-
-	_logger->log_info("socket %d connect to server %s port %d success", sock, host, port);
-
-	return sock;
-}
-
-int RealTimeDataCollector::sendData(int socket, const char *buf, int buflen)
-{
-	int ret = 0, bytes = 0;
-
-	while (bytes < buflen)
-	{
-		ret = send(socket, buf+bytes, buflen-bytes, 0);
-		//check for errors
-		if (ret == -1)
-		{
-			return ret;
-		}
-		bytes+=ret;
-	}
-
-	if (ret)
-		_logger->log_debug("Send data size %d over socket %d", buflen, socket);
-
-	return ret;
-}
-
-void RealTimeDataCollector::onTriggerRealTime(ProcessContext *context, ProcessSession *session)
-{
-	if (_realTimeAccumulated >= this->_realTimeInterval)
-	{
-		std::string value;
-		if (this->getProperty(REALTIMEMSGID.getName(), value))
-		{
-			this->_realTimeMsgID.clear();
-			this->_logger->log_info("Real Time Msg IDs %s", value.c_str());
-			std::stringstream lineStream(value);
-			std::string cell;
-
-			while(std::getline(lineStream, cell, ','))
-		    {
-		        this->_realTimeMsgID.push_back(cell);
-		        // this->_logger->log_debug("Real Time Msg ID %s", cell.c_str());
-		    }
-		}
-		if (this->getProperty(BATCHMSGID.getName(), value))
-		{
-			this->_batchMsgID.clear();
-			this->_logger->log_info("Batch Msg IDs %s", value.c_str());
-			std::stringstream lineStream(value);
-			std::string cell;
-
-			while(std::getline(lineStream, cell, ','))
-		    {
-				cell = Property::trim(cell);
-		        this->_batchMsgID.push_back(cell);
-		        // this->_logger->log_debug("Batch Msg ID %s", cell.c_str());
-		    }
-		}
-		// _logger->log_info("onTriggerRealTime");
-		// Open the file
-		if (!this->_fileStream.is_open())
-		{
-			_fileStream.open(this->_fileName.c_str(), std::ifstream::in);
-			if (this->_fileStream.is_open())
-				_logger->log_debug("open %s", _fileName.c_str());
-		}
-		if (!_fileStream.good())
-		{
-			_logger->log_error("load data file failed %s", _fileName.c_str());
-			return;
-		}
-		if (this->_fileStream.is_open())
-		{
-			std::string line;
-
-			while (std::getline(_fileStream, line))
-			{
-				line += "\n";
-				std::stringstream lineStream(line);
-				std::string cell;
-				if (std::getline(lineStream, cell, ','))
-				{
-					cell = Property::trim(cell);
-					// Check whether it match to the batch traffic
-					for (std::vector<std::string>::iterator it = _batchMsgID.begin(); it != _batchMsgID.end(); ++it)
-					{
-						if (cell == *it)
-						{
-							// push the batch data to the queue
-							std::lock_guard<std::mutex> lock(_mtx);
-							while ((_queuedDataSize + line.size()) > _batchMaxBufferSize)
-							{
-								std::string item = _queue.front();
-								_queuedDataSize -= item.size();
-								_logger->log_debug("Pop item size %d from batch queue, queue buffer size %d", item.size(), _queuedDataSize);
-								_queue.pop();
-							}
-							_queue.push(line);
-							_queuedDataSize += line.size();
-							_logger->log_debug("Push batch msg ID %s into batch queue, queue buffer size %d", cell.c_str(), _queuedDataSize);
-						}
-					}
-					bool findRealTime = false;
-					// Check whether it match to the real time traffic
-					for (std::vector<std::string>::iterator it = _realTimeMsgID.begin(); it != _realTimeMsgID.end(); ++it)
-					{
-						if (cell == *it)
-						{
-							int status = 0;
-							if (this->_realTimeSocket <= 0)
-							{
-								// Connect the LTE socket
-								uint16_t port = _realTimeServerPort;
-								this->_realTimeSocket = connectServer(_realTimeServerName.c_str(), port);
-							}
-							if (this->_realTimeSocket)
-							{
-								// try to send the data
-								status = sendData(_realTimeSocket, line.data(), line.size());
-								if (status < 0)
-								{
-									close(_realTimeSocket);
-									_realTimeSocket = 0;
-								}
-							}
-							if (this->_realTimeSocket <= 0 || status < 0)
-							{
-								// push the batch data to the queue
-								std::lock_guard<std::mutex> lock(_mtx);
-								while ((_queuedDataSize + line.size()) > _batchMaxBufferSize)
-								{
-									std::string item = _queue.front();
-									_queuedDataSize -= item.size();
-									_logger->log_debug("Pop item size %d from batch queue, queue buffer size %d", item.size(), _queuedDataSize);
-									_queue.pop();
-								}
-								_queue.push(line);
-								_queuedDataSize += line.size();
-								_logger->log_debug("Push real time msg ID %s into batch queue, queue buffer size %d", cell.c_str(), _queuedDataSize);
-							}
-							// find real time
-							findRealTime = true;
-						} // cell
-					} // for real time pattern
-					if (findRealTime)
-						// we break the while once we find the first real time
-						break;
-				}  // if get line
-			} // while
-			if (_fileStream.eof())
-			{
-				_fileStream.close();
-			}
-		} // if open
-		_realTimeAccumulated = 0;
-	}
-	_realTimeAccumulated += context->getProcessor()->getSchedulingPeriodNano();
-}
-
-void RealTimeDataCollector::onTriggerBatch(ProcessContext *context, ProcessSession *session)
-{
-	if (_batchAcccumulated >= this->_batchInterval)
-	{
-		// _logger->log_info("onTriggerBatch");
-		// dequeue the batch and send over WIFI
-		int status = 0;
-		if (this->_batchSocket <= 0)
-		{
-			// Connect the WIFI socket
-			uint16_t port = _batchServerPort;
-			this->_batchSocket = connectServer(_batchServerName.c_str(), port);
-		}
-		if (this->_batchSocket)
-		{
-			std::lock_guard<std::mutex> lock(_mtx);
-
-			while (!_queue.empty())
-			{
-				std::string line = _queue.front();
-				status = sendData(_batchSocket, line.data(), line.size());
-				_queue.pop();
-				_queuedDataSize -= line.size();
-				if (status < 0)
-				{
-					close(_batchSocket);
-					_batchSocket = 0;
-					break;
-				}
-			}
-		}
-		_batchAcccumulated = 0;
-	}
-	_batchAcccumulated += context->getProcessor()->getSchedulingPeriodNano();
-}
-
-void RealTimeDataCollector::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::thread::id id = std::this_thread::get_id();
-
-	if (id == _realTimeThreadId)
-		return onTriggerRealTime(context, session);
-	else if (id == _batchThreadId)
-		return onTriggerBatch(context, session);
-	else
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		if (!this->_firstInvoking)
-		{
-			this->_fileName = "data.osp";
-			std::string value;
-			if (this->getProperty(FILENAME.getName(), value))
-			{
-				this->_fileName = value;
-				this->_logger->log_info("Data Collector File Name %s", _fileName.c_str());
-			}
-			this->_realTimeServerName = "localhost";
-			if (this->getProperty(REALTIMESERVERNAME.getName(), value))
-			{
-				this->_realTimeServerName = value;
-				this->_logger->log_info("Real Time Server Name %s", this->_realTimeServerName.c_str());
-			}
-			this->_realTimeServerPort = 10000;
-			if (this->getProperty(REALTIMESERVERPORT.getName(), value))
-			{
-				Property::StringToInt(value, _realTimeServerPort);
-				this->_logger->log_info("Real Time Server Port %d", _realTimeServerPort);
-			}
-			if (this->getProperty(BATCHSERVERNAME.getName(), value))
-			{
-				this->_batchServerName = value;
-				this->_logger->log_info("Batch Server Name %s", this->_batchServerName.c_str());
-			}
-			this->_batchServerPort = 10001;
-			if (this->getProperty(BATCHSERVERPORT.getName(), value))
-			{
-				Property::StringToInt(value, _batchServerPort);
-				this->_logger->log_info("Batch Server Port %d", _batchServerPort);
-			}
-			if (this->getProperty(ITERATION.getName(), value))
-			{
-				Property::StringToBool(value, this->_iteration);
-				_logger->log_info("Iteration %d", _iteration);
-			}
-			this->_realTimeInterval = 10000000; //10 msec
-			if (this->getProperty(REALTIMEINTERVAL.getName(), value))
-			{
-				TimeUnit unit;
-				if (Property::StringToTime(value, _realTimeInterval, unit) &&
-								Property::ConvertTimeUnitToNS(_realTimeInterval, unit, _realTimeInterval))
-				{
-					_logger->log_info("Real Time Interval: [%d] ns", _realTimeInterval);
-				}
-			}
-			this->_batchInterval = 100000000; //100 msec
-			if (this->getProperty(BATCHINTERVAL.getName(), value))
-			{
-				TimeUnit unit;
-				if (Property::StringToTime(value, _batchInterval, unit) &&
-								Property::ConvertTimeUnitToNS(_batchInterval, unit, _batchInterval))
-				{
-					_logger->log_info("Batch Time Interval: [%d] ns", _batchInterval);
-				}
-			}
-			this->_batchMaxBufferSize = 256*1024;
-			if (this->getProperty(BATCHMAXBUFFERSIZE.getName(), value))
-			{
-				Property::StringToInt(value, _batchMaxBufferSize);
-				this->_logger->log_info("Batch Max Buffer Size %d", _batchMaxBufferSize);
-			}
-			if (this->getProperty(REALTIMEMSGID.getName(), value))
-			{
-				this->_logger->log_info("Real Time Msg IDs %s", value.c_str());
-				std::stringstream lineStream(value);
-				std::string cell;
-
-				while(std::getline(lineStream, cell, ','))
-			    {
-			        this->_realTimeMsgID.push_back(cell);
-			        this->_logger->log_info("Real Time Msg ID %s", cell.c_str());
-			    }
-			}
-			if (this->getProperty(BATCHMSGID.getName(), value))
-			{
-				this->_logger->log_info("Batch Msg IDs %s", value.c_str());
-				std::stringstream lineStream(value);
-				std::string cell;
-
-				while(std::getline(lineStream, cell, ','))
-			    {
-					cell = Property::trim(cell);
-			        this->_batchMsgID.push_back(cell);
-			        this->_logger->log_info("Batch Msg ID %s", cell.c_str());
-			    }
-			}
-			// Connect the LTE socket
-			uint16_t port = _realTimeServerPort;
-
-			this->_realTimeSocket = connectServer(_realTimeServerName.c_str(), port);
-
-			// Connect the WIFI socket
-			port = _batchServerPort;
-
-			this->_batchSocket = connectServer(_batchServerName.c_str(), port);
-
-			// Open the file
-			_fileStream.open(this->_fileName.c_str(), std::ifstream::in);
-			if (!_fileStream.good())
-			{
-				_logger->log_error("load data file failed %s", _fileName.c_str());
-				return;
-			}
-			else
-			{
-				_logger->log_debug("open %s", _fileName.c_str());
-			}
-			_realTimeThreadId = id;
-			this->_firstInvoking = true;
-		}
-		else
-		{
-			if (id != _realTimeThreadId)
-				_batchThreadId = id;
-			this->_firstInvoking = false;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/RemoteProcessorGroupPort.cpp
----------------------------------------------------------------------
diff --git a/src/RemoteProcessorGroupPort.cpp b/src/RemoteProcessorGroupPort.cpp
deleted file mode 100644
index 9d849ae..0000000
--- a/src/RemoteProcessorGroupPort.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * @file RemoteProcessorGroupPort.cpp
- * RemoteProcessorGroupPort class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <sstream>
-#include <string.h>
-#include <iostream>
-
-#include "TimeUtil.h"
-#include "RemoteProcessorGroupPort.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string RemoteProcessorGroupPort::ProcessorName("RemoteProcessorGroupPort");
-Property RemoteProcessorGroupPort::hostName("Host Name", "Remote Host Name.", "localhost");
-Property RemoteProcessorGroupPort::port("Port", "Remote Port", "9999");
-Relationship RemoteProcessorGroupPort::relation;
-
-void RemoteProcessorGroupPort::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(hostName);
-	properties.insert(port);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(relation);
-	setSupportedRelationships(relationships);
-}
-
-void RemoteProcessorGroupPort::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string value;
-
-	if (!_transmitting)
-		return;
-
-	std::string host = _peer->getHostName();
-	uint16_t sport = _peer->getPort();
-	int64_t lvalue;
-	bool needReset = false;
-
-	if (context->getProperty(hostName.getName(), value))
-	{
-		host = value;
-	}
-	if (context->getProperty(port.getName(), value) && Property::StringToInt(value, lvalue))
-	{
-		sport = (uint16_t) lvalue;
-	}
-	if (host != _peer->getHostName())
-	{
-		_peer->setHostName(host);
-		needReset= true;
-	}
-	if (sport != _peer->getPort())
-	{
-		_peer->setPort(sport);
-		needReset = true;
-	}
-	if (needReset)
-		_protocol->tearDown();
-
-	if (!_protocol->bootstrap())
-	{
-		// bootstrap the client protocol if needeed
-		context->yield();
-		_logger->log_error("Site2Site bootstrap failed yield period %d peer timeout %d", context->getProcessor()->getYieldPeriodMsec(), _protocol->getPeer()->getTimeOut());
-		return;
-	}
-
-	if (_direction == RECEIVE)
-		_protocol->receiveFlowFiles(context, session);
-	else
-		_protocol->transferFlowFiles(context, session);
-
-	return;
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/ResourceClaim.cpp
----------------------------------------------------------------------
diff --git a/src/ResourceClaim.cpp b/src/ResourceClaim.cpp
deleted file mode 100644
index 3c22ac9..0000000
--- a/src/ResourceClaim.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file ResourceClaim.cpp
- * ResourceClaim class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-
-#include "ResourceClaim.h"
-
-std::atomic<uint64_t> ResourceClaim::_localResourceClaimNumber(0);
-
-ResourceClaim::ResourceClaim(const std::string contentDirectory)
-: _id(_localResourceClaimNumber.load()),
-  _flowFileRecordOwnedCount(0)
-{
-	char uuidStr[37];
-
-	// Generate the global UUID for the resource claim
-	uuid_generate(_uuid);
-	// Increase the local ID for the resource claim
-	++_localResourceClaimNumber;
-	uuid_unparse(_uuid, uuidStr);
-	// Create the full content path for the content
-	_contentFullPath = contentDirectory + "/" + uuidStr;
-
-	_configure = Configure::getConfigure();
-	_logger = Logger::getLogger();
-	_logger->log_debug("Resource Claim created %s", _contentFullPath.c_str());
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/SchedulingAgent.cpp
----------------------------------------------------------------------
diff --git a/src/SchedulingAgent.cpp b/src/SchedulingAgent.cpp
deleted file mode 100644
index 211c328..0000000
--- a/src/SchedulingAgent.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * @file SchedulingAgent.cpp
- * SchedulingAgent class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <chrono>
-#include <thread>
-#include <iostream>
-#include "Exception.h"
-#include "SchedulingAgent.h"
-
-bool SchedulingAgent::hasWorkToDo(Processor *processor)
-{
-	// Whether it has work to do
-	if (processor->getTriggerWhenEmpty() || !processor->hasIncomingConnections() ||
-			processor->flowFilesQueued())
-		return true;
-	else
-		return false;
-}
-
-bool SchedulingAgent::hasTooMuchOutGoing(Processor *processor)
-{
-	return processor->flowFilesOutGoingFull();
-}
-
-bool SchedulingAgent::onTrigger(Processor *processor)
-{
-	if (processor->isYield())
-		return false;
-
-	// No need to yield, reset yield expiration to 0
-	processor->clearYield();
-
-	if (!hasWorkToDo(processor))
-		// No work to do, yield
-		return true;
-
-	if(hasTooMuchOutGoing(processor))
-		// need to apply backpressure
-		return true;
-
-	//TODO runDuration
-
-	processor->incrementActiveTasks();
-	try
-	{
-		processor->onTrigger();
-		processor->decrementActiveTask();
-	}
-	catch (Exception &exception)
-	{
-		// Normal exception
-		_logger->log_debug("Caught Exception %s", exception.what());
-		processor->decrementActiveTask();
-	}
-	catch (std::exception &exception)
-	{
-		_logger->log_debug("Caught Exception %s", exception.what());
-		processor->yield(_administrativeYieldDuration);
-		processor->decrementActiveTask();
-	}
-	catch (...)
-	{
-		_logger->log_debug("Caught Exception during SchedulingAgent::onTrigger");
-		processor->yield(_administrativeYieldDuration);
-		processor->decrementActiveTask();
-	}
-
-	return false;
-}
-


[16/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/async_log_helper.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/async_log_helper.h b/inc/spdlog/details/async_log_helper.h
deleted file mode 100644
index 59c1b2d..0000000
--- a/inc/spdlog/details/async_log_helper.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-// async log helper :
-// Process logs asynchronously using a back thread.
-//
-// If the internal queue of log messages reaches its max size,
-// then the client call will block until there is more room.
-//
-// If the back thread throws during logging, a spdlog::spdlog_ex exception
-// will be thrown in client's thread when tries to log the next message
-
-#pragma once
-
-#include <chrono>
-#include <thread>
-#include <atomic>
-#include <functional>
-
-#include "../common.h"
-#include "../sinks/sink.h"
-#include "./mpmc_bounded_q.h"
-#include "./log_msg.h"
-#include "./format.h"
-#include "os.h"
-
-
-namespace spdlog
-{
-namespace details
-{
-
-class async_log_helper
-{
-    // Async msg to move to/from the queue
-    // Movable only. should never be copied
-    struct async_msg
-    {
-        std::string logger_name;
-        level::level_enum level;
-        log_clock::time_point time;
-        size_t thread_id;
-        std::string txt;
-
-        async_msg() = default;
-        ~async_msg() = default;
-
-async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
-        logger_name(std::move(other.logger_name)),
-                    level(std::move(other.level)),
-                    time(std::move(other.time)),
-                    txt(std::move(other.txt))
-        {}
-
-        async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
-        {
-            logger_name = std::move(other.logger_name);
-            level = other.level;
-            time = std::move(other.time);
-            thread_id = other.thread_id;
-            txt = std::move(other.txt);
-            return *this;
-        }
-        // never copy or assign. should only be moved..
-        async_msg(const async_msg&) = delete;
-        async_msg& operator=(async_msg& other) = delete;
-
-        // construct from log_msg
-        async_msg(const details::log_msg& m) :
-            logger_name(m.logger_name),
-            level(m.level),
-            time(m.time),
-            thread_id(m.thread_id),
-            txt(m.raw.data(), m.raw.size())
-        {}
-
-
-        // copy into log_msg
-        void fill_log_msg(log_msg &msg)
-        {
-            msg.clear();
-            msg.logger_name = logger_name;
-            msg.level = level;
-            msg.time = time;
-            msg.thread_id = thread_id;
-            msg.raw << txt;
-        }
-    };
-
-public:
-
-    using item_type = async_msg;
-    using q_type = details::mpmc_bounded_queue<item_type>;
-
-    using clock = std::chrono::steady_clock;
-
-
-    async_log_helper(formatter_ptr formatter,
-                     const std::vector<sink_ptr>& sinks,
-                     size_t queue_size,
-                     const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
-                     const std::function<void()>& worker_warmup_cb = nullptr,
-                     const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
-    void log(const details::log_msg& msg);
-
-    // stop logging and join the back thread
-    ~async_log_helper();
-
-    void set_formatter(formatter_ptr);
-
-
-private:
-    formatter_ptr _formatter;
-    std::vector<std::shared_ptr<sinks::sink>> _sinks;
-
-    // queue of messages to log
-    q_type _q;
-
-    // last exception thrown from the worker thread
-    std::shared_ptr<spdlog_ex> _last_workerthread_ex;
-
-    // overflow policy
-    const async_overflow_policy _overflow_policy;
-
-    // worker thread warmup callback - one can set thread priority, affinity, etc
-    const std::function<void()> _worker_warmup_cb;
-
-    // auto periodic sink flush parameter
-    const std::chrono::milliseconds _flush_interval_ms;
-
-    // worker thread
-    std::thread _worker_thread;
-
-    // throw last worker thread exception or if worker thread is not active
-    void throw_if_bad_worker();
-
-    // worker thread main loop
-    void worker_loop();
-
-    // pop next message from the queue and process it
-    // return true if a message was available (queue was not empty), will set the last_pop to the pop time
-    bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
-
-    void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
-
-    // sleep,yield or return immediatly using the time passed since last message as a hint
-    static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time);
-
-
-
-};
-}
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// async_sink class implementation
-///////////////////////////////////////////////////////////////////////////////
-inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, const std::vector<sink_ptr>& sinks, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms):
-    _formatter(formatter),
-    _sinks(sinks),
-    _q(queue_size),
-    _overflow_policy(overflow_policy),
-    _worker_warmup_cb(worker_warmup_cb),
-    _flush_interval_ms(flush_interval_ms),
-    _worker_thread(&async_log_helper::worker_loop, this)
-{}
-
-// Send to the worker thread termination message(level=off)
-// and wait for it to finish gracefully
-inline spdlog::details::async_log_helper::~async_log_helper()
-{
-
-    try
-    {
-        log(log_msg(level::off));
-        _worker_thread.join();
-    }
-    catch (...) //Dont crash if thread not joinable
-    {}
-}
-
-
-//Try to push and block until succeeded
-inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
-{
-    throw_if_bad_worker();
-    async_msg new_msg(msg);
-    if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
-    {
-        auto last_op_time = details::os::now();
-        auto now = last_op_time;
-        do
-        {
-            now = details::os::now();
-            sleep_or_yield(now, last_op_time);
-        }
-        while (!_q.enqueue(std::move(new_msg)));
-    }
-
-}
-
-inline void spdlog::details::async_log_helper::worker_loop()
-{
-    try
-    {
-        if (_worker_warmup_cb) _worker_warmup_cb();
-        auto last_pop = details::os::now();
-        auto last_flush = last_pop;
-        while(process_next_msg(last_pop, last_flush));
-    }
-    catch (const std::exception& ex)
-    {
-        _last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
-    }
-    catch (...)
-    {
-        _last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
-    }
-}
-
-// process next message in the queue
-// return true if this thread should still be active (no msg with level::off was received)
-inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
-{
-
-    async_msg incoming_async_msg;
-    log_msg incoming_log_msg;
-
-    if (_q.dequeue(incoming_async_msg))
-    {
-        last_pop = details::os::now();
-
-        if(incoming_async_msg.level == level::off)
-            return false;
-
-        incoming_async_msg.fill_log_msg(incoming_log_msg);
-        _formatter->format(incoming_log_msg);
-        for (auto &s : _sinks)
-            s->log(incoming_log_msg);
-    }
-    else //empty queue
-    {
-        auto now = details::os::now();
-        handle_flush_interval(now, last_flush);
-        sleep_or_yield(now, last_pop);
-    }
-    return true;
-}
-
-inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
-{
-    if (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms)
-    {
-        for (auto &s : _sinks)
-            s->flush();
-        now = last_flush = details::os::now();
-    }
-}
-inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
-{
-    _formatter = msg_formatter;
-}
-
-
-// sleep,yield or return immediatly using the time passed since last message as a hint
-inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time)
-{
-    using std::chrono::milliseconds;
-    using namespace std::this_thread;
-
-    auto time_since_op = now - last_op_time;
-
-    // spin upto 1 ms
-    if (time_since_op <= milliseconds(1))
-        return;
-
-    // yield upto 10ms
-    if (time_since_op <= milliseconds(10))
-        return yield();
-
-
-    // sleep for half of duration since last op
-    if (time_since_op <= milliseconds(100))
-        return sleep_for(time_since_op / 2);
-
-    return sleep_for(milliseconds(100));
-}
-
-// throw if the worker thread threw an exception or not active
-inline void spdlog::details::async_log_helper::throw_if_bad_worker()
-{
-    if (_last_workerthread_ex)
-    {
-        auto ex = std::move(_last_workerthread_ex);
-        throw *ex;
-    }
-}
-
-
-
-
-
-
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/async_logger_impl.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/async_logger_impl.h b/inc/spdlog/details/async_logger_impl.h
deleted file mode 100644
index f60407e..0000000
--- a/inc/spdlog/details/async_logger_impl.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-
-#include "./async_log_helper.h"
-
-//
-// Async Logger implementation
-// Use single async_sink (queue) to perform the logging in a worker thread
-//
-
-
-template<class It>
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
-        const It& begin,
-        const It& end,
-        size_t queue_size,
-        const  async_overflow_policy overflow_policy,
-        const std::function<void()>& worker_warmup_cb,
-        const std::chrono::milliseconds& flush_interval_ms) :
-    logger(logger_name, begin, end),
-    _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms))
-{
-}
-
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
-        sinks_init_list sinks,
-        size_t queue_size,
-        const  async_overflow_policy overflow_policy,
-        const std::function<void()>& worker_warmup_cb,
-        const std::chrono::milliseconds& flush_interval_ms) :
-    async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
-
-inline spdlog::async_logger::async_logger(const std::string& logger_name,
-        sink_ptr single_sink,
-        size_t queue_size,
-        const  async_overflow_policy overflow_policy,
-        const std::function<void()>& worker_warmup_cb,
-        const std::chrono::milliseconds& flush_interval_ms) :
-    async_logger(logger_name, { single_sink }, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
-
-
-inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
-{
-    _formatter = msg_formatter;
-    _async_log_helper->set_formatter(_formatter);
-}
-
-inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
-{
-    _formatter = std::make_shared<pattern_formatter>(pattern);
-    _async_log_helper->set_formatter(_formatter);
-}
-
-
-inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
-{
-    _async_log_helper->log(msg);
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/file_helper.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/file_helper.h b/inc/spdlog/details/file_helper.h
deleted file mode 100644
index 8e1f600..0000000
--- a/inc/spdlog/details/file_helper.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-// Helper class for file sink
-// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
-// Can be set to auto flush on every line
-// Throw spdlog_ex exception on errors
-
-#include <string>
-#include <thread>
-#include <chrono>
-#include "os.h"
-
-
-
-
-namespace spdlog
-{
-namespace details
-{
-
-class file_helper
-{
-public:
-    const int open_tries = 5;
-    const int open_interval = 10;
-
-    explicit file_helper(bool force_flush):
-        _fd(nullptr),
-        _force_flush(force_flush)
-    {}
-
-    file_helper(const file_helper&) = delete;
-    file_helper& operator=(const file_helper&) = delete;
-
-    ~file_helper()
-    {
-        close();
-    }
-
-
-    void open(const std::string& fname, bool truncate=false)
-    {
-
-        close();
-        const char* mode = truncate ? "wb" : "ab";
-        _filename = fname;
-        for (int tries = 0; tries < open_tries; ++tries)
-        {
-            if(!os::fopen_s(&_fd, fname, mode))
-                return;
-
-            std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
-        }
-
-        throw spdlog_ex("Failed opening file " + fname + " for writing");
-    }
-
-    void reopen(bool truncate)
-    {
-        if(_filename.empty())
-            throw spdlog_ex("Failed re opening file - was not opened before");
-        open(_filename, truncate);
-
-    }
-
-    void flush() {
-        std::fflush(_fd);
-    }
-
-    void close()
-    {
-        if (_fd)
-        {
-            std::fclose(_fd);
-            _fd = nullptr;
-        }
-    }
-
-    void write(const log_msg& msg)
-    {
-
-        size_t size = msg.formatted.size();
-        auto data = msg.formatted.data();
-        if(std::fwrite(data, 1, size, _fd) != size)
-            throw spdlog_ex("Failed writing to file " + _filename);
-
-        if(_force_flush)
-            std::fflush(_fd);
-
-    }
-
-    const std::string& filename() const
-    {
-        return _filename;
-    }
-
-    static bool file_exists(const std::string& name)
-    {
-        FILE* file;
-        if (!os::fopen_s(&file, name.c_str(), "r"))
-        {
-            fclose(file);
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-
-private:
-    FILE* _fd;
-    std::string _filename;
-    bool _force_flush;
-
-
-};
-}
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/format.cc
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/format.cc b/inc/spdlog/details/format.cc
deleted file mode 100644
index fb0ef9e..0000000
--- a/inc/spdlog/details/format.cc
+++ /dev/null
@@ -1,1353 +0,0 @@
-/*
-Formatting library for C++
-
-Copyright (c) 2012 - 2015, Victor Zverovich
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-2. 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.
-
-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 "format.h"
-
-#include <string.h>
-
-#include <cctype>
-#include <cerrno>
-#include <climits>
-#include <cmath>
-#include <cstdarg>
-
-#if defined(_WIN32) && defined(__MINGW32__)
-# include <cstring>
-#endif
-
-#if FMT_USE_WINDOWS_H
-# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
-#  include <windows.h>
-# else
-#  define NOMINMAX
-#  include <windows.h>
-#  undef NOMINMAX
-# endif
-#endif
-
-using fmt::internal::Arg;
-
-// Check if exceptions are disabled.
-#if __GNUC__ && !__EXCEPTIONS
-# define FMT_EXCEPTIONS 0
-#endif
-#if _MSC_VER && !_HAS_EXCEPTIONS
-# define FMT_EXCEPTIONS 0
-#endif
-#ifndef FMT_EXCEPTIONS
-# define FMT_EXCEPTIONS 1
-#endif
-
-#if FMT_EXCEPTIONS
-# define FMT_TRY try
-# define FMT_CATCH(x) catch (x)
-#else
-# define FMT_TRY if (true)
-# define FMT_CATCH(x) if (false)
-#endif
-
-#ifndef FMT_THROW
-# if FMT_EXCEPTIONS
-#  define FMT_THROW(x) throw x
-# else
-#  define FMT_THROW(x) assert(false)
-# endif
-#endif
-
-#ifdef FMT_HEADER_ONLY
-# define FMT_FUNC inline
-#else
-# define FMT_FUNC
-#endif
-
-#if _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4127)  // conditional expression is constant
-# pragma warning(disable: 4702)  // unreachable code
-// Disable deprecation warning for strerror. The latter is not called but
-// MSVC fails to detect it.
-# pragma warning(disable: 4996)
-#endif
-
-// Dummy implementations of strerror_r and strerror_s called if corresponding
-// system functions are not available.
-static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
-    return fmt::internal::Null<>();
-}
-static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
-    return fmt::internal::Null<>();
-}
-
-namespace fmt {
-namespace {
-
-#ifndef _MSC_VER
-# define FMT_SNPRINTF snprintf
-#else  // _MSC_VER
-inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
-    va_list args;
-    va_start(args, format);
-    int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
-    va_end(args);
-    return result;
-}
-# define FMT_SNPRINTF fmt_snprintf
-#endif  // _MSC_VER
-
-#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-# define FMT_SWPRINTF snwprintf
-#else
-# define FMT_SWPRINTF swprintf
-#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
-
-// Checks if a value fits in int - used to avoid warnings about comparing
-// signed and unsigned integers.
-template <bool IsSigned>
-struct IntChecker {
-    template <typename T>
-    static bool fits_in_int(T value) {
-        unsigned max = INT_MAX;
-        return value <= max;
-    }
-    static bool fits_in_int(bool) {
-        return true;
-    }
-};
-
-template <>
-struct IntChecker<true> {
-    template <typename T>
-    static bool fits_in_int(T value) {
-        return value >= INT_MIN && value <= INT_MAX;
-    }
-};
-
-const char RESET_COLOR[] = "\x1b[0m";
-
-typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
-
-// Portable thread-safe version of strerror.
-// Sets buffer to point to a string describing the error code.
-// This can be either a pointer to a string stored in buffer,
-// or a pointer to some static immutable string.
-// Returns one of the following values:
-//   0      - success
-//   ERANGE - buffer is not large enough to store the error message
-//   other  - failure
-// Buffer should be at least of size 1.
-int safe_strerror(
-    int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
-    FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
-
-    class StrError {
-    private:
-        int error_code_;
-        char *&buffer_;
-        std::size_t buffer_size_;
-
-        // A noop assignment operator to avoid bogus warnings.
-        void operator=(const StrError &) {}
-
-        // Handle the result of XSI-compliant version of strerror_r.
-        int handle(int result) {
-            // glibc versions before 2.13 return result in errno.
-            return result == -1 ? errno : result;
-        }
-
-        // Handle the result of GNU-specific version of strerror_r.
-        int handle(char *message) {
-            // If the buffer is full then the message is probably truncated.
-            if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
-                return ERANGE;
-            buffer_ = message;
-            return 0;
-        }
-
-        // Handle the case when strerror_r is not available.
-        int handle(fmt::internal::Null<>) {
-            return fallback(strerror_s(buffer_, buffer_size_, error_code_));
-        }
-
-        // Fallback to strerror_s when strerror_r is not available.
-        int fallback(int result) {
-            // If the buffer is full then the message is probably truncated.
-            return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
-            ERANGE : result;
-        }
-
-        // Fallback to strerror if strerror_r and strerror_s are not available.
-        int fallback(fmt::internal::Null<>) {
-            errno = 0;
-            buffer_ = strerror(error_code_);
-            return errno;
-        }
-
-    public:
-        StrError(int error_code, char *&buffer, std::size_t buffer_size)
-            : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
-
-        int run() {
-            strerror_r(0, 0, "");  // Suppress a warning about unused strerror_r.
-            return handle(strerror_r(error_code_, buffer_, buffer_size_));
-        }
-    };
-    return StrError(error_code, buffer, buffer_size).run();
-}
-
-void format_error_code(fmt::Writer &out, int error_code,
-                       fmt::StringRef message) FMT_NOEXCEPT{
-    // Report error code making sure that the output fits into
-    // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
-    // bad_alloc.
-    out.clear();
-    static const char SEP[] = ": ";
-    static const char ERROR_STR[] = "error ";
-    fmt::internal::IntTraits<int>::MainType ec_value = error_code;
-    // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
-    std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
-    error_code_size += fmt::internal::count_digits(ec_value);
-    if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
-        out << message << SEP;
-    out << ERROR_STR << error_code;
-    assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
-}
-
-void report_error(FormatFunc func,
-                  int error_code, fmt::StringRef message) FMT_NOEXCEPT{
-    fmt::MemoryWriter full_message;
-    func(full_message, error_code, message);
-    // Use Writer::data instead of Writer::c_str to avoid potential memory
-    // allocation.
-    std::fwrite(full_message.data(), full_message.size(), 1, stderr);
-    std::fputc('\n', stderr);
-}
-
-// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
-class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
-public:
-    template <typename T>
-    bool visit_any_int(T value) {
-        return value == 0;
-    }
-};
-
-// Parses an unsigned integer advancing s to the end of the parsed input.
-// This function assumes that the first character of s is a digit.
-template <typename Char>
-int parse_nonnegative_int(const Char *&s) {
-    assert('0' <= *s && *s <= '9');
-    unsigned value = 0;
-    do {
-        unsigned new_value = value * 10 + (*s++ - '0');
-        // Check if value wrapped around.
-        if (new_value < value) {
-            value = UINT_MAX;
-            break;
-        }
-        value = new_value;
-    } while ('0' <= *s && *s <= '9');
-    if (value > INT_MAX)
-        FMT_THROW(fmt::FormatError("number is too big"));
-    return value;
-}
-
-template <typename Char>
-inline bool is_name_start(Char c) {
-    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
-}
-
-inline void require_numeric_argument(const Arg &arg, char spec) {
-    if (arg.type > Arg::LAST_NUMERIC_TYPE) {
-        std::string message =
-            fmt::format("format specifier '{}' requires numeric argument", spec);
-        FMT_THROW(fmt::FormatError(message));
-    }
-}
-
-template <typename Char>
-void check_sign(const Char *&s, const Arg &arg) {
-    char sign = static_cast<char>(*s);
-    require_numeric_argument(arg, sign);
-    if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
-        FMT_THROW(fmt::FormatError(fmt::format(
-                                       "format specifier '{}' requires signed argument", sign)));
-    }
-    ++s;
-}
-
-// Checks if an argument is a valid printf width specifier and sets
-// left alignment if it is negative.
-class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
-private:
-    fmt::FormatSpec &spec_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
-
-public:
-    explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
-
-    void report_unhandled_arg() {
-        FMT_THROW(fmt::FormatError("width is not integer"));
-    }
-
-    template <typename T>
-    unsigned visit_any_int(T value) {
-        typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
-        UnsignedType width = value;
-        if (fmt::internal::is_negative(value)) {
-            spec_.align_ = fmt::ALIGN_LEFT;
-            width = 0 - width;
-        }
-        if (width > INT_MAX)
-            FMT_THROW(fmt::FormatError("number is too big"));
-        return static_cast<unsigned>(width);
-    }
-};
-
-class PrecisionHandler :
-    public fmt::internal::ArgVisitor<PrecisionHandler, int> {
-public:
-    void report_unhandled_arg() {
-        FMT_THROW(fmt::FormatError("precision is not integer"));
-    }
-
-    template <typename T>
-    int visit_any_int(T value) {
-        if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
-            FMT_THROW(fmt::FormatError("number is too big"));
-        return static_cast<int>(value);
-    }
-};
-
-// Converts an integer argument to an integral type T for printf.
-template <typename T>
-class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
-private:
-    fmt::internal::Arg &arg_;
-    wchar_t type_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
-
-public:
-    ArgConverter(fmt::internal::Arg &arg, wchar_t type)
-        : arg_(arg), type_(type) {}
-
-    template <typename U>
-    void visit_any_int(U value) {
-        bool is_signed = type_ == 'd' || type_ == 'i';
-        using fmt::internal::Arg;
-        if (sizeof(T) <= sizeof(int)) {
-            // Extra casts are used to silence warnings.
-            if (is_signed) {
-                arg_.type = Arg::INT;
-                arg_.int_value = static_cast<int>(static_cast<T>(value));
-            }
-            else {
-                arg_.type = Arg::UINT;
-                arg_.uint_value = static_cast<unsigned>(
-                                      static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
-            }
-        }
-        else {
-            if (is_signed) {
-                arg_.type = Arg::LONG_LONG;
-                arg_.long_long_value =
-                    static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
-            }
-            else {
-                arg_.type = Arg::ULONG_LONG;
-                arg_.ulong_long_value =
-                    static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
-            }
-        }
-    }
-};
-
-// Converts an integer argument to char for printf.
-class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
-private:
-    fmt::internal::Arg &arg_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
-
-public:
-    explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
-
-    template <typename T>
-    void visit_any_int(T value) {
-        arg_.type = Arg::CHAR;
-        arg_.int_value = static_cast<char>(value);
-    }
-};
-}  // namespace
-
-namespace internal {
-
-template <typename Impl, typename Char>
-class BasicArgFormatter : public ArgVisitor<Impl, void> {
-private:
-    BasicWriter<Char> &writer_;
-    FormatSpec &spec_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
-
-protected:
-    BasicWriter<Char> &writer() {
-        return writer_;
-    }
-    const FormatSpec &spec() const {
-        return spec_;
-    }
-
-public:
-    BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
-        : writer_(w), spec_(s) {}
-
-    template <typename T>
-    void visit_any_int(T value) {
-        writer_.write_int(value, spec_);
-    }
-
-    template <typename T>
-    void visit_any_double(T value) {
-        writer_.write_double(value, spec_);
-    }
-
-    void visit_bool(bool value) {
-        if (spec_.type_) {
-            writer_.write_int(value, spec_);
-            return;
-        }
-        const char *str_value = value ? "true" : "false";
-        Arg::StringValue<char> str = { str_value, strlen(str_value) };
-        writer_.write_str(str, spec_);
-    }
-
-    void visit_char(int value) {
-        if (spec_.type_ && spec_.type_ != 'c') {
-            spec_.flags_ |= CHAR_FLAG;
-            writer_.write_int(value, spec_);
-            return;
-        }
-        if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
-            FMT_THROW(FormatError("invalid format specifier for char"));
-        typedef typename BasicWriter<Char>::CharPtr CharPtr;
-        Char fill = internal::CharTraits<Char>::cast(spec_.fill());
-        CharPtr out = CharPtr();
-        if (spec_.width_ > 1) {
-            out = writer_.grow_buffer(spec_.width_);
-            if (spec_.align_ == ALIGN_RIGHT) {
-                std::fill_n(out, spec_.width_ - 1, fill);
-                out += spec_.width_ - 1;
-            }
-            else if (spec_.align_ == ALIGN_CENTER) {
-                out = writer_.fill_padding(out, spec_.width_, 1, fill);
-            }
-            else {
-                std::fill_n(out + 1, spec_.width_ - 1, fill);
-            }
-        }
-        else {
-            out = writer_.grow_buffer(1);
-        }
-        *out = internal::CharTraits<Char>::cast(value);
-    }
-
-    void visit_string(Arg::StringValue<char> value) {
-        writer_.write_str(value, spec_);
-    }
-
-    using ArgVisitor<Impl, void>::visit_wstring;
-
-    void visit_wstring(Arg::StringValue<Char> value) {
-        writer_.write_str(value, spec_);
-    }
-
-    void visit_pointer(const void *value) {
-        if (spec_.type_ && spec_.type_ != 'p')
-            report_unknown_type(spec_.type_, "pointer");
-        spec_.flags_ = HASH_FLAG;
-        spec_.type_ = 'x';
-        writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
-    }
-};
-
-// An argument formatter.
-template <typename Char>
-class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
-private:
-    BasicFormatter<Char> &formatter_;
-    const Char *format_;
-
-public:
-    ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
-        : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
-          formatter_(f), format_(fmt) {}
-
-    void visit_custom(Arg::CustomValue c) {
-        c.format(&formatter_, c.value, &format_);
-    }
-};
-
-template <typename Char>
-class PrintfArgFormatter :
-    public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
-public:
-    PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
-        : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
-
-    void visit_char(int value) {
-        const FormatSpec &spec = this->spec();
-        BasicWriter<Char> &writer = this->writer();
-        if (spec.type_ && spec.type_ != 'c')
-            writer.write_int(value, spec);
-        typedef typename BasicWriter<Char>::CharPtr CharPtr;
-        CharPtr out = CharPtr();
-        if (spec.width_ > 1) {
-            Char fill = ' ';
-            out = writer.grow_buffer(spec.width_);
-            if (spec.align_ != ALIGN_LEFT) {
-                std::fill_n(out, spec.width_ - 1, fill);
-                out += spec.width_ - 1;
-            }
-            else {
-                std::fill_n(out + 1, spec.width_ - 1, fill);
-            }
-        }
-        else {
-            out = writer.grow_buffer(1);
-        }
-        *out = static_cast<Char>(value);
-    }
-};
-}  // namespace internal
-}  // namespace fmt
-
-FMT_FUNC void fmt::SystemError::init(
-    int err_code, CStringRef format_str, ArgList args) {
-    error_code_ = err_code;
-    MemoryWriter w;
-    internal::format_system_error(w, err_code, format(format_str, args));
-    std::runtime_error &base = *this;
-    base = std::runtime_error(w.str());
-}
-
-template <typename T>
-int fmt::internal::CharTraits<char>::format_float(
-    char *buffer, std::size_t size, const char *format,
-    unsigned width, int precision, T value) {
-    if (width == 0) {
-        return precision < 0 ?
-               FMT_SNPRINTF(buffer, size, format, value) :
-               FMT_SNPRINTF(buffer, size, format, precision, value);
-    }
-    return precision < 0 ?
-           FMT_SNPRINTF(buffer, size, format, width, value) :
-           FMT_SNPRINTF(buffer, size, format, width, precision, value);
-}
-
-template <typename T>
-int fmt::internal::CharTraits<wchar_t>::format_float(
-    wchar_t *buffer, std::size_t size, const wchar_t *format,
-    unsigned width, int precision, T value) {
-    if (width == 0) {
-        return precision < 0 ?
-               FMT_SWPRINTF(buffer, size, format, value) :
-               FMT_SWPRINTF(buffer, size, format, precision, value);
-    }
-    return precision < 0 ?
-           FMT_SWPRINTF(buffer, size, format, width, value) :
-           FMT_SWPRINTF(buffer, size, format, width, precision, value);
-}
-
-template <typename T>
-const char fmt::internal::BasicData<T>::DIGITS[] =
-    "0001020304050607080910111213141516171819"
-    "2021222324252627282930313233343536373839"
-    "4041424344454647484950515253545556575859"
-    "6061626364656667686970717273747576777879"
-    "8081828384858687888990919293949596979899";
-
-#define FMT_POWERS_OF_10(factor) \
-  factor * 10, \
-  factor * 100, \
-  factor * 1000, \
-  factor * 10000, \
-  factor * 100000, \
-  factor * 1000000, \
-  factor * 10000000, \
-  factor * 100000000, \
-  factor * 1000000000
-
-template <typename T>
-const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
-    0, FMT_POWERS_OF_10(1)
-};
-
-template <typename T>
-const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
-    0,
-    FMT_POWERS_OF_10(1),
-    FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
-    // Multiply several constants instead of using a single long long constant
-    // to avoid warnings about C++98 not supporting long long.
-    fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
-};
-
-FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
-    (void)type;
-    if (std::isprint(static_cast<unsigned char>(code))) {
-        FMT_THROW(fmt::FormatError(
-                      fmt::format("unknown format code '{}' for {}", code, type)));
-    }
-    FMT_THROW(fmt::FormatError(
-                  fmt::format("unknown format code '\\x{:02x}' for {}",
-                              static_cast<unsigned>(code), type)));
-}
-
-#if FMT_USE_WINDOWS_H
-
-FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
-    int length = MultiByteToWideChar(
-                     CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
-    static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
-    if (length == 0)
-        FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
-    buffer_.resize(length + 1);
-    length = MultiByteToWideChar(
-                 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
-    if (length == 0)
-        FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
-    buffer_[length] = 0;
-}
-
-FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
-    if (int error_code = convert(s)) {
-        FMT_THROW(WindowsError(error_code,
-                               "cannot convert string from UTF-16 to UTF-8"));
-    }
-}
-
-FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
-    int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
-    if (length == 0)
-        return GetLastError();
-    buffer_.resize(length + 1);
-    length = WideCharToMultiByte(
-                 CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
-    if (length == 0)
-        return GetLastError();
-    buffer_[length] = 0;
-    return 0;
-}
-
-FMT_FUNC void fmt::WindowsError::init(
-    int err_code, CStringRef format_str, ArgList args) {
-    error_code_ = err_code;
-    MemoryWriter w;
-    internal::format_windows_error(w, err_code, format(format_str, args));
-    std::runtime_error &base = *this;
-    base = std::runtime_error(w.str());
-}
-
-FMT_FUNC void fmt::internal::format_windows_error(
-    fmt::Writer &out, int error_code,
-    fmt::StringRef message) FMT_NOEXCEPT{
-    class String {
-    private:
-        LPWSTR str_;
-
-    public:
-        String() : str_() {}
-        ~String() {
-            LocalFree(str_);
-        }
-        LPWSTR *ptr() {
-            return &str_;
-        }
-        LPCWSTR c_str() const { return str_; }
-    };
-    FMT_TRY{
-        String system_message;
-        if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
-        error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-        reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
-            UTF16ToUTF8 utf8_message;
-            if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
-                out << message << ": " << utf8_message;
-                return;
-            }
-        }
-    } FMT_CATCH(...) {}
-    format_error_code(out, error_code, message);
-}
-
-#endif  // FMT_USE_WINDOWS_H
-
-FMT_FUNC void fmt::internal::format_system_error(
-    fmt::Writer &out, int error_code,
-    fmt::StringRef message) FMT_NOEXCEPT{
-    FMT_TRY{
-        MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
-        buffer.resize(INLINE_BUFFER_SIZE);
-        for (;;) {
-            char *system_message = &buffer[0];
-            int result = safe_strerror(error_code, system_message, buffer.size());
-            if (result == 0) {
-                out << message << ": " << system_message;
-                return;
-            }
-            if (result != ERANGE)
-                break;  // Can't get error message, report error code instead.
-            buffer.resize(buffer.size() * 2);
-        }
-    } FMT_CATCH(...) {}
-    format_error_code(out, error_code, message);
-}
-
-template <typename Char>
-void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
-    if (!map_.empty())
-        return;
-    typedef internal::NamedArg<Char> NamedArg;
-    const NamedArg *named_arg = 0;
-    bool use_values =
-        args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
-    if (use_values) {
-        for (unsigned i = 0;/*nothing*/; ++i) {
-            internal::Arg::Type arg_type = args.type(i);
-            switch (arg_type) {
-            case internal::Arg::NONE:
-                return;
-            case internal::Arg::NAMED_ARG:
-                named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
-                map_.insert(Pair(named_arg->name, *named_arg));
-                break;
-            default:
-                /*nothing*/
-                ;
-            }
-        }
-        return;
-    }
-    for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
-        internal::Arg::Type arg_type = args.type(i);
-        if (arg_type == internal::Arg::NAMED_ARG) {
-            named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
-            map_.insert(Pair(named_arg->name, *named_arg));
-        }
-    }
-    for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
-        switch (args.args_[i].type) {
-        case internal::Arg::NONE:
-            return;
-        case internal::Arg::NAMED_ARG:
-            named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
-            map_.insert(Pair(named_arg->name, *named_arg));
-            break;
-        default:
-            /*nothing*/
-            ;
-        }
-    }
-}
-
-template <typename Char>
-void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
-    FMT_THROW(std::runtime_error("buffer overflow"));
-}
-
-template <typename Char>
-template <typename StrChar>
-void fmt::BasicWriter<Char>::write_str(
-    const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
-    // Check if StrChar is convertible to Char.
-    internal::CharTraits<Char>::convert(StrChar());
-    if (spec.type_ && spec.type_ != 's')
-        internal::report_unknown_type(spec.type_, "string");
-    const StrChar *str_value = s.value;
-    std::size_t str_size = s.size;
-    if (str_size == 0) {
-        if (!str_value)
-            FMT_THROW(FormatError("string pointer is null"));
-        if (*str_value)
-            str_size = std::char_traits<StrChar>::length(str_value);
-    }
-    std::size_t precision = spec.precision_;
-    if (spec.precision_ >= 0 && precision < str_size)
-        str_size = spec.precision_;
-    write_str(str_value, str_size, spec);
-}
-
-template <typename Char>
-inline Arg fmt::BasicFormatter<Char>::get_arg(
-    BasicStringRef<Char> arg_name, const char *&error) {
-    if (check_no_auto_index(error)) {
-        map_.init(args());
-        const Arg *arg = map_.find(arg_name);
-        if (arg)
-            return *arg;
-        error = "argument not found";
-    }
-    return Arg();
-}
-
-template <typename Char>
-inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
-    const char *error = 0;
-    Arg arg = *s < '0' || *s > '9' ?
-              next_arg(error) : get_arg(parse_nonnegative_int(s), error);
-    if (error) {
-        FMT_THROW(FormatError(
-                      *s != '}' && *s != ':' ? "invalid format string" : error));
-    }
-    return arg;
-}
-
-template <typename Char>
-inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
-    assert(is_name_start(*s));
-    const Char *start = s;
-    Char c;
-    do {
-        c = *++s;
-    } while (is_name_start(c) || ('0' <= c && c <= '9'));
-    const char *error = 0;
-    Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
-    if (error)
-        FMT_THROW(fmt::FormatError(error));
-    return arg;
-}
-
-FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
-    unsigned arg_index, const char *&error) {
-    Arg arg = args_[arg_index];
-    switch (arg.type) {
-    case Arg::NONE:
-        error = "argument index out of range";
-        break;
-    case Arg::NAMED_ARG:
-        arg = *static_cast<const internal::Arg*>(arg.pointer);
-    default:
-        /*nothing*/
-        ;
-    }
-    return arg;
-}
-
-inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
-    if (next_arg_index_ >= 0)
-        return do_get_arg(next_arg_index_++, error);
-    error = "cannot switch from manual to automatic argument indexing";
-    return Arg();
-}
-
-inline bool fmt::internal::FormatterBase::check_no_auto_index(
-    const char *&error) {
-    if (next_arg_index_ > 0) {
-        error = "cannot switch from automatic to manual argument indexing";
-        return false;
-    }
-    next_arg_index_ = -1;
-    return true;
-}
-
-inline Arg fmt::internal::FormatterBase::get_arg(
-    unsigned arg_index, const char *&error) {
-    return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
-}
-
-template <typename Char>
-void fmt::internal::PrintfFormatter<Char>::parse_flags(
-    FormatSpec &spec, const Char *&s) {
-    for (;;) {
-        switch (*s++) {
-        case '-':
-            spec.align_ = ALIGN_LEFT;
-            break;
-        case '+':
-            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
-            break;
-        case '0':
-            spec.fill_ = '0';
-            break;
-        case ' ':
-            spec.flags_ |= SIGN_FLAG;
-            break;
-        case '#':
-            spec.flags_ |= HASH_FLAG;
-            break;
-        default:
-            --s;
-            return;
-        }
-    }
-}
-
-template <typename Char>
-Arg fmt::internal::PrintfFormatter<Char>::get_arg(
-    const Char *s, unsigned arg_index) {
-    (void)s;
-    const char *error = 0;
-    Arg arg = arg_index == UINT_MAX ?
-              next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
-    if (error)
-        FMT_THROW(FormatError(!*s ? "invalid format string" : error));
-    return arg;
-}
-
-template <typename Char>
-unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
-    const Char *&s, FormatSpec &spec) {
-    unsigned arg_index = UINT_MAX;
-    Char c = *s;
-    if (c >= '0' && c <= '9') {
-        // Parse an argument index (if followed by '$') or a width possibly
-        // preceded with '0' flag(s).
-        unsigned value = parse_nonnegative_int(s);
-        if (*s == '$') {  // value is an argument index
-            ++s;
-            arg_index = value;
-        }
-        else {
-            if (c == '0')
-                spec.fill_ = '0';
-            if (value != 0) {
-                // Nonzero value means that we parsed width and don't need to
-                // parse it or flags again, so return now.
-                spec.width_ = value;
-                return arg_index;
-            }
-        }
-    }
-    parse_flags(spec, s);
-    // Parse width.
-    if (*s >= '0' && *s <= '9') {
-        spec.width_ = parse_nonnegative_int(s);
-    }
-    else if (*s == '*') {
-        ++s;
-        spec.width_ = WidthHandler(spec).visit(get_arg(s));
-    }
-    return arg_index;
-}
-
-template <typename Char>
-void fmt::internal::PrintfFormatter<Char>::format(
-    BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
-    const ArgList &args) {
-    const Char *start = format_str.c_str();
-    set_args(args);
-    const Char *s = start;
-    while (*s) {
-        Char c = *s++;
-        if (c != '%') continue;
-        if (*s == c) {
-            write(writer, start, s);
-            start = ++s;
-            continue;
-        }
-        write(writer, start, s - 1);
-
-        FormatSpec spec;
-        spec.align_ = ALIGN_RIGHT;
-
-        // Parse argument index, flags and width.
-        unsigned arg_index = parse_header(s, spec);
-
-        // Parse precision.
-        if (*s == '.') {
-            ++s;
-            if ('0' <= *s && *s <= '9') {
-                spec.precision_ = parse_nonnegative_int(s);
-            }
-            else if (*s == '*') {
-                ++s;
-                spec.precision_ = PrecisionHandler().visit(get_arg(s));
-            }
-        }
-
-        Arg arg = get_arg(s, arg_index);
-        if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
-            spec.flags_ &= ~HASH_FLAG;
-        if (spec.fill_ == '0') {
-            if (arg.type <= Arg::LAST_NUMERIC_TYPE)
-                spec.align_ = ALIGN_NUMERIC;
-            else
-                spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
-        }
-
-        // Parse length and convert the argument to the required type.
-        switch (*s++) {
-        case 'h':
-            if (*s == 'h')
-                ArgConverter<signed char>(arg, *++s).visit(arg);
-            else
-                ArgConverter<short>(arg, *s).visit(arg);
-            break;
-        case 'l':
-            if (*s == 'l')
-                ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
-            else
-                ArgConverter<long>(arg, *s).visit(arg);
-            break;
-        case 'j':
-            ArgConverter<intmax_t>(arg, *s).visit(arg);
-            break;
-        case 'z':
-            ArgConverter<size_t>(arg, *s).visit(arg);
-            break;
-        case 't':
-            ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
-            break;
-        case 'L':
-            // printf produces garbage when 'L' is omitted for long double, no
-            // need to do the same.
-            break;
-        default:
-            --s;
-            ArgConverter<int>(arg, *s).visit(arg);
-        }
-
-        // Parse type.
-        if (!*s)
-            FMT_THROW(FormatError("invalid format string"));
-        spec.type_ = static_cast<char>(*s++);
-        if (arg.type <= Arg::LAST_INTEGER_TYPE) {
-            // Normalize type.
-            switch (spec.type_) {
-            case 'i':
-            case 'u':
-                spec.type_ = 'd';
-                break;
-            case 'c':
-                // TODO: handle wchar_t
-                CharConverter(arg).visit(arg);
-                break;
-            }
-        }
-
-        start = s;
-
-        // Format argument.
-        internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
-    }
-    write(writer, start, s);
-}
-
-template <typename Char>
-const Char *fmt::BasicFormatter<Char>::format(
-    const Char *&format_str, const Arg &arg) {
-    const Char *s = format_str;
-    FormatSpec spec;
-    if (*s == ':') {
-        if (arg.type == Arg::CUSTOM) {
-            arg.custom.format(this, arg.custom.value, &s);
-            return s;
-        }
-        ++s;
-        // Parse fill and alignment.
-        if (Char c = *s) {
-            const Char *p = s + 1;
-            spec.align_ = ALIGN_DEFAULT;
-            do {
-                switch (*p) {
-                case '<':
-                    spec.align_ = ALIGN_LEFT;
-                    break;
-                case '>':
-                    spec.align_ = ALIGN_RIGHT;
-                    break;
-                case '=':
-                    spec.align_ = ALIGN_NUMERIC;
-                    break;
-                case '^':
-                    spec.align_ = ALIGN_CENTER;
-                    break;
-                }
-                if (spec.align_ != ALIGN_DEFAULT) {
-                    if (p != s) {
-                        if (c == '}') break;
-                        if (c == '{')
-                            FMT_THROW(FormatError("invalid fill character '{'"));
-                        s += 2;
-                        spec.fill_ = c;
-                    }
-                    else ++s;
-                    if (spec.align_ == ALIGN_NUMERIC)
-                        require_numeric_argument(arg, '=');
-                    break;
-                }
-            } while (--p >= s);
-        }
-
-        // Parse sign.
-        switch (*s) {
-        case '+':
-            check_sign(s, arg);
-            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
-            break;
-        case '-':
-            check_sign(s, arg);
-            spec.flags_ |= MINUS_FLAG;
-            break;
-        case ' ':
-            check_sign(s, arg);
-            spec.flags_ |= SIGN_FLAG;
-            break;
-        }
-
-        if (*s == '#') {
-            require_numeric_argument(arg, '#');
-            spec.flags_ |= HASH_FLAG;
-            ++s;
-        }
-
-        // Parse zero flag.
-        if (*s == '0') {
-            require_numeric_argument(arg, '0');
-            spec.align_ = ALIGN_NUMERIC;
-            spec.fill_ = '0';
-            ++s;
-        }
-
-        // Parse width.
-        if ('0' <= *s && *s <= '9') {
-            spec.width_ = parse_nonnegative_int(s);
-        }
-        else if (*s == '{') {
-            ++s;
-            Arg width_arg = is_name_start(*s) ?
-                            parse_arg_name(s) : parse_arg_index(s);
-            if (*s++ != '}')
-                FMT_THROW(FormatError("invalid format string"));
-            ULongLong value = 0;
-            switch (width_arg.type) {
-            case Arg::INT:
-                if (width_arg.int_value < 0)
-                    FMT_THROW(FormatError("negative width"));
-                value = width_arg.int_value;
-                break;
-            case Arg::UINT:
-                value = width_arg.uint_value;
-                break;
-            case Arg::LONG_LONG:
-                if (width_arg.long_long_value < 0)
-                    FMT_THROW(FormatError("negative width"));
-                value = width_arg.long_long_value;
-                break;
-            case Arg::ULONG_LONG:
-                value = width_arg.ulong_long_value;
-                break;
-            default:
-                FMT_THROW(FormatError("width is not integer"));
-            }
-            if (value > INT_MAX)
-                FMT_THROW(FormatError("number is too big"));
-            spec.width_ = static_cast<int>(value);
-        }
-
-        // Parse precision.
-        if (*s == '.') {
-            ++s;
-            spec.precision_ = 0;
-            if ('0' <= *s && *s <= '9') {
-                spec.precision_ = parse_nonnegative_int(s);
-            }
-            else if (*s == '{') {
-                ++s;
-                Arg precision_arg =
-                    is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
-                if (*s++ != '}')
-                    FMT_THROW(FormatError("invalid format string"));
-                ULongLong value = 0;
-                switch (precision_arg.type) {
-                case Arg::INT:
-                    if (precision_arg.int_value < 0)
-                        FMT_THROW(FormatError("negative precision"));
-                    value = precision_arg.int_value;
-                    break;
-                case Arg::UINT:
-                    value = precision_arg.uint_value;
-                    break;
-                case Arg::LONG_LONG:
-                    if (precision_arg.long_long_value < 0)
-                        FMT_THROW(FormatError("negative precision"));
-                    value = precision_arg.long_long_value;
-                    break;
-                case Arg::ULONG_LONG:
-                    value = precision_arg.ulong_long_value;
-                    break;
-                default:
-                    FMT_THROW(FormatError("precision is not integer"));
-                }
-                if (value > INT_MAX)
-                    FMT_THROW(FormatError("number is too big"));
-                spec.precision_ = static_cast<int>(value);
-            }
-            else {
-                FMT_THROW(FormatError("missing precision specifier"));
-            }
-            if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
-                FMT_THROW(FormatError(
-                              fmt::format("precision not allowed in {} format specifier",
-                                          arg.type == Arg::POINTER ? "pointer" : "integer")));
-            }
-        }
-
-        // Parse type.
-        if (*s != '}' && *s)
-            spec.type_ = static_cast<char>(*s++);
-    }
-
-    if (*s++ != '}')
-        FMT_THROW(FormatError("missing '}' in format string"));
-    start_ = s;
-
-    // Format argument.
-    internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
-    return s;
-}
-
-template <typename Char>
-void fmt::BasicFormatter<Char>::format(
-    BasicCStringRef<Char> format_str, const ArgList &args) {
-    const Char *s = start_ = format_str.c_str();
-    set_args(args);
-    while (*s) {
-        Char c = *s++;
-        if (c != '{' && c != '}') continue;
-        if (*s == c) {
-            write(writer_, start_, s);
-            start_ = ++s;
-            continue;
-        }
-        if (c == '}')
-            FMT_THROW(FormatError("unmatched '}' in format string"));
-        write(writer_, start_, s - 1);
-        Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
-        s = format(s, arg);
-    }
-    write(writer_, start_, s);
-}
-
-FMT_FUNC void fmt::report_system_error(
-    int error_code, fmt::StringRef message) FMT_NOEXCEPT{
-    report_error(internal::format_system_error, error_code, message);
-}
-
-#if FMT_USE_WINDOWS_H
-FMT_FUNC void fmt::report_windows_error(
-    int error_code, fmt::StringRef message) FMT_NOEXCEPT{
-    report_error(internal::format_windows_error, error_code, message);
-}
-#endif
-
-FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
-    MemoryWriter w;
-    w.write(format_str, args);
-    std::fwrite(w.data(), 1, w.size(), f);
-}
-
-FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
-    print(stdout, format_str, args);
-}
-
-FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
-    MemoryWriter w;
-    w.write(format_str, args);
-    os.write(w.data(), w.size());
-}
-
-FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
-    char escape[] = "\x1b[30m";
-    escape[3] = '0' + static_cast<char>(c);
-    std::fputs(escape, stdout);
-    print(format, args);
-    std::fputs(RESET_COLOR, stdout);
-}
-
-FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
-    MemoryWriter w;
-    printf(w, format, args);
-    std::size_t size = w.size();
-    return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
-}
-
-#ifndef FMT_HEADER_ONLY
-
-template struct fmt::internal::BasicData<void>;
-
-// Explicit instantiations for char.
-
-template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
-
-template const char *fmt::BasicFormatter<char>::format(
-    const char *&format_str, const fmt::internal::Arg &arg);
-
-template void fmt::BasicFormatter<char>::format(
-    CStringRef format, const ArgList &args);
-
-template void fmt::internal::PrintfFormatter<char>::format(
-    BasicWriter<char> &writer, CStringRef format, const ArgList &args);
-
-template int fmt::internal::CharTraits<char>::format_float(
-    char *buffer, std::size_t size, const char *format,
-    unsigned width, int precision, double value);
-
-template int fmt::internal::CharTraits<char>::format_float(
-    char *buffer, std::size_t size, const char *format,
-    unsigned width, int precision, long double value);
-
-// Explicit instantiations for wchar_t.
-
-template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
-
-template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
-    const wchar_t *&format_str, const fmt::internal::Arg &arg);
-
-template void fmt::BasicFormatter<wchar_t>::format(
-    BasicCStringRef<wchar_t> format, const ArgList &args);
-
-template void fmt::internal::PrintfFormatter<wchar_t>::format(
-    BasicWriter<wchar_t> &writer, WCStringRef format,
-    const ArgList &args);
-
-template int fmt::internal::CharTraits<wchar_t>::format_float(
-    wchar_t *buffer, std::size_t size, const wchar_t *format,
-    unsigned width, int precision, double value);
-
-template int fmt::internal::CharTraits<wchar_t>::format_float(
-    wchar_t *buffer, std::size_t size, const wchar_t *format,
-    unsigned width, int precision, long double value);
-
-#endif  // FMT_HEADER_ONLY
-
-#if _MSC_VER
-# pragma warning(pop)
-#endif
\ No newline at end of file


[08/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/ProcessContext.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ProcessContext.h b/libminifi/include/ProcessContext.h
new file mode 100644
index 0000000..2a88b93
--- /dev/null
+++ b/libminifi/include/ProcessContext.h
@@ -0,0 +1,99 @@
+/**
+ * @file ProcessContext.h
+ * ProcessContext class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __PROCESS_CONTEXT_H__
+#define __PROCESS_CONTEXT_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+
+#include "Logger.h"
+#include "Processor.h"
+
+//! ProcessContext Class
+class ProcessContext
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new process context associated with the processor/controller service/state manager
+	 */
+	ProcessContext(Processor *processor = NULL) : _processor(processor) {
+		_logger = Logger::getLogger();
+	}
+	//! Destructor
+	virtual ~ProcessContext() {}
+	//! Get Processor associated with the Process Context
+	Processor *getProcessor() {
+		return _processor;
+	}
+	bool getProperty(std::string name, std::string &value) {
+		if (_processor)
+			return _processor->getProperty(name, value);
+		else
+			return false;
+	}
+	//! Whether the relationship is supported
+	bool isSupportedRelationship(Relationship relationship) {
+		if (_processor)
+			return _processor->isSupportedRelationship(relationship);
+		else
+			return false;
+	}
+	//! Check whether the relationship is auto terminated
+	bool isAutoTerminated(Relationship relationship) {
+		if (_processor)
+			return _processor->isAutoTerminated(relationship);
+		else
+			return false;
+	}
+	//! Get ProcessContext Maximum Concurrent Tasks
+	uint8_t getMaxConcurrentTasks(void) {
+		if (_processor)
+			return _processor->getMaxConcurrentTasks();
+		else
+			return 0;
+	}
+	//! Yield based on the yield period
+	void yield() {
+		if (_processor)
+			_processor->yield();
+	}
+
+protected:
+
+private:
+
+	//! Processor
+	Processor *_processor;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	ProcessContext(const ProcessContext &parent);
+	ProcessContext &operator=(const ProcessContext &parent);
+	//! Logger
+	Logger *_logger;
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/ProcessGroup.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ProcessGroup.h b/libminifi/include/ProcessGroup.h
new file mode 100644
index 0000000..4dd26f8
--- /dev/null
+++ b/libminifi/include/ProcessGroup.h
@@ -0,0 +1,182 @@
+/**
+ * @file ProcessGroup.h
+ * ProcessGroup class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __PROCESS_GROUP_H__
+#define __PROCESS_GROUP_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+#include <set>
+
+#include "Logger.h"
+#include "Processor.h"
+#include "Exception.h"
+#include "TimerDrivenSchedulingAgent.h"
+
+//! Process Group Type
+enum ProcessGroupType
+{
+	ROOT_PROCESS_GROUP = 0,
+	REMOTE_PROCESS_GROUP,
+	MAX_PROCESS_GROUP_TYPE
+};
+
+//! ProcessGroup Class
+class ProcessGroup
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new process group
+	 */
+	ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid = NULL, ProcessGroup *parent = NULL);
+	//! Destructor
+	virtual ~ProcessGroup();
+	//! Set Processor Name
+	void setName(std::string name) {
+		_name = name;
+	}
+	//! Get Process Name
+	std::string getName(void) {
+		return (_name);
+	}
+	//! Set URL
+	void setURL(std::string url) {
+		_url = url;
+	}
+	//! Get URL
+	std::string getURL(void) {
+		return (_url);
+	}
+	//! SetTransmitting
+	void setTransmitting(bool val)
+	{
+		_transmitting = val;
+	}
+	//! Get Transmitting
+	bool getTransmitting()
+	{
+		return _transmitting;
+	}
+	//! setTimeOut
+	void setTimeOut(uint64_t time)
+	{
+		_timeOut = time;
+	}
+	uint64_t getTimeOut()
+	{
+		return _timeOut;
+	}
+	//! Set Processor yield period in MilliSecond
+	void setYieldPeriodMsec(uint64_t period) {
+		_yieldPeriodMsec = period;
+	}
+	//! Get Processor yield period in MilliSecond
+	uint64_t getYieldPeriodMsec(void) {
+		return(_yieldPeriodMsec);
+	}
+	//! Set UUID
+	void setUUID(uuid_t uuid) {
+		uuid_copy(_uuid, uuid);
+	}
+	//! Get UUID
+	bool getUUID(uuid_t uuid) {
+		if (uuid)
+		{
+			uuid_copy(uuid, _uuid);
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Start Processing
+	void startProcessing(TimerDrivenSchedulingAgent *timeScheduler);
+	//! Stop Processing
+	void stopProcessing(TimerDrivenSchedulingAgent *timeScheduler);
+	//! Whether it is root process group
+	bool isRootProcessGroup();
+	//! set parent process group
+	void setParent(ProcessGroup *parent) {
+		std::lock_guard<std::mutex> lock(_mtx);
+		_parentProcessGroup = parent;
+	}
+	//! get parent process group
+	ProcessGroup *getParent(void) {
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _parentProcessGroup;
+	}
+	//! Add processor
+	void addProcessor(Processor *processor);
+	//! Remove processor
+	void removeProcessor(Processor *processor);
+	//! Add child processor group
+	void addProcessGroup(ProcessGroup *child);
+	//! Remove child processor group
+	void removeProcessGroup(ProcessGroup *child);
+	// ! Add connections
+	void addConnection(Connection *connection);
+	//! findProcessor based on UUID
+	Processor *findProcessor(uuid_t uuid);
+	//! findProcessor based on name
+	Processor *findProcessor(std::string processorName);
+	//! removeConnection
+	void removeConnection(Connection *connection);
+	//! update property value
+	void updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue);
+
+protected:
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! Processor Group Name
+	std::string _name;
+	//! Process Group Type
+	ProcessGroupType _type;
+	//! Processors (ProcessNode) inside this process group which include Input/Output Port, Remote Process Group input/Output port
+	std::set<Processor *> _processors;
+	std::set<ProcessGroup *> _childProcessGroups;
+	//! Connections between the processor inside the group;
+	std::set<Connection *> _connections;
+	//! Parent Process Group
+	ProcessGroup* _parentProcessGroup;
+	//! Yield Period in Milliseconds
+	std::atomic<uint64_t> _yieldPeriodMsec;
+	std::atomic<uint64_t> _timeOut;
+	//! URL
+	std::string _url;
+	//! Transmitting
+	std::atomic<bool> _transmitting;
+
+private:
+
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Logger
+	Logger *_logger;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	ProcessGroup(const ProcessGroup &parent);
+	ProcessGroup &operator=(const ProcessGroup &parent);
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/ProcessSession.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ProcessSession.h b/libminifi/include/ProcessSession.h
new file mode 100644
index 0000000..c8ec3a5
--- /dev/null
+++ b/libminifi/include/ProcessSession.h
@@ -0,0 +1,116 @@
+/**
+ * @file ProcessSession.h
+ * ProcessSession class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __PROCESS_SESSION_H__
+#define __PROCESS_SESSION_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+#include <set>
+
+#include "Logger.h"
+#include "Processor.h"
+#include "ProcessContext.h"
+#include "FlowFileRecord.h"
+#include "Exception.h"
+
+//! ProcessSession Class
+class ProcessSession
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new process session
+	 */
+	ProcessSession(ProcessContext *processContext = NULL) : _processContext(processContext) {
+		_logger = Logger::getLogger();
+		_logger->log_trace("ProcessSession created for %s", _processContext->getProcessor()->getName().c_str());
+	}
+	//! Destructor
+	virtual ~ProcessSession() {}
+	//! Commit the session
+	void commit();
+	//! Roll Back the session
+	void rollback();
+	//!
+	//! Get the FlowFile from the highest priority queue
+	FlowFileRecord *get();
+	//! Create a new UUID FlowFile with no content resource claim and without parent
+	FlowFileRecord *create();
+	//! Create a new UUID FlowFile with no content resource claim and inherit all attributes from parent
+	FlowFileRecord *create(FlowFileRecord *parent);
+	//! Clone a new UUID FlowFile from parent both for content resource claim and attributes
+	FlowFileRecord *clone(FlowFileRecord *parent);
+	//! Clone a new UUID FlowFile from parent for attributes and sub set of parent content resource claim
+	FlowFileRecord *clone(FlowFileRecord *parent, long offset, long size);
+	//! Duplicate a FlowFile with the same UUID and all attributes and content resource claim for the roll back of the session
+	FlowFileRecord *duplicate(FlowFileRecord *orignal);
+	//! Transfer the FlowFile to the relationship
+	void transfer(FlowFileRecord *flow, Relationship relationship);
+	//! Put Attribute
+	void putAttribute(FlowFileRecord *flow, std::string key, std::string value);
+	//! Remove Attribute
+	void removeAttribute(FlowFileRecord *flow, std::string key);
+	//! Remove Flow File
+	void remove(FlowFileRecord *flow);
+	//! Execute the given read callback against the content
+	void read(FlowFileRecord *flow, InputStreamCallback *callback);
+	//! Execute the given write callback against the content
+	void write(FlowFileRecord *flow, OutputStreamCallback *callback);
+	//! Execute the given write/append callback against the content
+	void append(FlowFileRecord *flow, OutputStreamCallback *callback);
+	//! Penalize the flow
+	void penalize(FlowFileRecord *flow);
+	//! Import the existed file into the flow
+	void import(std::string source, FlowFileRecord *flow, bool keepSource = true, uint64_t offset = 0);
+
+protected:
+	//! FlowFiles being modified by current process session
+	std::map<std::string, FlowFileRecord *> _updatedFlowFiles;
+	//! Copy of the original FlowFiles being modified by current process session as above
+	std::map<std::string, FlowFileRecord *> _originalFlowFiles;
+	//! FlowFiles being added by current process session
+	std::map<std::string, FlowFileRecord *> _addedFlowFiles;
+	//! FlowFiles being deleted by current process session
+	std::map<std::string, FlowFileRecord *> _deletedFlowFiles;
+	//! FlowFiles being transfered to the relationship
+	std::map<std::string, Relationship> _transferRelationship;
+	//! FlowFiles being cloned for multiple connections per relationship
+	std::map<std::string, FlowFileRecord *> _clonedFlowFiles;
+
+private:
+	// Clone the flow file during transfer to multiple connections for a relationship
+	FlowFileRecord* cloneDuringTransfer(FlowFileRecord *parent);
+	//! ProcessContext
+	ProcessContext *_processContext;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	ProcessSession(const ProcessSession &parent);
+	ProcessSession &operator=(const ProcessSession &parent);
+	//! Logger
+	Logger *_logger;
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Processor.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Processor.h b/libminifi/include/Processor.h
new file mode 100644
index 0000000..db26ad0
--- /dev/null
+++ b/libminifi/include/Processor.h
@@ -0,0 +1,346 @@
+/**
+ * @file Processor.h
+ * Processor class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __PROCESSOR_H__
+#define __PROCESSOR_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+#include <set>
+
+#include "TimeUtil.h"
+#include "Property.h"
+#include "Relationship.h"
+#include "Connection.h"
+
+//! Forwarder declaration
+class ProcessContext;
+class ProcessSession;
+
+//! Minimum scheduling period in Nano Second
+#define MINIMUM_SCHEDULING_NANOS 30000
+
+//! Default yield period in second
+#define DEFAULT_YIELD_PERIOD_SECONDS 1
+
+//! Default penalization period in second
+#define DEFAULT_PENALIZATION_PERIOD_SECONDS 30
+
+/*!
+ * Indicates the valid values for the state of a entity
+ * with respect to scheduling the entity to run.
+ */
+enum ScheduledState {
+
+    /**
+     * Entity cannot be scheduled to run
+     */
+    DISABLED,
+    /**
+     * Entity can be scheduled to run but currently is not
+     */
+    STOPPED,
+    /**
+     * Entity is currently scheduled to run
+     */
+    RUNNING
+};
+
+/*!
+ * Scheduling Strategy
+ */
+enum SchedulingStrategy {
+	//! Event driven
+	EVENT_DRIVEN,
+	//! Timer driven
+	TIMER_DRIVEN,
+	//! Cron Driven
+	CRON_DRIVEN
+};
+
+//! Processor Class
+class Processor
+{
+	friend class ProcessContext;
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	Processor(std::string name, uuid_t uuid = NULL);
+	//! Destructor
+	virtual ~Processor();
+	//! Set Processor Name
+	void setName(std::string name) {
+		_name = name;
+	}
+	//! Get Process Name
+	std::string getName(void) {
+		return (_name);
+	}
+	//! Set UUID
+	void setUUID(uuid_t uuid) {
+		uuid_copy(_uuid, uuid);
+		char uuidStr[37];
+		uuid_unparse(_uuid, uuidStr);
+		_uuidStr = uuidStr;
+	}
+	//! Get UUID
+	bool getUUID(uuid_t uuid) {
+		if (uuid)
+		{
+			uuid_copy(uuid, _uuid);
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Set the supported processor properties while the process is not running
+	bool setSupportedProperties(std::set<Property> properties);
+	//! Set the supported relationships while the process is not running
+	bool setSupportedRelationships(std::set<Relationship> relationships);
+	//! Get the supported property value by name
+	bool getProperty(std::string name, std::string &value);
+	//! Set the supported property value by name wile the process is not running
+	bool setProperty(std::string name, std::string value);
+	//! Whether the relationship is supported
+	bool isSupportedRelationship(Relationship relationship);
+	//! Set the auto terminated relationships while the process is not running
+	bool setAutoTerminatedRelationships(std::set<Relationship> relationships);
+	//! Check whether the relationship is auto terminated
+	bool isAutoTerminated(Relationship relationship);
+	//! Check whether the processor is running
+	bool isRunning();
+	//! Set Processor Scheduled State
+	void setScheduledState(ScheduledState state) {
+		_state = state;
+	}
+	//! Get Processor Scheduled State
+	ScheduledState getScheduledState(void) {
+		return _state;
+	}
+	//! Set Processor Scheduling Strategy
+	void setSchedulingStrategy(SchedulingStrategy strategy) {
+		_strategy = strategy;
+	}
+	//! Get Processor Scheduling Strategy
+	SchedulingStrategy getSchedulingStrategy(void) {
+		return _strategy;
+	}
+	//! Set Processor Loss Tolerant
+	void setlossTolerant(bool lossTolerant) {
+		_lossTolerant = lossTolerant;
+	}
+	//! Get Processor Loss Tolerant
+	bool getlossTolerant(void) {
+		return _lossTolerant;
+	}
+	//! Set Processor Scheduling Period in Nano Second
+	void setSchedulingPeriodNano(uint64_t period) {
+		uint64_t minPeriod = MINIMUM_SCHEDULING_NANOS;
+		_schedulingPeriodNano = std::max(period, minPeriod);
+	}
+	//! Get Processor Scheduling Period in Nano Second
+	uint64_t getSchedulingPeriodNano(void) {
+		return _schedulingPeriodNano;
+	}
+	//! Set Processor Run Duration in Nano Second
+	void setRunDurationNano(uint64_t period) {
+		_runDurantionNano = period;
+	}
+	//! Get Processor Run Duration in Nano Second
+	uint64_t getRunDurationNano(void) {
+		return(_runDurantionNano);
+	}
+	//! Set Processor yield period in MilliSecond
+	void setYieldPeriodMsec(uint64_t period) {
+		_yieldPeriodMsec = period;
+	}
+	//! Get Processor yield period in MilliSecond
+	uint64_t getYieldPeriodMsec(void) {
+		return(_yieldPeriodMsec);
+	}
+	//! Set Processor penalization period in MilliSecond
+	void setPenalizationPeriodMsec(uint64_t period) {
+		_penalizationPeriodMsec = period;
+	}
+	//! Get Processor penalization period in MilliSecond
+	uint64_t getPenalizationPeriodMsec(void) {
+		return(_penalizationPeriodMsec);
+	}
+	//! Set Processor Maximum Concurrent Tasks
+	void setMaxConcurrentTasks(uint8_t tasks) {
+		_maxConcurrentTasks = tasks;
+	}
+	//! Get Processor Maximum Concurrent Tasks
+	uint8_t getMaxConcurrentTasks(void) {
+		return(_maxConcurrentTasks);
+	}
+	//! Set Trigger when empty
+	void setTriggerWhenEmpty(bool value) {
+		_triggerWhenEmpty = value;
+	}
+	//! Get Trigger when empty
+	bool getTriggerWhenEmpty(void) {
+		return(_triggerWhenEmpty);
+	}
+	//! Get Active Task Counts
+	uint8_t getActiveTasks(void) {
+		return(_activeTasks);
+	}
+	//! Increment Active Task Counts
+	void incrementActiveTasks(void) {
+		_activeTasks++;
+	}
+	//! decrement Active Task Counts
+	void decrementActiveTask(void) {
+		_activeTasks--;
+	}
+	void clearActiveTask(void) {
+		_activeTasks = 0;
+	}
+	//! Yield based on the yield period
+	void yield()
+	{
+		_yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
+	}
+	//! Yield based on the input time
+	void yield(uint64_t time)
+	{
+		_yieldExpiration = (getTimeMillis() + time);
+	}
+	//! whether need be to yield
+	bool isYield()
+	{
+		if (_yieldExpiration > 0)
+			return (_yieldExpiration >= getTimeMillis());
+		else
+			return false;
+	}
+	// clear yield expiration
+	void clearYield()
+	{
+		_yieldExpiration = 0;
+	}
+	// get yield time
+	uint64_t getYieldTime()
+	{
+		uint64_t curTime = getTimeMillis();
+		if (_yieldExpiration > curTime)
+			return (_yieldExpiration - curTime);
+		else
+			return 0;;
+	}
+	//! Whether flow file queued in incoming connection
+	bool flowFilesQueued();
+	//! Whether flow file queue full in any of the outgoin connection
+	bool flowFilesOutGoingFull();
+	//! Get incoming connections
+	std::set<Connection *> getIncomingConnections() {
+		return _incomingConnections;
+	}
+	//! Has Incoming Connection
+	bool hasIncomingConnections() {
+		return (_incomingConnections.size() > 0);
+	}
+	//! Get outgoing connections based on relationship name
+	std::set<Connection *> getOutGoingConnections(std::string relationship);
+	//! Add connection
+	bool addConnection(Connection *connection);
+	//! Remove connection
+	void removeConnection(Connection *connection);
+	//! Get the UUID as string
+	std::string getUUIDStr() {
+		return _uuidStr;
+	}
+	//! Get the Next RoundRobin incoming connection
+	Connection *getNextIncomingConnection();
+	//! On Trigger
+	void onTrigger();
+
+public:
+	//! OnTrigger method, implemented by NiFi Processor Designer
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session) = 0;
+	//! Initialize, over write by NiFi Process Designer
+	virtual void initialize(void) {
+		return;
+	}
+
+protected:
+
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! Processor Name
+	std::string _name;
+	//! Supported properties
+	std::map<std::string, Property> _properties;
+	//! Supported relationships
+	std::map<std::string, Relationship> _relationships;
+	//! Autoterminated relationships
+	std::map<std::string, Relationship> _autoTerminatedRelationships;
+	//! Processor state
+	std::atomic<ScheduledState> _state;
+	//! Scheduling Strategy
+	std::atomic<SchedulingStrategy> _strategy;
+	//! lossTolerant
+	std::atomic<bool> _lossTolerant;
+	//! SchedulePeriod in Nano Seconds
+	std::atomic<uint64_t> _schedulingPeriodNano;
+	//! Run Duration in Nano Seconds
+	std::atomic<uint64_t> _runDurantionNano;
+	//! Yield Period in Milliseconds
+	std::atomic<uint64_t> _yieldPeriodMsec;
+	//! Penalization Period in MilliSecond
+	std::atomic<uint64_t> _penalizationPeriodMsec;
+	//! Maximum Concurrent Tasks
+	std::atomic<uint8_t> _maxConcurrentTasks;
+	//! Active Tasks
+	std::atomic<uint8_t> _activeTasks;
+	//! Trigger the Processor even if the incoming connection is empty
+	std::atomic<bool> _triggerWhenEmpty;
+	//! Incoming connections
+	std::set<Connection *> _incomingConnections;
+	//! Outgoing connections map based on Relationship name
+	std::map<std::string, std::set<Connection *>> _outGoingConnections;
+	//! UUID string
+	std::string _uuidStr;
+
+private:
+
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Yield Expiration
+	std::atomic<uint64_t> _yieldExpiration;
+	//! Incoming connection Iterator
+	std::set<Connection *>::iterator _incomingConnectionsIter;
+	//! Logger
+	Logger *_logger;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Processor(const Processor &parent);
+	Processor &operator=(const Processor &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Property.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Property.h b/libminifi/include/Property.h
new file mode 100644
index 0000000..a724394
--- /dev/null
+++ b/libminifi/include/Property.h
@@ -0,0 +1,344 @@
+/**
+ * @file Property.h
+ * Processor Property class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __PROPERTY_H__
+#define __PROPERTY_H__
+
+#include <string>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <set>
+#include <stdlib.h>
+#include <math.h>
+
+//! Time Unit
+enum TimeUnit {
+	DAY,
+	HOUR,
+	MINUTE,
+	SECOND,
+	MILLISECOND,
+	NANOSECOND
+};
+
+//! Property Class
+class Property {
+
+public:
+	//! Constructor
+	/*!
+	 * Create a new property
+	 */
+	Property(const std::string name, const std::string description, const std::string value)
+		: _name(name), _description(description), _value(value) {
+	}
+	Property() {}
+	//! Destructor
+	virtual ~Property() {}
+	//! Get Name for the property
+	std::string getName() {
+		return _name;
+	}
+	//! Get Description for the property
+	std::string getDescription() {
+		return _description;
+	}
+	//! Get value for the property
+	std::string getValue() {
+		return _value;
+	}
+	//! Set value for the property
+	void setValue(std::string value) {
+		_value = value;
+	}
+	//! Compare
+	bool operator < (const Property & right) const {
+		return _name < right._name;
+	}
+
+	//! Convert TimeUnit to MilliSecond
+	static bool ConvertTimeUnitToMS(int64_t input, TimeUnit unit, int64_t &out)
+	{
+		if (unit == MILLISECOND)
+		{
+			out = input;
+			return true;
+		}
+		else if (unit == SECOND)
+		{
+			out = input * 1000;
+			return true;
+		}
+		else if (unit == MINUTE)
+		{
+			out = input * 60 * 1000;
+			return true;
+		}
+		else if (unit == HOUR)
+		{
+			out = input * 60 * 60 * 1000;
+			return true;
+		}
+		else if (unit == DAY)
+		{
+			out = 24 * 60 * 60 * 1000;
+			return true;
+		}
+		else if (unit == NANOSECOND)
+		{
+			out = input/1000/1000;
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	//! Convert TimeUnit to NanoSecond
+	static bool ConvertTimeUnitToNS(int64_t input, TimeUnit unit, int64_t &out)
+	{
+		if (unit == MILLISECOND)
+		{
+			out = input * 1000 * 1000;
+			return true;
+		}
+		else if (unit == SECOND)
+		{
+			out = input * 1000 * 1000 * 1000;
+			return true;
+		}
+		else if (unit == MINUTE)
+		{
+			out = input * 60 * 1000 * 1000 * 1000;
+			return true;
+		}
+		else if (unit == HOUR)
+		{
+			out = input * 60 * 60 * 1000 * 1000 * 1000;
+			return true;
+		}
+		else if (unit == NANOSECOND)
+		{
+			out = input;
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	//! Convert String
+	static bool StringToTime(std::string input, int64_t &output, TimeUnit &timeunit)
+	{
+		if (input.size() == 0) {
+			return false;
+		}
+
+		const char *cvalue = input.c_str();
+		char *pEnd;
+		long int ival = strtol(cvalue, &pEnd, 0);
+
+		if (pEnd[0] == '\0')
+		{
+			return false;
+		}
+
+		while (*pEnd == ' ')
+		{
+			// Skip the space
+			pEnd++;
+		}
+
+		std::string unit(pEnd);
+
+		if (unit == "sec" || unit == "s" || unit == "second" || unit == "seconds" || unit == "secs")
+		{
+			timeunit = SECOND;
+			output = ival;
+			return true;
+		}
+		else if (unit == "min" || unit == "m" || unit == "mins" || unit == "minute" || unit == "minutes")
+		{
+			timeunit = MINUTE;
+			output = ival;
+			return true;
+		}
+		else if (unit == "ns" || unit == "nano" || unit == "nanos" || unit == "nanoseconds")
+		{
+			timeunit = NANOSECOND;
+			output = ival;
+			return true;
+		}
+		else if (unit == "ms" || unit == "milli" || unit == "millis" || unit == "milliseconds")
+		{
+			timeunit = MILLISECOND;
+			output = ival;
+			return true;
+		}
+		else if (unit == "h" || unit == "hr" || unit == "hour" || unit == "hrs" || unit == "hours")
+		{
+			timeunit = HOUR;
+			output = ival;
+			return true;
+		}
+		else if (unit == "d" || unit == "day" || unit == "days")
+		{
+			timeunit = DAY;
+			output = ival;
+			return true;
+		}
+		else
+			return false;
+	}
+
+	//! Convert String to Integer
+	static bool StringToInt(std::string input, int64_t &output)
+	{
+		if (input.size() == 0) {
+			return false;
+		}
+
+		const char *cvalue = input.c_str();
+		char *pEnd;
+		long int ival = strtol(cvalue, &pEnd, 0);
+
+		if (pEnd[0] == '\0')
+		{
+			output = ival;
+			return true;
+		}
+
+		while (*pEnd == ' ')
+		{
+			// Skip the space
+			pEnd++;
+		}
+
+		char end0 = toupper(pEnd[0]);
+		if ( (end0 == 'K') || (end0 == 'M') || (end0 == 'G') || (end0 == 'T') || (end0 == 'P') )
+		{
+			if (pEnd[1] == '\0')
+			{
+				unsigned long int multiplier = 1000;
+
+				if ( (end0 != 'K') ) {
+					multiplier *= 1000;
+					if (end0 != 'M') {
+						multiplier *= 1000;
+						if (end0 != 'G') {
+							multiplier *= 1000;
+							if (end0 != 'T') {
+								multiplier *= 1000;
+							}
+						}
+					}
+				}
+				output = ival * multiplier;
+				return true;
+
+			} else if ((pEnd[1] == 'b' || pEnd[1] == 'B') && (pEnd[2] == '\0')) {
+
+				unsigned long int multiplier = 1024;
+
+				if ( (end0 != 'K') ) {
+					multiplier *= 1024;
+					if (end0 != 'M') {
+						multiplier *= 1024;
+						if (end0 != 'G') {
+							multiplier *= 1024;
+							if (end0 != 'T') {
+								multiplier *= 1024;
+							}
+						}
+					}
+				}
+				output = ival * multiplier;
+				return true;
+			}
+		}
+
+		return false;
+	}
+	//! Convert String to Float
+	static bool StringToFloat(std::string input, float &output)
+	{
+		const char *cvalue = input.c_str();
+		char *pEnd;
+		float val = strtof(cvalue, &pEnd);
+
+		if (pEnd[0] == '\0')
+		{
+			output = val;
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Convert String to Bool
+	static bool StringToBool(std::string input, bool &output)
+	{
+		if (input == "true" || input == "True" || input == "TRUE")
+		{
+			output = true;
+			return true;
+		}
+		if (input == "false" || input == "False" || input == "FALSE")
+		{
+			output = false;
+			return true;
+		}
+		return false;
+	}
+
+	// Trim String utils
+	static std::string trim(const std::string& s)
+	{
+	    return trimRight(trimLeft(s));
+	}
+
+	static std::string trimLeft(const std::string& s)
+	{
+		const char *WHITESPACE = " \n\r\t";
+	    size_t startpos = s.find_first_not_of(WHITESPACE);
+	    return (startpos == std::string::npos) ? "" : s.substr(startpos);
+	}
+
+	static std::string trimRight(const std::string& s)
+	{
+		const char *WHITESPACE = " \n\r\t";
+	    size_t endpos = s.find_last_not_of(WHITESPACE);
+	    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
+	}
+
+protected:
+	//! Name
+	std::string _name;
+	//! Description
+	std::string _description;
+	//! Value
+	std::string _value;
+
+private:
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/RealTimeDataCollector.h
----------------------------------------------------------------------
diff --git a/libminifi/include/RealTimeDataCollector.h b/libminifi/include/RealTimeDataCollector.h
new file mode 100644
index 0000000..760b566
--- /dev/null
+++ b/libminifi/include/RealTimeDataCollector.h
@@ -0,0 +1,131 @@
+/**
+ * @file RealTimeDataCollector.h
+ * RealTimeDataCollector class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __REAL_TIME_DATA_COLLECTOR_H__
+#define __REAL_TIME_DATA_COLLECTOR_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string>
+#include <errno.h>
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! RealTimeDataCollector Class
+class RealTimeDataCollector : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	RealTimeDataCollector(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_realTimeSocket = 0;
+		_batchSocket = 0;
+		_logger = Logger::getLogger();
+		_firstInvoking = false;
+		_realTimeAccumulated = 0;
+		_batchAcccumulated = 0;
+		_queuedDataSize = 0;
+	}
+	//! Destructor
+	virtual ~RealTimeDataCollector()
+	{
+		if (_realTimeSocket)
+			close(_realTimeSocket);
+		if (_batchSocket)
+			close(_batchSocket);
+		if (_fileStream.is_open())
+			_fileStream.close();
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property REALTIMESERVERNAME;
+	static Property REALTIMESERVERPORT;
+	static Property BATCHSERVERNAME;
+	static Property BATCHSERVERPORT;
+	static Property FILENAME;
+	static Property ITERATION;
+	static Property REALTIMEMSGID;
+	static Property BATCHMSGID;
+	static Property REALTIMEINTERVAL;
+	static Property BATCHINTERVAL;
+	static Property BATCHMAXBUFFERSIZE;
+	//! Supported Relationships
+	static Relationship Success;
+	//! Connect to the socket
+	int connectServer(const char *host, uint16_t port);
+	int sendData(int socket, const char *buf, int buflen);
+	void onTriggerRealTime(ProcessContext *context, ProcessSession *session);
+	void onTriggerBatch(ProcessContext *context, ProcessSession *session);
+
+public:
+	//! OnTrigger method, implemented by NiFi RealTimeDataCollector
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi RealTimeDataCollector
+	virtual void initialize(void);
+
+protected:
+
+private:
+	//! realtime server Name
+	std::string _realTimeServerName;
+	int64_t _realTimeServerPort;
+	std::string _batchServerName;
+	int64_t _batchServerPort;
+	int64_t _realTimeInterval;
+	int64_t _batchInterval;
+	int64_t _batchMaxBufferSize;
+	//! Match pattern for Real time Message ID
+	std::vector<std::string> _realTimeMsgID;
+	//! Match pattern for Batch Message ID
+	std::vector<std::string> _batchMsgID;
+	//! file for which the realTime collector will tail
+	std::string _fileName;
+	//! Whether we need to iterate from the beginning for demo
+	bool _iteration;
+	int _realTimeSocket;
+	int _batchSocket;
+	//! Logger
+	Logger *_logger;
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Queued data size
+	uint64_t _queuedDataSize;
+	//! Queue for the batch process
+	std::queue<std::string> _queue;
+	std::thread::id _realTimeThreadId;
+	std::thread::id _batchThreadId;
+	std::atomic<bool> _firstInvoking;
+	int64_t _realTimeAccumulated;
+	int64_t _batchAcccumulated;
+	std::ifstream _fileStream;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Relationship.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Relationship.h b/libminifi/include/Relationship.h
new file mode 100644
index 0000000..3454ee5
--- /dev/null
+++ b/libminifi/include/Relationship.h
@@ -0,0 +1,87 @@
+/**
+ * @file Relationship.h
+ * Relationship class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __RELATIONSHIP_H__
+#define __RELATIONSHIP_H__
+
+#include <string>
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+
+//! undefined relationship for remote process group outgoing port and root process group incoming port
+#define UNDEFINED_RELATIONSHIP "undefined"
+
+inline bool isRelationshipNameUndefined(std::string name)
+{
+	if (name == UNDEFINED_RELATIONSHIP)
+		return true;
+	else
+		return false;
+}
+
+//! Relationship Class
+class Relationship {
+
+public:
+	//! Constructor
+	/*!
+	 * Create a new relationship 
+	 */
+	Relationship(const std::string name, const std::string description)
+		: _name(name), _description(description) {
+	}
+	Relationship()
+		: _name(UNDEFINED_RELATIONSHIP) {
+	}
+	//! Destructor
+	virtual ~Relationship() {
+	}
+	//! Get Name for the relationship
+	std::string getName() {
+		return _name;
+	}
+	//! Get Description for the relationship
+	std::string getDescription() {
+		return _description;
+	}
+	//! Compare
+	bool operator < (const Relationship & right) const {
+		return _name < right._name;
+	}
+	//! Whether it is a undefined relationship
+	bool isRelationshipUndefined()
+	{
+		return isRelationshipNameUndefined(_name);
+	}
+
+protected:
+
+	//! Name
+	std::string _name;
+	//! Description
+	std::string _description;
+
+private:
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/RemoteProcessorGroupPort.h
----------------------------------------------------------------------
diff --git a/libminifi/include/RemoteProcessorGroupPort.h b/libminifi/include/RemoteProcessorGroupPort.h
new file mode 100644
index 0000000..cd99e50
--- /dev/null
+++ b/libminifi/include/RemoteProcessorGroupPort.h
@@ -0,0 +1,96 @@
+/**
+ * @file RemoteProcessorGroupPort.h
+ * RemoteProcessorGroupPort class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __REMOTE_PROCESSOR_GROUP_PORT_H__
+#define __REMOTE_PROCESSOR_GROUP_PORT_H__
+
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+#include "Site2SiteClientProtocol.h"
+
+//! RemoteProcessorGroupPort Class
+class RemoteProcessorGroupPort : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	RemoteProcessorGroupPort(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+		_peer = new Site2SitePeer("", 9999);
+		_protocol = new Site2SiteClientProtocol(_peer);
+		_protocol->setPortId(uuid);
+	}
+	//! Destructor
+	virtual ~RemoteProcessorGroupPort()
+	{
+		delete _protocol;
+		delete _peer;
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property hostName;
+	static Property port;
+	//! Supported Relationships
+	static Relationship relation;
+public:
+	//! OnTrigger method, implemented by NiFi RemoteProcessorGroupPort
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi RemoteProcessorGroupPort
+	virtual void initialize(void);
+	//! Set Direction
+	void setDirection(TransferDirection direction)
+	{
+		_direction = direction;
+		if (_direction == RECEIVE)
+			this->setTriggerWhenEmpty(true);
+	}
+	//! Set Timeout
+	void setTimeOut(uint64_t timeout)
+	{
+		_protocol->setTimeOut(timeout);
+	}
+	//! SetTransmitting
+	void setTransmitting(bool val)
+	{
+		_transmitting = val;
+	}
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+	//! Peer Connection
+	Site2SitePeer *_peer;
+	//! Peer Protocol
+	Site2SiteClientProtocol *_protocol;
+	//! Transaction Direction
+	TransferDirection _direction;
+	//! Transmitting
+	bool _transmitting;
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/ResourceClaim.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ResourceClaim.h b/libminifi/include/ResourceClaim.h
new file mode 100644
index 0000000..d8f9979
--- /dev/null
+++ b/libminifi/include/ResourceClaim.h
@@ -0,0 +1,92 @@
+/**
+ * @file ResourceClaim.h
+ * Resource Claim class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __RESOURCE_CLAIM_H__
+#define __RESOURCE_CLAIM_H__
+
+#include <string>
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include "Configure.h"
+
+//! Default content directory
+#define DEFAULT_CONTENT_DIRECTORY "."
+
+//! ResourceClaim Class
+class ResourceClaim {
+
+public:
+	//! Constructor
+	/*!
+	 * Create a new resource claim
+	 */
+	ResourceClaim(const std::string contentDirectory);
+	//! Destructor
+	virtual ~ResourceClaim() {}
+	//! increaseFlowFileRecordOwnedCount
+	void increaseFlowFileRecordOwnedCount()
+	{
+		++_flowFileRecordOwnedCount;
+	}
+	//! decreaseFlowFileRecordOwenedCount
+	void decreaseFlowFileRecordOwnedCount()
+	{
+		--_flowFileRecordOwnedCount;
+	}
+	//! getFlowFileRecordOwenedCount
+	uint64_t getFlowFileRecordOwnedCount()
+	{
+		return _flowFileRecordOwnedCount;
+	}
+	//! Get the content full path
+	std::string getContentFullPath()
+	{
+		return _contentFullPath;
+	}
+
+protected:
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! A local unique identifier
+	uint64_t _id;
+	//! Full path to the content
+	std::string _contentFullPath;
+
+	//! How many FlowFileRecord Own this cliam
+	std::atomic<uint64_t> _flowFileRecordOwnedCount;
+
+private:
+	//! Configure
+	Configure *_configure;
+	//! Logger
+	Logger *_logger;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	ResourceClaim(const ResourceClaim &parent);
+	ResourceClaim &operator=(const ResourceClaim &parent);
+
+	//! Local resource claim number
+	static std::atomic<uint64_t> _localResourceClaimNumber;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/SchedulingAgent.h
----------------------------------------------------------------------
diff --git a/libminifi/include/SchedulingAgent.h b/libminifi/include/SchedulingAgent.h
new file mode 100644
index 0000000..2e3f6b8
--- /dev/null
+++ b/libminifi/include/SchedulingAgent.h
@@ -0,0 +1,98 @@
+/**
+ * @file SchedulingAgent.h
+ * SchedulingAgent class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SCHEDULING_AGENT_H__
+#define __SCHEDULING_AGENT_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+#include <thread>
+#include "TimeUtil.h"
+#include "Logger.h"
+#include "Configure.h"
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessContext.h"
+
+//! SchedulingAgent Class
+class SchedulingAgent
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	SchedulingAgent() {
+		_configure = Configure::getConfigure();
+		_logger = Logger::getLogger();
+		_running = false;
+	}
+	//! Destructor
+	virtual ~SchedulingAgent()
+	{
+
+	}
+	//! onTrigger, return whether the yield is need
+	bool onTrigger(Processor *processor);
+	//! Whether agent has work to do
+	bool hasWorkToDo(Processor *processor);
+	//! Whether the outgoing need to be backpressure
+	bool hasTooMuchOutGoing(Processor *processor);
+	//! start
+	void start() {
+		_running = true;
+	}
+	//! stop
+	void stop() {
+		_running = false;
+	}
+
+public:
+	//! schedule, overwritten by different DrivenSchedulingAgent
+	virtual void schedule(Processor *processor) = 0;
+	//! unschedule, overwritten by different DrivenSchedulingAgent
+	virtual void unschedule(Processor *processor) = 0;
+
+protected:
+	//! Logger
+	Logger *_logger;
+	//! Configure
+	Configure *_configure;
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Whether it is running
+	std::atomic<bool> _running;
+	//! AdministrativeYieldDuration
+	int64_t _administrativeYieldDuration;
+	//! BoredYieldDuration
+	int64_t _boredYieldDuration;
+
+private:
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	SchedulingAgent(const SchedulingAgent &parent);
+	SchedulingAgent &operator=(const SchedulingAgent &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Site2SiteClientProtocol.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Site2SiteClientProtocol.h b/libminifi/include/Site2SiteClientProtocol.h
new file mode 100644
index 0000000..5b72b11
--- /dev/null
+++ b/libminifi/include/Site2SiteClientProtocol.h
@@ -0,0 +1,638 @@
+/**
+ * @file Site2SiteClientProtocol.h
+ * Site2SiteClientProtocol class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SITE2SITE_CLIENT_PROTOCOL_H__
+#define __SITE2SITE_CLIENT_PROTOCOL_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string>
+#include <errno.h>
+#include <chrono>
+#include <thread>
+#include <algorithm>
+#include <uuid/uuid.h>
+#include "Logger.h"
+#include "Configure.h"
+#include "Property.h"
+#include "Site2SitePeer.h"
+#include "FlowFileRecord.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+//! Resource Negotiated Status Code
+#define RESOURCE_OK 20
+#define DIFFERENT_RESOURCE_VERSION 21
+#define NEGOTIATED_ABORT 255
+// ! Max attributes
+#define MAX_NUM_ATTRIBUTES 25000
+
+/**
+ * An enumeration for specifying the direction in which data should be
+ * transferred between a client and a remote NiFi instance.
+ */
+typedef enum {
+	/**
+	 * * The client is to send data to the remote instance.
+	 * */
+	SEND,
+	/**
+	 * * The client is to receive data from the remote instance.
+	 * */
+	RECEIVE
+} TransferDirection;
+
+
+//! Peer State
+typedef enum {
+	/**
+	 * * IDLE
+	 * */
+	IDLE = 0,
+	/**
+	 * * Socket Established
+	 * */
+	ESTABLISHED,
+	/**
+	 * * HandShake Done
+	 * */
+	HANDSHAKED,
+	/**
+	 * * After CodeDec Completion
+	 * */
+	READY
+} PeerState;
+
+//! Transaction State
+typedef enum {
+	/**
+	 * * Transaction has been started but no data has been sent or received.
+	 * */
+	TRANSACTION_STARTED,
+	/**
+	 * * Transaction has been started and data has been sent or received.
+	 * */
+	DATA_EXCHANGED,
+	/**
+	 * * Data that has been transferred has been confirmed via its CRC.
+	 * * Transaction is ready to be completed.
+	 * */
+	TRANSACTION_CONFIRMED,
+	/**
+	 * * Transaction has been successfully completed.
+	 * */
+	TRANSACTION_COMPLETED,
+	/**
+	 * * The Transaction has been canceled.
+	 * */
+	TRANSACTION_CANCELED,
+	/**
+	 * * The Transaction ended in an error.
+	 * */
+	TRANSACTION_ERROR
+} TransactionState;
+
+//! Request Type
+typedef enum {
+    NEGOTIATE_FLOWFILE_CODEC = 0,
+    REQUEST_PEER_LIST,
+    SEND_FLOWFILES,
+    RECEIVE_FLOWFILES,
+    SHUTDOWN,
+	MAX_REQUEST_TYPE
+} RequestType;
+
+//! Request Type Str
+static const char *RequestTypeStr[MAX_REQUEST_TYPE] =
+{
+		"NEGOTIATE_FLOWFILE_CODEC",
+		"REQUEST_PEER_LIST",
+		"SEND_FLOWFILES",
+		"RECEIVE_FLOWFILES",
+		"SHUTDOWN"
+};
+
+//! Respond Code
+typedef enum {
+		RESERVED = 0,
+		// ResponseCode, so that we can indicate a 0 followed by some other bytes
+
+		// handshaking properties
+		PROPERTIES_OK = 1,
+		UNKNOWN_PROPERTY_NAME = 230,
+		ILLEGAL_PROPERTY_VALUE = 231,
+		MISSING_PROPERTY = 232,
+		// transaction indicators
+		CONTINUE_TRANSACTION = 10,
+		FINISH_TRANSACTION = 11,
+		CONFIRM_TRANSACTION = 12, // "Explanation" of this code is the checksum
+		TRANSACTION_FINISHED = 13,
+		TRANSACTION_FINISHED_BUT_DESTINATION_FULL = 14,
+		CANCEL_TRANSACTION = 15,
+		BAD_CHECKSUM = 19,
+		// data availability indicators
+		MORE_DATA = 20,
+		NO_MORE_DATA = 21,
+		// port state indicators
+		UNKNOWN_PORT = 200,
+		PORT_NOT_IN_VALID_STATE = 201,
+		PORTS_DESTINATION_FULL = 202,
+		// authorization
+		UNAUTHORIZED = 240,
+		// error indicators
+		ABORT = 250,
+		UNRECOGNIZED_RESPONSE_CODE = 254,
+		END_OF_STREAM = 255
+} RespondCode;
+
+//! Respond Code Class
+typedef struct {
+	RespondCode code;
+	const char *description;
+	bool hasDescription;
+} RespondCodeContext;
+
+//! Respond Code Context
+static RespondCodeContext respondCodeContext[]  =
+{
+		{RESERVED, "Reserved for Future Use", false},
+		{PROPERTIES_OK, "Properties OK", false},
+		{UNKNOWN_PROPERTY_NAME, "Unknown Property Name", true},
+		{ILLEGAL_PROPERTY_VALUE, "Illegal Property Value", true},
+		{MISSING_PROPERTY, "Missing Property", true},
+		{CONTINUE_TRANSACTION, "Continue Transaction", false},
+		{FINISH_TRANSACTION, "Finish Transaction", false},
+		{CONFIRM_TRANSACTION, "Confirm Transaction", true},
+		{TRANSACTION_FINISHED, "Transaction Finished", false},
+		{TRANSACTION_FINISHED_BUT_DESTINATION_FULL, "Transaction Finished But Destination is Full", false},
+		{CANCEL_TRANSACTION, "Cancel Transaction", true},
+		{BAD_CHECKSUM, "Bad Checksum", false},
+		{MORE_DATA, "More Data Exists", false},
+		{NO_MORE_DATA, "No More Data Exists", false},
+		{UNKNOWN_PORT, "Unknown Port", false},
+	    {PORT_NOT_IN_VALID_STATE, "Port Not in a Valid State", true},
+		{PORTS_DESTINATION_FULL, "Port's Destination is Full", false},
+		{UNAUTHORIZED, "User Not Authorized", true},
+		{ABORT, "Abort", true},
+		{UNRECOGNIZED_RESPONSE_CODE, "Unrecognized Response Code", false},
+		{END_OF_STREAM, "End of Stream", false}
+};
+
+//! Respond Code Sequence Pattern
+static const uint8_t CODE_SEQUENCE_VALUE_1 = (uint8_t) 'R';
+static const uint8_t CODE_SEQUENCE_VALUE_2 = (uint8_t) 'C';
+
+/**
+ * Enumeration of Properties that can be used for the Site-to-Site Socket
+ * Protocol.
+ */
+typedef enum {
+		/**
+		 * Boolean value indicating whether or not the contents of a FlowFile should
+		 * be GZipped when transferred.
+		 */
+		GZIP,
+		/**
+		 * The unique identifier of the port to communicate with
+		 */
+		PORT_IDENTIFIER,
+		/**
+		 * Indicates the number of milliseconds after the request was made that the
+		 * client will wait for a response. If no response has been received by the
+		 * time this value expires, the server can move on without attempting to
+		 * service the request because the client will have already disconnected.
+		 */
+		REQUEST_EXPIRATION_MILLIS,
+		/**
+		 * The preferred number of FlowFiles that the server should send to the
+		 * client when pulling data. This property was introduced in version 5 of
+		 * the protocol.
+		 */
+		BATCH_COUNT,
+		/**
+		 * The preferred number of bytes that the server should send to the client
+		 * when pulling data. This property was introduced in version 5 of the
+		 * protocol.
+		 */
+		BATCH_SIZE,
+		/**
+		 * The preferred amount of time that the server should send data to the
+		 * client when pulling data. This property was introduced in version 5 of
+		 * the protocol. Value is in milliseconds.
+		 */
+		BATCH_DURATION,
+		MAX_HANDSHAKE_PROPERTY
+} HandshakeProperty;
+
+//! HandShakeProperty Str
+static const char *HandShakePropertyStr[MAX_HANDSHAKE_PROPERTY] =
+{
+		/**
+		 * Boolean value indicating whether or not the contents of a FlowFile should
+		 * be GZipped when transferred.
+		 */
+		"GZIP",
+		/**
+		 * The unique identifier of the port to communicate with
+		 */
+		"PORT_IDENTIFIER",
+		/**
+		 * Indicates the number of milliseconds after the request was made that the
+		 * client will wait for a response. If no response has been received by the
+		 * time this value expires, the server can move on without attempting to
+		 * service the request because the client will have already disconnected.
+		 */
+		"REQUEST_EXPIRATION_MILLIS",
+		/**
+		 * The preferred number of FlowFiles that the server should send to the
+		 * client when pulling data. This property was introduced in version 5 of
+		 * the protocol.
+		 */
+		"BATCH_COUNT",
+		/**
+		 * The preferred number of bytes that the server should send to the client
+		 * when pulling data. This property was introduced in version 5 of the
+		 * protocol.
+		 */
+		"BATCH_SIZE",
+		/**
+		 * The preferred amount of time that the server should send data to the
+		 * client when pulling data. This property was introduced in version 5 of
+		 * the protocol. Value is in milliseconds.
+		 */
+		"BATCH_DURATION"
+};
+
+class Site2SiteClientProtocol;
+
+//! Transaction Class
+class Transaction
+{
+	friend class Site2SiteClientProtocol;
+public:
+	//! Constructor
+	/*!
+	 * Create a new transaction
+	 */
+	Transaction(TransferDirection direction) {
+		_state = TRANSACTION_STARTED;
+		_direction = direction;
+		_dataAvailable = false;
+		_transfers = 0;
+		_bytes = 0;
+
+		char uuidStr[37];
+
+		// Generate the global UUID for the transaction
+		uuid_generate(_uuid);
+		uuid_unparse(_uuid, uuidStr);
+		_uuidStr = uuidStr;
+	}
+	//! Destructor
+	virtual ~Transaction()
+	{
+	}
+	//! getUUIDStr
+	std::string getUUIDStr()
+	{
+		return _uuidStr;
+	}
+	//! getState
+	TransactionState getState()
+	{
+		return _state;
+	}
+	//! isDataAvailable
+	bool isDataAvailable()
+	{
+		return _dataAvailable;
+	}
+	//! setDataAvailable()
+	void setDataAvailable(bool value)
+	{
+		_dataAvailable = value;
+	}
+	//! getDirection
+	TransferDirection getDirection()
+	{
+		return _direction;
+	}
+	//! getCRC
+	long getCRC()
+	{
+		return _crc.getCRC();
+	}
+	//! updateCRC
+	void updateCRC(uint8_t *buffer, uint32_t length)
+	{
+		_crc.update(buffer, length);
+	}
+
+protected:
+
+private:
+	//! Transaction State
+	TransactionState _state;
+	//! Transaction Direction
+	TransferDirection _direction;
+	//! Whether received data is available
+	bool _dataAvailable;
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! UUID string
+	std::string _uuidStr;
+	//! Number of transfer
+	int _transfers;
+	//! Number of content bytes
+	uint64_t _bytes;
+	//! CRC32
+	CRC32 _crc;
+
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Transaction(const Transaction &parent);
+	Transaction &operator=(const Transaction &parent);
+};
+
+/**
+ * Represents a piece of data that is to be sent to or that was received from a
+ * NiFi instance.
+ */
+class DataPacket
+{
+public:
+	DataPacket(Site2SiteClientProtocol *protocol, Transaction *transaction,
+			std::map<std::string, std::string> attributes) {
+		_protocol = protocol;
+		_size = 0;
+		_transaction = transaction;
+		_attributes = attributes;
+	}
+	std::map<std::string, std::string> _attributes;
+	uint64_t _size;
+	Site2SiteClientProtocol *_protocol;
+	Transaction *_transaction;
+};
+
+//! Site2SiteClientProtocol Class
+class Site2SiteClientProtocol
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new control protocol
+	 */
+	Site2SiteClientProtocol(Site2SitePeer *peer) {
+		_logger = Logger::getLogger();
+		_configure = Configure::getConfigure();
+		_peer = peer;
+		_batchSize = 0;
+		_batchCount = 0;
+		_batchDuration = 0;
+		_batchSendNanos = 5000000000; // 5 seconds
+		_timeOut = 30000; // 30 seconds
+		_peerState = IDLE;
+		_supportedVersion[0] = 5;
+		_supportedVersion[1] = 4;
+		_supportedVersion[2] = 3;
+		_supportedVersion[3] = 2;
+		_supportedVersion[4] = 1;
+		_currentVersion = _supportedVersion[0];
+		_currentVersionIndex = 0;
+		_supportedCodecVersion[0] = 1;
+		_currentCodecVersion = _supportedCodecVersion[0];
+		_currentCodecVersionIndex = 0;
+	}
+	//! Destructor
+	virtual ~Site2SiteClientProtocol()
+	{
+	}
+
+public:
+	//! setBatchSize
+	void setBatchSize(uint64_t size)
+	{
+		_batchSize = size;
+	}
+	//! setBatchCount
+	void setBatchCount(uint64_t count)
+	{
+		_batchCount = count;
+	}
+	//! setBatchDuration
+	void setBatchDuration(uint64_t duration)
+	{
+		_batchDuration = duration;
+	}
+	//! setTimeOut
+	void setTimeOut(uint64_t time)
+	{
+		_timeOut = time;
+		if (_peer)
+			_peer->setTimeOut(time);
+
+	}
+	//! getTimeout
+	uint64_t getTimeOut()
+	{
+		return _timeOut;
+	}
+	//! setPortId
+	void setPortId(uuid_t id)
+	{
+		uuid_copy(_portId, id);
+		char idStr[37];
+		uuid_unparse(id, idStr);
+		_portIdStr = idStr;
+	}
+	//! getResourceName
+	std::string getResourceName()
+	{
+		return "SocketFlowFileProtocol";
+	}
+	//! getCodecResourceName
+	std::string getCodecResourceName()
+	{
+		return "StandardFlowFileCodec";
+	}
+	//! bootstrap the protocol to the ready for transaction state by going through the state machine
+	bool bootstrap();
+	//! establish
+	bool establish();
+	//! handShake
+	bool handShake();
+	//! negotiateCodec
+	bool negotiateCodec();
+	//! initiateResourceNegotiation
+	bool initiateResourceNegotiation();
+	//! initiateCodecResourceNegotiation
+	bool initiateCodecResourceNegotiation();
+	//! tearDown
+	void tearDown();
+	//! write Request Type
+	int writeRequestType(RequestType type);
+	//! read Request Type
+	int readRequestType(RequestType &type);
+	//! read Respond
+	int readRespond(RespondCode &code, std::string &message);
+	//! write respond
+	int writeRespond(RespondCode code, std::string message);
+	//! getRespondCodeContext
+	RespondCodeContext *getRespondCodeContext(RespondCode code)
+	{
+		for (unsigned int i = 0; i < sizeof(respondCodeContext)/sizeof(RespondCodeContext); i++)
+		{
+			if (respondCodeContext[i].code == code)
+			{
+				return &respondCodeContext[i];
+			}
+		}
+		return NULL;
+	}
+	//! getPeer
+	Site2SitePeer *getPeer()
+	{
+		return _peer;
+	}
+	//! Creation of a new transaction, return the transaction ID if success,
+	//! Return NULL when any error occurs
+	Transaction *createTransaction(std::string &transactionID, TransferDirection direction);
+	//! Receive the data packet from the transaction
+	//! Return false when any error occurs
+	bool receive(std::string transactionID, DataPacket *packet, bool &eof);
+	//! Send the data packet from the transaction
+	//! Return false when any error occurs
+	bool send(std::string transactionID, DataPacket *packet, FlowFileRecord *flowFile, ProcessSession *session);
+	//! Confirm the data that was sent or received by comparing CRC32's of the data sent and the data received.
+	bool confirm(std::string transactionID);
+	//! Cancel the transaction
+	void cancel(std::string transactionID);
+	//! Complete the transaction
+	bool complete(std::string transactionID);
+	//! Error the transaction
+	void error(std::string transactionID);
+	//! Receive flow files for the process session
+	void receiveFlowFiles(ProcessContext *context, ProcessSession *session);
+	//! Transfer flow files for the process session
+	void transferFlowFiles(ProcessContext *context, ProcessSession *session);
+	//! deleteTransaction
+	void deleteTransaction(std::string transactionID);
+	//! Nest Callback Class for write stream
+	class WriteCallback : public OutputStreamCallback
+	{
+		public:
+		WriteCallback(DataPacket *packet)
+		: _packet(packet) {}
+		DataPacket *_packet;
+		void process(std::ofstream *stream) {
+			uint8_t buffer[8192];
+			int len = _packet->_size;
+			while (len > 0)
+			{
+				int size = std::min(len, (int) sizeof(buffer));
+				int ret = _packet->_protocol->_peer->readData(buffer, size, &_packet->_transaction->_crc);
+				if (ret != size)
+				{
+					_packet->_protocol->_logger->log_error("Site2Site Receive Flow Size %d Failed %d", size, ret);
+					break;
+				}
+				stream->write((const char *) buffer, size);
+				len -= size;
+			}
+		}
+	};
+	//! Nest Callback Class for read stream
+	class ReadCallback : public InputStreamCallback
+	{
+		public:
+		ReadCallback(DataPacket *packet)
+		: _packet(packet) {}
+		DataPacket *_packet;
+		void process(std::ifstream *stream) {
+			_packet->_size = 0;
+			uint8_t buffer[8192];
+			int readSize;
+			while (stream->good())
+			{
+				if (!stream->read((char *)buffer, 8192))
+					readSize = stream->gcount();
+				else
+					readSize = 8192;
+				int ret = _packet->_protocol->_peer->write(buffer, readSize, &_packet->_transaction->_crc);
+				if (ret != readSize)
+				{
+					_packet->_protocol->_logger->log_error("Site2Site Send Flow Size %d Failed %d", readSize, ret);
+					break;
+				}
+				_packet->_size += readSize;
+			}
+		}
+	};
+
+protected:
+
+private:
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Logger
+	Logger *_logger;
+	//! Configure
+	Configure *_configure;
+	//! Batch Count
+	std::atomic<uint64_t> _batchCount;
+	//! Batch Size
+	std::atomic<uint64_t> _batchSize;
+	//! Batch Duration in msec
+	std::atomic<uint64_t> _batchDuration;
+	//! Timeout in msec
+	std::atomic<uint64_t> _timeOut;
+	//! Peer Connection
+	Site2SitePeer *_peer;
+	//! portId
+	uuid_t _portId;
+	//! portIDStr
+	std::string _portIdStr;
+	//! BATCH_SEND_NANOS
+	uint64_t _batchSendNanos;
+	//! Peer State
+	PeerState _peerState;
+	uint32_t _supportedVersion[5];
+	uint32_t _currentVersion;
+	int _currentVersionIndex;
+	uint32_t _supportedCodecVersion[1];
+	uint32_t _currentCodecVersion;
+	int _currentCodecVersionIndex;
+	//! commsIdentifier
+	std::string _commsIdentifier;
+	//! transaction map
+	std::map<std::string, Transaction *> _transactionMap;
+
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Site2SiteClientProtocol(const Site2SiteClientProtocol &parent);
+	Site2SiteClientProtocol &operator=(const Site2SiteClientProtocol &parent);
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Site2SitePeer.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Site2SitePeer.h b/libminifi/include/Site2SitePeer.h
new file mode 100644
index 0000000..ff11637
--- /dev/null
+++ b/libminifi/include/Site2SitePeer.h
@@ -0,0 +1,364 @@
+/**
+ * @file Site2SitePeer.h
+ * Site2SitePeer class declaration for site to site peer  
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SITE2SITE_PEER_H__
+#define __SITE2SITE_PEER_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string>
+#include <errno.h>
+#include <mutex>
+#include <atomic>
+#include "TimeUtil.h"
+#include "Logger.h"
+#include "Configure.h"
+#include "Property.h"
+
+class CRC32
+{
+public:
+    CRC32() {
+    	crc = 0;
+
+    	if (tableInit)
+    		return;
+
+    	tableInit = true;
+        unsigned int poly = 0xedb88320;
+        unsigned int temp = 0;
+        for(unsigned int i = 0; i < 256; ++i) {
+            temp = i;
+            for(int j = 8; j > 0; --j) {
+                if((temp & 1) == 1) {
+                    temp = (unsigned int)((temp >> 1) ^ poly);
+                }else {
+                    temp >>= 1;
+                }
+            }
+            table[i] = temp;
+        }
+    }
+
+    unsigned int update(uint8_t * bytes, size_t size) {
+    	crc = crc ^ ~0U;
+        for(unsigned int i = 0; i < size; ++i) {
+            uint8_t index = (uint8_t)(((crc) & 0xff) ^ bytes[i]);
+            crc = (unsigned int)((crc >> 8) ^ table[index]);
+        }
+        crc = crc ^ ~0U;
+        return crc;
+    }
+
+    long getCRC()
+    {
+    	return crc;
+    }
+
+private:
+    static unsigned int table[256];
+    static std::atomic<bool> tableInit;
+    unsigned int crc;
+};
+
+static const char MAGIC_BYTES[] = {'N', 'i', 'F', 'i'};
+
+//! Site2SitePeer Class
+class Site2SitePeer
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new site2site peer
+	 */
+	Site2SitePeer(std::string host, uint16_t port) {
+		_logger = Logger::getLogger();
+		_configure = Configure::getConfigure();
+		_socket = 0;
+		_host = host;
+		_port = port;
+		_yieldExpiration = 0;
+		_timeOut = 30000; // 30 seconds
+		_url = "nifi://" + _host + ":" + std::to_string(_port);
+	}
+	//! Destructor
+	virtual ~Site2SitePeer() { Close();}
+	//! Set Processor yield period in MilliSecond
+	void setYieldPeriodMsec(uint64_t period) {
+		_yieldPeriodMsec = period;
+	}
+	//! get URL
+	std::string getURL() {
+		return _url;
+	}
+	//! Get Processor yield period in MilliSecond
+	uint64_t getYieldPeriodMsec(void) {
+		return(_yieldPeriodMsec);
+	}
+	//! Yield based on the yield period
+	void yield()
+	{
+		_yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
+	}
+	//! setHostName
+	void setHostName(std::string host)
+	{
+		_host = host;
+		_url = "nifi://" + _host + ":" + std::to_string(_port);
+	}
+	//! setPort
+	void setPort(uint16_t port)
+	{
+		_port = port;
+		_url = "nifi://" + _host + ":" + std::to_string(_port);
+	}
+	//! getHostName
+	std::string getHostName()
+	{
+		return _host;
+	}
+	//! getPort
+	uint16_t getPort()
+	{
+		return _port;
+	}
+	//! Yield based on the input time
+	void yield(uint64_t time)
+	{
+		_yieldExpiration = (getTimeMillis() + time);
+	}
+	//! whether need be to yield
+	bool isYield()
+	{
+		if (_yieldExpiration > 0)
+			return (_yieldExpiration >= getTimeMillis());
+		else
+			return false;
+	}
+	// clear yield expiration
+	void clearYield()
+	{
+		_yieldExpiration = 0;
+	}
+	//! Yield based on the yield period
+	void yield(std::string portId)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		uint64_t yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
+		_yieldExpirationPortIdMap[portId] = yieldExpiration;
+	}
+	//! Yield based on the input time
+	void yield(std::string portId, uint64_t time)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		uint64_t yieldExpiration = (getTimeMillis() + time);
+		_yieldExpirationPortIdMap[portId] = yieldExpiration;
+	}
+	//! whether need be to yield
+	bool isYield(std::string portId)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		std::map<std::string, uint64_t>::iterator it = this->_yieldExpirationPortIdMap.find(portId);
+		if (it != _yieldExpirationPortIdMap.end())
+		{
+			uint64_t yieldExpiration = it->second;
+			return (yieldExpiration >= getTimeMillis());
+		}
+		else
+		{
+			return false;
+		}
+	}
+	//! clear yield expiration
+	void clearYield(std::string portId)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		std::map<std::string, uint64_t>::iterator it = this->_yieldExpirationPortIdMap.find(portId);
+		if (it != _yieldExpirationPortIdMap.end())
+		{
+			_yieldExpirationPortIdMap.erase(portId);
+		}
+	}
+	//! setTimeOut
+	void setTimeOut(uint64_t time)
+	{
+		_timeOut = time;
+	}
+	//! getTimeOut
+	uint64_t getTimeOut()
+	{
+		return _timeOut;
+	}
+	int write(uint8_t value, CRC32 *crc = NULL)
+	{
+		return sendData(&value, 1, crc);
+	}
+	int write(char value, CRC32 *crc = NULL)
+	{
+		return sendData((uint8_t *)&value, 1, crc);
+	}
+	int write(uint32_t value, CRC32 *crc = NULL)
+	{
+		uint8_t temp[4];
+
+		temp[0] = (value & 0xFF000000) >> 24;
+		temp[1] = (value & 0x00FF0000) >> 16;
+		temp[2] = (value & 0x0000FF00) >> 8;
+		temp[3] = (value & 0x000000FF);
+		return sendData(temp, 4, crc);
+	}
+	int write(uint16_t value, CRC32 *crc = NULL)
+	{
+		uint8_t temp[2];
+		temp[0] = (value & 0xFF00) >> 8;
+		temp[1] = (value & 0xFF);
+		return sendData(temp, 2, crc);
+	}
+	int write(uint8_t *value, int len, CRC32 *crc = NULL)
+	{
+		return sendData(value, len, crc);
+	}
+	int write(uint64_t value, CRC32 *crc = NULL)
+	{
+		uint8_t temp[8];
+
+		temp[0] = (value >> 56) & 0xFF;
+		temp[1] = (value >> 48) & 0xFF;
+		temp[2] = (value >> 40) & 0xFF;
+		temp[3] = (value >> 32) & 0xFF;
+		temp[4] = (value >> 24) & 0xFF;
+		temp[5] = (value >> 16) & 0xFF;
+		temp[6] = (value >>  8) & 0xFF;
+		temp[7] = (value >>  0) & 0xFF;
+		return sendData(temp, 8, crc);
+	}
+	int write(bool value, CRC32 *crc = NULL)
+	{
+		uint8_t temp = value;
+		return write(temp, crc);
+	}
+	int writeUTF(std::string str, bool widen = false, CRC32 *crc = NULL);
+	int read(uint8_t &value, CRC32 *crc = NULL)
+	{
+		uint8_t buf;
+
+		int ret = readData(&buf, 1, crc);
+		if (ret == 1)
+			value = buf;
+		return ret;
+	}
+	int read(uint16_t &value, CRC32 *crc = NULL)
+	{
+		uint8_t buf[2];
+
+		int ret = readData(buf, 2, crc);
+		if (ret == 2)
+			value = (buf[0] << 8) | buf[1];
+		return ret;
+	}
+	int read(char &value, CRC32 *crc = NULL)
+	{
+		uint8_t buf;
+
+		int ret = readData(&buf, 1, crc);
+		if (ret == 1)
+			value = (char) buf;
+		return ret;
+	}
+	int read(uint8_t *value, int len, CRC32 *crc = NULL)
+	{
+		return readData(value, len, crc);
+	}
+	int read(uint32_t &value, CRC32 *crc = NULL)
+	{
+		uint8_t buf[4];
+
+		int ret = readData(buf, 4, crc);
+		if (ret == 4)
+			value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+		return ret;
+	}
+	int read(uint64_t &value, CRC32 *crc = NULL)
+	{
+		uint8_t buf[8];
+
+		int ret = readData(buf, 8, crc);
+		if (ret == 8)
+		{
+			value = ((uint64_t) buf[0] << 56) |
+					((uint64_t) (buf[1] & 255) << 48) |
+					((uint64_t) (buf[2] & 255) << 40) |
+					((uint64_t) (buf[3] & 255) << 32) |
+					((uint64_t) (buf[4] & 255) << 24) |
+					((uint64_t) (buf[5] & 255) << 16) |
+					((uint64_t) (buf[6] & 255) <<  8) |
+					((uint64_t) (buf[7] & 255) <<  0);
+		}
+		return ret;
+	}
+	int readUTF(std::string &str, bool widen = false, CRC32 *crc = NULL);
+	//! open connection to the peer
+	bool Open();
+	//! close connection to the peer
+	void Close();
+	//! Send Data via the socket, return -1 for failure
+	int sendData(uint8_t *buf, int buflen, CRC32 *crc = NULL);
+	//! Read length into buf, return -1 for failure and 0 for EOF
+	int readData(uint8_t *buf, int buflen, CRC32 *crc = NULL);
+	//! Select on the socket
+	int Select(int msec);
+
+protected:
+
+private:
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! S2S server Name
+	std::string _host;
+	//! S2S server port
+	uint16_t _port;
+	//! socket to server
+	int _socket;
+	//! URL
+	std::string _url;
+	//! socket timeout;
+	std::atomic<uint64_t> _timeOut;
+	//! Logger
+	Logger *_logger;
+	//! Configure
+	Configure *_configure;
+	//! Yield Period in Milliseconds
+	std::atomic<uint64_t> _yieldPeriodMsec;
+	//! Yield Expiration
+	std::atomic<uint64_t> _yieldExpiration;
+	//! Yield Expiration per destination PortID
+	std::map<std::string, uint64_t> _yieldExpirationPortIdMap;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Site2SitePeer(const Site2SitePeer &parent);
+	Site2SitePeer &operator=(const Site2SitePeer &parent);
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/TailFile.h
----------------------------------------------------------------------
diff --git a/libminifi/include/TailFile.h b/libminifi/include/TailFile.h
new file mode 100644
index 0000000..5c4ba09
--- /dev/null
+++ b/libminifi/include/TailFile.h
@@ -0,0 +1,93 @@
+/**
+ * @file TailFile.h
+ * TailFile class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __TAIL_FILE_H__
+#define __TAIL_FILE_H__
+
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! TailFile Class
+class TailFile : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	TailFile(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+		_stateRecovered = false;
+	}
+	//! Destructor
+	virtual ~TailFile()
+	{
+		storeState();
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property FileName;
+	static Property StateFile;
+	//! Supported Relationships
+	static Relationship Success;
+
+public:
+	//! OnTrigger method, implemented by NiFi TailFile
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi TailFile
+	virtual void initialize(void);
+	//! recoverState
+	void recoverState();
+	//! storeState
+	void storeState();
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+	std::string _fileLocation;
+	//! Property Specified Tailed File Name
+	std::string _fileName;
+	//! File to save state
+	std::string _stateFile;
+	//! State related to the tailed file
+	std::string _currentTailFileName;
+	uint64_t _currentTailFilePosition;
+	bool _stateRecovered;
+	uint64_t _currentTailFileCreatedTime;
+	//! Utils functions for parse state file
+	std::string trimLeft(const std::string& s);
+	std::string trimRight(const std::string& s);
+	void parseStateFileLine(char *buf);
+	void checkRollOver();
+
+};
+
+//! Matched File Item for Roll over check
+typedef struct {
+	std::string fileName;
+	uint64_t modifiedTime;
+} TailMatchedFileItem;
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/TimeUtil.h
----------------------------------------------------------------------
diff --git a/libminifi/include/TimeUtil.h b/libminifi/include/TimeUtil.h
new file mode 100644
index 0000000..b024245
--- /dev/null
+++ b/libminifi/include/TimeUtil.h
@@ -0,0 +1,82 @@
+/**
+ * @file TimeUtil.h
+ * Basic Time Utility 
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __TIME_UTIL_H__
+#define __TIME_UTIL_H__
+
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <iostream>
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
+inline uint64_t getTimeMillis()
+{
+	uint64_t value;
+
+	timeval time;
+	gettimeofday(&time, NULL);
+	value = ((uint64_t) (time.tv_sec) * 1000) + (time.tv_usec / 1000);
+
+	return value;
+}
+
+inline uint64_t getTimeNano()
+{
+	struct timespec ts;
+	
+#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
+	clock_serv_t cclock;
+	mach_timespec_t mts;
+	host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+	clock_get_time(cclock, &mts);
+	mach_port_deallocate(mach_task_self(), cclock);
+	ts.tv_sec = mts.tv_sec;
+	ts.tv_nsec = mts.tv_nsec;
+#else
+	clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+
+	return ((uint64_t) (ts.tv_sec) * 1000000000 + ts.tv_nsec);
+}
+
+//! Convert millisecond since UTC to a time display string
+inline std::string getTimeStr(uint64_t msec)
+{
+	char date[120];
+	time_t second = (time_t) (msec/1000);
+	msec = msec % 1000;
+	strftime(date, sizeof(date) / sizeof(*date), "%Y-%m-%d %H:%M:%S",
+	             localtime(&second));
+
+	std::string ret = date;
+	date[0] = '\0';
+	sprintf(date, ".%03llu", (unsigned long long) msec);
+
+	ret += date;
+	return ret;
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/TimerDrivenSchedulingAgent.h
----------------------------------------------------------------------
diff --git a/libminifi/include/TimerDrivenSchedulingAgent.h b/libminifi/include/TimerDrivenSchedulingAgent.h
new file mode 100644
index 0000000..9195745
--- /dev/null
+++ b/libminifi/include/TimerDrivenSchedulingAgent.h
@@ -0,0 +1,66 @@
+/**
+ * @file TimerDrivenSchedulingAgent.h
+ * TimerDrivenSchedulingAgent class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __TIMER_DRIVEN_SCHEDULING_AGENT_H__
+#define __TIMER_DRIVEN_SCHEDULING_AGENT_H__
+
+#include "Logger.h"
+#include "Configure.h"
+#include "Processor.h"
+#include "ProcessContext.h"
+#include "SchedulingAgent.h"
+
+//! TimerDrivenSchedulingAgent Class
+class TimerDrivenSchedulingAgent : public SchedulingAgent
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	TimerDrivenSchedulingAgent()
+	: SchedulingAgent()
+	{
+	}
+	//! Destructor
+	virtual ~TimerDrivenSchedulingAgent()
+	{
+	}
+	//! Run function for the thread
+	static void run(TimerDrivenSchedulingAgent *agent, Processor *processor);
+
+public:
+	//! schedule, overwritten by different DrivenTimerDrivenSchedulingAgent
+	virtual void schedule(Processor *processor);
+	//! unschedule, overwritten by different DrivenTimerDrivenSchedulingAgent
+	virtual void unschedule(Processor *processor);
+
+protected:
+
+private:
+	//! Threads
+	std::map<std::string, std::vector<std::thread *>> _threads;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	TimerDrivenSchedulingAgent(const TimerDrivenSchedulingAgent &parent);
+	TimerDrivenSchedulingAgent &operator=(const TimerDrivenSchedulingAgent &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Configure.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Configure.cpp b/libminifi/src/Configure.cpp
new file mode 100644
index 0000000..d7fd95b
--- /dev/null
+++ b/libminifi/src/Configure.cpp
@@ -0,0 +1,167 @@
+/**
+ * @file Configure.cpp
+ * Configure class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Configure.h"
+
+Configure *Configure::_configure(NULL);
+const char *Configure::nifi_flow_configuration_file = "nifi.flow.configuration.file";
+const char *Configure::nifi_administrative_yield_duration = "nifi.administrative.yield.duration";
+const char *Configure::nifi_bored_yield_duration = "nifi.bored.yield.duration";
+const char *Configure::nifi_server_name = "nifi.server.name";
+const char *Configure::nifi_server_port = "nifi.server.port";
+const char *Configure::nifi_server_report_interval= "nifi.server.report.interval";
+
+
+//! Get the config value
+bool Configure::get(std::string key, std::string &value)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+	std::map<std::string,std::string>::iterator it = _properties.find(key);
+
+	if (it != _properties.end())
+	{
+		value = it->second;
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// Trim String utils
+std::string Configure::trim(const std::string& s)
+{
+    return trimRight(trimLeft(s));
+}
+
+std::string Configure::trimLeft(const std::string& s)
+{
+	const char *WHITESPACE = " \n\r\t";
+    size_t startpos = s.find_first_not_of(WHITESPACE);
+    return (startpos == std::string::npos) ? "" : s.substr(startpos);
+}
+
+std::string Configure::trimRight(const std::string& s)
+{
+	const char *WHITESPACE = " \n\r\t";
+    size_t endpos = s.find_last_not_of(WHITESPACE);
+    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
+}
+
+//! Parse one line in configure file like key=value
+void Configure::parseConfigureFileLine(char *buf)
+{
+	char *line = buf;
+
+    while ((line[0] == ' ') || (line[0] =='\t'))
+    	++line;
+
+    char first = line[0];
+    if ((first == '\0') || (first == '#')  || (first == '\r') || (first == '\n') || (first == '='))
+    {
+    	return;
+    }
+
+    char *equal = strchr(line, '=');
+    if (equal == NULL)
+    {
+    	return;
+    }
+
+    equal[0] = '\0';
+    std::string key = line;
+
+    equal++;
+    while ((equal[0] == ' ') || (equal[0] == '\t'))
+    	++equal;
+
+    first = equal[0];
+    if ((first == '\0') || (first == '\r') || (first== '\n'))
+    {
+    	return;
+    }
+
+    std::string value = equal;
+    key = trimRight(key);
+    value = trimRight(value);
+    set(key, value);
+}
+
+//! Load Configure File
+void Configure::loadConfigureFile(const char *fileName)
+{
+
+    std::string adjustedFilename;
+    if (fileName)
+    {
+        // perform a naive determination if this is a relative path
+        if (fileName[0] != '/')
+        {
+            adjustedFilename = adjustedFilename + _configure->getHome() + "/" + fileName;
+        }
+        else
+        {
+            adjustedFilename += fileName;
+        }
+    }
+    char *path = NULL;
+    char full_path[PATH_MAX];
+    path = realpath(adjustedFilename.c_str(), full_path);
+    _logger->log_info("Using configuration file located at %s", path);
+
+    std::ifstream file(path, std::ifstream::in);
+    if (!file.good())
+    {
+        _logger->log_error("load configure file failed %s", path);
+        return;
+    }
+    this->clear();
+    const unsigned int bufSize = 512;
+    char buf[bufSize];
+    for (file.getline(buf, bufSize); file.good(); file.getline(buf, bufSize))
+    {
+        parseConfigureFileLine(buf);
+    }
+}
+
+//! Parse Command Line
+void Configure::parseCommandLine(int argc, char **argv)
+{
+	int i;
+	bool keyFound = false;
+	std::string key, value;
+
+	for (i = 1; i < argc; i++)
+	{
+		if (argv[i][0] == '-' && argv[i][1] != '\0')
+		{
+			keyFound = true;
+			key = &argv[i][1];
+			continue;
+		}
+		if (keyFound)
+		{
+			value = argv[i];
+			set(key,value);
+			keyFound = false;
+		}
+	}
+	return;
+}


[11/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/format.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h
new file mode 100644
index 0000000..7ec3b39
--- /dev/null
+++ b/include/spdlog/details/format.h
@@ -0,0 +1,3155 @@
+/*
+Formatting library for C++
+
+Copyright (c) 2012 - 2015, Victor Zverovich
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+2. 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.
+
+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.
+*/
+
+#ifndef FMT_FORMAT_H_
+#define FMT_FORMAT_H_
+
+#define FMT_HEADER_ONLY
+
+#include <stdint.h>
+
+#include <cassert>
+#include <cmath>
+#include <cstddef>  // for std::ptrdiff_t
+#include <cstdio>
+#include <algorithm>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <map>
+
+#if _SECURE_SCL
+# include <iterator>
+#endif
+
+#ifdef _MSC_VER
+# include <intrin.h>  // _BitScanReverse, _BitScanReverse64
+
+namespace fmt {
+namespace internal {
+# pragma intrinsic(_BitScanReverse)
+inline uint32_t clz(uint32_t x) {
+    unsigned long r = 0;
+    _BitScanReverse(&r, x);
+    return 31 - r;
+}
+# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
+
+# ifdef _WIN64
+#  pragma intrinsic(_BitScanReverse64)
+# endif
+
+inline uint32_t clzll(uint64_t x) {
+    unsigned long r = 0;
+# ifdef _WIN64
+    _BitScanReverse64(&r, x);
+# else
+    // Scan the high 32 bits.
+    if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
+        return 63 - (r + 32);
+
+    // Scan the low 32 bits.
+    _BitScanReverse(&r, static_cast<uint32_t>(x));
+# endif
+    return 63 - r;
+}
+# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
+}
+}
+#endif
+
+#ifdef __GNUC__
+# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+# define FMT_GCC_EXTENSION __extension__
+# if FMT_GCC_VERSION >= 406
+#  pragma GCC diagnostic push
+// Disable the warning about "long long" which is sometimes reported even
+// when using __extension__.
+#  pragma GCC diagnostic ignored "-Wlong-long"
+// Disable the warning about declaration shadowing because it affects too
+// many valid cases.
+#  pragma GCC diagnostic ignored "-Wshadow"
+# endif
+# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
+#  define FMT_HAS_GXX_CXX11 1
+# endif
+#else
+# define FMT_GCC_EXTENSION
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdocumentation"
+#endif
+
+#ifdef __GNUC_LIBSTD__
+# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
+#endif
+
+#ifdef __has_feature
+# define FMT_HAS_FEATURE(x) __has_feature(x)
+#else
+# define FMT_HAS_FEATURE(x) 0
+#endif
+
+#ifdef __has_builtin
+# define FMT_HAS_BUILTIN(x) __has_builtin(x)
+#else
+# define FMT_HAS_BUILTIN(x) 0
+#endif
+
+#ifdef __has_cpp_attribute
+# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define FMT_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+
+#ifndef FMT_USE_VARIADIC_TEMPLATES
+// Variadic templates are available in GCC since version 4.4
+// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
+// since version 2013.
+# define FMT_USE_VARIADIC_TEMPLATES \
+   (FMT_HAS_FEATURE(cxx_variadic_templates) || \
+       (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800)
+#endif
+
+#ifndef FMT_USE_RVALUE_REFERENCES
+// Don't use rvalue references when compiling with clang and an old libstdc++
+// as the latter doesn't provide std::move.
+# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402
+#  define FMT_USE_RVALUE_REFERENCES 0
+# else
+#  define FMT_USE_RVALUE_REFERENCES \
+    (FMT_HAS_FEATURE(cxx_rvalue_references) || \
+        (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600)
+# endif
+#endif
+
+#if FMT_USE_RVALUE_REFERENCES
+# include <utility>  // for std::move
+#endif
+
+// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
+#ifndef FMT_NOEXCEPT
+# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
+   (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11)
+#  define FMT_NOEXCEPT noexcept
+# else
+#  define FMT_NOEXCEPT throw()
+# endif
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
+  (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
+# define FMT_DELETED_OR_UNDEFINED  = delete
+# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+    TypeName(const TypeName&) = delete; \
+    TypeName& operator=(const TypeName&) = delete
+#else
+# define FMT_DELETED_OR_UNDEFINED
+# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+    TypeName(const TypeName&); \
+    TypeName& operator=(const TypeName&)
+#endif
+
+#ifndef FMT_ASSERT
+# define FMT_ASSERT(condition, message) assert((condition) && message)
+#endif
+
+namespace fmt {
+
+// Fix the warning about long long on older versions of GCC
+// that don't support the diagnostic pragma.
+FMT_GCC_EXTENSION typedef long long LongLong;
+FMT_GCC_EXTENSION typedef unsigned long long ULongLong;
+
+#if FMT_USE_RVALUE_REFERENCES
+using std::move;
+#endif
+
+template <typename Char>
+class BasicWriter;
+
+typedef BasicWriter<char> Writer;
+typedef BasicWriter<wchar_t> WWriter;
+
+template <typename Char>
+class BasicFormatter;
+
+template <typename Char, typename T>
+void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value);
+
+/**
+\rst
+A string reference. It can be constructed from a C string or ``std::string``.
+
+You can use one of the following typedefs for common character types:
+
++------------+-------------------------+
+| Type       | Definition              |
++============+=========================+
+| StringRef  | BasicStringRef<char>    |
++------------+-------------------------+
+| WStringRef | BasicStringRef<wchar_t> |
++------------+-------------------------+
+
+This class is most useful as a parameter type to allow passing
+different types of strings to a function, for example::
+
+template <typename... Args>
+std::string format(StringRef format_str, const Args & ... args);
+
+format("{}", 42);
+format(std::string("{}"), 42);
+\endrst
+*/
+template <typename Char>
+class BasicStringRef {
+private:
+    const Char *data_;
+    std::size_t size_;
+
+public:
+    /** Constructs a string reference object from a C string and a size. */
+    BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {}
+
+    /**
+    \rst
+    Constructs a string reference object from a C string computing
+    the size with ``std::char_traits<Char>::length``.
+    \endrst
+    */
+    BasicStringRef(const Char *s)
+        : data_(s), size_(std::char_traits<Char>::length(s)) {}
+
+    /**
+    \rst
+    Constructs a string reference from an ``std::string`` object.
+    \endrst
+    */
+    BasicStringRef(const std::basic_string<Char> &s)
+        : data_(s.c_str()), size_(s.size()) {}
+
+    /**
+    \rst
+    Converts a string reference to an ``std::string`` object.
+    \endrst
+    */
+    std::basic_string<Char> to_string() const {
+        return std::basic_string<Char>(data_, size_);
+    }
+
+    /** Returns the pointer to a C string. */
+    const Char *data() const {
+        return data_;
+    }
+
+    /** Returns the string size. */
+    std::size_t size() const {
+        return size_;
+    }
+
+    friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
+        return lhs.data_ == rhs.data_;
+    }
+    friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
+        return lhs.data_ != rhs.data_;
+    }
+    friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) {
+        return std::lexicographical_compare(
+                   lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_);
+    }
+};
+
+typedef BasicStringRef<char> StringRef;
+typedef BasicStringRef<wchar_t> WStringRef;
+
+
+/**
+\rst
+A reference to a null terminated string. It can be constructed from a C
+string or ``std::string``.
+
+You can use one of the following typedefs for common character types:
+
++-------------+--------------------------+
+| Type        | Definition               |
++=============+==========================+
+| CStringRef  | BasicCStringRef<char>    |
++-------------+--------------------------+
+| WCStringRef | BasicCStringRef<wchar_t> |
++-------------+--------------------------+
+
+This class is most useful as a parameter type to allow passing
+different types of strings to a function, for example::
+
+template <typename... Args>
+std::string format(CStringRef format_str, const Args & ... args);
+
+format("{}", 42);
+format(std::string("{}"), 42);
+\endrst
+*/
+template <typename Char>
+class BasicCStringRef {
+private:
+    const Char *data_;
+
+public:
+    /** Constructs a string reference object from a C string. */
+    BasicCStringRef(const Char *s) : data_(s) {}
+
+    /**
+    \rst
+    Constructs a string reference from an ``std::string`` object.
+    \endrst
+    */
+    BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {}
+
+    /** Returns the pointer to a C string. */
+    const Char *c_str() const {
+        return data_;
+    }
+};
+
+typedef BasicCStringRef<char> CStringRef;
+typedef BasicCStringRef<wchar_t> WCStringRef;
+
+/**
+A formatting error such as invalid format string.
+*/
+class FormatError : public std::runtime_error {
+public:
+    explicit FormatError(CStringRef message)
+        : std::runtime_error(message.c_str()) {}
+};
+
+namespace internal {
+// The number of characters to store in the MemoryBuffer object itself
+// to avoid dynamic memory allocation.
+enum { INLINE_BUFFER_SIZE = 500 };
+
+#if _SECURE_SCL
+// Use checked iterator to avoid warnings on MSVC.
+template <typename T>
+inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
+    return stdext::checked_array_iterator<T*>(ptr, size);
+}
+#else
+template <typename T>
+inline T *make_ptr(T *ptr, std::size_t) {
+    return ptr;
+}
+#endif
+}  // namespace internal
+
+/**
+\rst
+A buffer supporting a subset of ``std::vector``'s operations.
+\endrst
+*/
+template <typename T>
+class Buffer {
+private:
+    FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);
+
+protected:
+    T *ptr_;
+    std::size_t size_;
+    std::size_t capacity_;
+
+    Buffer(T *ptr = 0, std::size_t capacity = 0)
+        : ptr_(ptr), size_(0), capacity_(capacity) {}
+
+    /**
+    \rst
+    Increases the buffer capacity to hold at least *size* elements updating
+    ``ptr_`` and ``capacity_``.
+    \endrst
+    */
+    virtual void grow(std::size_t size) = 0;
+
+public:
+    virtual ~Buffer() {}
+
+    /** Returns the size of this buffer. */
+    std::size_t size() const {
+        return size_;
+    }
+
+    /** Returns the capacity of this buffer. */
+    std::size_t capacity() const {
+        return capacity_;
+    }
+
+    /**
+    Resizes the buffer. If T is a POD type new elements may not be initialized.
+    */
+    void resize(std::size_t new_size) {
+        if (new_size > capacity_)
+            grow(new_size);
+        size_ = new_size;
+    }
+
+    /**
+    \rst
+    Reserves space to store at least *capacity* elements.
+    \endrst
+    */
+    void reserve(std::size_t capacity) {
+        if (capacity > capacity_)
+            grow(capacity);
+    }
+
+    void clear() FMT_NOEXCEPT{ size_ = 0; }
+
+    void push_back(const T &value) {
+        if (size_ == capacity_)
+            grow(size_ + 1);
+        ptr_[size_++] = value;
+    }
+
+    /** Appends data to the end of the buffer. */
+    template <typename U>
+    void append(const U *begin, const U *end);
+
+    T &operator[](std::size_t index) {
+        return ptr_[index];
+    }
+    const T &operator[](std::size_t index) const {
+        return ptr_[index];
+    }
+};
+
+template <typename T>
+template <typename U>
+void Buffer<T>::append(const U *begin, const U *end) {
+    std::ptrdiff_t num_elements = end - begin;
+    if (size_ + num_elements > capacity_)
+        grow(size_ + num_elements);
+    std::copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_);
+    size_ += num_elements;
+}
+
+namespace internal {
+
+// A memory buffer for POD types with the first SIZE elements stored in
+// the object itself.
+template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
+class MemoryBuffer : private Allocator, public Buffer<T> {
+private:
+    T data_[SIZE];
+
+    // Free memory allocated by the buffer.
+    void free() {
+        if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
+    }
+
+protected:
+    void grow(std::size_t size);
+
+public:
+    explicit MemoryBuffer(const Allocator &alloc = Allocator())
+        : Allocator(alloc), Buffer<T>(data_, SIZE) {}
+    ~MemoryBuffer() {
+        free();
+    }
+
+#if FMT_USE_RVALUE_REFERENCES
+private:
+    // Move data from other to this buffer.
+    void move(MemoryBuffer &other) {
+        Allocator &this_alloc = *this, &other_alloc = other;
+        this_alloc = std::move(other_alloc);
+        this->size_ = other.size_;
+        this->capacity_ = other.capacity_;
+        if (other.ptr_ == other.data_) {
+            this->ptr_ = data_;
+            std::copy(other.data_,
+                      other.data_ + this->size_, make_ptr(data_, this->capacity_));
+        }
+        else {
+            this->ptr_ = other.ptr_;
+            // Set pointer to the inline array so that delete is not called
+            // when freeing.
+            other.ptr_ = other.data_;
+        }
+    }
+
+public:
+    MemoryBuffer(MemoryBuffer &&other) {
+        move(other);
+    }
+
+    MemoryBuffer &operator=(MemoryBuffer &&other) {
+        assert(this != &other);
+        free();
+        move(other);
+        return *this;
+    }
+#endif
+
+    // Returns a copy of the allocator associated with this buffer.
+    Allocator get_allocator() const {
+        return *this;
+    }
+};
+
+template <typename T, std::size_t SIZE, typename Allocator>
+void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
+    std::size_t new_capacity =
+        (std::max)(size, this->capacity_ + this->capacity_ / 2);
+    T *new_ptr = this->allocate(new_capacity);
+    // The following code doesn't throw, so the raw pointer above doesn't leak.
+    std::copy(this->ptr_,
+              this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity));
+    std::size_t old_capacity = this->capacity_;
+    T *old_ptr = this->ptr_;
+    this->capacity_ = new_capacity;
+    this->ptr_ = new_ptr;
+    // deallocate may throw (at least in principle), but it doesn't matter since
+    // the buffer already uses the new storage and will deallocate it in case
+    // of exception.
+    if (old_ptr != data_)
+        this->deallocate(old_ptr, old_capacity);
+}
+
+// A fixed-size buffer.
+template <typename Char>
+class FixedBuffer : public fmt::Buffer<Char> {
+public:
+    FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
+
+protected:
+    void grow(std::size_t size);
+};
+
+#ifndef _MSC_VER
+// Portable version of signbit.
+inline int getsign(double x) {
+    // When compiled in C++11 mode signbit is no longer a macro but a function
+    // defined in namespace std and the macro is undefined.
+# ifdef signbit
+    return signbit(x);
+# else
+    return std::signbit(x);
+# endif
+}
+
+// Portable version of isinf.
+# ifdef isinf
+inline int isinfinity(double x) {
+    return isinf(x);
+}
+inline int isinfinity(long double x) {
+    return isinf(x);
+}
+# else
+inline int isinfinity(double x) {
+    return std::isinf(x);
+}
+inline int isinfinity(long double x) {
+    return std::isinf(x);
+}
+# endif
+#else
+inline int getsign(double value) {
+    if (value < 0) return 1;
+    if (value == value) return 0;
+    int dec = 0, sign = 0;
+    char buffer[2];  // The buffer size must be >= 2 or _ecvt_s will fail.
+    _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
+    return sign;
+}
+inline int isinfinity(double x) {
+    return !_finite(x);
+}
+inline int isinfinity(long double x) {
+    return !_finite(static_cast<double>(x));
+}
+#endif
+
+template <typename Char>
+class BasicCharTraits {
+public:
+#if _SECURE_SCL
+    typedef stdext::checked_array_iterator<Char*> CharPtr;
+#else
+    typedef Char *CharPtr;
+#endif
+    static Char cast(wchar_t value) {
+        return static_cast<Char>(value);
+    }
+};
+
+template <typename Char>
+class CharTraits;
+
+template <>
+class CharTraits<char> : public BasicCharTraits<char> {
+private:
+    // Conversion from wchar_t to char is not allowed.
+    static char convert(wchar_t);
+
+public:
+    static char convert(char value) {
+        return value;
+    }
+
+    // Formats a floating-point number.
+    template <typename T>
+    static int format_float(char *buffer, std::size_t size,
+                            const char *format, unsigned width, int precision, T value);
+};
+
+template <>
+class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
+public:
+    static wchar_t convert(char value) {
+        return value;
+    }
+    static wchar_t convert(wchar_t value) {
+        return value;
+    }
+
+    template <typename T>
+    static int format_float(wchar_t *buffer, std::size_t size,
+                            const wchar_t *format, unsigned width, int precision, T value);
+};
+
+// Checks if a number is negative - used to avoid warnings.
+template <bool IsSigned>
+struct SignChecker {
+    template <typename T>
+    static bool is_negative(T value) {
+        return value < 0;
+    }
+};
+
+template <>
+struct SignChecker<false> {
+    template <typename T>
+    static bool is_negative(T) {
+        return false;
+    }
+};
+
+// Returns true if value is negative, false otherwise.
+// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
+template <typename T>
+inline bool is_negative(T value) {
+    return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value);
+}
+
+// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
+template <bool FitsIn32Bits>
+struct TypeSelector {
+    typedef uint32_t Type;
+};
+
+template <>
+struct TypeSelector<false> {
+    typedef uint64_t Type;
+};
+
+template <typename T>
+struct IntTraits {
+    // Smallest of uint32_t and uint64_t that is large enough to represent
+    // all values of T.
+    typedef typename
+    TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
+};
+
+// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
+template <typename T>
+struct MakeUnsigned {
+    typedef T Type;
+};
+
+#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
+  template <> \
+  struct MakeUnsigned<T> { typedef U Type; }
+
+FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
+FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
+FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
+FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
+
+void report_unknown_type(char code, const char *type);
+
+// Static data is placed in this class template to allow header-only
+// configuration.
+template <typename T = void>
+struct BasicData {
+    static const uint32_t POWERS_OF_10_32[];
+    static const uint64_t POWERS_OF_10_64[];
+    static const char DIGITS[];
+};
+
+typedef BasicData<> Data;
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
+# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
+#endif
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
+# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
+#endif
+
+#ifdef FMT_BUILTIN_CLZLL
+// Returns the number of decimal digits in n. Leading zeros are not counted
+// except for n == 0 in which case count_digits returns 1.
+inline unsigned count_digits(uint64_t n) {
+    // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+    // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
+    unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
+    return t - (n < Data::POWERS_OF_10_64[t]) + 1;
+}
+#else
+// Fallback version of count_digits used when __builtin_clz is not available.
+inline unsigned count_digits(uint64_t n) {
+    unsigned count = 1;
+    for (;;) {
+        // Integer division is slow so do it for a group of four digits instead
+        // of for every digit. The idea comes from the talk by Alexandrescu
+        // "Three Optimization Tips for C++". See speed-test for a comparison.
+        if (n < 10) return count;
+        if (n < 100) return count + 1;
+        if (n < 1000) return count + 2;
+        if (n < 10000) return count + 3;
+        n /= 10000u;
+        count += 4;
+    }
+}
+#endif
+
+#ifdef FMT_BUILTIN_CLZ
+// Optional version of count_digits for better performance on 32-bit platforms.
+inline unsigned count_digits(uint32_t n) {
+    uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
+    return t - (n < Data::POWERS_OF_10_32[t]) + 1;
+}
+#endif
+
+// Formats a decimal unsigned integer value writing into buffer.
+template <typename UInt, typename Char>
+inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
+    --num_digits;
+    while (value >= 100) {
+        // Integer division is slow so do it for a group of two digits instead
+        // of for every digit. The idea comes from the talk by Alexandrescu
+        // "Three Optimization Tips for C++". See speed-test for a comparison.
+        unsigned index = (value % 100) * 2;
+        value /= 100;
+        buffer[num_digits] = Data::DIGITS[index + 1];
+        buffer[num_digits - 1] = Data::DIGITS[index];
+        num_digits -= 2;
+    }
+    if (value < 10) {
+        *buffer = static_cast<char>('0' + value);
+        return;
+    }
+    unsigned index = static_cast<unsigned>(value * 2);
+    buffer[1] = Data::DIGITS[index + 1];
+    buffer[0] = Data::DIGITS[index];
+}
+
+#ifndef _WIN32
+# define FMT_USE_WINDOWS_H 0
+#elif !defined(FMT_USE_WINDOWS_H)
+# define FMT_USE_WINDOWS_H 1
+#endif
+
+// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
+// All the functionality that relies on it will be disabled too.
+#if FMT_USE_WINDOWS_H
+// A converter from UTF-8 to UTF-16.
+// It is only provided for Windows since other systems support UTF-8 natively.
+class UTF8ToUTF16 {
+private:
+    MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
+
+public:
+    explicit UTF8ToUTF16(StringRef s);
+    operator WStringRef() const {
+        return WStringRef(&buffer_[0], size());
+    }
+    size_t size() const {
+        return buffer_.size() - 1;
+    }
+    const wchar_t *c_str() const {
+        return &buffer_[0];
+    }
+    std::wstring str() const {
+        return std::wstring(&buffer_[0], size());
+    }
+};
+
+// A converter from UTF-16 to UTF-8.
+// It is only provided for Windows since other systems support UTF-8 natively.
+class UTF16ToUTF8 {
+private:
+    MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;
+
+public:
+    UTF16ToUTF8() {}
+    explicit UTF16ToUTF8(WStringRef s);
+    operator StringRef() const {
+        return StringRef(&buffer_[0], size());
+    }
+    size_t size() const {
+        return buffer_.size() - 1;
+    }
+    const char *c_str() const {
+        return &buffer_[0];
+    }
+    std::string str() const {
+        return std::string(&buffer_[0], size());
+    }
+
+    // Performs conversion returning a system error code instead of
+    // throwing exception on conversion error. This method may still throw
+    // in case of memory allocation error.
+    int convert(WStringRef s);
+};
+
+void format_windows_error(fmt::Writer &out, int error_code,
+                          fmt::StringRef message) FMT_NOEXCEPT;
+#endif
+
+void format_system_error(fmt::Writer &out, int error_code,
+                         fmt::StringRef message) FMT_NOEXCEPT;
+
+// A formatting argument value.
+struct Value {
+    template <typename Char>
+    struct StringValue {
+        const Char *value;
+        std::size_t size;
+    };
+
+    typedef void(*FormatFunc)(
+        void *formatter, const void *arg, void *format_str_ptr);
+
+    struct CustomValue {
+        const void *value;
+        FormatFunc format;
+    };
+
+    union {
+        int int_value;
+        unsigned uint_value;
+        LongLong long_long_value;
+        ULongLong ulong_long_value;
+        double double_value;
+        long double long_double_value;
+        const void *pointer;
+        StringValue<char> string;
+        StringValue<signed char> sstring;
+        StringValue<unsigned char> ustring;
+        StringValue<wchar_t> wstring;
+        CustomValue custom;
+    };
+
+    enum Type {
+        NONE, NAMED_ARG,
+        // Integer types should go first,
+        INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
+        // followed by floating-point types.
+        DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
+        CSTRING, STRING, WSTRING, POINTER, CUSTOM
+    };
+};
+
+// A formatting argument. It is a POD type to allow storage in
+// internal::MemoryBuffer.
+struct Arg : Value {
+    Type type;
+};
+
+template <typename Char>
+struct NamedArg;
+
+template <typename T = void>
+struct Null {};
+
+// A helper class template to enable or disable overloads taking wide
+// characters and strings in MakeValue.
+template <typename T, typename Char>
+struct WCharHelper {
+    typedef Null<T> Supported;
+    typedef T Unsupported;
+};
+
+template <typename T>
+struct WCharHelper<T, wchar_t> {
+    typedef T Supported;
+    typedef Null<T> Unsupported;
+};
+
+template <typename T>
+class IsConvertibleToInt {
+private:
+    typedef char yes[1];
+    typedef char no[2];
+
+    static const T &get();
+
+    static yes &check(fmt::ULongLong);
+    static no &check(...);
+
+public:
+    enum { value = (sizeof(check(get())) == sizeof(yes)) };
+};
+
+#define FMT_CONVERTIBLE_TO_INT(Type) \
+  template <> \
+  class IsConvertibleToInt<Type> { \
+   public: \
+    enum { value = 1 }; \
+          }
+
+// Silence warnings about convering float to int.
+FMT_CONVERTIBLE_TO_INT(float);
+FMT_CONVERTIBLE_TO_INT(double);
+FMT_CONVERTIBLE_TO_INT(long double);
+
+template<bool B, class T = void>
+struct EnableIf {};
+
+template<class T>
+struct EnableIf<true, T> {
+    typedef T type;
+};
+
+template<bool B, class T, class F>
+struct Conditional {
+    typedef T type;
+};
+
+template<class T, class F>
+struct Conditional<false, T, F> {
+    typedef F type;
+};
+
+// A helper function to suppress bogus "conditional expression is constant"
+// warnings.
+inline bool check(bool value) {
+    return value;
+}
+
+// Makes an Arg object from any type.
+template <typename Char>
+class MakeValue : public Arg {
+private:
+    // The following two methods are private to disallow formatting of
+    // arbitrary pointers. If you want to output a pointer cast it to
+    // "void *" or "const void *". In particular, this forbids formatting
+    // of "[const] volatile char *" which is printed as bool by iostreams.
+    // Do not implement!
+    template <typename T>
+    MakeValue(const T *value);
+    template <typename T>
+    MakeValue(T *value);
+
+    // The following methods are private to disallow formatting of wide
+    // characters and strings into narrow strings as in
+    //   fmt::format("{}", L"test");
+    // To fix this, use a wide format string: fmt::format(L"{}", L"test").
+    MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);
+    MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
+    MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);
+    MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
+    MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
+
+    void set_string(StringRef str) {
+        string.value = str.data();
+        string.size = str.size();
+    }
+
+    void set_string(WStringRef str) {
+        wstring.value = str.data();
+        wstring.size = str.size();
+    }
+
+    // Formats an argument of a custom type, such as a user-defined class.
+    template <typename T>
+    static void format_custom_arg(
+        void *formatter, const void *arg, void *format_str_ptr) {
+        format(*static_cast<BasicFormatter<Char>*>(formatter),
+               *static_cast<const Char**>(format_str_ptr),
+               *static_cast<const T*>(arg));
+    }
+
+public:
+    MakeValue() {}
+
+#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \
+  MakeValue(Type value) { field = rhs; } \
+  static uint64_t type(Type) { return Arg::TYPE; }
+
+#define FMT_MAKE_VALUE(Type, field, TYPE) \
+  FMT_MAKE_VALUE_(Type, field, TYPE, value)
+
+    FMT_MAKE_VALUE(bool, int_value, BOOL)
+    FMT_MAKE_VALUE(short, int_value, INT)
+    FMT_MAKE_VALUE(unsigned short, uint_value, UINT)
+    FMT_MAKE_VALUE(int, int_value, INT)
+    FMT_MAKE_VALUE(unsigned, uint_value, UINT)
+
+    MakeValue(long value) {
+        // To minimize the number of types we need to deal with, long is
+        // translated either to int or to long long depending on its size.
+        if (check(sizeof(long) == sizeof(int)))
+            int_value = static_cast<int>(value);
+        else
+            long_long_value = value;
+    }
+    static uint64_t type(long) {
+        return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG;
+    }
+
+    MakeValue(unsigned long value) {
+        if (check(sizeof(unsigned long) == sizeof(unsigned)))
+            uint_value = static_cast<unsigned>(value);
+        else
+            ulong_long_value = value;
+    }
+    static uint64_t type(unsigned long) {
+        return sizeof(unsigned long) == sizeof(unsigned) ?
+               Arg::UINT : Arg::ULONG_LONG;
+    }
+
+    FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG)
+    FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG)
+    FMT_MAKE_VALUE(float, double_value, DOUBLE)
+    FMT_MAKE_VALUE(double, double_value, DOUBLE)
+    FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE)
+    FMT_MAKE_VALUE(signed char, int_value, CHAR)
+    FMT_MAKE_VALUE(unsigned char, int_value, CHAR)
+    FMT_MAKE_VALUE(char, int_value, CHAR)
+
+    MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
+        int_value = value;
+    }
+    static uint64_t type(wchar_t) {
+        return Arg::CHAR;
+    }
+
+#define FMT_MAKE_STR_VALUE(Type, TYPE) \
+  MakeValue(Type value) { set_string(value); } \
+  static uint64_t type(Type) { return Arg::TYPE; }
+
+    FMT_MAKE_VALUE(char *, string.value, CSTRING)
+    FMT_MAKE_VALUE(const char *, string.value, CSTRING)
+    FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING)
+    FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
+    FMT_MAKE_STR_VALUE(const std::string &, STRING)
+    FMT_MAKE_STR_VALUE(StringRef, STRING)
+    FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
+
+#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
+  MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
+    set_string(value); \
+              } \
+  static uint64_t type(Type) { return Arg::TYPE; }
+
+    FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)
+    FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)
+    FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)
+    FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
+
+    FMT_MAKE_VALUE(void *, pointer, POINTER)
+    FMT_MAKE_VALUE(const void *, pointer, POINTER)
+
+    template <typename T>
+    MakeValue(const T &value,
+              typename EnableIf<!IsConvertibleToInt<T>::value, int>::type = 0) {
+        custom.value = &value;
+        custom.format = &format_custom_arg<T>;
+    }
+
+    template <typename T>
+    MakeValue(const T &value,
+              typename EnableIf<IsConvertibleToInt<T>::value, int>::type = 0) {
+        int_value = value;
+    }
+
+    template <typename T>
+    static uint64_t type(const T &) {
+        return IsConvertibleToInt<T>::value ? Arg::INT : Arg::CUSTOM;
+    }
+
+    // Additional template param `Char_` is needed here because make_type always
+    // uses MakeValue<char>.
+    template <typename Char_>
+    MakeValue(const NamedArg<Char_> &value) {
+        pointer = &value;
+    }
+
+    template <typename Char_>
+    static uint64_t type(const NamedArg<Char_> &) {
+        return Arg::NAMED_ARG;
+    }
+};
+
+template <typename Char>
+struct NamedArg : Arg {
+    BasicStringRef<Char> name;
+
+    template <typename T>
+    NamedArg(BasicStringRef<Char> name, const T &value)
+        : name(name), Arg(MakeValue<Char>(value)) {
+        type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
+    }
+};
+
+#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
+
+// An argument visitor.
+// To use ArgVisitor define a subclass that implements some or all of the
+// visit methods with the same signatures as the methods in ArgVisitor,
+// for example, visit_int(int).
+// Specify the subclass name as the Impl template parameter. Then calling
+// ArgVisitor::visit for some argument will dispatch to a visit method
+// specific to the argument type. For example, if the argument type is
+// double then visit_double(double) method of a subclass will be called.
+// If the subclass doesn't contain a method with this signature, then
+// a corresponding method of ArgVisitor will be called.
+//
+// Example:
+//  class MyArgVisitor : public ArgVisitor<MyArgVisitor, void> {
+//   public:
+//    void visit_int(int value) { print("{}", value); }
+//    void visit_double(double value) { print("{}", value ); }
+//  };
+//
+// ArgVisitor uses the curiously recurring template pattern:
+// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
+template <typename Impl, typename Result>
+class ArgVisitor {
+public:
+    void report_unhandled_arg() {}
+
+    Result visit_unhandled_arg() {
+        FMT_DISPATCH(report_unhandled_arg());
+        return Result();
+    }
+
+    Result visit_int(int value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    Result visit_long_long(LongLong value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    Result visit_uint(unsigned value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    Result visit_ulong_long(ULongLong value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    Result visit_bool(bool value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    Result visit_char(int value) {
+        return FMT_DISPATCH(visit_any_int(value));
+    }
+    template <typename T>
+    Result visit_any_int(T) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+
+    Result visit_double(double value) {
+        return FMT_DISPATCH(visit_any_double(value));
+    }
+    Result visit_long_double(long double value) {
+        return FMT_DISPATCH(visit_any_double(value));
+    }
+    template <typename T>
+    Result visit_any_double(T) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+
+    Result visit_string(Arg::StringValue<char>) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+    Result visit_wstring(Arg::StringValue<wchar_t>) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+    Result visit_pointer(const void *) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+    Result visit_custom(Arg::CustomValue) {
+        return FMT_DISPATCH(visit_unhandled_arg());
+    }
+
+    Result visit(const Arg &arg) {
+        switch (arg.type) {
+        default:
+            FMT_ASSERT(false, "invalid argument type");
+            return Result();
+        case Arg::INT:
+            return FMT_DISPATCH(visit_int(arg.int_value));
+        case Arg::UINT:
+            return FMT_DISPATCH(visit_uint(arg.uint_value));
+        case Arg::LONG_LONG:
+            return FMT_DISPATCH(visit_long_long(arg.long_long_value));
+        case Arg::ULONG_LONG:
+            return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));
+        case Arg::BOOL:
+            return FMT_DISPATCH(visit_bool(arg.int_value != 0));
+        case Arg::CHAR:
+            return FMT_DISPATCH(visit_char(arg.int_value));
+        case Arg::DOUBLE:
+            return FMT_DISPATCH(visit_double(arg.double_value));
+        case Arg::LONG_DOUBLE:
+            return FMT_DISPATCH(visit_long_double(arg.long_double_value));
+        case Arg::CSTRING: {
+            Arg::StringValue<char> str = arg.string;
+            str.size = 0;
+            return FMT_DISPATCH(visit_string(str));
+        }
+        case Arg::STRING:
+            return FMT_DISPATCH(visit_string(arg.string));
+        case Arg::WSTRING:
+            return FMT_DISPATCH(visit_wstring(arg.wstring));
+        case Arg::POINTER:
+            return FMT_DISPATCH(visit_pointer(arg.pointer));
+        case Arg::CUSTOM:
+            return FMT_DISPATCH(visit_custom(arg.custom));
+        }
+    }
+};
+
+class RuntimeError : public std::runtime_error {
+protected:
+    RuntimeError() : std::runtime_error("") {}
+};
+
+template <typename Impl, typename Char>
+class BasicArgFormatter;
+
+template <typename Char>
+class PrintfArgFormatter;
+
+template <typename Char>
+class ArgMap;
+}  // namespace internal
+
+/** An argument list. */
+class ArgList {
+private:
+    // To reduce compiled code size per formatting function call, types of first
+    // MAX_PACKED_ARGS arguments are passed in the types_ field.
+    uint64_t types_;
+    union {
+        // If the number of arguments is less than MAX_PACKED_ARGS, the argument
+        // values are stored in values_, otherwise they are stored in args_.
+        // This is done to reduce compiled code size as storing larger objects
+        // may require more code (at least on x86-64) even if the same amount of
+        // data is actually copied to stack. It saves ~10% on the bloat test.
+        const internal::Value *values_;
+        const internal::Arg *args_;
+    };
+
+    internal::Arg::Type type(unsigned index) const {
+        unsigned shift = index * 4;
+        uint64_t mask = 0xf;
+        return static_cast<internal::Arg::Type>(
+                   (types_ & (mask << shift)) >> shift);
+    }
+
+    template <typename Char>
+    friend class internal::ArgMap;
+
+public:
+    // Maximum number of arguments with packed types.
+    enum { MAX_PACKED_ARGS = 16 };
+
+    ArgList() : types_(0) {}
+
+    ArgList(ULongLong types, const internal::Value *values)
+        : types_(types), values_(values) {}
+    ArgList(ULongLong types, const internal::Arg *args)
+        : types_(types), args_(args) {}
+
+    /** Returns the argument at specified index. */
+    internal::Arg operator[](unsigned index) const {
+        using internal::Arg;
+        Arg arg;
+        bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
+        if (index < MAX_PACKED_ARGS) {
+            Arg::Type arg_type = type(index);
+            internal::Value &val = arg;
+            if (arg_type != Arg::NONE)
+                val = use_values ? values_[index] : args_[index];
+            arg.type = arg_type;
+            return arg;
+        }
+        if (use_values) {
+            // The index is greater than the number of arguments that can be stored
+            // in values, so return a "none" argument.
+            arg.type = Arg::NONE;
+            return arg;
+        }
+        for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) {
+            if (args_[i].type == Arg::NONE)
+                return args_[i];
+        }
+        return args_[index];
+    }
+};
+
+struct FormatSpec;
+
+namespace internal {
+
+template <typename Char>
+class ArgMap {
+private:
+    typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType;
+    typedef typename MapType::value_type Pair;
+
+    MapType map_;
+
+public:
+    void init(const ArgList &args);
+
+    const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
+        typename MapType::const_iterator it = map_.find(name);
+        return it != map_.end() ? &it->second : 0;
+    }
+};
+
+class FormatterBase {
+private:
+    ArgList args_;
+    int next_arg_index_;
+
+    // Returns the argument with specified index.
+    Arg do_get_arg(unsigned arg_index, const char *&error);
+
+protected:
+    const ArgList &args() const {
+        return args_;
+    }
+
+    void set_args(const ArgList &args) {
+        args_ = args;
+        next_arg_index_ = 0;
+    }
+
+    // Returns the next argument.
+    Arg next_arg(const char *&error);
+
+    // Checks if manual indexing is used and returns the argument with
+    // specified index.
+    Arg get_arg(unsigned arg_index, const char *&error);
+
+    bool check_no_auto_index(const char *&error);
+
+    template <typename Char>
+    void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
+        if (start != end)
+            w << BasicStringRef<Char>(start, end - start);
+    }
+};
+
+// A printf formatter.
+template <typename Char>
+class PrintfFormatter : private FormatterBase {
+private:
+    void parse_flags(FormatSpec &spec, const Char *&s);
+
+    // Returns the argument with specified index or, if arg_index is equal
+    // to the maximum unsigned value, the next argument.
+    Arg get_arg(const Char *s,
+                unsigned arg_index = (std::numeric_limits<unsigned>::max)());
+
+    // Parses argument index, flags and width and returns the argument index.
+    unsigned parse_header(const Char *&s, FormatSpec &spec);
+
+public:
+    void format(BasicWriter<Char> &writer,
+                BasicCStringRef<Char> format_str, const ArgList &args);
+};
+}  // namespace internal
+
+// A formatter.
+template <typename Char>
+class BasicFormatter : private internal::FormatterBase {
+private:
+    BasicWriter<Char> &writer_;
+    const Char *start_;
+    internal::ArgMap<Char> map_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
+
+    using FormatterBase::get_arg;
+
+    // Checks if manual indexing is used and returns the argument with
+    // specified name.
+    internal::Arg get_arg(BasicStringRef<Char> arg_name, const char *&error);
+
+    // Parses argument index and returns corresponding argument.
+    internal::Arg parse_arg_index(const Char *&s);
+
+    // Parses argument name and returns corresponding argument.
+    internal::Arg parse_arg_name(const Char *&s);
+
+public:
+    explicit BasicFormatter(BasicWriter<Char> &w) : writer_(w) {}
+
+    BasicWriter<Char> &writer() {
+        return writer_;
+    }
+
+    void format(BasicCStringRef<Char> format_str, const ArgList &args);
+
+    const Char *format(const Char *&format_str, const internal::Arg &arg);
+};
+
+enum Alignment {
+    ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
+};
+
+// Flags.
+enum {
+    SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8,
+    CHAR_FLAG = 0x10  // Argument has char type - used in error reporting.
+};
+
+// An empty format specifier.
+struct EmptySpec {};
+
+// A type specifier.
+template <char TYPE>
+struct TypeSpec : EmptySpec {
+    Alignment align() const {
+        return ALIGN_DEFAULT;
+    }
+    unsigned width() const {
+        return 0;
+    }
+    int precision() const {
+        return -1;
+    }
+    bool flag(unsigned) const {
+        return false;
+    }
+    char type() const {
+        return TYPE;
+    }
+    char fill() const {
+        return ' ';
+    }
+};
+
+// A width specifier.
+struct WidthSpec {
+    unsigned width_;
+    // Fill is always wchar_t and cast to char if necessary to avoid having
+    // two specialization of WidthSpec and its subclasses.
+    wchar_t fill_;
+
+    WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {}
+
+    unsigned width() const {
+        return width_;
+    }
+    wchar_t fill() const {
+        return fill_;
+    }
+};
+
+// An alignment specifier.
+struct AlignSpec : WidthSpec {
+    Alignment align_;
+
+    AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)
+        : WidthSpec(width, fill), align_(align) {}
+
+    Alignment align() const {
+        return align_;
+    }
+
+    int precision() const {
+        return -1;
+    }
+};
+
+// An alignment and type specifier.
+template <char TYPE>
+struct AlignTypeSpec : AlignSpec {
+    AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {}
+
+    bool flag(unsigned) const {
+        return false;
+    }
+    char type() const {
+        return TYPE;
+    }
+};
+
+// A full format specifier.
+struct FormatSpec : AlignSpec {
+    unsigned flags_;
+    int precision_;
+    char type_;
+
+    FormatSpec(
+        unsigned width = 0, char type = 0, wchar_t fill = ' ')
+        : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {}
+
+    bool flag(unsigned f) const {
+        return (flags_ & f) != 0;
+    }
+    int precision() const {
+        return precision_;
+    }
+    char type() const {
+        return type_;
+    }
+};
+
+// An integer format specifier.
+template <typename T, typename SpecT = TypeSpec<0>, typename Char = char>
+class IntFormatSpec : public SpecT {
+private:
+    T value_;
+
+public:
+    IntFormatSpec(T val, const SpecT &spec = SpecT())
+        : SpecT(spec), value_(val) {}
+
+    T value() const {
+        return value_;
+    }
+};
+
+// A string format specifier.
+template <typename Char>
+class StrFormatSpec : public AlignSpec {
+private:
+    const Char *str_;
+
+public:
+    template <typename FillChar>
+    StrFormatSpec(const Char *str, unsigned width, FillChar fill)
+        : AlignSpec(width, fill), str_(str) {
+        internal::CharTraits<Char>::convert(FillChar());
+    }
+
+    const Char *str() const {
+        return str_;
+    }
+};
+
+/**
+Returns an integer format specifier to format the value in base 2.
+*/
+IntFormatSpec<int, TypeSpec<'b'> > bin(int value);
+
+/**
+Returns an integer format specifier to format the value in base 8.
+*/
+IntFormatSpec<int, TypeSpec<'o'> > oct(int value);
+
+/**
+Returns an integer format specifier to format the value in base 16 using
+lower-case letters for the digits above 9.
+*/
+IntFormatSpec<int, TypeSpec<'x'> > hex(int value);
+
+/**
+Returns an integer formatter format specifier to format in base 16 using
+upper-case letters for the digits above 9.
+*/
+IntFormatSpec<int, TypeSpec<'X'> > hexu(int value);
+
+/**
+\rst
+Returns an integer format specifier to pad the formatted argument with the
+fill character to the specified width using the default (right) numeric
+alignment.
+
+**Example**::
+
+MemoryWriter out;
+out << pad(hex(0xcafe), 8, '0');
+// out.str() == "0000cafe"
+
+\endrst
+*/
+template <char TYPE_CODE, typename Char>
+IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(
+    int value, unsigned width, Char fill = ' ');
+
+#define FMT_DEFINE_INT_FORMATTERS(TYPE) \
+inline IntFormatSpec<TYPE, TypeSpec<'b'> > bin(TYPE value) { \
+  return IntFormatSpec<TYPE, TypeSpec<'b'> >(value, TypeSpec<'b'>()); \
+    } \
+ \
+inline IntFormatSpec<TYPE, TypeSpec<'o'> > oct(TYPE value) { \
+  return IntFormatSpec<TYPE, TypeSpec<'o'> >(value, TypeSpec<'o'>()); \
+    } \
+ \
+inline IntFormatSpec<TYPE, TypeSpec<'x'> > hex(TYPE value) { \
+  return IntFormatSpec<TYPE, TypeSpec<'x'> >(value, TypeSpec<'x'>()); \
+    } \
+ \
+inline IntFormatSpec<TYPE, TypeSpec<'X'> > hexu(TYPE value) { \
+  return IntFormatSpec<TYPE, TypeSpec<'X'> >(value, TypeSpec<'X'>()); \
+    } \
+ \
+template <char TYPE_CODE> \
+inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> > pad( \
+    IntFormatSpec<TYPE, TypeSpec<TYPE_CODE> > f, unsigned width) { \
+  return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> >( \
+      f.value(), AlignTypeSpec<TYPE_CODE>(width, ' ')); \
+    } \
+ \
+/* For compatibility with older compilers we provide two overloads for pad, */ \
+/* one that takes a fill character and one that doesn't. In the future this */ \
+/* can be replaced with one overload making the template argument Char      */ \
+/* default to char (C++11). */ \
+template <char TYPE_CODE, typename Char> \
+inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad( \
+    IntFormatSpec<TYPE, TypeSpec<TYPE_CODE>, Char> f, \
+    unsigned width, Char fill) { \
+  return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>( \
+      f.value(), AlignTypeSpec<TYPE_CODE>(width, fill)); \
+    } \
+ \
+inline IntFormatSpec<TYPE, AlignTypeSpec<0> > pad( \
+    TYPE value, unsigned width) { \
+  return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \
+      value, AlignTypeSpec<0>(width, ' ')); \
+    } \
+ \
+template <typename Char> \
+inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \
+   TYPE value, unsigned width, Char fill) { \
+ return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \
+     value, AlignTypeSpec<0>(width, fill)); \
+    }
+
+FMT_DEFINE_INT_FORMATTERS(int)
+FMT_DEFINE_INT_FORMATTERS(long)
+FMT_DEFINE_INT_FORMATTERS(unsigned)
+FMT_DEFINE_INT_FORMATTERS(unsigned long)
+FMT_DEFINE_INT_FORMATTERS(LongLong)
+FMT_DEFINE_INT_FORMATTERS(ULongLong)
+
+/**
+\rst
+Returns a string formatter that pads the formatted argument with the fill
+character to the specified width using the default (left) string alignment.
+
+**Example**::
+
+std::string s = str(MemoryWriter() << pad("abc", 8));
+// s == "abc     "
+
+\endrst
+*/
+template <typename Char>
+inline StrFormatSpec<Char> pad(
+    const Char *str, unsigned width, Char fill = ' ') {
+    return StrFormatSpec<Char>(str, width, fill);
+}
+
+inline StrFormatSpec<wchar_t> pad(
+    const wchar_t *str, unsigned width, char fill = ' ') {
+    return StrFormatSpec<wchar_t>(str, width, fill);
+}
+
+// Generates a comma-separated list with results of applying f to
+// numbers 0..n-1.
+# define FMT_GEN(n, f) FMT_GEN##n(f)
+# define FMT_GEN1(f)  f(0)
+# define FMT_GEN2(f)  FMT_GEN1(f),  f(1)
+# define FMT_GEN3(f)  FMT_GEN2(f),  f(2)
+# define FMT_GEN4(f)  FMT_GEN3(f),  f(3)
+# define FMT_GEN5(f)  FMT_GEN4(f),  f(4)
+# define FMT_GEN6(f)  FMT_GEN5(f),  f(5)
+# define FMT_GEN7(f)  FMT_GEN6(f),  f(6)
+# define FMT_GEN8(f)  FMT_GEN7(f),  f(7)
+# define FMT_GEN9(f)  FMT_GEN8(f),  f(8)
+# define FMT_GEN10(f) FMT_GEN9(f),  f(9)
+# define FMT_GEN11(f) FMT_GEN10(f), f(10)
+# define FMT_GEN12(f) FMT_GEN11(f), f(11)
+# define FMT_GEN13(f) FMT_GEN12(f), f(12)
+# define FMT_GEN14(f) FMT_GEN13(f), f(13)
+# define FMT_GEN15(f) FMT_GEN14(f), f(14)
+
+namespace internal {
+inline uint64_t make_type() {
+    return 0;
+}
+
+template <typename T>
+inline uint64_t make_type(const T &arg) {
+    return MakeValue<char>::type(arg);
+}
+
+template <unsigned N>
+struct ArgArray {
+    // Computes the argument array size by adding 1 to N, which is the number of
+    // arguments, if N is zero, because array of zero size is invalid, or if N
+    // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
+    // argument that marks the end of the list.
+    enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) };
+
+    typedef typename Conditional<
+    (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE];
+};
+
+#if FMT_USE_VARIADIC_TEMPLATES
+template <typename Arg, typename... Args>
+inline uint64_t make_type(const Arg &first, const Args & ... tail) {
+    return make_type(first) | (make_type(tail...) << 4);
+}
+
+inline void do_set_types(Arg *) {}
+
+template <typename T, typename... Args>
+inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
+    args->type = static_cast<Arg::Type>(MakeValue<T>::type(arg));
+    do_set_types(args + 1, tail...);
+}
+
+template <typename... Args>
+inline void set_types(Arg *array, const Args & ... args) {
+    if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS))
+        do_set_types(array, args...);
+    array[sizeof...(Args)].type = Arg::NONE;
+}
+
+template <typename... Args>
+inline void set_types(Value *, const Args & ...) {
+    // Do nothing as types are passed separately from values.
+}
+
+template <typename Char, typename Value>
+inline void store_args(Value *) {}
+
+template <typename Char, typename Arg, typename T, typename... Args>
+inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
+    // Assign only the Value subobject of Arg and don't overwrite type (if any)
+    // that is assigned by set_types.
+    Value &value = *args;
+    value = MakeValue<Char>(arg);
+    store_args<Char>(args + 1, tail...);
+}
+
+template <typename Char, typename... Args>
+ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
+                      const Args & ... args) {
+    if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
+        set_types(array, args...);
+    store_args<Char>(array, args...);
+    return ArgList(make_type(args...), array);
+}
+#else
+
+struct ArgType {
+    uint64_t type;
+
+    ArgType() : type(0) {}
+
+    template <typename T>
+    ArgType(const T &arg) : type(make_type(arg)) {}
+};
+
+# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
+
+inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
+    return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) |
+           (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) |
+           (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) |
+           (t12.type << 48) | (t13.type << 52) | (t14.type << 56);
+}
+#endif
+}  // namespace internal
+
+# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
+# define FMT_MAKE_ARG_TYPE(n) T##n
+# define FMT_MAKE_ARG(n) const T##n &v##n
+# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue<char>(v##n)
+# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue<wchar_t>(v##n)
+
+#if FMT_USE_VARIADIC_TEMPLATES
+// Defines a variadic function returning void.
+# define FMT_VARIADIC_VOID(func, arg_type) \
+  template <typename... Args> \
+  void func(arg_type arg0, const Args & ... args) { \
+    typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
+    func(arg0, fmt::internal::make_arg_list<Char>(array, args...)); \
+      }
+
+// Defines a variadic constructor.
+# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
+  template <typename... Args> \
+  ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
+    typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
+    func(arg0, arg1, fmt::internal::make_arg_list<Char>(array, args...)); \
+      }
+
+#else
+
+# define FMT_MAKE_REF(n) fmt::internal::MakeValue<Char>(v##n)
+# define FMT_MAKE_REF2(n) v##n
+
+// Defines a wrapper for a function taking one argument of type arg_type
+// and n additional arguments of arbitrary types.
+# define FMT_WRAP1(func, arg_type, n) \
+  template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
+  inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
+    const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
+    func(arg1, fmt::ArgList( \
+      fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
+      }
+
+// Emulates a variadic function returning void on a pre-C++11 compiler.
+# define FMT_VARIADIC_VOID(func, arg_type) \
+  inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \
+  FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \
+  FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \
+  FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \
+  FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \
+  FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10)
+
+# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \
+  template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
+  ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
+    const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
+    func(arg0, arg1, fmt::ArgList( \
+      fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
+      }
+
+// Emulates a variadic constructor on a pre-C++11 compiler.
+# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \
+  FMT_CTOR(ctor, func, arg0_type, arg1_type, 10)
+#endif
+
+// Generates a comma-separated list with results of applying f to pairs
+// (argument, index).
+#define FMT_FOR_EACH1(f, x0) f(x0, 0)
+#define FMT_FOR_EACH2(f, x0, x1) \
+  FMT_FOR_EACH1(f, x0), f(x1, 1)
+#define FMT_FOR_EACH3(f, x0, x1, x2) \
+  FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2)
+#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \
+  FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3)
+#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \
+  FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4)
+#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \
+  FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5)
+#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \
+  FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6)
+#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \
+  FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7)
+#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \
+  FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8)
+#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \
+  FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9)
+
+/**
+An error returned by an operating system or a language runtime,
+for example a file opening error.
+*/
+class SystemError : public internal::RuntimeError {
+private:
+    void init(int err_code, CStringRef format_str, ArgList args);
+
+protected:
+    int error_code_;
+
+    typedef char Char;  // For FMT_VARIADIC_CTOR.
+
+    SystemError() {}
+
+public:
+    /**
+    \rst
+    Constructs a :class:`fmt::SystemError` object with the description
+    of the form
+
+    .. parsed-literal::
+    *<message>*: *<system-message>*
+
+    where *<message>* is the formatted message and *<system-message>* is
+    the system message corresponding to the error code.
+    *error_code* is a system error code as given by ``errno``.
+    If *error_code* is not a valid error code such as -1, the system message
+    may look like "Unknown error -1" and is platform-dependent.
+
+    **Example**::
+
+    // This throws a SystemError with the description
+    //   cannot open file 'madeup': No such file or directory
+    // or similar (system message may vary).
+    const char *filename = "madeup";
+    std::FILE *file = std::fopen(filename, "r");
+    if (!file)
+    throw fmt::SystemError(errno, "cannot open file '{}'", filename);
+    \endrst
+    */
+    SystemError(int error_code, CStringRef message) {
+        init(error_code, message, ArgList());
+    }
+    FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
+
+    int error_code() const {
+        return error_code_;
+    }
+};
+
+/**
+\rst
+This template provides operations for formatting and writing data into
+a character stream. The output is stored in a buffer provided by a subclass
+such as :class:`fmt::BasicMemoryWriter`.
+
+You can use one of the following typedefs for common character types:
+
++---------+----------------------+
+| Type    | Definition           |
++=========+======================+
+| Writer  | BasicWriter<char>    |
++---------+----------------------+
+| WWriter | BasicWriter<wchar_t> |
++---------+----------------------+
+
+\endrst
+*/
+template <typename Char>
+class BasicWriter {
+private:
+    // Output buffer.
+    Buffer<Char> &buffer_;
+
+    FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter);
+
+    typedef typename internal::CharTraits<Char>::CharPtr CharPtr;
+
+#if _SECURE_SCL
+    // Returns pointer value.
+    static Char *get(CharPtr p) {
+        return p.base();
+    }
+#else
+    static Char *get(Char *p) {
+        return p;
+    }
+#endif
+
+    // Fills the padding around the content and returns the pointer to the
+    // content area.
+    static CharPtr fill_padding(CharPtr buffer,
+                                unsigned total_size, std::size_t content_size, wchar_t fill);
+
+    // Grows the buffer by n characters and returns a pointer to the newly
+    // allocated area.
+    CharPtr grow_buffer(std::size_t n) {
+        std::size_t size = buffer_.size();
+        buffer_.resize(size + n);
+        return internal::make_ptr(&buffer_[size], n);
+    }
+
+    // Prepare a buffer for integer formatting.
+    CharPtr prepare_int_buffer(unsigned num_digits,
+                               const EmptySpec &, const char *prefix, unsigned prefix_size) {
+        unsigned size = prefix_size + num_digits;
+        CharPtr p = grow_buffer(size);
+        std::copy(prefix, prefix + prefix_size, p);
+        return p + size - 1;
+    }
+
+    template <typename Spec>
+    CharPtr prepare_int_buffer(unsigned num_digits,
+                               const Spec &spec, const char *prefix, unsigned prefix_size);
+
+    // Formats an integer.
+    template <typename T, typename Spec>
+    void write_int(T value, Spec spec);
+
+    // Formats a floating-point number (double or long double).
+    template <typename T>
+    void write_double(T value, const FormatSpec &spec);
+
+    // Writes a formatted string.
+    template <typename StrChar>
+    CharPtr write_str(
+        const StrChar *s, std::size_t size, const AlignSpec &spec);
+
+    template <typename StrChar>
+    void write_str(
+        const internal::Arg::StringValue<StrChar> &str, const FormatSpec &spec);
+
+    // This following methods are private to disallow writing wide characters
+    // and strings to a char stream. If you want to print a wide string as a
+    // pointer as std::ostream does, cast it to const void*.
+    // Do not implement!
+    void operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported);
+    void operator<<(
+        typename internal::WCharHelper<const wchar_t *, Char>::Unsupported);
+
+    // Appends floating-point length specifier to the format string.
+    // The second argument is only used for overload resolution.
+    void append_float_length(Char *&format_ptr, long double) {
+        *format_ptr++ = 'L';
+    }
+
+    template<typename T>
+    void append_float_length(Char *&, T) {}
+
+    template <typename Impl, typename Char_>
+    friend class internal::BasicArgFormatter;
+
+    friend class internal::PrintfArgFormatter<Char>;
+
+protected:
+    /**
+    Constructs a ``BasicWriter`` object.
+    */
+    explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {}
+
+public:
+    /**
+    \rst
+    Destroys a ``BasicWriter`` object.
+    \endrst
+    */
+    virtual ~BasicWriter() {}
+
+    /**
+    Returns the total number of characters written.
+    */
+    std::size_t size() const {
+        return buffer_.size();
+    }
+
+    /**
+    Returns a pointer to the output buffer content. No terminating null
+    character is appended.
+    */
+    const Char *data() const FMT_NOEXCEPT {
+        return &buffer_[0];
+    }
+
+    /**
+    Returns a pointer to the output buffer content with terminating null
+    character appended.
+    */
+    const Char *c_str() const {
+        std::size_t size = buffer_.size();
+        buffer_.reserve(size + 1);
+        buffer_[size] = '\0';
+        return &buffer_[0];
+    }
+
+    /**
+    \rst
+    Returns the content of the output buffer as an `std::string`.
+    \endrst
+    */
+    std::basic_string<Char> str() const {
+        return std::basic_string<Char>(&buffer_[0], buffer_.size());
+    }
+
+    /**
+    \rst
+    Writes formatted data.
+
+    *args* is an argument list representing arbitrary arguments.
+
+    **Example**::
+
+    MemoryWriter out;
+    out.write("Current point:\n");
+    out.write("({:+f}, {:+f})", -3.14, 3.14);
+
+    This will write the following output to the ``out`` object:
+
+    .. code-block:: none
+
+    Current point:
+    (-3.140000, +3.140000)
+
+    The output can be accessed using :func:`data()`, :func:`c_str` or
+    :func:`str` methods.
+
+    See also :ref:`syntax`.
+    \endrst
+    */
+    void write(BasicCStringRef<Char> format, ArgList args) {
+        BasicFormatter<Char>(*this).format(format, args);
+    }
+    FMT_VARIADIC_VOID(write, BasicCStringRef<Char>)
+
+    BasicWriter &operator<<(int value) {
+        return *this << IntFormatSpec<int>(value);
+    }
+    BasicWriter &operator<<(unsigned value) {
+        return *this << IntFormatSpec<unsigned>(value);
+    }
+    BasicWriter &operator<<(long value) {
+        return *this << IntFormatSpec<long>(value);
+    }
+    BasicWriter &operator<<(unsigned long value) {
+        return *this << IntFormatSpec<unsigned long>(value);
+    }
+    BasicWriter &operator<<(LongLong value) {
+        return *this << IntFormatSpec<LongLong>(value);
+    }
+
+    /**
+    \rst
+    Formats *value* and writes it to the stream.
+    \endrst
+    */
+    BasicWriter &operator<<(ULongLong value) {
+        return *this << IntFormatSpec<ULongLong>(value);
+    }
+
+    BasicWriter &operator<<(double value) {
+        write_double(value, FormatSpec());
+        return *this;
+    }
+
+    /**
+    \rst
+    Formats *value* using the general format for floating-point numbers
+    (``'g'``) and writes it to the stream.
+    \endrst
+    */
+    BasicWriter &operator<<(long double value) {
+        write_double(value, FormatSpec());
+        return *this;
+    }
+
+    /**
+    Writes a character to the stream.
+    */
+    BasicWriter &operator<<(char value) {
+        buffer_.push_back(value);
+        return *this;
+    }
+
+    BasicWriter &operator<<(
+        typename internal::WCharHelper<wchar_t, Char>::Supported value) {
+        buffer_.push_back(value);
+        return *this;
+    }
+
+    /**
+    \rst
+    Writes *value* to the stream.
+    \endrst
+    */
+    BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
+        const Char *str = value.data();
+        buffer_.append(str, str + value.size());
+        return *this;
+    }
+
+    BasicWriter &operator<<(
+        typename internal::WCharHelper<StringRef, Char>::Supported value) {
+        const char *str = value.data();
+        buffer_.append(str, str + value.size());
+        return *this;
+    }
+
+    template <typename T, typename Spec, typename FillChar>
+    BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
+        internal::CharTraits<Char>::convert(FillChar());
+        write_int(spec.value(), spec);
+        return *this;
+    }
+
+    template <typename StrChar>
+    BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) {
+        const StrChar *s = spec.str();
+        write_str(s, std::char_traits<Char>::length(s), spec);
+        return *this;
+    }
+
+    void clear() FMT_NOEXCEPT{ buffer_.clear(); }
+};
+
+template <typename Char>
+template <typename StrChar>
+typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
+    const StrChar *s, std::size_t size, const AlignSpec &spec) {
+    CharPtr out = CharPtr();
+    if (spec.width() > size) {
+        out = grow_buffer(spec.width());
+        Char fill = internal::CharTraits<Char>::cast(spec.fill());
+        if (spec.align() == ALIGN_RIGHT) {
+            std::fill_n(out, spec.width() - size, fill);
+            out += spec.width() - size;
+        }
+        else if (spec.align() == ALIGN_CENTER) {
+            out = fill_padding(out, spec.width(), size, fill);
+        }
+        else {
+            std::fill_n(out + size, spec.width() - size, fill);
+        }
+    }
+    else {
+        out = grow_buffer(size);
+    }
+    std::copy(s, s + size, out);
+    return out;
+}
+
+template <typename Char>
+typename BasicWriter<Char>::CharPtr
+BasicWriter<Char>::fill_padding(
+    CharPtr buffer, unsigned total_size,
+    std::size_t content_size, wchar_t fill) {
+    std::size_t padding = total_size - content_size;
+    std::size_t left_padding = padding / 2;
+    Char fill_char = internal::CharTraits<Char>::cast(fill);
+    std::fill_n(buffer, left_padding, fill_char);
+    buffer += left_padding;
+    CharPtr content = buffer;
+    std::fill_n(buffer + content_size, padding - left_padding, fill_char);
+    return content;
+}
+
+template <typename Char>
+template <typename Spec>
+typename BasicWriter<Char>::CharPtr
+BasicWriter<Char>::prepare_int_buffer(
+    unsigned num_digits, const Spec &spec,
+    const char *prefix, unsigned prefix_size) {
+    unsigned width = spec.width();
+    Alignment align = spec.align();
+    Char fill = internal::CharTraits<Char>::cast(spec.fill());
+    if (spec.precision() > static_cast<int>(num_digits)) {
+        // Octal prefix '0' is counted as a digit, so ignore it if precision
+        // is specified.
+        if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
+            --prefix_size;
+        unsigned number_size = prefix_size + spec.precision();
+        AlignSpec subspec(number_size, '0', ALIGN_NUMERIC);
+        if (number_size >= width)
+            return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
+        buffer_.reserve(width);
+        unsigned fill_size = width - number_size;
+        if (align != ALIGN_LEFT) {
+            CharPtr p = grow_buffer(fill_size);
+            std::fill(p, p + fill_size, fill);
+        }
+        CharPtr result = prepare_int_buffer(
+                             num_digits, subspec, prefix, prefix_size);
+        if (align == ALIGN_LEFT) {
+            CharPtr p = grow_buffer(fill_size);
+            std::fill(p, p + fill_size, fill);
+        }
+        return result;
+    }
+    unsigned size = prefix_size + num_digits;
+    if (width <= size) {
+        CharPtr p = grow_buffer(size);
+        std::copy(prefix, prefix + prefix_size, p);
+        return p + size - 1;
+    }
+    CharPtr p = grow_buffer(width);
+    CharPtr end = p + width;
+    if (align == ALIGN_LEFT) {
+        std::copy(prefix, prefix + prefix_size, p);
+        p += size;
+        std::fill(p, end, fill);
+    }
+    else if (align == ALIGN_CENTER) {
+        p = fill_padding(p, width, size, fill);
+        std::copy(prefix, prefix + prefix_size, p);
+        p += size;
+    }
+    else {
+        if (align == ALIGN_NUMERIC) {
+            if (prefix_size != 0) {
+                p = std::copy(prefix, prefix + prefix_size, p);
+                size -= prefix_size;
+            }
+        }
+        else {
+            std::copy(prefix, prefix + prefix_size, end - size);
+        }
+        std::fill(p, end - size, fill);
+        p = end;
+    }
+    return p - 1;
+}
+
+template <typename Char>
+template <typename T, typename Spec>
+void BasicWriter<Char>::write_int(T value, Spec spec) {
+    unsigned prefix_size = 0;
+    typedef typename internal::IntTraits<T>::MainType UnsignedType;
+    UnsignedType abs_value = value;
+    char prefix[4] = "";
+    if (internal::is_negative(value)) {
+        prefix[0] = '-';
+        ++prefix_size;
+        abs_value = 0 - abs_value;
+    }
+    else if (spec.flag(SIGN_FLAG)) {
+        prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' ';
+        ++prefix_size;
+    }
+    switch (spec.type()) {
+    case 0:
+    case 'd': {
+        unsigned num_digits = internal::count_digits(abs_value);
+        CharPtr p = prepare_int_buffer(
+                        num_digits, spec, prefix, prefix_size) + 1 - num_digits;
+        internal::format_decimal(get(p), abs_value, num_digits);
+        break;
+    }
+    case 'x':
+    case 'X': {
+        UnsignedType n = abs_value;
+        if (spec.flag(HASH_FLAG)) {
+            prefix[prefix_size++] = '0';
+            prefix[prefix_size++] = spec.type();
+        }
+        unsigned num_digits = 0;
+        do {
+            ++num_digits;
+        } while ((n >>= 4) != 0);
+        Char *p = get(prepare_int_buffer(
+                          num_digits, spec, prefix, prefix_size));
+        n = abs_value;
+        const char *digits = spec.type() == 'x' ?
+                             "0123456789abcdef" : "0123456789ABCDEF";
+        do {
+            *p-- = digits[n & 0xf];
+        } while ((n >>= 4) != 0);
+        break;
+    }
+    case 'b':
+    case 'B': {
+        UnsignedType n = abs_value;
+        if (spec.flag(HASH_FLAG)) {
+            prefix[prefix_size++] = '0';
+            prefix[prefix_size++] = spec.type();
+        }
+        unsigned num_digits = 0;
+        do {
+            ++num_digits;
+        } while ((n >>= 1) != 0);
+        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
+        n = abs_value;
+        do {
+            *p-- = '0' + (n & 1);
+        } while ((n >>= 1) != 0);
+        break;
+    }
+    case 'o': {
+        UnsignedType n = abs_value;
+        if (spec.flag(HASH_FLAG))
+            prefix[prefix_size++] = '0';
+        unsigned num_digits = 0;
+        do {
+            ++num_digits;
+        } while ((n >>= 3) != 0);
+        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
+        n = abs_value;
+        do {
+            *p-- = '0' + (n & 7);
+        } while ((n >>= 3) != 0);
+        break;
+    }
+    default:
+        internal::report_unknown_type(
+            spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer");
+        break;
+    }
+}
+
+template <typename Char>
+template <typename T>
+void BasicWriter<Char>::write_double(
+    T value, const FormatSpec &spec) {
+    // Check type.
+    char type = spec.type();
+    bool upper = false;
+    switch (type) {
+    case 0:
+        type = 'g';
+        break;
+    case 'e':
+    case 'f':
+    case 'g':
+    case 'a':
+        break;
+    case 'F':
+#ifdef _MSC_VER
+        // MSVC's printf doesn't support 'F'.
+        type = 'f';
+#endif
+    // Fall through.
+    case 'E':
+    case 'G':
+    case 'A':
+        upper = true;
+        break;
+    default:
+        internal::report_unknown_type(type, "double");
+        break;
+    }
+
+    char sign = 0;
+    // Use getsign instead of value < 0 because the latter is always
+    // false for NaN.
+    if (internal::getsign(static_cast<double>(value))) {
+        sign = '-';
+        value = -value;
+    }
+    else if (spec.flag(SIGN_FLAG)) {
+        sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
+    }
+
+    if (value != value) {
+        // Format NaN ourselves because sprintf's output is not consistent
+        // across platforms.
+        std::size_t nan_size = 4;
+        const char *nan = upper ? " NAN" : " nan";
+        if (!sign) {
+            --nan_size;
+            ++nan;
+        }
+        CharPtr out = write_str(nan, nan_size, spec);
+        if (sign)
+            *out = sign;
+        return;
+    }
+
+    if (internal::isinfinity(value)) {
+        // Format infinity ourselves because sprintf's output is not consistent
+        // across platforms.
+        std::size_t inf_size = 4;
+        const char *inf = upper ? " INF" : " inf";
+        if (!sign) {
+            --inf_size;
+            ++inf;
+        }
+        CharPtr out = write_str(inf, inf_size, spec);
+        if (sign)
+            *out = sign;
+        return;
+    }
+
+    std::size_t offset = buffer_.size();
+    unsigned width = spec.width();
+    if (sign) {
+        buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
+        if (width > 0)
+            --width;
+        ++offset;
+    }
+
+    // Build format string.
+    enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg
+    Char format[MAX_FORMAT_SIZE];
+    Char *format_ptr = format;
+    *format_ptr++ = '%';
+    unsigned width_for_sprintf = width;
+    if (spec.flag(HASH_FLAG))
+        *format_ptr++ = '#';
+    if (spec.align() == ALIGN_CENTER) {
+        width_for_sprintf = 0;
+    }
+    else {
+        if (spec.align() == ALIGN_LEFT)
+            *format_ptr++ = '-';
+        if (width != 0)
+            *format_ptr++ = '*';
+    }
+    if (spec.precision() >= 0) {
+        *format_ptr++ = '.';
+        *format_ptr++ = '*';
+    }
+
+    append_float_length(format_ptr, value);
+    *format_ptr++ = type;
+    *format_ptr = '\0';
+
+    // Format using snprintf.
+    Char fill = internal::CharTraits<Char>::cast(spec.fill());
+    for (;;) {
+        std::size_t buffer_size = buffer_.capacity() - offset;
+#if _MSC_VER
+        // MSVC's vsnprintf_s doesn't work with zero size, so reserve
+        // space for at least one extra character to make the size non-zero.
+        // Note that the buffer's capacity will increase by more than 1.
+        if (buffer_size == 0) {
+            buffer_.reserve(offset + 1);
+            buffer_size = buffer_.capacity() - offset;
+        }
+#endif
+        Char *start = &buffer_[offset];
+        int n = internal::CharTraits<Char>::format_float(
+                    start, buffer_size, format, width_for_sprintf, spec.precision(), value);
+        if (n >= 0 && offset + n < buffer_.capacity()) {
+            if (sign) {
+                if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
+                        *start != ' ') {
+                    *(start - 1) = sign;
+                    sign = 0;
+                }
+                else {
+                    *(start - 1) = fill;
+                }
+                ++n;
+            }
+            if (spec.align() == ALIGN_CENTER &&
+                    spec.width() > static_cast<unsigned>(n)) {
+                width = spec.width();
+                CharPtr p = grow_buffer(width);
+                std::copy(p, p + n, p + (width - n) / 2);
+                fill_padding(p, spec.width(), n, fill);
+                return;
+            }
+            if (spec.fill() != ' ' || sign) {
+                while (*start == ' ')
+                    *start++ = fill;
+                if (sign)
+                    *(start - 1) = sign;
+            }
+            grow_buffer(n);
+            return;
+        }
+        // If n is negative we ask to increase the capacity by at least 1,
+        // but as std::vector, the buffer grows exponentially.
+        buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
+    }
+}
+
+/**
+\rst
+This class template provides operations for formatting and writing data
+into a character stream. The output is stored in a memory buffer that grows
+dynamically.
+
+You can use one of the following typedefs for common character types
+and the standard allocator:
+
++---------------+-----------------------------------------------------+
+| Type          | Definition                                          |
++===============+=====================================================+
+| MemoryWriter  | BasicMemoryWriter<char, std::allocator<char>>       |
++---------------+-----------------------------------------------------+
+| WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |
++---------------+-----------------------------------------------------+
+
+**Example**::
+
+MemoryWriter out;
+out << "The answer is " << 42 << "\n";
+out.write("({:+f}, {:+f})", -3.14, 3.14);
+
+This will write the following output to the ``out`` object:
+
+.. code-block:: none
+
+The answer is 42
+(-3.140000, +3.140000)
+
+The output can be converted to an ``std::string`` with ``out.str()`` or
+accessed as a C string with ``out.c_str()``.
+\endrst
+*/
+template <typename Char, typename Allocator = std::allocator<Char> >
+class BasicMemoryWriter : public BasicWriter<Char> {
+private:
+    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
+
+public:
+    explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
+        : BasicWriter<Char>(buffer_), buffer_(alloc) {}
+
+#if FMT_USE_RVALUE_REFERENCES
+    /**
+    \rst
+    Constructs a :class:`fmt::BasicMemoryWriter` object moving the content
+    of the other object to it.
+    \endrst
+    */
+    BasicMemoryWriter(BasicMemoryWriter &&other)
+        : BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) {
+    }
+
+    /**
+    \rst
+    Moves the content of the other ``BasicMemoryWriter`` object to this one.
+    \endrst
+    */
+    BasicMemoryWriter &operator=(BasicMemoryWriter &&other) {
+        buffer_ = std::move(other.buffer_);
+        return *this;
+    }
+#endif
+};
+
+typedef BasicMemoryWriter<char> MemoryWriter;
+typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
+
+/**
+\rst
+This class template provides operations for formatting and writing data
+into a fixed-size array. For writing into a dynamically growing buffer
+use :class:`fmt::BasicMemoryWriter`.
+
+Any write method will throw ``std::runtime_error`` if the output doesn't fit
+into the array.
+
+You can use one of the following typedefs for common character types:
+
++--------------+---------------------------+
+| Type         | Definition                |
++==============+===========================+
+| ArrayWriter  | BasicArrayWriter<char>    |
++--------------+---------------------------+
+| WArrayWriter | BasicArrayWriter<wchar_t> |
++--------------+---------------------------+
+\endrst
+*/
+template <typename Char>
+class BasicArrayWriter : public BasicWriter<Char> {
+private:
+    internal::FixedBuffer<Char> buffer_;
+
+public:
+    /**
+    \rst
+    Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
+    given size.
+    \endrst
+    */
+    BasicArrayWriter(Char *array, std::size_t size)
+        : BasicWriter<Char>(buffer_), buffer_(array, size) {}
+
+    /**
+    \rst
+    Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
+    size known at compile time.
+    \endrst
+    */
+    template <std::size_t SIZE>
+    explicit BasicArrayWriter(Char(&array)[SIZE])
+        : BasicWriter<Char>(buffer_), buffer_(array, SIZE) {}
+};
+
+typedef BasicArrayWriter<char> ArrayWriter;
+typedef BasicArrayWriter<wchar_t> WArrayWriter;
+
+// Formats a value.
+template <typename Char, typename T>
+void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
+    std::basic_ostringstream<Char> os;
+    os << value;
+    std::basic_string<Char> str = os.str();
+    internal::Arg arg = internal::MakeValue<Char>(str);
+    arg.type = static_cast<internal::Arg::Type>(
+                   internal::MakeValue<Char>::type(str));
+    format_str = f.format(format_str, arg);
+}
+
+// Reports a system error without throwing an exception.
+// Can be used to report errors from destructors.
+void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
+
+#if FMT_USE_WINDOWS_H
+
+/** A Windows error. */
+class WindowsError : public SystemError {
+private:
+    void init(int error_code, CStringRef format_str, ArgList args);
+
+public:
+    /**
+    \rst
+    Constructs a :class:`fmt::WindowsError` object with the description
+    of the form
+
+    .. parsed-literal::
+    *<message>*: *<system-message>*
+
+    where *<message>* is the formatted message and *<system-message>* is the
+    system message corresponding to the error code.
+    *error_code* is a Windows error code as given by ``GetLastError``.
+    If *error_code* is not a valid error code such as -1, the system message
+    will look like "error -1".
+
+    **Example**::
+
+    // This throws a WindowsError with the description
+    //   cannot open file 'madeup': The system cannot find the file specified.
+    // or similar (system message may vary).
+    const char *filename = "madeup";
+    LPOFSTRUCT of = LPOFSTRUCT();
+    HFILE file = OpenFile(filename, &of, OF_READ);
+    if (file == HFILE_ERROR) {
+    throw fmt::WindowsError(GetLastError(),
+    "cannot open file '{}'", filename);
+    }
+    \endrst
+    */
+    WindowsError(int error_code, CStringRef message) {
+        init(error_code, message, ArgList());
+    }
+    FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef)
+};
+
+// Reports a Windows error without throwing an exception.
+// Can be used to report errors from destructors.
+void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
+
+#endif
+
+enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
+
+/**
+Formats a string and prints it to stdout using ANSI escape sequences
+to specify color (experimental).
+Example:
+PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
+*/
+void print_colored(Color c, CStringRef format, ArgList args);
+
+/**
+\rst
+Formats arguments and returns the result as a string.
+
+**Example**::
+
+std::string message = format("The answer is {}", 42);
+\endrst
+*/
+inline std::string format(CStringRef format_str, ArgList args) {
+    MemoryWriter w;
+    w.write(format_str, args);
+    return w.str();
+}
+
+inline std::wstring format(WCStringRef format_str, ArgList args) {
+    WMemoryWriter w;
+    w.write(format_str, args);
+    return w.str();
+}
+
+/**
+\rst
+Prints formatted data to the file *f*.
+
+**Example**::
+
+print(stderr, "Don't {}!", "panic");
+\endrst
+*/
+void print(std::FILE *f, CStringRef format_str, ArgList args);
+
+/**
+\rst
+Prints formatted data to ``stdout``.
+
+**Example**::
+
+print("Elapsed time: {0:.2f} seconds", 1.23);
+\endrst
+*/
+void print(CStringRef format_str, ArgList args);
+
+/**
+\rst
+Prints formatted data to the stream *os*.
+
+**Example**::
+
+print(cerr, "Don't {}!", "panic");
+\endrst
+*/
+void print(std::ostream &os, CStringRef format_str, ArgList args);
+
+template <typename Char>
+void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
+    internal::PrintfFormatter<Char>().format(w, format, args);
+}
+
+/**
+\rst
+Formats arguments and returns the result as a string.
+
+**Example**::
+
+std::string message = fmt::sprintf("The answer is %d", 42);
+\endrst
+*/
+inline std::string sprintf(CStringRef format, ArgList args) {
+    MemoryWriter w;
+    printf(w, format, args);
+    return w.str();
+}
+
+/**
+\rst
+Prints formatted data to the file *f*.
+
+**Example**::
+
+fmt::fprintf(stderr, "Don't %s!", "panic");
+\endrst
+*/
+int fprintf(std::FILE *f, CStringRef format, ArgList args);
+
+/**
+\rst
+Prints formatted data to ``stdout``.
+
+**Example**::
+
+fmt::printf("Elapsed time: %.2f seconds", 1.23);
+\endrst
+*/
+inline int printf(CStringRef format, ArgList args) {
+    return fprintf(stdout, format, args);
+}
+
+/**
+Fast integer formatter.
+*/
+class FormatInt {
+private:
+    // Buffer should be large enough to hold all digits (digits10 + 1),
+    // a sign and a null character.
+    enum { BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3 };
+    mutable char buffer_[BUFFER_SIZE];
+    char *str_;
+
+    // Formats value in reverse and returns the number of digits.
+    char *format_decimal(ULongLong value) {
+        char *buffer_end = buffer_ + BUFFER_SIZE - 1;
+        while (value >= 100) {
+            // Integer division is slow so do it for a group of two digits instead
+            // of for every digit. The idea comes from the talk by Alexandrescu
+            // "Three Optimization Tips for C++". See speed-test for a comparison.
+            unsigned index = (value % 100) * 2;
+            value /= 100;
+            *--buffer_end = internal::Data::DIGITS[index + 1];
+            *--buffer_end = internal::Data::DIGITS[index];
+        }
+        if (value < 10) {
+            *--buffer_end = static_cast<char>('0' + value);
+            return buffer_end;
+        }
+        unsigned index = static_cast<unsigned>(value * 2);
+        *--buffer_end = internal::Data::DIGITS[index + 1];
+        *--buffer_end = internal::Data::DIGITS[index];
+        return buffer_end;
+    }
+
+    void FormatSigned(LongLong value) {
+        ULongLong abs_value = static_cast<ULongLong>(value);
+        bool negative = value < 0;
+        if (negative)
+            abs_value = 0 - abs_value;
+        str_ = format_decimal(abs_value);
+        if (negative)
+            *--str_ = '-';
+    }
+
+public:
+    explicit FormatInt(int value) {
+        FormatSigned(value);
+    }
+    explicit FormatInt(long value) {
+        FormatSigned(value);
+    }
+    explicit FormatInt(LongLong value) {
+        FormatSigned(value);
+   

<TRUNCATED>

[10/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/line_logger.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h
new file mode 100644
index 0000000..80d7cc1
--- /dev/null
+++ b/include/spdlog/details/line_logger.h
@@ -0,0 +1,221 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+#include <type_traits>
+#include "../common.h"
+#include "../logger.h"
+
+// Line logger class - aggregates operator<< calls to fast ostream
+// and logs upon destruction
+
+namespace spdlog
+{
+namespace details
+{
+class line_logger
+{
+public:
+    line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
+        _callback_logger(callback_logger),
+        _log_msg(msg_level),
+        _enabled(enabled)
+    {}
+
+    // No copy intended. Only move
+    line_logger(const line_logger& other) = delete;
+    line_logger& operator=(const line_logger&) = delete;
+    line_logger& operator=(line_logger&&) = delete;
+
+
+    line_logger(line_logger&& other) :
+        _callback_logger(other._callback_logger),
+        _log_msg(std::move(other._log_msg)),
+        _enabled(other._enabled)
+    {
+        other.disable();
+    }
+
+    //Log the log message using the callback logger
+    ~line_logger()
+    {
+        if (_enabled)
+        {
+#ifndef SPDLOG_NO_NAME
+            _log_msg.logger_name = _callback_logger->name();
+#endif
+#ifndef SPDLOG_NO_DATETIME
+            _log_msg.time = os::now();
+#endif
+
+#ifndef SPDLOG_NO_THREAD_ID
+            _log_msg.thread_id = os::thread_id();
+#endif
+            _callback_logger->_log_msg(_log_msg);
+        }
+    }
+
+    //
+    // Support for format string with variadic args
+    //
+
+
+    void write(const char* what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+    }
+
+    template <typename... Args>
+    void write(const char* fmt, const Args&... args)
+    {
+        if (!_enabled)
+            return;
+        try
+        {
+            _log_msg.raw.write(fmt, args...);
+        }
+        catch (const fmt::FormatError& e)
+        {
+            throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
+        }
+    }
+
+
+    //
+    // Support for operator<<
+    //
+    line_logger& operator<<(const char* what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(const std::string& what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(int what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(unsigned int what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+
+    line_logger& operator<<(long what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(unsigned long what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(long long what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(unsigned long long what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(double what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(long double what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(float what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    line_logger& operator<<(char what)
+    {
+        if (_enabled)
+            _log_msg.raw << what;
+        return *this;
+    }
+
+    //Support user types which implements operator<<
+    template<typename T>
+    line_logger& operator<<(const T& what)
+    {
+        if (_enabled)
+            _log_msg.raw.write("{}", what);
+        return *this;
+    }
+
+
+    void disable()
+    {
+        _enabled = false;
+    }
+
+    bool is_enabled() const
+    {
+        return _enabled;
+    }
+
+
+private:
+    logger* _callback_logger;
+    log_msg _log_msg;
+    bool _enabled;
+};
+} //Namespace details
+} // Namespace spdlog

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/log_msg.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h
new file mode 100644
index 0000000..bf58aca
--- /dev/null
+++ b/include/spdlog/details/log_msg.h
@@ -0,0 +1,98 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <thread>
+#include "../common.h"
+#include "./format.h"
+
+namespace spdlog
+{
+namespace details
+{
+struct log_msg
+{
+    log_msg() = default;
+    log_msg(level::level_enum l):
+        logger_name(),
+        level(l),
+        raw(),
+        formatted() {}
+
+
+    log_msg(const log_msg& other) :
+        logger_name(other.logger_name),
+        level(other.level),
+        time(other.time),
+        thread_id(other.thread_id)
+    {
+        if (other.raw.size())
+            raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
+        if (other.formatted.size())
+            formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
+    }
+
+    log_msg(log_msg&& other) :
+        logger_name(std::move(other.logger_name)),
+        level(other.level),
+        time(std::move(other.time)),
+        thread_id(other.thread_id),
+        raw(std::move(other.raw)),
+        formatted(std::move(other.formatted))
+    {
+        other.clear();
+    }
+
+    log_msg& operator=(log_msg&& other)
+    {
+        if (this == &other)
+            return *this;
+
+        logger_name = std::move(other.logger_name);
+        level = other.level;
+        time = std::move(other.time);
+        thread_id = other.thread_id;
+        raw = std::move(other.raw);
+        formatted = std::move(other.formatted);
+        other.clear();
+        return *this;
+    }
+
+    void clear()
+    {
+        level = level::off;
+        raw.clear();
+        formatted.clear();
+    }
+
+    std::string logger_name;
+    level::level_enum level;
+    log_clock::time_point time;
+    size_t thread_id;
+    fmt::MemoryWriter raw;
+    fmt::MemoryWriter formatted;
+};
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/logger_impl.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h
new file mode 100644
index 0000000..d658ac0
--- /dev/null
+++ b/include/spdlog/details/logger_impl.h
@@ -0,0 +1,320 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+//
+// Logger implementation
+//
+
+#include "./line_logger.h"
+
+
+// create logger with given name, sinks and the default pattern formatter
+// all other ctors will call this one
+template<class It>
+inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
+    _name(logger_name),
+    _sinks(begin, end),
+    _formatter(std::make_shared<pattern_formatter>("%+"))
+{
+
+    // no support under vs2013 for member initialization for std::atomic
+    _level = level::info;
+}
+
+// ctor with sinks as init list
+inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
+    logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
+
+
+// ctor with single sink
+inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
+    logger(logger_name, {
+    single_sink
+}) {}
+
+
+inline spdlog::logger::~logger() = default;
+
+
+inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
+{
+    _set_formatter(msg_formatter);
+}
+
+inline void spdlog::logger::set_pattern(const std::string& pattern)
+{
+    _set_pattern(pattern);
+}
+
+//
+// log only if given level>=logger's log level
+//
+
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
+{
+    bool msg_enabled = should_log(lvl);
+    details::line_logger l(this, lvl, msg_enabled);
+    l.write(fmt, args...);
+    return l;
+}
+
+inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
+{
+    return details::line_logger(this, lvl, should_log(lvl));
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
+{
+    bool msg_enabled = should_log(lvl);
+    details::line_logger l(this, lvl, msg_enabled);
+    l << msg;
+    return l;
+}
+
+//
+// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
+//
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::trace, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::debug, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::info, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::notice, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::warn, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::err, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::critical, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::alert, fmt, args...);
+}
+
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
+{
+    return _log_if_enabled(level::emerg, fmt, args...);
+}
+
+//
+// logger.info(msg) << ".." call style
+//
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
+{
+    return _log_if_enabled(level::trace, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
+{
+    return _log_if_enabled(level::debug, msg);
+}
+
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
+{
+    return _log_if_enabled(level::info, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
+{
+    return _log_if_enabled(level::notice, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
+{
+    return _log_if_enabled(level::warn, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
+{
+    return _log_if_enabled(level::err, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
+{
+    return _log_if_enabled(level::critical, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
+{
+    return _log_if_enabled(level::alert, msg);
+}
+
+template<typename T>
+inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
+{
+    return _log_if_enabled(level::emerg, msg);
+}
+
+
+
+
+//
+// logger.info() << ".." call  style
+//
+inline spdlog::details::line_logger spdlog::logger::trace()
+{
+    return _log_if_enabled(level::trace);
+}
+
+inline spdlog::details::line_logger spdlog::logger::debug()
+{
+    return _log_if_enabled(level::debug);
+}
+
+inline spdlog::details::line_logger spdlog::logger::info()
+{
+    return _log_if_enabled(level::info);
+}
+
+inline spdlog::details::line_logger spdlog::logger::notice()
+{
+    return _log_if_enabled(level::notice);
+}
+
+inline spdlog::details::line_logger spdlog::logger::warn()
+{
+    return _log_if_enabled(level::warn);
+}
+
+inline spdlog::details::line_logger spdlog::logger::error()
+{
+    return _log_if_enabled(level::err);
+}
+
+inline spdlog::details::line_logger spdlog::logger::critical()
+{
+    return _log_if_enabled(level::critical);
+}
+
+inline spdlog::details::line_logger spdlog::logger::alert()
+{
+    return _log_if_enabled(level::alert);
+}
+
+inline spdlog::details::line_logger spdlog::logger::emerg()
+{
+    return _log_if_enabled(level::emerg);
+}
+
+
+// always log, no matter what is the actual logger's log level
+template <typename... Args>
+inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
+{
+    details::line_logger l(this, lvl, true);
+    l.write(fmt, args...);
+    return l;
+}
+
+//
+// name and level
+//
+inline const std::string& spdlog::logger::name() const
+{
+    return _name;
+}
+
+inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
+{
+    _level.store(log_level);
+}
+
+inline spdlog::level::level_enum spdlog::logger::level() const
+{
+    return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
+}
+
+inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
+{
+    return msg_level >= _level.load(std::memory_order_relaxed);
+}
+
+//
+// protected virtual called at end of each user log call (if enabled) by the line_logger
+//
+inline void spdlog::logger::_log_msg(details::log_msg& msg)
+{
+    _formatter->format(msg);
+    for (auto &sink : _sinks)
+        sink->log(msg);
+}
+
+inline void spdlog::logger::_set_pattern(const std::string& pattern)
+{
+    _formatter = std::make_shared<pattern_formatter>(pattern);
+}
+inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
+{
+    _formatter = msg_formatter;
+}
+
+inline void spdlog::logger::flush() {
+    for (auto& sink : _sinks)
+        sink->flush();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/mpmc_bounded_q.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/mpmc_bounded_q.h b/include/spdlog/details/mpmc_bounded_q.h
new file mode 100644
index 0000000..7cbcfd7
--- /dev/null
+++ b/include/spdlog/details/mpmc_bounded_q.h
@@ -0,0 +1,175 @@
+/*
+A modified version of Bounded MPMC queue by Dmitry Vyukov.
+
+Original code from:
+http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
+
+licensed by Dmitry Vyukov under the terms below:
+
+Simplified BSD license
+
+Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this list of
+conditions and the following disclaimer.
+
+2. 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.
+
+THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "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 DMITRY VYUKOV 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.
+
+The views and conclusions contained in the software and documentation are those of the authors and
+should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
+*/
+
+/*
+The code in its current form adds the license below:
+
+spdlog - an extremely fast and easy to use c++11 logging library.
+Copyright (c) 2014 Gabi Melman.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#pragma once
+
+#include <atomic>
+#include "../common.h"
+
+namespace spdlog
+{
+namespace details
+{
+
+template<typename T>
+class mpmc_bounded_queue
+{
+public:
+
+    using item_type = T;
+    mpmc_bounded_queue(size_t buffer_size)
+        : buffer_(new cell_t [buffer_size]),
+          buffer_mask_(buffer_size - 1)
+    {
+        //queue size must be power of two
+        if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
+            throw spdlog_ex("async logger queue size must be power of two");
+
+        for (size_t i = 0; i != buffer_size; i += 1)
+            buffer_[i].sequence_.store(i, std::memory_order_relaxed);
+        enqueue_pos_.store(0, std::memory_order_relaxed);
+        dequeue_pos_.store(0, std::memory_order_relaxed);
+    }
+
+    ~mpmc_bounded_queue()
+    {
+        delete [] buffer_;
+    }
+
+
+    bool enqueue(T&& data)
+    {
+        cell_t* cell;
+        size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
+        for (;;)
+        {
+            cell = &buffer_[pos & buffer_mask_];
+            size_t seq = cell->sequence_.load(std::memory_order_acquire);
+            intptr_t dif = (intptr_t)seq - (intptr_t)pos;
+            if (dif == 0)
+            {
+                if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
+                    break;
+            }
+            else if (dif < 0)
+            {
+                return false;
+            }
+            else
+            {
+                pos = enqueue_pos_.load(std::memory_order_relaxed);
+            }
+        }
+        cell->data_ = std::move(data);
+        cell->sequence_.store(pos + 1, std::memory_order_release);
+        return true;
+    }
+
+    bool dequeue(T& data)
+    {
+        cell_t* cell;
+        size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
+        for (;;)
+        {
+            cell = &buffer_[pos & buffer_mask_];
+            size_t seq =
+                cell->sequence_.load(std::memory_order_acquire);
+            intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
+            if (dif == 0)
+            {
+                if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
+                    break;
+            }
+            else if (dif < 0)
+                return false;
+            else
+                pos = dequeue_pos_.load(std::memory_order_relaxed);
+        }
+        data = std::move(cell->data_);
+        cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
+        return true;
+    }
+
+private:
+    struct cell_t
+    {
+        std::atomic<size_t>   sequence_;
+        T                     data_;
+    };
+
+    static size_t const     cacheline_size = 64;
+    typedef char            cacheline_pad_t [cacheline_size];
+
+    cacheline_pad_t         pad0_;
+    cell_t* const           buffer_;
+    size_t const            buffer_mask_;
+    cacheline_pad_t         pad1_;
+    std::atomic<size_t>     enqueue_pos_;
+    cacheline_pad_t         pad2_;
+    std::atomic<size_t>     dequeue_pos_;
+    cacheline_pad_t         pad3_;
+
+    mpmc_bounded_queue(mpmc_bounded_queue const&);
+    void operator = (mpmc_bounded_queue const&);
+};
+
+} // ns details
+} // ns spdlog

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/null_mutex.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/null_mutex.h b/include/spdlog/details/null_mutex.h
new file mode 100644
index 0000000..ebb56a5
--- /dev/null
+++ b/include/spdlog/details/null_mutex.h
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+// null, no cost mutex
+
+namespace spdlog
+{
+namespace details
+{
+struct null_mutex
+{
+    void lock() {}
+    void unlock() {}
+    bool try_lock()
+    {
+        return true;
+    }
+};
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/os.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h
new file mode 100644
index 0000000..753b6d9
--- /dev/null
+++ b/include/spdlog/details/os.h
@@ -0,0 +1,198 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+#include<string>
+#include<cstdio>
+#include<ctime>
+
+#ifdef _WIN32
+# ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+# endif
+# include <Windows.h>
+
+#ifdef __MINGW32__
+#include <share.h>
+#endif
+
+#elif __linux__
+#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
+#include <unistd.h>
+#else
+#include <thread>
+#endif
+
+#include "../common.h"
+
+namespace spdlog
+{
+namespace details
+{
+namespace os
+{
+
+inline spdlog::log_clock::time_point now()
+{
+
+#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
+    timespec ts;
+    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
+    return std::chrono::time_point<log_clock, typename log_clock::duration>(
+               std::chrono::duration_cast<typename log_clock::duration>(
+                   std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
+
+#else
+    return log_clock::now();
+#endif
+
+}
+inline std::tm localtime(const std::time_t &time_tt)
+{
+
+#ifdef _WIN32
+    std::tm tm;
+    localtime_s(&tm, &time_tt);
+#else
+    std::tm tm;
+    localtime_r(&time_tt, &tm);
+#endif
+    return tm;
+}
+
+inline std::tm localtime()
+{
+    std::time_t now_t = time(nullptr);
+    return localtime(now_t);
+}
+
+
+inline std::tm gmtime(const std::time_t &time_tt)
+{
+
+#ifdef _WIN32
+    std::tm tm;
+    gmtime_s(&tm, &time_tt);
+#else
+    std::tm tm;
+    gmtime_r(&time_tt, &tm);
+#endif
+    return tm;
+}
+
+inline std::tm gmtime()
+{
+    std::time_t now_t = time(nullptr);
+    return gmtime(now_t);
+}
+inline bool operator==(const std::tm& tm1, const std::tm& tm2)
+{
+    return (tm1.tm_sec == tm2.tm_sec &&
+            tm1.tm_min == tm2.tm_min &&
+            tm1.tm_hour == tm2.tm_hour &&
+            tm1.tm_mday == tm2.tm_mday &&
+            tm1.tm_mon == tm2.tm_mon &&
+            tm1.tm_year == tm2.tm_year &&
+            tm1.tm_isdst == tm2.tm_isdst);
+}
+
+inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
+{
+    return !(tm1 == tm2);
+}
+
+#ifdef _WIN32
+inline const char* eol()
+{
+    return "\r\n";
+}
+#else
+constexpr inline const char* eol()
+{
+    return "\n";
+}
+#endif
+
+#ifdef _WIN32
+inline unsigned short eol_size()
+{
+    return 2;
+}
+#else
+constexpr inline unsigned short eol_size()
+{
+    return 1;
+}
+#endif
+
+//fopen_s on non windows for writing
+inline int fopen_s(FILE** fp, const std::string& filename, const char* mode)
+{
+#ifdef _WIN32
+    *fp = _fsopen((filename.c_str()), mode, _SH_DENYWR);
+    return *fp == nullptr;
+#else
+    *fp = fopen((filename.c_str()), mode);
+    return *fp == nullptr;
+#endif
+
+
+}
+
+//Return utc offset in minutes or -1 on failure
+inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
+{
+
+#ifdef _WIN32
+    (void)tm; // avoid unused param warning
+    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
+    auto rv = GetDynamicTimeZoneInformation(&tzinfo);
+    if (!rv)
+        return -1;
+    return -1 * (tzinfo.Bias + tzinfo.DaylightBias);
+#else
+    return static_cast<int>(tm.tm_gmtoff / 60);
+#endif
+}
+
+//Return current thread id as size_t
+//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
+inline size_t thread_id()
+{
+#ifdef _WIN32
+    return  static_cast<size_t>(::GetCurrentThreadId());
+#elif __linux__
+    return  static_cast<size_t>(syscall(SYS_gettid));
+#else //Default to standard C++11 (OSX and other Unix)
+    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
+#endif
+
+}
+
+} //os
+} //details
+} //spdlog
+
+
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/pattern_formatter_impl.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h
new file mode 100644
index 0000000..a5b2d21
--- /dev/null
+++ b/include/spdlog/details/pattern_formatter_impl.h
@@ -0,0 +1,628 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <chrono>
+#include <memory>
+#include <vector>
+#include <thread>
+
+
+#include "../formatter.h"
+#include "./log_msg.h"
+#include "./os.h"
+
+namespace spdlog
+{
+namespace details
+{
+class flag_formatter
+{
+public:
+    virtual ~flag_formatter() {}
+    virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////
+// name & level pattern appenders
+///////////////////////////////////////////////////////////////////////
+namespace
+{
+class name_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << msg.logger_name;
+    }
+};
+}
+
+// log level appender
+class level_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << level::to_str(msg.level);
+    }
+};
+
+// short log level appender
+class short_level_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << level::to_short_str(msg.level);
+    }
+};
+
+///////////////////////////////////////////////////////////////////////
+// Date time pattern appenders
+///////////////////////////////////////////////////////////////////////
+
+static const char* ampm(const tm& t)
+{
+    return t.tm_hour >= 12 ? "PM" : "AM";
+}
+
+static int to12h(const tm& t)
+{
+    return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
+}
+
+//Abbreviated weekday name
+static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+class a_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << days[tm_time.tm_wday];
+    }
+};
+
+//Full weekday name
+static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
+class A_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << full_days[tm_time.tm_wday];
+    }
+};
+
+//Abbreviated month
+static const std::string  months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
+class b_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted<< months[tm_time.tm_mon];
+    }
+};
+
+//Full month name
+static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
+class B_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << full_months[tm_time.tm_mon];
+    }
+};
+
+
+//write 2 ints seperated by sep with padding of 2
+static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep)
+{
+    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0');
+    return w;
+}
+
+//write 3 ints seperated by sep with padding of 2
+static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep)
+{
+    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0');
+    return w;
+}
+
+
+//Date and time representation (Thu Aug 23 15:35:46 2014)
+class c_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
+        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
+    }
+};
+
+
+// year - 2 digit
+class C_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0');
+    }
+};
+
+
+
+// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
+class D_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/');
+    }
+};
+
+
+// year - 4 digit
+class Y_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << tm_time.tm_year + 1900;
+    }
+};
+
+// month 1-12
+class m_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0');
+    }
+};
+
+// day of month 1-31
+class d_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0');
+    }
+};
+
+// hours in 24 format  0-23
+class H_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0');
+    }
+};
+
+// hours in 12 format  1-12
+class I_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(to12h(tm_time), 2, '0');
+    }
+};
+
+// ninutes 0-59
+class M_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_min, 2, '0');
+    }
+};
+
+// seconds 0-59
+class S_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0');
+    }
+};
+
+// milliseconds
+class e_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        auto duration = msg.time.time_since_epoch();
+        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
+        msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0');
+    }
+};
+
+// microseconds
+class f_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        auto duration = msg.time.time_since_epoch();
+        auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000;
+        msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0');
+    }
+};
+
+// AM/PM
+class p_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        msg.formatted << ampm(tm_time);
+    }
+};
+
+
+// 12 hour clock 02:55:02 pm
+class r_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time);
+    }
+};
+
+// 24-hour HH:MM time, equivalent to %H:%M
+class R_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':');
+    }
+};
+
+// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
+class T_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':');
+    }
+};
+
+
+// ISO 8601 offset from UTC in timezone (+-HH:MM)
+class z_formatter :public flag_formatter
+{
+public:
+    const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
+
+    z_formatter() :_last_update(std::chrono::seconds(0)) {}
+    z_formatter(const z_formatter&) = delete;
+    z_formatter& operator=(const z_formatter&) = delete;
+
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+#ifdef _WIN32
+        int total_minutes = get_cached_offset(msg, tm_time);
+#else
+        // No need to chache under gcc,
+        // it is very fast (already stored in tm.tm_gmtoff)
+        int total_minutes = os::utc_minutes_offset(tm_time);
+#endif
+
+        int h = total_minutes / 60;
+        int m = total_minutes % 60;
+        char sign = h >= 0 ? '+' : '-';
+        msg.formatted << sign;
+        pad_n_join(msg.formatted, h, m, ':');
+    }
+private:
+    log_clock::time_point _last_update;
+    int _offset_minutes;
+    std::mutex _mutex;
+
+    int get_cached_offset(const log_msg& msg, const std::tm& tm_time)
+    {
+        using namespace std::chrono;
+        std::lock_guard<std::mutex> l(_mutex);
+        if (msg.time - _last_update >= cache_refresh)
+        {
+            _offset_minutes = os::utc_minutes_offset(tm_time);
+            _last_update = msg.time;
+        }
+        return _offset_minutes;
+    }
+};
+
+
+
+//Thread id
+class t_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << msg.thread_id;
+    }
+};
+
+
+class v_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
+    }
+};
+
+class ch_formatter :public flag_formatter
+{
+public:
+    explicit ch_formatter(char ch) : _ch(ch)
+    {}
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << _ch;
+    }
+private:
+    char _ch;
+};
+
+
+//aggregate user chars to display as is
+class aggregate_formatter :public flag_formatter
+{
+public:
+    aggregate_formatter()
+    {}
+    void add_ch(char ch)
+    {
+        _str += ch;
+    }
+    void format(details::log_msg& msg, const std::tm&) override
+    {
+        msg.formatted << _str;
+    }
+private:
+    std::string _str;
+};
+
+// Full info formatter
+// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
+class full_formatter :public flag_formatter
+{
+    void format(details::log_msg& msg, const std::tm& tm_time) override
+    {
+#ifndef SPDLOG_NO_DATETIME
+        auto duration = msg.time.time_since_epoch();
+        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
+
+        /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
+        msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
+        tm_time.tm_year + 1900,
+        tm_time.tm_mon + 1,
+        tm_time.tm_mday,
+        tm_time.tm_hour,
+        tm_time.tm_min,
+        tm_time.tm_sec,
+        static_cast<int>(millis),
+        msg.logger_name,
+        level::to_str(msg.level),
+        msg.raw.str());*/
+
+
+        // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
+        msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'
+                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'
+                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' '
+                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':'
+                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':'
+                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'
+                      << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] ";
+
+//no datetime needed
+#else
+        (void)tm_time;
+#endif
+
+#ifndef SPDLOG_NO_NAME
+        msg.formatted << '[' << msg.logger_name << "] ";
+#endif
+
+        msg.formatted << '[' << level::to_str(msg.level) << "] ";
+        msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
+    }
+};
+
+}
+}
+///////////////////////////////////////////////////////////////////////////////
+// pattern_formatter inline impl
+///////////////////////////////////////////////////////////////////////////////
+inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
+{
+    compile_pattern(pattern);
+}
+
+inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
+{
+    auto end = pattern.end();
+    std::unique_ptr<details::aggregate_formatter> user_chars;
+    for (auto it = pattern.begin(); it != end; ++it)
+    {
+        if (*it == '%')
+        {
+            if (user_chars) //append user chars found so far
+                _formatters.push_back(std::move(user_chars));
+
+            if (++it != end)
+                handle_flag(*it);
+            else
+                break;
+        }
+        else // chars not following the % sign should be displayed as is
+        {
+            if (!user_chars)
+                user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
+            user_chars->add_ch(*it);
+        }
+    }
+    if (user_chars) //append raw chars found so far
+    {
+        _formatters.push_back(std::move(user_chars));
+    }
+
+}
+inline void spdlog::pattern_formatter::handle_flag(char flag)
+{
+    switch (flag)
+    {
+    // logger name
+    case 'n':
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
+        break;
+
+    case 'l':
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter()));
+        break;
+
+    case 'L':
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter()));
+        break;
+
+    case('t') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter()));
+        break;
+
+    case('v') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter()));
+        break;
+
+    case('a') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter()));
+        break;
+
+    case('A') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter()));
+        break;
+
+    case('b') :
+    case('h') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter()));
+        break;
+
+    case('B') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter()));
+        break;
+    case('c') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter()));
+        break;
+
+    case('C') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter()));
+        break;
+
+    case('Y') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter()));
+        break;
+
+    case('D') :
+    case('x') :
+
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter()));
+        break;
+
+    case('m') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter()));
+        break;
+
+    case('d') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter()));
+        break;
+
+    case('H') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter()));
+        break;
+
+    case('I') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter()));
+        break;
+
+    case('M') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter()));
+        break;
+
+    case('S') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter()));
+        break;
+
+    case('e') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter()));
+        break;
+
+    case('f') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter()));
+        break;
+
+    case('p') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter()));
+        break;
+
+    case('r') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter()));
+        break;
+
+    case('R') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter()));
+        break;
+
+    case('T') :
+    case('X') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter()));
+        break;
+
+    case('z') :
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter()));
+        break;
+
+    case ('+'):
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
+        break;
+
+    default: //Unkown flag appears as is
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
+        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));
+        break;
+    }
+}
+
+
+inline void spdlog::pattern_formatter::format(details::log_msg& msg)
+{
+    try
+    {
+        auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time));
+        for (auto &f : _formatters)
+        {
+            f->format(msg, tm_time);
+        }
+        //write eol
+        msg.formatted << details::os::eol();
+    }
+    catch(const fmt::FormatError& e)
+    {
+        throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/registry.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h
new file mode 100644
index 0000000..fd8e4be
--- /dev/null
+++ b/include/spdlog/details/registry.h
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+// Loggers registy of unique name->logger pointer
+// An attempt to create a logger with an alreasy existing name will be ignored
+// If user requests a non existing logger, nullptr will be returned
+// This class is thread safe
+
+#include <string>
+#include <mutex>
+#include <unordered_map>
+#include <functional>
+
+#include "./null_mutex.h"
+#include "../logger.h"
+#include "../async_logger.h"
+#include "../common.h"
+
+namespace spdlog
+{
+namespace details
+{
+template <class Mutex> class registry_t
+{
+public:
+
+    void register_logger(std::shared_ptr<logger> logger)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        register_logger_impl(logger);
+    }
+
+
+    std::shared_ptr<logger> get(const std::string& logger_name)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        auto found = _loggers.find(logger_name);
+        return found == _loggers.end() ? nullptr : found->second;
+    }
+
+    template<class It>
+    std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
+    {
+
+        std::shared_ptr<logger> new_logger;
+
+        std::lock_guard<Mutex> lock(_mutex);
+
+
+        if (_async_mode)
+            new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms);
+        else
+            new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
+
+        if (_formatter)
+            new_logger->set_formatter(_formatter);
+
+        new_logger->set_level(_level);
+        register_logger_impl(new_logger);
+        return new_logger;
+    }
+
+    void drop(const std::string& logger_name)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _loggers.erase(logger_name);
+    }
+
+    void drop_all()
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _loggers.clear();
+    }
+    std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
+    {
+        return create(logger_name, sinks.begin(), sinks.end());
+    }
+
+    std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
+    {
+        return create(logger_name, { sink });
+    }
+
+
+    void formatter(formatter_ptr f)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _formatter = f;
+        for (auto& l : _loggers)
+            l.second->set_formatter(_formatter);
+    }
+
+    void set_pattern(const std::string& pattern)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _formatter = std::make_shared<pattern_formatter>(pattern);
+        for (auto& l : _loggers)
+            l.second->set_formatter(_formatter);
+    }
+
+    void set_level(level::level_enum log_level)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        for (auto& l : _loggers)
+            l.second->set_level(log_level);
+        _level = log_level;
+    }
+
+    void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _async_mode = true;
+        _async_q_size = q_size;
+        _overflow_policy = overflow_policy;
+        _worker_warmup_cb = worker_warmup_cb;
+        _flush_interval_ms = flush_interval_ms;
+    }
+
+    void set_sync_mode()
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _async_mode = false;
+    }
+
+    static registry_t<Mutex>& instance()
+    {
+        static registry_t<Mutex> s_instance;
+        return s_instance;
+    }
+
+private:
+    void register_logger_impl(std::shared_ptr<logger> logger)
+    {
+        auto logger_name = logger->name();
+        if (_loggers.find(logger_name) != std::end(_loggers))
+            throw spdlog_ex("logger with name " + logger_name + " already exists");
+        _loggers[logger->name()] = logger;
+    }
+    registry_t<Mutex>(){}
+    registry_t<Mutex>(const registry_t<Mutex>&) = delete;
+    registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
+    Mutex _mutex;
+    std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
+    formatter_ptr _formatter;
+    level::level_enum _level = level::info;
+    bool _async_mode = false;
+    size_t _async_q_size = 0;
+    async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
+    std::function<void()> _worker_warmup_cb = nullptr;
+    std::chrono::milliseconds _flush_interval_ms;
+};
+#ifdef SPDLOG_NO_REGISTRY_MUTEX
+typedef registry_t<spdlog::details::null_mutex> registry;
+#else
+typedef registry_t<std::mutex> registry;
+#endif
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/spdlog_impl.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h
new file mode 100644
index 0000000..cfd6f82
--- /dev/null
+++ b/include/spdlog/details/spdlog_impl.h
@@ -0,0 +1,154 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+//
+// Global registry functions
+//
+#include "registry.h"
+#include "../sinks/file_sinks.h"
+#include "../sinks/stdout_sinks.h"
+#include "../sinks/syslog_sink.h"
+
+inline void spdlog::register_logger(std::shared_ptr<logger> logger)
+{
+    return details::registry::instance().register_logger(logger);
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
+{
+    return details::registry::instance().get(name);
+}
+
+inline void spdlog::drop(const std::string &name)
+{
+    details::registry::instance().drop(name);
+}
+
+// Create multi/single threaded rotating file logger
+inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
+{
+    return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
+{
+    return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
+}
+
+// Create file logger which creates new file at midnight):
+inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
+{
+    return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
+}
+inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
+{
+    return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
+}
+
+
+// Create stdout/stderr loggers
+inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name)
+{
+    return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name)
+{
+    return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name)
+{
+    return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name)
+{
+    return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());
+}
+
+#ifdef __linux__
+// Create syslog logger
+inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
+{
+    return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
+}
+#endif
+
+
+//Create logger with multiple sinks
+
+inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
+{
+    return details::registry::instance().create(logger_name, sinks);
+}
+
+
+template <typename Sink, typename... Args>
+inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const Args&... args)
+{
+    sink_ptr sink = std::make_shared<Sink>(args...);
+    return details::registry::instance().create(logger_name, { sink });
+}
+
+
+template<class It>
+inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
+{
+    return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
+}
+
+inline void spdlog::set_formatter(spdlog::formatter_ptr f)
+{
+    details::registry::instance().formatter(f);
+}
+
+inline void spdlog::set_pattern(const std::string& format_string)
+{
+    return details::registry::instance().set_pattern(format_string);
+}
+
+inline void spdlog::set_level(level::level_enum log_level)
+{
+    return details::registry::instance().set_level(log_level);
+}
+
+
+inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
+{
+    details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
+}
+
+inline void spdlog::set_sync_mode()
+{
+    details::registry::instance().set_sync_mode();
+}
+
+inline void spdlog::drop_all()
+{
+    details::registry::instance().drop_all();
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/formatter.h
----------------------------------------------------------------------
diff --git a/include/spdlog/formatter.h b/include/spdlog/formatter.h
new file mode 100644
index 0000000..35ea041
--- /dev/null
+++ b/include/spdlog/formatter.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#pragma once
+
+#include "details/log_msg.h"
+namespace spdlog
+{
+namespace details
+{
+class flag_formatter;
+}
+
+class formatter
+{
+public:
+    virtual ~formatter() {}
+    virtual void format(details::log_msg& msg) = 0;
+};
+
+class pattern_formatter : public formatter
+{
+
+public:
+    explicit pattern_formatter(const std::string& pattern);
+    pattern_formatter(const pattern_formatter&) = delete;
+    pattern_formatter& operator=(const pattern_formatter&) = delete;
+    void format(details::log_msg& msg) override;
+private:
+    const std::string _pattern;
+    std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
+    void handle_flag(char flag);
+    void compile_pattern(const std::string& pattern);
+};
+}
+
+#include "details/pattern_formatter_impl.h"
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/logger.h
----------------------------------------------------------------------
diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h
new file mode 100644
index 0000000..7aefcc7
--- /dev/null
+++ b/include/spdlog/logger.h
@@ -0,0 +1,132 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+// Thread safe logger
+// Has name, log level, vector of std::shared sink pointers and formatter
+// Upon each log write the logger:
+// 1. Checks if its log level is enough to log the message
+// 2. Format the message using the formatter function
+// 3. Pass the formatted message to its sinks to performa the actual logging
+
+#include<vector>
+#include<memory>
+#include "sinks/base_sink.h"
+#include "common.h"
+
+namespace spdlog
+{
+
+namespace details
+{
+class line_logger;
+}
+
+class logger
+{
+public:
+    logger(const std::string& logger_name, sink_ptr single_sink);
+    logger(const std::string& name, sinks_init_list);
+    template<class It>
+    logger(const std::string& name, const It& begin, const It& end);
+
+    virtual ~logger();
+    logger(const logger&) = delete;
+    logger& operator=(const logger&) = delete;
+
+    void set_level(level::level_enum);
+    level::level_enum level() const;
+
+    const std::string& name() const;
+    bool should_log(level::level_enum) const;
+
+    // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
+    template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger info(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger error(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args);
+    template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
+
+
+    // logger.info(msg) << ".." call style
+    template <typename T> details::line_logger trace(const T&);
+    template <typename T> details::line_logger debug(const T&);
+    template <typename T> details::line_logger info(const T&);
+    template <typename T> details::line_logger notice(const T&);
+    template <typename T> details::line_logger warn(const T&);
+    template <typename T> details::line_logger error(const T&);
+    template <typename T> details::line_logger critical(const T&);
+    template <typename T> details::line_logger alert(const T&);
+    template <typename T> details::line_logger emerg(const T&);
+
+
+    // logger.info() << ".." call  style
+    details::line_logger trace();
+    details::line_logger debug();
+    details::line_logger info();
+    details::line_logger notice();
+    details::line_logger warn();
+    details::line_logger error();
+    details::line_logger critical();
+    details::line_logger alert();
+    details::line_logger emerg();
+
+
+
+    // Create log message with the given level, no matter what is the actual logger's level
+    template <typename... Args>
+    details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
+
+    // Set the format of the log messages from this logger
+    void set_pattern(const std::string&);
+    void set_formatter(formatter_ptr);
+
+    void flush();
+
+protected:
+    virtual void _log_msg(details::log_msg&);
+    virtual void _set_pattern(const std::string&);
+    virtual void _set_formatter(formatter_ptr);
+    details::line_logger _log_if_enabled(level::level_enum lvl);
+    template <typename... Args>
+    details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
+    template<typename T>
+    inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
+
+
+    friend details::line_logger;
+    std::string _name;
+    std::vector<sink_ptr> _sinks;
+    formatter_ptr _formatter;
+    std::atomic_int _level;
+
+};
+}
+
+#include "details/logger_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/base_sink.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/base_sink.h b/include/spdlog/sinks/base_sink.h
new file mode 100644
index 0000000..12d63ea
--- /dev/null
+++ b/include/spdlog/sinks/base_sink.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+//
+// base sink templated over a mutex (either dummy or realy)
+// concrete implementation should only overrid the _sink_it method.
+// all locking is taken care of here so no locking needed by the implementors..
+//
+
+#include<string>
+#include<mutex>
+#include<atomic>
+#include "./sink.h"
+#include "../formatter.h"
+#include "../common.h"
+#include "../details/log_msg.h"
+
+
+namespace spdlog
+{
+namespace sinks
+{
+template<class Mutex>
+class base_sink:public sink
+{
+public:
+    base_sink():_mutex() {}
+    virtual ~base_sink() = default;
+
+    base_sink(const base_sink&) = delete;
+    base_sink& operator=(const base_sink&) = delete;
+
+    void log(const details::log_msg& msg) override
+    {
+        std::lock_guard<Mutex> lock(_mutex);
+        _sink_it(msg);
+    }
+
+protected:
+    virtual void _sink_it(const details::log_msg& msg) = 0;
+    Mutex _mutex;
+};
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/file_sinks.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h
new file mode 100644
index 0000000..79cbb4e
--- /dev/null
+++ b/include/spdlog/sinks/file_sinks.h
@@ -0,0 +1,232 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <mutex>
+#include "base_sink.h"
+#include "../details/null_mutex.h"
+#include "../details/file_helper.h"
+#include "../details/format.h"
+
+namespace spdlog
+{
+namespace sinks
+{
+/*
+* Trivial file sink with single file as target
+*/
+template<class Mutex>
+class simple_file_sink : public base_sink < Mutex >
+{
+public:
+    explicit simple_file_sink(const std::string &filename,
+                              bool force_flush = false) :
+        _file_helper(force_flush)
+    {
+        _file_helper.open(filename);
+    }
+    void flush() override
+    {
+        _file_helper.flush();
+    }
+
+protected:
+    void _sink_it(const details::log_msg& msg) override
+    {
+        _file_helper.write(msg);
+    }
+private:
+    details::file_helper _file_helper;
+};
+
+typedef simple_file_sink<std::mutex> simple_file_sink_mt;
+typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
+
+/*
+ * Rotating file sink based on size
+ */
+template<class Mutex>
+class rotating_file_sink : public base_sink < Mutex >
+{
+public:
+    rotating_file_sink(const std::string &base_filename, const std::string &extension,
+                       std::size_t max_size, std::size_t max_files,
+                       bool force_flush = false) :
+        _base_filename(base_filename),
+        _extension(extension),
+        _max_size(max_size),
+        _max_files(max_files),
+        _current_size(0),
+        _file_helper(force_flush)
+    {
+        _file_helper.open(calc_filename(_base_filename, 0, _extension));
+    }
+
+    void flush() override
+    {
+        _file_helper.flush();
+    }
+
+protected:
+    void _sink_it(const details::log_msg& msg) override
+    {
+        _current_size += msg.formatted.size();
+        if (_current_size > _max_size)
+        {
+            _rotate();
+            _current_size = msg.formatted.size();
+        }
+        _file_helper.write(msg);
+    }
+
+private:
+    static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
+    {
+        fmt::MemoryWriter w;
+        if (index)
+            w.write("{}.{}.{}", filename, index, extension);
+        else
+            w.write("{}.{}", filename, extension);
+        return w.str();
+    }
+
+    // Rotate files:
+    // log.txt -> log.1.txt
+    // log.1.txt -> log2.txt
+    // log.2.txt -> log3.txt
+    // log.3.txt -> delete
+
+    void _rotate()
+    {
+        _file_helper.close();
+        for (auto i = _max_files; i > 0; --i)
+        {
+            std::string src = calc_filename(_base_filename, i - 1, _extension);
+            std::string target = calc_filename(_base_filename, i, _extension);
+
+            if (details::file_helper::file_exists(target))
+            {
+                if (std::remove(target.c_str()) != 0)
+                {
+                    throw spdlog_ex("rotating_file_sink: failed removing " + target);
+                }
+            }
+            if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str()))
+            {
+                throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target);
+            }
+        }
+        _file_helper.reopen(true);
+    }
+    std::string _base_filename;
+    std::string _extension;
+    std::size_t _max_size;
+    std::size_t _max_files;
+    std::size_t _current_size;
+    details::file_helper _file_helper;
+};
+
+typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
+typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
+
+/*
+ * Rotating file sink based on date. rotates at midnight
+ */
+template<class Mutex>
+class daily_file_sink :public base_sink < Mutex >
+{
+public:
+    //create daily file sink which rotates on given time
+    daily_file_sink(
+        const std::string& base_filename,
+        const std::string& extension,
+        int rotation_hour,
+        int rotation_minute,
+        bool force_flush = false) : _base_filename(base_filename),
+        _extension(extension),
+        _rotation_h(rotation_hour),
+        _rotation_m(rotation_minute),
+        _file_helper(force_flush)
+    {
+        if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
+            throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
+        _rotation_tp = _next_rotation_tp();
+        _file_helper.open(calc_filename(_base_filename, _extension));
+    }
+
+    void flush() override
+    {
+        _file_helper.flush();
+    }
+
+protected:
+    void _sink_it(const details::log_msg& msg) override
+    {
+        if (std::chrono::system_clock::now() >= _rotation_tp)
+        {
+            _file_helper.open(calc_filename(_base_filename, _extension));
+            _rotation_tp = _next_rotation_tp();
+        }
+        _file_helper.write(msg);
+    }
+
+private:
+    std::chrono::system_clock::time_point _next_rotation_tp()
+    {
+        using namespace std::chrono;
+        auto now = system_clock::now();
+        time_t tnow = std::chrono::system_clock::to_time_t(now);
+        tm date = spdlog::details::os::localtime(tnow);
+        date.tm_hour = _rotation_h;
+        date.tm_min = _rotation_m;
+        date.tm_sec = 0;
+        auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
+        if (rotation_time > now)
+            return rotation_time;
+        else
+            return system_clock::time_point(rotation_time + hours(24));
+    }
+
+    //Create filename for the form basename.YYYY-MM-DD.extension
+    static std::string calc_filename(const std::string& basename, const std::string& extension)
+    {
+        std::tm tm = spdlog::details::os::localtime();
+        fmt::MemoryWriter w;
+        w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
+        return w.str();
+    }
+
+    std::string _base_filename;
+    std::string _extension;
+    int _rotation_h;
+    int _rotation_m;
+    std::chrono::system_clock::time_point _rotation_tp;
+    details::file_helper _file_helper;
+};
+
+typedef daily_file_sink<std::mutex> daily_file_sink_mt;
+typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
+}
+}


[15/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/format.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/format.h b/inc/spdlog/details/format.h
deleted file mode 100644
index 7ec3b39..0000000
--- a/inc/spdlog/details/format.h
+++ /dev/null
@@ -1,3155 +0,0 @@
-/*
-Formatting library for C++
-
-Copyright (c) 2012 - 2015, Victor Zverovich
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-2. 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.
-
-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.
-*/
-
-#ifndef FMT_FORMAT_H_
-#define FMT_FORMAT_H_
-
-#define FMT_HEADER_ONLY
-
-#include <stdint.h>
-
-#include <cassert>
-#include <cmath>
-#include <cstddef>  // for std::ptrdiff_t
-#include <cstdio>
-#include <algorithm>
-#include <limits>
-#include <stdexcept>
-#include <string>
-#include <sstream>
-#include <map>
-
-#if _SECURE_SCL
-# include <iterator>
-#endif
-
-#ifdef _MSC_VER
-# include <intrin.h>  // _BitScanReverse, _BitScanReverse64
-
-namespace fmt {
-namespace internal {
-# pragma intrinsic(_BitScanReverse)
-inline uint32_t clz(uint32_t x) {
-    unsigned long r = 0;
-    _BitScanReverse(&r, x);
-    return 31 - r;
-}
-# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
-
-# ifdef _WIN64
-#  pragma intrinsic(_BitScanReverse64)
-# endif
-
-inline uint32_t clzll(uint64_t x) {
-    unsigned long r = 0;
-# ifdef _WIN64
-    _BitScanReverse64(&r, x);
-# else
-    // Scan the high 32 bits.
-    if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
-        return 63 - (r + 32);
-
-    // Scan the low 32 bits.
-    _BitScanReverse(&r, static_cast<uint32_t>(x));
-# endif
-    return 63 - r;
-}
-# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
-}
-}
-#endif
-
-#ifdef __GNUC__
-# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
-# define FMT_GCC_EXTENSION __extension__
-# if FMT_GCC_VERSION >= 406
-#  pragma GCC diagnostic push
-// Disable the warning about "long long" which is sometimes reported even
-// when using __extension__.
-#  pragma GCC diagnostic ignored "-Wlong-long"
-// Disable the warning about declaration shadowing because it affects too
-// many valid cases.
-#  pragma GCC diagnostic ignored "-Wshadow"
-# endif
-# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
-#  define FMT_HAS_GXX_CXX11 1
-# endif
-#else
-# define FMT_GCC_EXTENSION
-#endif
-
-#ifdef __clang__
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdocumentation"
-#endif
-
-#ifdef __GNUC_LIBSTD__
-# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
-#endif
-
-#ifdef __has_feature
-# define FMT_HAS_FEATURE(x) __has_feature(x)
-#else
-# define FMT_HAS_FEATURE(x) 0
-#endif
-
-#ifdef __has_builtin
-# define FMT_HAS_BUILTIN(x) __has_builtin(x)
-#else
-# define FMT_HAS_BUILTIN(x) 0
-#endif
-
-#ifdef __has_cpp_attribute
-# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
-#else
-# define FMT_HAS_CPP_ATTRIBUTE(x) 0
-#endif
-
-#ifndef FMT_USE_VARIADIC_TEMPLATES
-// Variadic templates are available in GCC since version 4.4
-// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
-// since version 2013.
-# define FMT_USE_VARIADIC_TEMPLATES \
-   (FMT_HAS_FEATURE(cxx_variadic_templates) || \
-       (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800)
-#endif
-
-#ifndef FMT_USE_RVALUE_REFERENCES
-// Don't use rvalue references when compiling with clang and an old libstdc++
-// as the latter doesn't provide std::move.
-# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402
-#  define FMT_USE_RVALUE_REFERENCES 0
-# else
-#  define FMT_USE_RVALUE_REFERENCES \
-    (FMT_HAS_FEATURE(cxx_rvalue_references) || \
-        (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600)
-# endif
-#endif
-
-#if FMT_USE_RVALUE_REFERENCES
-# include <utility>  // for std::move
-#endif
-
-// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
-#ifndef FMT_NOEXCEPT
-# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
-   (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11)
-#  define FMT_NOEXCEPT noexcept
-# else
-#  define FMT_NOEXCEPT throw()
-# endif
-#endif
-
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
-  (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
-# define FMT_DELETED_OR_UNDEFINED  = delete
-# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
-    TypeName(const TypeName&) = delete; \
-    TypeName& operator=(const TypeName&) = delete
-#else
-# define FMT_DELETED_OR_UNDEFINED
-# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
-    TypeName(const TypeName&); \
-    TypeName& operator=(const TypeName&)
-#endif
-
-#ifndef FMT_ASSERT
-# define FMT_ASSERT(condition, message) assert((condition) && message)
-#endif
-
-namespace fmt {
-
-// Fix the warning about long long on older versions of GCC
-// that don't support the diagnostic pragma.
-FMT_GCC_EXTENSION typedef long long LongLong;
-FMT_GCC_EXTENSION typedef unsigned long long ULongLong;
-
-#if FMT_USE_RVALUE_REFERENCES
-using std::move;
-#endif
-
-template <typename Char>
-class BasicWriter;
-
-typedef BasicWriter<char> Writer;
-typedef BasicWriter<wchar_t> WWriter;
-
-template <typename Char>
-class BasicFormatter;
-
-template <typename Char, typename T>
-void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value);
-
-/**
-\rst
-A string reference. It can be constructed from a C string or ``std::string``.
-
-You can use one of the following typedefs for common character types:
-
-+------------+-------------------------+
-| Type       | Definition              |
-+============+=========================+
-| StringRef  | BasicStringRef<char>    |
-+------------+-------------------------+
-| WStringRef | BasicStringRef<wchar_t> |
-+------------+-------------------------+
-
-This class is most useful as a parameter type to allow passing
-different types of strings to a function, for example::
-
-template <typename... Args>
-std::string format(StringRef format_str, const Args & ... args);
-
-format("{}", 42);
-format(std::string("{}"), 42);
-\endrst
-*/
-template <typename Char>
-class BasicStringRef {
-private:
-    const Char *data_;
-    std::size_t size_;
-
-public:
-    /** Constructs a string reference object from a C string and a size. */
-    BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {}
-
-    /**
-    \rst
-    Constructs a string reference object from a C string computing
-    the size with ``std::char_traits<Char>::length``.
-    \endrst
-    */
-    BasicStringRef(const Char *s)
-        : data_(s), size_(std::char_traits<Char>::length(s)) {}
-
-    /**
-    \rst
-    Constructs a string reference from an ``std::string`` object.
-    \endrst
-    */
-    BasicStringRef(const std::basic_string<Char> &s)
-        : data_(s.c_str()), size_(s.size()) {}
-
-    /**
-    \rst
-    Converts a string reference to an ``std::string`` object.
-    \endrst
-    */
-    std::basic_string<Char> to_string() const {
-        return std::basic_string<Char>(data_, size_);
-    }
-
-    /** Returns the pointer to a C string. */
-    const Char *data() const {
-        return data_;
-    }
-
-    /** Returns the string size. */
-    std::size_t size() const {
-        return size_;
-    }
-
-    friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
-        return lhs.data_ == rhs.data_;
-    }
-    friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
-        return lhs.data_ != rhs.data_;
-    }
-    friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) {
-        return std::lexicographical_compare(
-                   lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_);
-    }
-};
-
-typedef BasicStringRef<char> StringRef;
-typedef BasicStringRef<wchar_t> WStringRef;
-
-
-/**
-\rst
-A reference to a null terminated string. It can be constructed from a C
-string or ``std::string``.
-
-You can use one of the following typedefs for common character types:
-
-+-------------+--------------------------+
-| Type        | Definition               |
-+=============+==========================+
-| CStringRef  | BasicCStringRef<char>    |
-+-------------+--------------------------+
-| WCStringRef | BasicCStringRef<wchar_t> |
-+-------------+--------------------------+
-
-This class is most useful as a parameter type to allow passing
-different types of strings to a function, for example::
-
-template <typename... Args>
-std::string format(CStringRef format_str, const Args & ... args);
-
-format("{}", 42);
-format(std::string("{}"), 42);
-\endrst
-*/
-template <typename Char>
-class BasicCStringRef {
-private:
-    const Char *data_;
-
-public:
-    /** Constructs a string reference object from a C string. */
-    BasicCStringRef(const Char *s) : data_(s) {}
-
-    /**
-    \rst
-    Constructs a string reference from an ``std::string`` object.
-    \endrst
-    */
-    BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {}
-
-    /** Returns the pointer to a C string. */
-    const Char *c_str() const {
-        return data_;
-    }
-};
-
-typedef BasicCStringRef<char> CStringRef;
-typedef BasicCStringRef<wchar_t> WCStringRef;
-
-/**
-A formatting error such as invalid format string.
-*/
-class FormatError : public std::runtime_error {
-public:
-    explicit FormatError(CStringRef message)
-        : std::runtime_error(message.c_str()) {}
-};
-
-namespace internal {
-// The number of characters to store in the MemoryBuffer object itself
-// to avoid dynamic memory allocation.
-enum { INLINE_BUFFER_SIZE = 500 };
-
-#if _SECURE_SCL
-// Use checked iterator to avoid warnings on MSVC.
-template <typename T>
-inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
-    return stdext::checked_array_iterator<T*>(ptr, size);
-}
-#else
-template <typename T>
-inline T *make_ptr(T *ptr, std::size_t) {
-    return ptr;
-}
-#endif
-}  // namespace internal
-
-/**
-\rst
-A buffer supporting a subset of ``std::vector``'s operations.
-\endrst
-*/
-template <typename T>
-class Buffer {
-private:
-    FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);
-
-protected:
-    T *ptr_;
-    std::size_t size_;
-    std::size_t capacity_;
-
-    Buffer(T *ptr = 0, std::size_t capacity = 0)
-        : ptr_(ptr), size_(0), capacity_(capacity) {}
-
-    /**
-    \rst
-    Increases the buffer capacity to hold at least *size* elements updating
-    ``ptr_`` and ``capacity_``.
-    \endrst
-    */
-    virtual void grow(std::size_t size) = 0;
-
-public:
-    virtual ~Buffer() {}
-
-    /** Returns the size of this buffer. */
-    std::size_t size() const {
-        return size_;
-    }
-
-    /** Returns the capacity of this buffer. */
-    std::size_t capacity() const {
-        return capacity_;
-    }
-
-    /**
-    Resizes the buffer. If T is a POD type new elements may not be initialized.
-    */
-    void resize(std::size_t new_size) {
-        if (new_size > capacity_)
-            grow(new_size);
-        size_ = new_size;
-    }
-
-    /**
-    \rst
-    Reserves space to store at least *capacity* elements.
-    \endrst
-    */
-    void reserve(std::size_t capacity) {
-        if (capacity > capacity_)
-            grow(capacity);
-    }
-
-    void clear() FMT_NOEXCEPT{ size_ = 0; }
-
-    void push_back(const T &value) {
-        if (size_ == capacity_)
-            grow(size_ + 1);
-        ptr_[size_++] = value;
-    }
-
-    /** Appends data to the end of the buffer. */
-    template <typename U>
-    void append(const U *begin, const U *end);
-
-    T &operator[](std::size_t index) {
-        return ptr_[index];
-    }
-    const T &operator[](std::size_t index) const {
-        return ptr_[index];
-    }
-};
-
-template <typename T>
-template <typename U>
-void Buffer<T>::append(const U *begin, const U *end) {
-    std::ptrdiff_t num_elements = end - begin;
-    if (size_ + num_elements > capacity_)
-        grow(size_ + num_elements);
-    std::copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_);
-    size_ += num_elements;
-}
-
-namespace internal {
-
-// A memory buffer for POD types with the first SIZE elements stored in
-// the object itself.
-template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
-class MemoryBuffer : private Allocator, public Buffer<T> {
-private:
-    T data_[SIZE];
-
-    // Free memory allocated by the buffer.
-    void free() {
-        if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
-    }
-
-protected:
-    void grow(std::size_t size);
-
-public:
-    explicit MemoryBuffer(const Allocator &alloc = Allocator())
-        : Allocator(alloc), Buffer<T>(data_, SIZE) {}
-    ~MemoryBuffer() {
-        free();
-    }
-
-#if FMT_USE_RVALUE_REFERENCES
-private:
-    // Move data from other to this buffer.
-    void move(MemoryBuffer &other) {
-        Allocator &this_alloc = *this, &other_alloc = other;
-        this_alloc = std::move(other_alloc);
-        this->size_ = other.size_;
-        this->capacity_ = other.capacity_;
-        if (other.ptr_ == other.data_) {
-            this->ptr_ = data_;
-            std::copy(other.data_,
-                      other.data_ + this->size_, make_ptr(data_, this->capacity_));
-        }
-        else {
-            this->ptr_ = other.ptr_;
-            // Set pointer to the inline array so that delete is not called
-            // when freeing.
-            other.ptr_ = other.data_;
-        }
-    }
-
-public:
-    MemoryBuffer(MemoryBuffer &&other) {
-        move(other);
-    }
-
-    MemoryBuffer &operator=(MemoryBuffer &&other) {
-        assert(this != &other);
-        free();
-        move(other);
-        return *this;
-    }
-#endif
-
-    // Returns a copy of the allocator associated with this buffer.
-    Allocator get_allocator() const {
-        return *this;
-    }
-};
-
-template <typename T, std::size_t SIZE, typename Allocator>
-void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
-    std::size_t new_capacity =
-        (std::max)(size, this->capacity_ + this->capacity_ / 2);
-    T *new_ptr = this->allocate(new_capacity);
-    // The following code doesn't throw, so the raw pointer above doesn't leak.
-    std::copy(this->ptr_,
-              this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity));
-    std::size_t old_capacity = this->capacity_;
-    T *old_ptr = this->ptr_;
-    this->capacity_ = new_capacity;
-    this->ptr_ = new_ptr;
-    // deallocate may throw (at least in principle), but it doesn't matter since
-    // the buffer already uses the new storage and will deallocate it in case
-    // of exception.
-    if (old_ptr != data_)
-        this->deallocate(old_ptr, old_capacity);
-}
-
-// A fixed-size buffer.
-template <typename Char>
-class FixedBuffer : public fmt::Buffer<Char> {
-public:
-    FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
-
-protected:
-    void grow(std::size_t size);
-};
-
-#ifndef _MSC_VER
-// Portable version of signbit.
-inline int getsign(double x) {
-    // When compiled in C++11 mode signbit is no longer a macro but a function
-    // defined in namespace std and the macro is undefined.
-# ifdef signbit
-    return signbit(x);
-# else
-    return std::signbit(x);
-# endif
-}
-
-// Portable version of isinf.
-# ifdef isinf
-inline int isinfinity(double x) {
-    return isinf(x);
-}
-inline int isinfinity(long double x) {
-    return isinf(x);
-}
-# else
-inline int isinfinity(double x) {
-    return std::isinf(x);
-}
-inline int isinfinity(long double x) {
-    return std::isinf(x);
-}
-# endif
-#else
-inline int getsign(double value) {
-    if (value < 0) return 1;
-    if (value == value) return 0;
-    int dec = 0, sign = 0;
-    char buffer[2];  // The buffer size must be >= 2 or _ecvt_s will fail.
-    _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
-    return sign;
-}
-inline int isinfinity(double x) {
-    return !_finite(x);
-}
-inline int isinfinity(long double x) {
-    return !_finite(static_cast<double>(x));
-}
-#endif
-
-template <typename Char>
-class BasicCharTraits {
-public:
-#if _SECURE_SCL
-    typedef stdext::checked_array_iterator<Char*> CharPtr;
-#else
-    typedef Char *CharPtr;
-#endif
-    static Char cast(wchar_t value) {
-        return static_cast<Char>(value);
-    }
-};
-
-template <typename Char>
-class CharTraits;
-
-template <>
-class CharTraits<char> : public BasicCharTraits<char> {
-private:
-    // Conversion from wchar_t to char is not allowed.
-    static char convert(wchar_t);
-
-public:
-    static char convert(char value) {
-        return value;
-    }
-
-    // Formats a floating-point number.
-    template <typename T>
-    static int format_float(char *buffer, std::size_t size,
-                            const char *format, unsigned width, int precision, T value);
-};
-
-template <>
-class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
-public:
-    static wchar_t convert(char value) {
-        return value;
-    }
-    static wchar_t convert(wchar_t value) {
-        return value;
-    }
-
-    template <typename T>
-    static int format_float(wchar_t *buffer, std::size_t size,
-                            const wchar_t *format, unsigned width, int precision, T value);
-};
-
-// Checks if a number is negative - used to avoid warnings.
-template <bool IsSigned>
-struct SignChecker {
-    template <typename T>
-    static bool is_negative(T value) {
-        return value < 0;
-    }
-};
-
-template <>
-struct SignChecker<false> {
-    template <typename T>
-    static bool is_negative(T) {
-        return false;
-    }
-};
-
-// Returns true if value is negative, false otherwise.
-// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
-template <typename T>
-inline bool is_negative(T value) {
-    return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value);
-}
-
-// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
-template <bool FitsIn32Bits>
-struct TypeSelector {
-    typedef uint32_t Type;
-};
-
-template <>
-struct TypeSelector<false> {
-    typedef uint64_t Type;
-};
-
-template <typename T>
-struct IntTraits {
-    // Smallest of uint32_t and uint64_t that is large enough to represent
-    // all values of T.
-    typedef typename
-    TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
-};
-
-// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
-template <typename T>
-struct MakeUnsigned {
-    typedef T Type;
-};
-
-#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
-  template <> \
-  struct MakeUnsigned<T> { typedef U Type; }
-
-FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
-FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
-FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
-FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
-
-void report_unknown_type(char code, const char *type);
-
-// Static data is placed in this class template to allow header-only
-// configuration.
-template <typename T = void>
-struct BasicData {
-    static const uint32_t POWERS_OF_10_32[];
-    static const uint64_t POWERS_OF_10_64[];
-    static const char DIGITS[];
-};
-
-typedef BasicData<> Data;
-
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
-# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
-#endif
-
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
-# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
-#endif
-
-#ifdef FMT_BUILTIN_CLZLL
-// Returns the number of decimal digits in n. Leading zeros are not counted
-// except for n == 0 in which case count_digits returns 1.
-inline unsigned count_digits(uint64_t n) {
-    // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
-    // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
-    unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
-    return t - (n < Data::POWERS_OF_10_64[t]) + 1;
-}
-#else
-// Fallback version of count_digits used when __builtin_clz is not available.
-inline unsigned count_digits(uint64_t n) {
-    unsigned count = 1;
-    for (;;) {
-        // Integer division is slow so do it for a group of four digits instead
-        // of for every digit. The idea comes from the talk by Alexandrescu
-        // "Three Optimization Tips for C++". See speed-test for a comparison.
-        if (n < 10) return count;
-        if (n < 100) return count + 1;
-        if (n < 1000) return count + 2;
-        if (n < 10000) return count + 3;
-        n /= 10000u;
-        count += 4;
-    }
-}
-#endif
-
-#ifdef FMT_BUILTIN_CLZ
-// Optional version of count_digits for better performance on 32-bit platforms.
-inline unsigned count_digits(uint32_t n) {
-    uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
-    return t - (n < Data::POWERS_OF_10_32[t]) + 1;
-}
-#endif
-
-// Formats a decimal unsigned integer value writing into buffer.
-template <typename UInt, typename Char>
-inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
-    --num_digits;
-    while (value >= 100) {
-        // Integer division is slow so do it for a group of two digits instead
-        // of for every digit. The idea comes from the talk by Alexandrescu
-        // "Three Optimization Tips for C++". See speed-test for a comparison.
-        unsigned index = (value % 100) * 2;
-        value /= 100;
-        buffer[num_digits] = Data::DIGITS[index + 1];
-        buffer[num_digits - 1] = Data::DIGITS[index];
-        num_digits -= 2;
-    }
-    if (value < 10) {
-        *buffer = static_cast<char>('0' + value);
-        return;
-    }
-    unsigned index = static_cast<unsigned>(value * 2);
-    buffer[1] = Data::DIGITS[index + 1];
-    buffer[0] = Data::DIGITS[index];
-}
-
-#ifndef _WIN32
-# define FMT_USE_WINDOWS_H 0
-#elif !defined(FMT_USE_WINDOWS_H)
-# define FMT_USE_WINDOWS_H 1
-#endif
-
-// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
-// All the functionality that relies on it will be disabled too.
-#if FMT_USE_WINDOWS_H
-// A converter from UTF-8 to UTF-16.
-// It is only provided for Windows since other systems support UTF-8 natively.
-class UTF8ToUTF16 {
-private:
-    MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
-
-public:
-    explicit UTF8ToUTF16(StringRef s);
-    operator WStringRef() const {
-        return WStringRef(&buffer_[0], size());
-    }
-    size_t size() const {
-        return buffer_.size() - 1;
-    }
-    const wchar_t *c_str() const {
-        return &buffer_[0];
-    }
-    std::wstring str() const {
-        return std::wstring(&buffer_[0], size());
-    }
-};
-
-// A converter from UTF-16 to UTF-8.
-// It is only provided for Windows since other systems support UTF-8 natively.
-class UTF16ToUTF8 {
-private:
-    MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;
-
-public:
-    UTF16ToUTF8() {}
-    explicit UTF16ToUTF8(WStringRef s);
-    operator StringRef() const {
-        return StringRef(&buffer_[0], size());
-    }
-    size_t size() const {
-        return buffer_.size() - 1;
-    }
-    const char *c_str() const {
-        return &buffer_[0];
-    }
-    std::string str() const {
-        return std::string(&buffer_[0], size());
-    }
-
-    // Performs conversion returning a system error code instead of
-    // throwing exception on conversion error. This method may still throw
-    // in case of memory allocation error.
-    int convert(WStringRef s);
-};
-
-void format_windows_error(fmt::Writer &out, int error_code,
-                          fmt::StringRef message) FMT_NOEXCEPT;
-#endif
-
-void format_system_error(fmt::Writer &out, int error_code,
-                         fmt::StringRef message) FMT_NOEXCEPT;
-
-// A formatting argument value.
-struct Value {
-    template <typename Char>
-    struct StringValue {
-        const Char *value;
-        std::size_t size;
-    };
-
-    typedef void(*FormatFunc)(
-        void *formatter, const void *arg, void *format_str_ptr);
-
-    struct CustomValue {
-        const void *value;
-        FormatFunc format;
-    };
-
-    union {
-        int int_value;
-        unsigned uint_value;
-        LongLong long_long_value;
-        ULongLong ulong_long_value;
-        double double_value;
-        long double long_double_value;
-        const void *pointer;
-        StringValue<char> string;
-        StringValue<signed char> sstring;
-        StringValue<unsigned char> ustring;
-        StringValue<wchar_t> wstring;
-        CustomValue custom;
-    };
-
-    enum Type {
-        NONE, NAMED_ARG,
-        // Integer types should go first,
-        INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
-        // followed by floating-point types.
-        DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
-        CSTRING, STRING, WSTRING, POINTER, CUSTOM
-    };
-};
-
-// A formatting argument. It is a POD type to allow storage in
-// internal::MemoryBuffer.
-struct Arg : Value {
-    Type type;
-};
-
-template <typename Char>
-struct NamedArg;
-
-template <typename T = void>
-struct Null {};
-
-// A helper class template to enable or disable overloads taking wide
-// characters and strings in MakeValue.
-template <typename T, typename Char>
-struct WCharHelper {
-    typedef Null<T> Supported;
-    typedef T Unsupported;
-};
-
-template <typename T>
-struct WCharHelper<T, wchar_t> {
-    typedef T Supported;
-    typedef Null<T> Unsupported;
-};
-
-template <typename T>
-class IsConvertibleToInt {
-private:
-    typedef char yes[1];
-    typedef char no[2];
-
-    static const T &get();
-
-    static yes &check(fmt::ULongLong);
-    static no &check(...);
-
-public:
-    enum { value = (sizeof(check(get())) == sizeof(yes)) };
-};
-
-#define FMT_CONVERTIBLE_TO_INT(Type) \
-  template <> \
-  class IsConvertibleToInt<Type> { \
-   public: \
-    enum { value = 1 }; \
-          }
-
-// Silence warnings about convering float to int.
-FMT_CONVERTIBLE_TO_INT(float);
-FMT_CONVERTIBLE_TO_INT(double);
-FMT_CONVERTIBLE_TO_INT(long double);
-
-template<bool B, class T = void>
-struct EnableIf {};
-
-template<class T>
-struct EnableIf<true, T> {
-    typedef T type;
-};
-
-template<bool B, class T, class F>
-struct Conditional {
-    typedef T type;
-};
-
-template<class T, class F>
-struct Conditional<false, T, F> {
-    typedef F type;
-};
-
-// A helper function to suppress bogus "conditional expression is constant"
-// warnings.
-inline bool check(bool value) {
-    return value;
-}
-
-// Makes an Arg object from any type.
-template <typename Char>
-class MakeValue : public Arg {
-private:
-    // The following two methods are private to disallow formatting of
-    // arbitrary pointers. If you want to output a pointer cast it to
-    // "void *" or "const void *". In particular, this forbids formatting
-    // of "[const] volatile char *" which is printed as bool by iostreams.
-    // Do not implement!
-    template <typename T>
-    MakeValue(const T *value);
-    template <typename T>
-    MakeValue(T *value);
-
-    // The following methods are private to disallow formatting of wide
-    // characters and strings into narrow strings as in
-    //   fmt::format("{}", L"test");
-    // To fix this, use a wide format string: fmt::format(L"{}", L"test").
-    MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);
-    MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
-    MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);
-    MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
-    MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
-
-    void set_string(StringRef str) {
-        string.value = str.data();
-        string.size = str.size();
-    }
-
-    void set_string(WStringRef str) {
-        wstring.value = str.data();
-        wstring.size = str.size();
-    }
-
-    // Formats an argument of a custom type, such as a user-defined class.
-    template <typename T>
-    static void format_custom_arg(
-        void *formatter, const void *arg, void *format_str_ptr) {
-        format(*static_cast<BasicFormatter<Char>*>(formatter),
-               *static_cast<const Char**>(format_str_ptr),
-               *static_cast<const T*>(arg));
-    }
-
-public:
-    MakeValue() {}
-
-#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \
-  MakeValue(Type value) { field = rhs; } \
-  static uint64_t type(Type) { return Arg::TYPE; }
-
-#define FMT_MAKE_VALUE(Type, field, TYPE) \
-  FMT_MAKE_VALUE_(Type, field, TYPE, value)
-
-    FMT_MAKE_VALUE(bool, int_value, BOOL)
-    FMT_MAKE_VALUE(short, int_value, INT)
-    FMT_MAKE_VALUE(unsigned short, uint_value, UINT)
-    FMT_MAKE_VALUE(int, int_value, INT)
-    FMT_MAKE_VALUE(unsigned, uint_value, UINT)
-
-    MakeValue(long value) {
-        // To minimize the number of types we need to deal with, long is
-        // translated either to int or to long long depending on its size.
-        if (check(sizeof(long) == sizeof(int)))
-            int_value = static_cast<int>(value);
-        else
-            long_long_value = value;
-    }
-    static uint64_t type(long) {
-        return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG;
-    }
-
-    MakeValue(unsigned long value) {
-        if (check(sizeof(unsigned long) == sizeof(unsigned)))
-            uint_value = static_cast<unsigned>(value);
-        else
-            ulong_long_value = value;
-    }
-    static uint64_t type(unsigned long) {
-        return sizeof(unsigned long) == sizeof(unsigned) ?
-               Arg::UINT : Arg::ULONG_LONG;
-    }
-
-    FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG)
-    FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG)
-    FMT_MAKE_VALUE(float, double_value, DOUBLE)
-    FMT_MAKE_VALUE(double, double_value, DOUBLE)
-    FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE)
-    FMT_MAKE_VALUE(signed char, int_value, CHAR)
-    FMT_MAKE_VALUE(unsigned char, int_value, CHAR)
-    FMT_MAKE_VALUE(char, int_value, CHAR)
-
-    MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
-        int_value = value;
-    }
-    static uint64_t type(wchar_t) {
-        return Arg::CHAR;
-    }
-
-#define FMT_MAKE_STR_VALUE(Type, TYPE) \
-  MakeValue(Type value) { set_string(value); } \
-  static uint64_t type(Type) { return Arg::TYPE; }
-
-    FMT_MAKE_VALUE(char *, string.value, CSTRING)
-    FMT_MAKE_VALUE(const char *, string.value, CSTRING)
-    FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING)
-    FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
-    FMT_MAKE_STR_VALUE(const std::string &, STRING)
-    FMT_MAKE_STR_VALUE(StringRef, STRING)
-    FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
-
-#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
-  MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
-    set_string(value); \
-              } \
-  static uint64_t type(Type) { return Arg::TYPE; }
-
-    FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)
-    FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)
-    FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)
-    FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
-
-    FMT_MAKE_VALUE(void *, pointer, POINTER)
-    FMT_MAKE_VALUE(const void *, pointer, POINTER)
-
-    template <typename T>
-    MakeValue(const T &value,
-              typename EnableIf<!IsConvertibleToInt<T>::value, int>::type = 0) {
-        custom.value = &value;
-        custom.format = &format_custom_arg<T>;
-    }
-
-    template <typename T>
-    MakeValue(const T &value,
-              typename EnableIf<IsConvertibleToInt<T>::value, int>::type = 0) {
-        int_value = value;
-    }
-
-    template <typename T>
-    static uint64_t type(const T &) {
-        return IsConvertibleToInt<T>::value ? Arg::INT : Arg::CUSTOM;
-    }
-
-    // Additional template param `Char_` is needed here because make_type always
-    // uses MakeValue<char>.
-    template <typename Char_>
-    MakeValue(const NamedArg<Char_> &value) {
-        pointer = &value;
-    }
-
-    template <typename Char_>
-    static uint64_t type(const NamedArg<Char_> &) {
-        return Arg::NAMED_ARG;
-    }
-};
-
-template <typename Char>
-struct NamedArg : Arg {
-    BasicStringRef<Char> name;
-
-    template <typename T>
-    NamedArg(BasicStringRef<Char> name, const T &value)
-        : name(name), Arg(MakeValue<Char>(value)) {
-        type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
-    }
-};
-
-#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
-
-// An argument visitor.
-// To use ArgVisitor define a subclass that implements some or all of the
-// visit methods with the same signatures as the methods in ArgVisitor,
-// for example, visit_int(int).
-// Specify the subclass name as the Impl template parameter. Then calling
-// ArgVisitor::visit for some argument will dispatch to a visit method
-// specific to the argument type. For example, if the argument type is
-// double then visit_double(double) method of a subclass will be called.
-// If the subclass doesn't contain a method with this signature, then
-// a corresponding method of ArgVisitor will be called.
-//
-// Example:
-//  class MyArgVisitor : public ArgVisitor<MyArgVisitor, void> {
-//   public:
-//    void visit_int(int value) { print("{}", value); }
-//    void visit_double(double value) { print("{}", value ); }
-//  };
-//
-// ArgVisitor uses the curiously recurring template pattern:
-// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
-template <typename Impl, typename Result>
-class ArgVisitor {
-public:
-    void report_unhandled_arg() {}
-
-    Result visit_unhandled_arg() {
-        FMT_DISPATCH(report_unhandled_arg());
-        return Result();
-    }
-
-    Result visit_int(int value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    Result visit_long_long(LongLong value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    Result visit_uint(unsigned value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    Result visit_ulong_long(ULongLong value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    Result visit_bool(bool value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    Result visit_char(int value) {
-        return FMT_DISPATCH(visit_any_int(value));
-    }
-    template <typename T>
-    Result visit_any_int(T) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-
-    Result visit_double(double value) {
-        return FMT_DISPATCH(visit_any_double(value));
-    }
-    Result visit_long_double(long double value) {
-        return FMT_DISPATCH(visit_any_double(value));
-    }
-    template <typename T>
-    Result visit_any_double(T) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-
-    Result visit_string(Arg::StringValue<char>) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-    Result visit_wstring(Arg::StringValue<wchar_t>) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-    Result visit_pointer(const void *) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-    Result visit_custom(Arg::CustomValue) {
-        return FMT_DISPATCH(visit_unhandled_arg());
-    }
-
-    Result visit(const Arg &arg) {
-        switch (arg.type) {
-        default:
-            FMT_ASSERT(false, "invalid argument type");
-            return Result();
-        case Arg::INT:
-            return FMT_DISPATCH(visit_int(arg.int_value));
-        case Arg::UINT:
-            return FMT_DISPATCH(visit_uint(arg.uint_value));
-        case Arg::LONG_LONG:
-            return FMT_DISPATCH(visit_long_long(arg.long_long_value));
-        case Arg::ULONG_LONG:
-            return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));
-        case Arg::BOOL:
-            return FMT_DISPATCH(visit_bool(arg.int_value != 0));
-        case Arg::CHAR:
-            return FMT_DISPATCH(visit_char(arg.int_value));
-        case Arg::DOUBLE:
-            return FMT_DISPATCH(visit_double(arg.double_value));
-        case Arg::LONG_DOUBLE:
-            return FMT_DISPATCH(visit_long_double(arg.long_double_value));
-        case Arg::CSTRING: {
-            Arg::StringValue<char> str = arg.string;
-            str.size = 0;
-            return FMT_DISPATCH(visit_string(str));
-        }
-        case Arg::STRING:
-            return FMT_DISPATCH(visit_string(arg.string));
-        case Arg::WSTRING:
-            return FMT_DISPATCH(visit_wstring(arg.wstring));
-        case Arg::POINTER:
-            return FMT_DISPATCH(visit_pointer(arg.pointer));
-        case Arg::CUSTOM:
-            return FMT_DISPATCH(visit_custom(arg.custom));
-        }
-    }
-};
-
-class RuntimeError : public std::runtime_error {
-protected:
-    RuntimeError() : std::runtime_error("") {}
-};
-
-template <typename Impl, typename Char>
-class BasicArgFormatter;
-
-template <typename Char>
-class PrintfArgFormatter;
-
-template <typename Char>
-class ArgMap;
-}  // namespace internal
-
-/** An argument list. */
-class ArgList {
-private:
-    // To reduce compiled code size per formatting function call, types of first
-    // MAX_PACKED_ARGS arguments are passed in the types_ field.
-    uint64_t types_;
-    union {
-        // If the number of arguments is less than MAX_PACKED_ARGS, the argument
-        // values are stored in values_, otherwise they are stored in args_.
-        // This is done to reduce compiled code size as storing larger objects
-        // may require more code (at least on x86-64) even if the same amount of
-        // data is actually copied to stack. It saves ~10% on the bloat test.
-        const internal::Value *values_;
-        const internal::Arg *args_;
-    };
-
-    internal::Arg::Type type(unsigned index) const {
-        unsigned shift = index * 4;
-        uint64_t mask = 0xf;
-        return static_cast<internal::Arg::Type>(
-                   (types_ & (mask << shift)) >> shift);
-    }
-
-    template <typename Char>
-    friend class internal::ArgMap;
-
-public:
-    // Maximum number of arguments with packed types.
-    enum { MAX_PACKED_ARGS = 16 };
-
-    ArgList() : types_(0) {}
-
-    ArgList(ULongLong types, const internal::Value *values)
-        : types_(types), values_(values) {}
-    ArgList(ULongLong types, const internal::Arg *args)
-        : types_(types), args_(args) {}
-
-    /** Returns the argument at specified index. */
-    internal::Arg operator[](unsigned index) const {
-        using internal::Arg;
-        Arg arg;
-        bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
-        if (index < MAX_PACKED_ARGS) {
-            Arg::Type arg_type = type(index);
-            internal::Value &val = arg;
-            if (arg_type != Arg::NONE)
-                val = use_values ? values_[index] : args_[index];
-            arg.type = arg_type;
-            return arg;
-        }
-        if (use_values) {
-            // The index is greater than the number of arguments that can be stored
-            // in values, so return a "none" argument.
-            arg.type = Arg::NONE;
-            return arg;
-        }
-        for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) {
-            if (args_[i].type == Arg::NONE)
-                return args_[i];
-        }
-        return args_[index];
-    }
-};
-
-struct FormatSpec;
-
-namespace internal {
-
-template <typename Char>
-class ArgMap {
-private:
-    typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType;
-    typedef typename MapType::value_type Pair;
-
-    MapType map_;
-
-public:
-    void init(const ArgList &args);
-
-    const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
-        typename MapType::const_iterator it = map_.find(name);
-        return it != map_.end() ? &it->second : 0;
-    }
-};
-
-class FormatterBase {
-private:
-    ArgList args_;
-    int next_arg_index_;
-
-    // Returns the argument with specified index.
-    Arg do_get_arg(unsigned arg_index, const char *&error);
-
-protected:
-    const ArgList &args() const {
-        return args_;
-    }
-
-    void set_args(const ArgList &args) {
-        args_ = args;
-        next_arg_index_ = 0;
-    }
-
-    // Returns the next argument.
-    Arg next_arg(const char *&error);
-
-    // Checks if manual indexing is used and returns the argument with
-    // specified index.
-    Arg get_arg(unsigned arg_index, const char *&error);
-
-    bool check_no_auto_index(const char *&error);
-
-    template <typename Char>
-    void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
-        if (start != end)
-            w << BasicStringRef<Char>(start, end - start);
-    }
-};
-
-// A printf formatter.
-template <typename Char>
-class PrintfFormatter : private FormatterBase {
-private:
-    void parse_flags(FormatSpec &spec, const Char *&s);
-
-    // Returns the argument with specified index or, if arg_index is equal
-    // to the maximum unsigned value, the next argument.
-    Arg get_arg(const Char *s,
-                unsigned arg_index = (std::numeric_limits<unsigned>::max)());
-
-    // Parses argument index, flags and width and returns the argument index.
-    unsigned parse_header(const Char *&s, FormatSpec &spec);
-
-public:
-    void format(BasicWriter<Char> &writer,
-                BasicCStringRef<Char> format_str, const ArgList &args);
-};
-}  // namespace internal
-
-// A formatter.
-template <typename Char>
-class BasicFormatter : private internal::FormatterBase {
-private:
-    BasicWriter<Char> &writer_;
-    const Char *start_;
-    internal::ArgMap<Char> map_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
-
-    using FormatterBase::get_arg;
-
-    // Checks if manual indexing is used and returns the argument with
-    // specified name.
-    internal::Arg get_arg(BasicStringRef<Char> arg_name, const char *&error);
-
-    // Parses argument index and returns corresponding argument.
-    internal::Arg parse_arg_index(const Char *&s);
-
-    // Parses argument name and returns corresponding argument.
-    internal::Arg parse_arg_name(const Char *&s);
-
-public:
-    explicit BasicFormatter(BasicWriter<Char> &w) : writer_(w) {}
-
-    BasicWriter<Char> &writer() {
-        return writer_;
-    }
-
-    void format(BasicCStringRef<Char> format_str, const ArgList &args);
-
-    const Char *format(const Char *&format_str, const internal::Arg &arg);
-};
-
-enum Alignment {
-    ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
-};
-
-// Flags.
-enum {
-    SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8,
-    CHAR_FLAG = 0x10  // Argument has char type - used in error reporting.
-};
-
-// An empty format specifier.
-struct EmptySpec {};
-
-// A type specifier.
-template <char TYPE>
-struct TypeSpec : EmptySpec {
-    Alignment align() const {
-        return ALIGN_DEFAULT;
-    }
-    unsigned width() const {
-        return 0;
-    }
-    int precision() const {
-        return -1;
-    }
-    bool flag(unsigned) const {
-        return false;
-    }
-    char type() const {
-        return TYPE;
-    }
-    char fill() const {
-        return ' ';
-    }
-};
-
-// A width specifier.
-struct WidthSpec {
-    unsigned width_;
-    // Fill is always wchar_t and cast to char if necessary to avoid having
-    // two specialization of WidthSpec and its subclasses.
-    wchar_t fill_;
-
-    WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {}
-
-    unsigned width() const {
-        return width_;
-    }
-    wchar_t fill() const {
-        return fill_;
-    }
-};
-
-// An alignment specifier.
-struct AlignSpec : WidthSpec {
-    Alignment align_;
-
-    AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)
-        : WidthSpec(width, fill), align_(align) {}
-
-    Alignment align() const {
-        return align_;
-    }
-
-    int precision() const {
-        return -1;
-    }
-};
-
-// An alignment and type specifier.
-template <char TYPE>
-struct AlignTypeSpec : AlignSpec {
-    AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {}
-
-    bool flag(unsigned) const {
-        return false;
-    }
-    char type() const {
-        return TYPE;
-    }
-};
-
-// A full format specifier.
-struct FormatSpec : AlignSpec {
-    unsigned flags_;
-    int precision_;
-    char type_;
-
-    FormatSpec(
-        unsigned width = 0, char type = 0, wchar_t fill = ' ')
-        : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {}
-
-    bool flag(unsigned f) const {
-        return (flags_ & f) != 0;
-    }
-    int precision() const {
-        return precision_;
-    }
-    char type() const {
-        return type_;
-    }
-};
-
-// An integer format specifier.
-template <typename T, typename SpecT = TypeSpec<0>, typename Char = char>
-class IntFormatSpec : public SpecT {
-private:
-    T value_;
-
-public:
-    IntFormatSpec(T val, const SpecT &spec = SpecT())
-        : SpecT(spec), value_(val) {}
-
-    T value() const {
-        return value_;
-    }
-};
-
-// A string format specifier.
-template <typename Char>
-class StrFormatSpec : public AlignSpec {
-private:
-    const Char *str_;
-
-public:
-    template <typename FillChar>
-    StrFormatSpec(const Char *str, unsigned width, FillChar fill)
-        : AlignSpec(width, fill), str_(str) {
-        internal::CharTraits<Char>::convert(FillChar());
-    }
-
-    const Char *str() const {
-        return str_;
-    }
-};
-
-/**
-Returns an integer format specifier to format the value in base 2.
-*/
-IntFormatSpec<int, TypeSpec<'b'> > bin(int value);
-
-/**
-Returns an integer format specifier to format the value in base 8.
-*/
-IntFormatSpec<int, TypeSpec<'o'> > oct(int value);
-
-/**
-Returns an integer format specifier to format the value in base 16 using
-lower-case letters for the digits above 9.
-*/
-IntFormatSpec<int, TypeSpec<'x'> > hex(int value);
-
-/**
-Returns an integer formatter format specifier to format in base 16 using
-upper-case letters for the digits above 9.
-*/
-IntFormatSpec<int, TypeSpec<'X'> > hexu(int value);
-
-/**
-\rst
-Returns an integer format specifier to pad the formatted argument with the
-fill character to the specified width using the default (right) numeric
-alignment.
-
-**Example**::
-
-MemoryWriter out;
-out << pad(hex(0xcafe), 8, '0');
-// out.str() == "0000cafe"
-
-\endrst
-*/
-template <char TYPE_CODE, typename Char>
-IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(
-    int value, unsigned width, Char fill = ' ');
-
-#define FMT_DEFINE_INT_FORMATTERS(TYPE) \
-inline IntFormatSpec<TYPE, TypeSpec<'b'> > bin(TYPE value) { \
-  return IntFormatSpec<TYPE, TypeSpec<'b'> >(value, TypeSpec<'b'>()); \
-    } \
- \
-inline IntFormatSpec<TYPE, TypeSpec<'o'> > oct(TYPE value) { \
-  return IntFormatSpec<TYPE, TypeSpec<'o'> >(value, TypeSpec<'o'>()); \
-    } \
- \
-inline IntFormatSpec<TYPE, TypeSpec<'x'> > hex(TYPE value) { \
-  return IntFormatSpec<TYPE, TypeSpec<'x'> >(value, TypeSpec<'x'>()); \
-    } \
- \
-inline IntFormatSpec<TYPE, TypeSpec<'X'> > hexu(TYPE value) { \
-  return IntFormatSpec<TYPE, TypeSpec<'X'> >(value, TypeSpec<'X'>()); \
-    } \
- \
-template <char TYPE_CODE> \
-inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> > pad( \
-    IntFormatSpec<TYPE, TypeSpec<TYPE_CODE> > f, unsigned width) { \
-  return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> >( \
-      f.value(), AlignTypeSpec<TYPE_CODE>(width, ' ')); \
-    } \
- \
-/* For compatibility with older compilers we provide two overloads for pad, */ \
-/* one that takes a fill character and one that doesn't. In the future this */ \
-/* can be replaced with one overload making the template argument Char      */ \
-/* default to char (C++11). */ \
-template <char TYPE_CODE, typename Char> \
-inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad( \
-    IntFormatSpec<TYPE, TypeSpec<TYPE_CODE>, Char> f, \
-    unsigned width, Char fill) { \
-  return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>( \
-      f.value(), AlignTypeSpec<TYPE_CODE>(width, fill)); \
-    } \
- \
-inline IntFormatSpec<TYPE, AlignTypeSpec<0> > pad( \
-    TYPE value, unsigned width) { \
-  return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \
-      value, AlignTypeSpec<0>(width, ' ')); \
-    } \
- \
-template <typename Char> \
-inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \
-   TYPE value, unsigned width, Char fill) { \
- return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \
-     value, AlignTypeSpec<0>(width, fill)); \
-    }
-
-FMT_DEFINE_INT_FORMATTERS(int)
-FMT_DEFINE_INT_FORMATTERS(long)
-FMT_DEFINE_INT_FORMATTERS(unsigned)
-FMT_DEFINE_INT_FORMATTERS(unsigned long)
-FMT_DEFINE_INT_FORMATTERS(LongLong)
-FMT_DEFINE_INT_FORMATTERS(ULongLong)
-
-/**
-\rst
-Returns a string formatter that pads the formatted argument with the fill
-character to the specified width using the default (left) string alignment.
-
-**Example**::
-
-std::string s = str(MemoryWriter() << pad("abc", 8));
-// s == "abc     "
-
-\endrst
-*/
-template <typename Char>
-inline StrFormatSpec<Char> pad(
-    const Char *str, unsigned width, Char fill = ' ') {
-    return StrFormatSpec<Char>(str, width, fill);
-}
-
-inline StrFormatSpec<wchar_t> pad(
-    const wchar_t *str, unsigned width, char fill = ' ') {
-    return StrFormatSpec<wchar_t>(str, width, fill);
-}
-
-// Generates a comma-separated list with results of applying f to
-// numbers 0..n-1.
-# define FMT_GEN(n, f) FMT_GEN##n(f)
-# define FMT_GEN1(f)  f(0)
-# define FMT_GEN2(f)  FMT_GEN1(f),  f(1)
-# define FMT_GEN3(f)  FMT_GEN2(f),  f(2)
-# define FMT_GEN4(f)  FMT_GEN3(f),  f(3)
-# define FMT_GEN5(f)  FMT_GEN4(f),  f(4)
-# define FMT_GEN6(f)  FMT_GEN5(f),  f(5)
-# define FMT_GEN7(f)  FMT_GEN6(f),  f(6)
-# define FMT_GEN8(f)  FMT_GEN7(f),  f(7)
-# define FMT_GEN9(f)  FMT_GEN8(f),  f(8)
-# define FMT_GEN10(f) FMT_GEN9(f),  f(9)
-# define FMT_GEN11(f) FMT_GEN10(f), f(10)
-# define FMT_GEN12(f) FMT_GEN11(f), f(11)
-# define FMT_GEN13(f) FMT_GEN12(f), f(12)
-# define FMT_GEN14(f) FMT_GEN13(f), f(13)
-# define FMT_GEN15(f) FMT_GEN14(f), f(14)
-
-namespace internal {
-inline uint64_t make_type() {
-    return 0;
-}
-
-template <typename T>
-inline uint64_t make_type(const T &arg) {
-    return MakeValue<char>::type(arg);
-}
-
-template <unsigned N>
-struct ArgArray {
-    // Computes the argument array size by adding 1 to N, which is the number of
-    // arguments, if N is zero, because array of zero size is invalid, or if N
-    // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
-    // argument that marks the end of the list.
-    enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) };
-
-    typedef typename Conditional<
-    (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE];
-};
-
-#if FMT_USE_VARIADIC_TEMPLATES
-template <typename Arg, typename... Args>
-inline uint64_t make_type(const Arg &first, const Args & ... tail) {
-    return make_type(first) | (make_type(tail...) << 4);
-}
-
-inline void do_set_types(Arg *) {}
-
-template <typename T, typename... Args>
-inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
-    args->type = static_cast<Arg::Type>(MakeValue<T>::type(arg));
-    do_set_types(args + 1, tail...);
-}
-
-template <typename... Args>
-inline void set_types(Arg *array, const Args & ... args) {
-    if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS))
-        do_set_types(array, args...);
-    array[sizeof...(Args)].type = Arg::NONE;
-}
-
-template <typename... Args>
-inline void set_types(Value *, const Args & ...) {
-    // Do nothing as types are passed separately from values.
-}
-
-template <typename Char, typename Value>
-inline void store_args(Value *) {}
-
-template <typename Char, typename Arg, typename T, typename... Args>
-inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
-    // Assign only the Value subobject of Arg and don't overwrite type (if any)
-    // that is assigned by set_types.
-    Value &value = *args;
-    value = MakeValue<Char>(arg);
-    store_args<Char>(args + 1, tail...);
-}
-
-template <typename Char, typename... Args>
-ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
-                      const Args & ... args) {
-    if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
-        set_types(array, args...);
-    store_args<Char>(array, args...);
-    return ArgList(make_type(args...), array);
-}
-#else
-
-struct ArgType {
-    uint64_t type;
-
-    ArgType() : type(0) {}
-
-    template <typename T>
-    ArgType(const T &arg) : type(make_type(arg)) {}
-};
-
-# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
-
-inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
-    return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) |
-           (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) |
-           (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) |
-           (t12.type << 48) | (t13.type << 52) | (t14.type << 56);
-}
-#endif
-}  // namespace internal
-
-# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
-# define FMT_MAKE_ARG_TYPE(n) T##n
-# define FMT_MAKE_ARG(n) const T##n &v##n
-# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue<char>(v##n)
-# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue<wchar_t>(v##n)
-
-#if FMT_USE_VARIADIC_TEMPLATES
-// Defines a variadic function returning void.
-# define FMT_VARIADIC_VOID(func, arg_type) \
-  template <typename... Args> \
-  void func(arg_type arg0, const Args & ... args) { \
-    typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
-    func(arg0, fmt::internal::make_arg_list<Char>(array, args...)); \
-      }
-
-// Defines a variadic constructor.
-# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
-  template <typename... Args> \
-  ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
-    typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
-    func(arg0, arg1, fmt::internal::make_arg_list<Char>(array, args...)); \
-      }
-
-#else
-
-# define FMT_MAKE_REF(n) fmt::internal::MakeValue<Char>(v##n)
-# define FMT_MAKE_REF2(n) v##n
-
-// Defines a wrapper for a function taking one argument of type arg_type
-// and n additional arguments of arbitrary types.
-# define FMT_WRAP1(func, arg_type, n) \
-  template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
-  inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
-    const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
-    func(arg1, fmt::ArgList( \
-      fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
-      }
-
-// Emulates a variadic function returning void on a pre-C++11 compiler.
-# define FMT_VARIADIC_VOID(func, arg_type) \
-  inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \
-  FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \
-  FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \
-  FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \
-  FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \
-  FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10)
-
-# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \
-  template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
-  ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
-    const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
-    func(arg0, arg1, fmt::ArgList( \
-      fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
-      }
-
-// Emulates a variadic constructor on a pre-C++11 compiler.
-# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \
-  FMT_CTOR(ctor, func, arg0_type, arg1_type, 10)
-#endif
-
-// Generates a comma-separated list with results of applying f to pairs
-// (argument, index).
-#define FMT_FOR_EACH1(f, x0) f(x0, 0)
-#define FMT_FOR_EACH2(f, x0, x1) \
-  FMT_FOR_EACH1(f, x0), f(x1, 1)
-#define FMT_FOR_EACH3(f, x0, x1, x2) \
-  FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2)
-#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \
-  FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3)
-#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \
-  FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4)
-#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \
-  FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5)
-#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \
-  FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6)
-#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \
-  FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7)
-#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \
-  FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8)
-#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \
-  FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9)
-
-/**
-An error returned by an operating system or a language runtime,
-for example a file opening error.
-*/
-class SystemError : public internal::RuntimeError {
-private:
-    void init(int err_code, CStringRef format_str, ArgList args);
-
-protected:
-    int error_code_;
-
-    typedef char Char;  // For FMT_VARIADIC_CTOR.
-
-    SystemError() {}
-
-public:
-    /**
-    \rst
-    Constructs a :class:`fmt::SystemError` object with the description
-    of the form
-
-    .. parsed-literal::
-    *<message>*: *<system-message>*
-
-    where *<message>* is the formatted message and *<system-message>* is
-    the system message corresponding to the error code.
-    *error_code* is a system error code as given by ``errno``.
-    If *error_code* is not a valid error code such as -1, the system message
-    may look like "Unknown error -1" and is platform-dependent.
-
-    **Example**::
-
-    // This throws a SystemError with the description
-    //   cannot open file 'madeup': No such file or directory
-    // or similar (system message may vary).
-    const char *filename = "madeup";
-    std::FILE *file = std::fopen(filename, "r");
-    if (!file)
-    throw fmt::SystemError(errno, "cannot open file '{}'", filename);
-    \endrst
-    */
-    SystemError(int error_code, CStringRef message) {
-        init(error_code, message, ArgList());
-    }
-    FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
-
-    int error_code() const {
-        return error_code_;
-    }
-};
-
-/**
-\rst
-This template provides operations for formatting and writing data into
-a character stream. The output is stored in a buffer provided by a subclass
-such as :class:`fmt::BasicMemoryWriter`.
-
-You can use one of the following typedefs for common character types:
-
-+---------+----------------------+
-| Type    | Definition           |
-+=========+======================+
-| Writer  | BasicWriter<char>    |
-+---------+----------------------+
-| WWriter | BasicWriter<wchar_t> |
-+---------+----------------------+
-
-\endrst
-*/
-template <typename Char>
-class BasicWriter {
-private:
-    // Output buffer.
-    Buffer<Char> &buffer_;
-
-    FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter);
-
-    typedef typename internal::CharTraits<Char>::CharPtr CharPtr;
-
-#if _SECURE_SCL
-    // Returns pointer value.
-    static Char *get(CharPtr p) {
-        return p.base();
-    }
-#else
-    static Char *get(Char *p) {
-        return p;
-    }
-#endif
-
-    // Fills the padding around the content and returns the pointer to the
-    // content area.
-    static CharPtr fill_padding(CharPtr buffer,
-                                unsigned total_size, std::size_t content_size, wchar_t fill);
-
-    // Grows the buffer by n characters and returns a pointer to the newly
-    // allocated area.
-    CharPtr grow_buffer(std::size_t n) {
-        std::size_t size = buffer_.size();
-        buffer_.resize(size + n);
-        return internal::make_ptr(&buffer_[size], n);
-    }
-
-    // Prepare a buffer for integer formatting.
-    CharPtr prepare_int_buffer(unsigned num_digits,
-                               const EmptySpec &, const char *prefix, unsigned prefix_size) {
-        unsigned size = prefix_size + num_digits;
-        CharPtr p = grow_buffer(size);
-        std::copy(prefix, prefix + prefix_size, p);
-        return p + size - 1;
-    }
-
-    template <typename Spec>
-    CharPtr prepare_int_buffer(unsigned num_digits,
-                               const Spec &spec, const char *prefix, unsigned prefix_size);
-
-    // Formats an integer.
-    template <typename T, typename Spec>
-    void write_int(T value, Spec spec);
-
-    // Formats a floating-point number (double or long double).
-    template <typename T>
-    void write_double(T value, const FormatSpec &spec);
-
-    // Writes a formatted string.
-    template <typename StrChar>
-    CharPtr write_str(
-        const StrChar *s, std::size_t size, const AlignSpec &spec);
-
-    template <typename StrChar>
-    void write_str(
-        const internal::Arg::StringValue<StrChar> &str, const FormatSpec &spec);
-
-    // This following methods are private to disallow writing wide characters
-    // and strings to a char stream. If you want to print a wide string as a
-    // pointer as std::ostream does, cast it to const void*.
-    // Do not implement!
-    void operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported);
-    void operator<<(
-        typename internal::WCharHelper<const wchar_t *, Char>::Unsupported);
-
-    // Appends floating-point length specifier to the format string.
-    // The second argument is only used for overload resolution.
-    void append_float_length(Char *&format_ptr, long double) {
-        *format_ptr++ = 'L';
-    }
-
-    template<typename T>
-    void append_float_length(Char *&, T) {}
-
-    template <typename Impl, typename Char_>
-    friend class internal::BasicArgFormatter;
-
-    friend class internal::PrintfArgFormatter<Char>;
-
-protected:
-    /**
-    Constructs a ``BasicWriter`` object.
-    */
-    explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {}
-
-public:
-    /**
-    \rst
-    Destroys a ``BasicWriter`` object.
-    \endrst
-    */
-    virtual ~BasicWriter() {}
-
-    /**
-    Returns the total number of characters written.
-    */
-    std::size_t size() const {
-        return buffer_.size();
-    }
-
-    /**
-    Returns a pointer to the output buffer content. No terminating null
-    character is appended.
-    */
-    const Char *data() const FMT_NOEXCEPT {
-        return &buffer_[0];
-    }
-
-    /**
-    Returns a pointer to the output buffer content with terminating null
-    character appended.
-    */
-    const Char *c_str() const {
-        std::size_t size = buffer_.size();
-        buffer_.reserve(size + 1);
-        buffer_[size] = '\0';
-        return &buffer_[0];
-    }
-
-    /**
-    \rst
-    Returns the content of the output buffer as an `std::string`.
-    \endrst
-    */
-    std::basic_string<Char> str() const {
-        return std::basic_string<Char>(&buffer_[0], buffer_.size());
-    }
-
-    /**
-    \rst
-    Writes formatted data.
-
-    *args* is an argument list representing arbitrary arguments.
-
-    **Example**::
-
-    MemoryWriter out;
-    out.write("Current point:\n");
-    out.write("({:+f}, {:+f})", -3.14, 3.14);
-
-    This will write the following output to the ``out`` object:
-
-    .. code-block:: none
-
-    Current point:
-    (-3.140000, +3.140000)
-
-    The output can be accessed using :func:`data()`, :func:`c_str` or
-    :func:`str` methods.
-
-    See also :ref:`syntax`.
-    \endrst
-    */
-    void write(BasicCStringRef<Char> format, ArgList args) {
-        BasicFormatter<Char>(*this).format(format, args);
-    }
-    FMT_VARIADIC_VOID(write, BasicCStringRef<Char>)
-
-    BasicWriter &operator<<(int value) {
-        return *this << IntFormatSpec<int>(value);
-    }
-    BasicWriter &operator<<(unsigned value) {
-        return *this << IntFormatSpec<unsigned>(value);
-    }
-    BasicWriter &operator<<(long value) {
-        return *this << IntFormatSpec<long>(value);
-    }
-    BasicWriter &operator<<(unsigned long value) {
-        return *this << IntFormatSpec<unsigned long>(value);
-    }
-    BasicWriter &operator<<(LongLong value) {
-        return *this << IntFormatSpec<LongLong>(value);
-    }
-
-    /**
-    \rst
-    Formats *value* and writes it to the stream.
-    \endrst
-    */
-    BasicWriter &operator<<(ULongLong value) {
-        return *this << IntFormatSpec<ULongLong>(value);
-    }
-
-    BasicWriter &operator<<(double value) {
-        write_double(value, FormatSpec());
-        return *this;
-    }
-
-    /**
-    \rst
-    Formats *value* using the general format for floating-point numbers
-    (``'g'``) and writes it to the stream.
-    \endrst
-    */
-    BasicWriter &operator<<(long double value) {
-        write_double(value, FormatSpec());
-        return *this;
-    }
-
-    /**
-    Writes a character to the stream.
-    */
-    BasicWriter &operator<<(char value) {
-        buffer_.push_back(value);
-        return *this;
-    }
-
-    BasicWriter &operator<<(
-        typename internal::WCharHelper<wchar_t, Char>::Supported value) {
-        buffer_.push_back(value);
-        return *this;
-    }
-
-    /**
-    \rst
-    Writes *value* to the stream.
-    \endrst
-    */
-    BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
-        const Char *str = value.data();
-        buffer_.append(str, str + value.size());
-        return *this;
-    }
-
-    BasicWriter &operator<<(
-        typename internal::WCharHelper<StringRef, Char>::Supported value) {
-        const char *str = value.data();
-        buffer_.append(str, str + value.size());
-        return *this;
-    }
-
-    template <typename T, typename Spec, typename FillChar>
-    BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
-        internal::CharTraits<Char>::convert(FillChar());
-        write_int(spec.value(), spec);
-        return *this;
-    }
-
-    template <typename StrChar>
-    BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) {
-        const StrChar *s = spec.str();
-        write_str(s, std::char_traits<Char>::length(s), spec);
-        return *this;
-    }
-
-    void clear() FMT_NOEXCEPT{ buffer_.clear(); }
-};
-
-template <typename Char>
-template <typename StrChar>
-typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
-    const StrChar *s, std::size_t size, const AlignSpec &spec) {
-    CharPtr out = CharPtr();
-    if (spec.width() > size) {
-        out = grow_buffer(spec.width());
-        Char fill = internal::CharTraits<Char>::cast(spec.fill());
-        if (spec.align() == ALIGN_RIGHT) {
-            std::fill_n(out, spec.width() - size, fill);
-            out += spec.width() - size;
-        }
-        else if (spec.align() == ALIGN_CENTER) {
-            out = fill_padding(out, spec.width(), size, fill);
-        }
-        else {
-            std::fill_n(out + size, spec.width() - size, fill);
-        }
-    }
-    else {
-        out = grow_buffer(size);
-    }
-    std::copy(s, s + size, out);
-    return out;
-}
-
-template <typename Char>
-typename BasicWriter<Char>::CharPtr
-BasicWriter<Char>::fill_padding(
-    CharPtr buffer, unsigned total_size,
-    std::size_t content_size, wchar_t fill) {
-    std::size_t padding = total_size - content_size;
-    std::size_t left_padding = padding / 2;
-    Char fill_char = internal::CharTraits<Char>::cast(fill);
-    std::fill_n(buffer, left_padding, fill_char);
-    buffer += left_padding;
-    CharPtr content = buffer;
-    std::fill_n(buffer + content_size, padding - left_padding, fill_char);
-    return content;
-}
-
-template <typename Char>
-template <typename Spec>
-typename BasicWriter<Char>::CharPtr
-BasicWriter<Char>::prepare_int_buffer(
-    unsigned num_digits, const Spec &spec,
-    const char *prefix, unsigned prefix_size) {
-    unsigned width = spec.width();
-    Alignment align = spec.align();
-    Char fill = internal::CharTraits<Char>::cast(spec.fill());
-    if (spec.precision() > static_cast<int>(num_digits)) {
-        // Octal prefix '0' is counted as a digit, so ignore it if precision
-        // is specified.
-        if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
-            --prefix_size;
-        unsigned number_size = prefix_size + spec.precision();
-        AlignSpec subspec(number_size, '0', ALIGN_NUMERIC);
-        if (number_size >= width)
-            return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
-        buffer_.reserve(width);
-        unsigned fill_size = width - number_size;
-        if (align != ALIGN_LEFT) {
-            CharPtr p = grow_buffer(fill_size);
-            std::fill(p, p + fill_size, fill);
-        }
-        CharPtr result = prepare_int_buffer(
-                             num_digits, subspec, prefix, prefix_size);
-        if (align == ALIGN_LEFT) {
-            CharPtr p = grow_buffer(fill_size);
-            std::fill(p, p + fill_size, fill);
-        }
-        return result;
-    }
-    unsigned size = prefix_size + num_digits;
-    if (width <= size) {
-        CharPtr p = grow_buffer(size);
-        std::copy(prefix, prefix + prefix_size, p);
-        return p + size - 1;
-    }
-    CharPtr p = grow_buffer(width);
-    CharPtr end = p + width;
-    if (align == ALIGN_LEFT) {
-        std::copy(prefix, prefix + prefix_size, p);
-        p += size;
-        std::fill(p, end, fill);
-    }
-    else if (align == ALIGN_CENTER) {
-        p = fill_padding(p, width, size, fill);
-        std::copy(prefix, prefix + prefix_size, p);
-        p += size;
-    }
-    else {
-        if (align == ALIGN_NUMERIC) {
-            if (prefix_size != 0) {
-                p = std::copy(prefix, prefix + prefix_size, p);
-                size -= prefix_size;
-            }
-        }
-        else {
-            std::copy(prefix, prefix + prefix_size, end - size);
-        }
-        std::fill(p, end - size, fill);
-        p = end;
-    }
-    return p - 1;
-}
-
-template <typename Char>
-template <typename T, typename Spec>
-void BasicWriter<Char>::write_int(T value, Spec spec) {
-    unsigned prefix_size = 0;
-    typedef typename internal::IntTraits<T>::MainType UnsignedType;
-    UnsignedType abs_value = value;
-    char prefix[4] = "";
-    if (internal::is_negative(value)) {
-        prefix[0] = '-';
-        ++prefix_size;
-        abs_value = 0 - abs_value;
-    }
-    else if (spec.flag(SIGN_FLAG)) {
-        prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' ';
-        ++prefix_size;
-    }
-    switch (spec.type()) {
-    case 0:
-    case 'd': {
-        unsigned num_digits = internal::count_digits(abs_value);
-        CharPtr p = prepare_int_buffer(
-                        num_digits, spec, prefix, prefix_size) + 1 - num_digits;
-        internal::format_decimal(get(p), abs_value, num_digits);
-        break;
-    }
-    case 'x':
-    case 'X': {
-        UnsignedType n = abs_value;
-        if (spec.flag(HASH_FLAG)) {
-            prefix[prefix_size++] = '0';
-            prefix[prefix_size++] = spec.type();
-        }
-        unsigned num_digits = 0;
-        do {
-            ++num_digits;
-        } while ((n >>= 4) != 0);
-        Char *p = get(prepare_int_buffer(
-                          num_digits, spec, prefix, prefix_size));
-        n = abs_value;
-        const char *digits = spec.type() == 'x' ?
-                             "0123456789abcdef" : "0123456789ABCDEF";
-        do {
-            *p-- = digits[n & 0xf];
-        } while ((n >>= 4) != 0);
-        break;
-    }
-    case 'b':
-    case 'B': {
-        UnsignedType n = abs_value;
-        if (spec.flag(HASH_FLAG)) {
-            prefix[prefix_size++] = '0';
-            prefix[prefix_size++] = spec.type();
-        }
-        unsigned num_digits = 0;
-        do {
-            ++num_digits;
-        } while ((n >>= 1) != 0);
-        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
-        n = abs_value;
-        do {
-            *p-- = '0' + (n & 1);
-        } while ((n >>= 1) != 0);
-        break;
-    }
-    case 'o': {
-        UnsignedType n = abs_value;
-        if (spec.flag(HASH_FLAG))
-            prefix[prefix_size++] = '0';
-        unsigned num_digits = 0;
-        do {
-            ++num_digits;
-        } while ((n >>= 3) != 0);
-        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
-        n = abs_value;
-        do {
-            *p-- = '0' + (n & 7);
-        } while ((n >>= 3) != 0);
-        break;
-    }
-    default:
-        internal::report_unknown_type(
-            spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer");
-        break;
-    }
-}
-
-template <typename Char>
-template <typename T>
-void BasicWriter<Char>::write_double(
-    T value, const FormatSpec &spec) {
-    // Check type.
-    char type = spec.type();
-    bool upper = false;
-    switch (type) {
-    case 0:
-        type = 'g';
-        break;
-    case 'e':
-    case 'f':
-    case 'g':
-    case 'a':
-        break;
-    case 'F':
-#ifdef _MSC_VER
-        // MSVC's printf doesn't support 'F'.
-        type = 'f';
-#endif
-    // Fall through.
-    case 'E':
-    case 'G':
-    case 'A':
-        upper = true;
-        break;
-    default:
-        internal::report_unknown_type(type, "double");
-        break;
-    }
-
-    char sign = 0;
-    // Use getsign instead of value < 0 because the latter is always
-    // false for NaN.
-    if (internal::getsign(static_cast<double>(value))) {
-        sign = '-';
-        value = -value;
-    }
-    else if (spec.flag(SIGN_FLAG)) {
-        sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
-    }
-
-    if (value != value) {
-        // Format NaN ourselves because sprintf's output is not consistent
-        // across platforms.
-        std::size_t nan_size = 4;
-        const char *nan = upper ? " NAN" : " nan";
-        if (!sign) {
-            --nan_size;
-            ++nan;
-        }
-        CharPtr out = write_str(nan, nan_size, spec);
-        if (sign)
-            *out = sign;
-        return;
-    }
-
-    if (internal::isinfinity(value)) {
-        // Format infinity ourselves because sprintf's output is not consistent
-        // across platforms.
-        std::size_t inf_size = 4;
-        const char *inf = upper ? " INF" : " inf";
-        if (!sign) {
-            --inf_size;
-            ++inf;
-        }
-        CharPtr out = write_str(inf, inf_size, spec);
-        if (sign)
-            *out = sign;
-        return;
-    }
-
-    std::size_t offset = buffer_.size();
-    unsigned width = spec.width();
-    if (sign) {
-        buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
-        if (width > 0)
-            --width;
-        ++offset;
-    }
-
-    // Build format string.
-    enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg
-    Char format[MAX_FORMAT_SIZE];
-    Char *format_ptr = format;
-    *format_ptr++ = '%';
-    unsigned width_for_sprintf = width;
-    if (spec.flag(HASH_FLAG))
-        *format_ptr++ = '#';
-    if (spec.align() == ALIGN_CENTER) {
-        width_for_sprintf = 0;
-    }
-    else {
-        if (spec.align() == ALIGN_LEFT)
-            *format_ptr++ = '-';
-        if (width != 0)
-            *format_ptr++ = '*';
-    }
-    if (spec.precision() >= 0) {
-        *format_ptr++ = '.';
-        *format_ptr++ = '*';
-    }
-
-    append_float_length(format_ptr, value);
-    *format_ptr++ = type;
-    *format_ptr = '\0';
-
-    // Format using snprintf.
-    Char fill = internal::CharTraits<Char>::cast(spec.fill());
-    for (;;) {
-        std::size_t buffer_size = buffer_.capacity() - offset;
-#if _MSC_VER
-        // MSVC's vsnprintf_s doesn't work with zero size, so reserve
-        // space for at least one extra character to make the size non-zero.
-        // Note that the buffer's capacity will increase by more than 1.
-        if (buffer_size == 0) {
-            buffer_.reserve(offset + 1);
-            buffer_size = buffer_.capacity() - offset;
-        }
-#endif
-        Char *start = &buffer_[offset];
-        int n = internal::CharTraits<Char>::format_float(
-                    start, buffer_size, format, width_for_sprintf, spec.precision(), value);
-        if (n >= 0 && offset + n < buffer_.capacity()) {
-            if (sign) {
-                if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
-                        *start != ' ') {
-                    *(start - 1) = sign;
-                    sign = 0;
-                }
-                else {
-                    *(start - 1) = fill;
-                }
-                ++n;
-            }
-            if (spec.align() == ALIGN_CENTER &&
-                    spec.width() > static_cast<unsigned>(n)) {
-                width = spec.width();
-                CharPtr p = grow_buffer(width);
-                std::copy(p, p + n, p + (width - n) / 2);
-                fill_padding(p, spec.width(), n, fill);
-                return;
-            }
-            if (spec.fill() != ' ' || sign) {
-                while (*start == ' ')
-                    *start++ = fill;
-                if (sign)
-                    *(start - 1) = sign;
-            }
-            grow_buffer(n);
-            return;
-        }
-        // If n is negative we ask to increase the capacity by at least 1,
-        // but as std::vector, the buffer grows exponentially.
-        buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
-    }
-}
-
-/**
-\rst
-This class template provides operations for formatting and writing data
-into a character stream. The output is stored in a memory buffer that grows
-dynamically.
-
-You can use one of the following typedefs for common character types
-and the standard allocator:
-
-+---------------+-----------------------------------------------------+
-| Type          | Definition                                          |
-+===============+=====================================================+
-| MemoryWriter  | BasicMemoryWriter<char, std::allocator<char>>       |
-+---------------+-----------------------------------------------------+
-| WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |
-+---------------+-----------------------------------------------------+
-
-**Example**::
-
-MemoryWriter out;
-out << "The answer is " << 42 << "\n";
-out.write("({:+f}, {:+f})", -3.14, 3.14);
-
-This will write the following output to the ``out`` object:
-
-.. code-block:: none
-
-The answer is 42
-(-3.140000, +3.140000)
-
-The output can be converted to an ``std::string`` with ``out.str()`` or
-accessed as a C string with ``out.c_str()``.
-\endrst
-*/
-template <typename Char, typename Allocator = std::allocator<Char> >
-class BasicMemoryWriter : public BasicWriter<Char> {
-private:
-    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
-
-public:
-    explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
-        : BasicWriter<Char>(buffer_), buffer_(alloc) {}
-
-#if FMT_USE_RVALUE_REFERENCES
-    /**
-    \rst
-    Constructs a :class:`fmt::BasicMemoryWriter` object moving the content
-    of the other object to it.
-    \endrst
-    */
-    BasicMemoryWriter(BasicMemoryWriter &&other)
-        : BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) {
-    }
-
-    /**
-    \rst
-    Moves the content of the other ``BasicMemoryWriter`` object to this one.
-    \endrst
-    */
-    BasicMemoryWriter &operator=(BasicMemoryWriter &&other) {
-        buffer_ = std::move(other.buffer_);
-        return *this;
-    }
-#endif
-};
-
-typedef BasicMemoryWriter<char> MemoryWriter;
-typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
-
-/**
-\rst
-This class template provides operations for formatting and writing data
-into a fixed-size array. For writing into a dynamically growing buffer
-use :class:`fmt::BasicMemoryWriter`.
-
-Any write method will throw ``std::runtime_error`` if the output doesn't fit
-into the array.
-
-You can use one of the following typedefs for common character types:
-
-+--------------+---------------------------+
-| Type         | Definition                |
-+==============+===========================+
-| ArrayWriter  | BasicArrayWriter<char>    |
-+--------------+---------------------------+
-| WArrayWriter | BasicArrayWriter<wchar_t> |
-+--------------+---------------------------+
-\endrst
-*/
-template <typename Char>
-class BasicArrayWriter : public BasicWriter<Char> {
-private:
-    internal::FixedBuffer<Char> buffer_;
-
-public:
-    /**
-    \rst
-    Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
-    given size.
-    \endrst
-    */
-    BasicArrayWriter(Char *array, std::size_t size)
-        : BasicWriter<Char>(buffer_), buffer_(array, size) {}
-
-    /**
-    \rst
-    Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
-    size known at compile time.
-    \endrst
-    */
-    template <std::size_t SIZE>
-    explicit BasicArrayWriter(Char(&array)[SIZE])
-        : BasicWriter<Char>(buffer_), buffer_(array, SIZE) {}
-};
-
-typedef BasicArrayWriter<char> ArrayWriter;
-typedef BasicArrayWriter<wchar_t> WArrayWriter;
-
-// Formats a value.
-template <typename Char, typename T>
-void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
-    std::basic_ostringstream<Char> os;
-    os << value;
-    std::basic_string<Char> str = os.str();
-    internal::Arg arg = internal::MakeValue<Char>(str);
-    arg.type = static_cast<internal::Arg::Type>(
-                   internal::MakeValue<Char>::type(str));
-    format_str = f.format(format_str, arg);
-}
-
-// Reports a system error without throwing an exception.
-// Can be used to report errors from destructors.
-void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
-
-#if FMT_USE_WINDOWS_H
-
-/** A Windows error. */
-class WindowsError : public SystemError {
-private:
-    void init(int error_code, CStringRef format_str, ArgList args);
-
-public:
-    /**
-    \rst
-    Constructs a :class:`fmt::WindowsError` object with the description
-    of the form
-
-    .. parsed-literal::
-    *<message>*: *<system-message>*
-
-    where *<message>* is the formatted message and *<system-message>* is the
-    system message corresponding to the error code.
-    *error_code* is a Windows error code as given by ``GetLastError``.
-    If *error_code* is not a valid error code such as -1, the system message
-    will look like "error -1".
-
-    **Example**::
-
-    // This throws a WindowsError with the description
-    //   cannot open file 'madeup': The system cannot find the file specified.
-    // or similar (system message may vary).
-    const char *filename = "madeup";
-    LPOFSTRUCT of = LPOFSTRUCT();
-    HFILE file = OpenFile(filename, &of, OF_READ);
-    if (file == HFILE_ERROR) {
-    throw fmt::WindowsError(GetLastError(),
-    "cannot open file '{}'", filename);
-    }
-    \endrst
-    */
-    WindowsError(int error_code, CStringRef message) {
-        init(error_code, message, ArgList());
-    }
-    FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef)
-};
-
-// Reports a Windows error without throwing an exception.
-// Can be used to report errors from destructors.
-void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
-
-#endif
-
-enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
-
-/**
-Formats a string and prints it to stdout using ANSI escape sequences
-to specify color (experimental).
-Example:
-PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
-*/
-void print_colored(Color c, CStringRef format, ArgList args);
-
-/**
-\rst
-Formats arguments and returns the result as a string.
-
-**Example**::
-
-std::string message = format("The answer is {}", 42);
-\endrst
-*/
-inline std::string format(CStringRef format_str, ArgList args) {
-    MemoryWriter w;
-    w.write(format_str, args);
-    return w.str();
-}
-
-inline std::wstring format(WCStringRef format_str, ArgList args) {
-    WMemoryWriter w;
-    w.write(format_str, args);
-    return w.str();
-}
-
-/**
-\rst
-Prints formatted data to the file *f*.
-
-**Example**::
-
-print(stderr, "Don't {}!", "panic");
-\endrst
-*/
-void print(std::FILE *f, CStringRef format_str, ArgList args);
-
-/**
-\rst
-Prints formatted data to ``stdout``.
-
-**Example**::
-
-print("Elapsed time: {0:.2f} seconds", 1.23);
-\endrst
-*/
-void print(CStringRef format_str, ArgList args);
-
-/**
-\rst
-Prints formatted data to the stream *os*.
-
-**Example**::
-
-print(cerr, "Don't {}!", "panic");
-\endrst
-*/
-void print(std::ostream &os, CStringRef format_str, ArgList args);
-
-template <typename Char>
-void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
-    internal::PrintfFormatter<Char>().format(w, format, args);
-}
-
-/**
-\rst
-Formats arguments and returns the result as a string.
-
-**Example**::
-
-std::string message = fmt::sprintf("The answer is %d", 42);
-\endrst
-*/
-inline std::string sprintf(CStringRef format, ArgList args) {
-    MemoryWriter w;
-    printf(w, format, args);
-    return w.str();
-}
-
-/**
-\rst
-Prints formatted data to the file *f*.
-
-**Example**::
-
-fmt::fprintf(stderr, "Don't %s!", "panic");
-\endrst
-*/
-int fprintf(std::FILE *f, CStringRef format, ArgList args);
-
-/**
-\rst
-Prints formatted data to ``stdout``.
-
-**Example**::
-
-fmt::printf("Elapsed time: %.2f seconds", 1.23);
-\endrst
-*/
-inline int printf(CStringRef format, ArgList args) {
-    return fprintf(stdout, format, args);
-}
-
-/**
-Fast integer formatter.
-*/
-class FormatInt {
-private:
-    // Buffer should be large enough to hold all digits (digits10 + 1),
-    // a sign and a null character.
-    enum { BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3 };
-    mutable char buffer_[BUFFER_SIZE];
-    char *str_;
-
-    // Formats value in reverse and returns the number of digits.
-    char *format_decimal(ULongLong value) {
-        char *buffer_end = buffer_ + BUFFER_SIZE - 1;
-        while (value >= 100) {
-            // Integer division is slow so do it for a group of two digits instead
-            // of for every digit. The idea comes from the talk by Alexandrescu
-            // "Three Optimization Tips for C++". See speed-test for a comparison.
-            unsigned index = (value % 100) * 2;
-            value /= 100;
-            *--buffer_end = internal::Data::DIGITS[index + 1];
-            *--buffer_end = internal::Data::DIGITS[index];
-        }
-        if (value < 10) {
-            *--buffer_end = static_cast<char>('0' + value);
-            return buffer_end;
-        }
-        unsigned index = static_cast<unsigned>(value * 2);
-        *--buffer_end = internal::Data::DIGITS[index + 1];
-        *--buffer_end = internal::Data::DIGITS[index];
-        return buffer_end;
-    }
-
-    void FormatSigned(LongLong value) {
-        ULongLong abs_value = static_cast<ULongLong>(value);
-        bool negative = value < 0;
-        if (negative)
-            abs_value = 0 - abs_value;
-        str_ = format_decimal(abs_value);
-        if (negative)
-            *--str_ = '-';
-    }
-
-public:
-    explicit FormatInt(int value) {
-        FormatSigned(value);
-    }
-    explicit FormatInt(long value) {
-        FormatSigned(value);
-    }
-    explicit FormatInt(LongLong value) {
-        FormatSigned(value);
-    }
-    expl

<TRUNCATED>

[13/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/null_sink.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/null_sink.h b/inc/spdlog/sinks/null_sink.h
deleted file mode 100644
index 992b3b7..0000000
--- a/inc/spdlog/sinks/null_sink.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-#include <mutex>
-#include "./base_sink.h"
-#include "../details/null_mutex.h"
-
-
-namespace spdlog
-{
-namespace sinks
-{
-
-template <class Mutex>
-class null_sink : public base_sink < Mutex >
-{
-protected:
-    void _sink_it(const details::log_msg&) override
-    {}
-
-    void flush() override
-    {}
-
-};
-typedef null_sink<details::null_mutex> null_sink_st;
-typedef null_sink<std::mutex> null_sink_mt;
-
-}
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/ostream_sink.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/ostream_sink.h b/inc/spdlog/sinks/ostream_sink.h
deleted file mode 100644
index f2fe3b2..0000000
--- a/inc/spdlog/sinks/ostream_sink.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <ostream>
-#include <mutex>
-#include <memory>
-
-#include "../details/null_mutex.h"
-#include "./base_sink.h"
-
-namespace spdlog
-{
-namespace sinks
-{
-template<class Mutex>
-class ostream_sink: public base_sink<Mutex>
-{
-public:
-    explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
-    ostream_sink(const ostream_sink&) = delete;
-    ostream_sink& operator=(const ostream_sink&) = delete;
-    virtual ~ostream_sink() = default;
-
-protected:
-    void _sink_it(const details::log_msg& msg) override
-    {
-        _ostream.write(msg.formatted.data(), msg.formatted.size());
-        if (_force_flush)
-            _ostream.flush();
-    }
-
-    void flush() override
-    {
-        _ostream.flush();
-    }
-
-    std::ostream& _ostream;
-    bool _force_flush;
-};
-
-typedef ostream_sink<std::mutex> ostream_sink_mt;
-typedef ostream_sink<details::null_mutex> ostream_sink_st;
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/sink.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/sink.h b/inc/spdlog/sinks/sink.h
deleted file mode 100644
index 88c423a..0000000
--- a/inc/spdlog/sinks/sink.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include "../details/log_msg.h"
-
-namespace spdlog
-{
-namespace sinks
-{
-class sink
-{
-public:
-    virtual ~sink() {}
-    virtual void log(const details::log_msg& msg) = 0;
-    virtual void flush() = 0;
-};
-}
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/stdout_sinks.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/stdout_sinks.h b/inc/spdlog/sinks/stdout_sinks.h
deleted file mode 100644
index 5ad06c2..0000000
--- a/inc/spdlog/sinks/stdout_sinks.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <iostream>
-#include <mutex>
-#include "./ostream_sink.h"
-#include "../details/null_mutex.h"
-
-namespace spdlog
-{
-namespace sinks
-{
-
-template <class Mutex>
-class stdout_sink : public ostream_sink<Mutex>
-{
-    using MyType = stdout_sink<Mutex>;
-public:
-    stdout_sink() : ostream_sink<Mutex>(std::cout, true) {}
-    static std::shared_ptr<MyType> instance()
-    {
-        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
-        return instance;
-    }
-};
-
-typedef stdout_sink<details::null_mutex> stdout_sink_st;
-typedef stdout_sink<std::mutex> stdout_sink_mt;
-
-
-template <class Mutex>
-class stderr_sink : public ostream_sink<Mutex>
-{
-    using MyType = stderr_sink<Mutex>;
-public:
-    stderr_sink() : ostream_sink<Mutex>(std::cerr, true) {}
-    static std::shared_ptr<MyType> instance()
-    {
-        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
-        return instance;
-    }
-
-};
-
-typedef stderr_sink<std::mutex> stderr_sink_mt;
-typedef stderr_sink<details::null_mutex> stderr_sink_st;
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/syslog_sink.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/syslog_sink.h b/inc/spdlog/sinks/syslog_sink.h
deleted file mode 100644
index 37b6513..0000000
--- a/inc/spdlog/sinks/syslog_sink.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#ifdef __linux__
-
-#include <array>
-#include <string>
-#include <syslog.h>
-
-#include "./sink.h"
-#include "../common.h"
-#include "../details/log_msg.h"
-
-
-namespace spdlog
-{
-namespace sinks
-{
-/**
- * Sink that write to syslog using the `syscall()` library call.
- *
- * Locking is not needed, as `syslog()` itself is thread-safe.
- */
-class syslog_sink : public sink
-{
-public:
-    //
-    syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
-        _ident(ident)
-    {
-        _priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
-        _priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
-        _priorities[static_cast<int>(level::info)] = LOG_INFO;
-        _priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
-        _priorities[static_cast<int>(level::warn)] = LOG_WARNING;
-        _priorities[static_cast<int>(level::err)] = LOG_ERR;
-        _priorities[static_cast<int>(level::critical)] = LOG_CRIT;
-        _priorities[static_cast<int>(level::alert)] = LOG_ALERT;
-        _priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
-        _priorities[static_cast<int>(level::off)] = LOG_INFO;
-
-        //set ident to be program name if empty
-        ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
-    }
-    ~syslog_sink()
-    {
-        ::closelog();
-    }
-
-    syslog_sink(const syslog_sink&) = delete;
-    syslog_sink& operator=(const syslog_sink&) = delete;
-
-    void log(const details::log_msg &msg) override
-    {
-        ::syslog(syslog_prio_from_level(msg), "%s", msg.formatted.str().c_str());
-    }
-
-    void flush() override
-    {
-    }
-
-
-private:
-    std::array<int, 10> _priorities;
-    //must store the ident because the man says openlog might use the pointer as is and not a string copy
-    const std::string _ident;
-
-    //
-    // Simply maps spdlog's log level to syslog priority level.
-    //
-    int syslog_prio_from_level(const details::log_msg &msg) const
-    {
-        return _priorities[static_cast<int>(msg.level)];
-    }
-};
-}
-}
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/spdlog.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/spdlog.h b/inc/spdlog/spdlog.h
deleted file mode 100644
index 5cec562..0000000
--- a/inc/spdlog/spdlog.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-
-// spdlog main header file.
-//see example.cpp for usage example
-
-#pragma once
-
-#include "tweakme.h"
-#include "common.h"
-#include "logger.h"
-
-namespace spdlog
-{
-// Return an existing logger or nullptr if a logger with such name doesn't exist.
-// Examples:
-//
-// spdlog::get("mylog")->info("Hello");
-// auto logger = spdlog::get("mylog");
-// logger.info("This is another message" , x, y, z);
-// logger.info() << "This is another message" << x << y << z;
-std::shared_ptr<logger> get(const std::string& name);
-
-//
-// Set global formatting
-// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
-//
-void set_pattern(const std::string& format_string);
-void set_formatter(formatter_ptr f);
-
-//
-// Set global logging level for
-//
-void set_level(level::level_enum log_level);
-
-//
-// Turn on async mode (off by default) and set the queue size for each async_logger.
-// effective only for loggers created after this call.
-// queue_size: size of queue (must be power of 2):
-//    Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
-//
-// async_overflow_policy (optional, block_retry by default):
-//    async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
-//    async_overflow_policy::discard_log_msg - never block and discard any new messages when queue  overflows.
-//
-// worker_warmup_cb (optional):
-//     callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
-//
-void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
-// Turn off async mode
-void set_sync_mode();
-
-//
-// Create and register multi/single threaded rotating file logger
-//
-std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
-std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
-
-//
-// Create file logger which creates new file on the given time (default in  midnight):
-//
-std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
-std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
-
-
-//
-// Create and register stdout/stderr loggers
-//
-std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name);
-std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name);
-std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name);
-std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name);
-
-
-//
-// Create and register a syslog logger
-//
-#ifdef __linux__
-std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
-#endif
-
-
-// Create and register a logger with multiple sinks
-std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
-template<class It>
-std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end);
-
-
-// Create and register a logger with templated sink type
-// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
-template <typename Sink, typename... Args>
-std::shared_ptr<spdlog::logger> create(const std::string& logger_name, const Args&...);
-
-
-// Register the given logger with the given name
-void register_logger(std::shared_ptr<logger> logger);
-
-// Drop the reference to the given logger
-void drop(const std::string &name);
-
-// Drop all references
-void drop_all();
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// Macros to be display source file & line
-// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
-// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
-//
-// Example:
-// spdlog::set_level(spdlog::level::debug);
-// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef SPDLOG_TRACE_ON
-#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
-#else
-#define SPDLOG_TRACE(logger, ...)
-#endif
-
-#ifdef SPDLOG_DEBUG_ON
-#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__)  << " (" << __FILE__ << " #" << __LINE__ <<")";
-#else
-#define SPDLOG_DEBUG(logger, ...)
-#endif
-
-
-}
-
-
-#include "details/spdlog_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/tweakme.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/tweakme.h b/inc/spdlog/tweakme.h
deleted file mode 100644
index b651658..0000000
--- a/inc/spdlog/tweakme.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-
-#pragma once
-
-///////////////////////////////////////////////////////////////////////////////
-// Edit this file to squeeze every last drop of performance out of spdlog.
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.
-// This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ.
-// Uncomment to use it instead of the regular (but slower) clock.
-// #define SPDLOG_CLOCK_COARSE
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment if date/time logging is not needed.
-// This will prevent spdlog from quering the clock on each log call.
-// #define SPDLOG_NO_DATETIME
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
-// This will prevent spdlog from quering the thread id on each log call.
-// #define SPDLOG_NO_THREAD_ID
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment if logger name logging is not needed.
-// This will prevent spdlog from copying the logger name  on each log call.
-// #define SPDLOG_NO_NAME
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros.
-// #define SPDLOG_DEBUG_ON
-// #define SPDLOG_TRACE_ON
-///////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()).
-// Use only if your code never modifes concurrently the registry.
-// Note that upon creating a logger the registry is modified by spdlog..
-// #define SPDLOG_NO_REGISTRY_MUTEX
-///////////////////////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/async_logger.h
----------------------------------------------------------------------
diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h
new file mode 100644
index 0000000..6f07921
--- /dev/null
+++ b/include/spdlog/async_logger.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+// Very fast asynchronous logger (millions of logs per second on an average desktop)
+// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
+// Creates a single back thread to pop messages from the queue and log them.
+//
+// Upon each log write the logger:
+//    1. Checks if its log level is enough to log the message
+//    2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
+//    3. will throw spdlog_ex upon log exceptions
+// Upong destruction, logs all remaining messages in the queue before destructing..
+
+#include <chrono>
+#include <functional>
+#include "common.h"
+#include "logger.h"
+#include "spdlog.h"
+
+
+namespace spdlog
+{
+
+namespace details
+{
+class async_log_helper;
+}
+
+class async_logger :public logger
+{
+public:
+    template<class It>
+    async_logger(const std::string& name,
+                 const It& begin,
+                 const It& end,
+                 size_t queue_size,
+                 const async_overflow_policy overflow_policy =  async_overflow_policy::block_retry,
+                 const std::function<void()>& worker_warmup_cb = nullptr,
+                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
+
+    async_logger(const std::string& logger_name,
+                 sinks_init_list sinks,
+                 size_t queue_size,
+                 const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
+                 const std::function<void()>& worker_warmup_cb = nullptr,
+                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
+
+    async_logger(const std::string& logger_name,
+                 sink_ptr single_sink,
+                 size_t queue_size,
+                 const async_overflow_policy overflow_policy =  async_overflow_policy::block_retry,
+                 const std::function<void()>& worker_warmup_cb = nullptr,
+                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
+
+
+protected:
+    void _log_msg(details::log_msg& msg) override;
+    void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
+    void _set_pattern(const std::string& pattern) override;
+
+private:
+    std::unique_ptr<details::async_log_helper> _async_log_helper;
+};
+}
+
+
+#include "details/async_logger_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/common.h
----------------------------------------------------------------------
diff --git a/include/spdlog/common.h b/include/spdlog/common.h
new file mode 100644
index 0000000..cde5a9e
--- /dev/null
+++ b/include/spdlog/common.h
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <initializer_list>
+#include <chrono>
+#include <memory>
+
+//visual studio does not support noexcept yet
+#ifndef _MSC_VER
+#define SPDLOG_NOEXCEPT noexcept
+#else
+#define SPDLOG_NOEXCEPT throw()
+#endif
+
+
+namespace spdlog
+{
+
+class formatter;
+
+namespace sinks
+{
+class sink;
+}
+
+// Common types across the lib
+using log_clock = std::chrono::system_clock;
+using sink_ptr = std::shared_ptr < sinks::sink > ;
+using sinks_init_list = std::initializer_list < sink_ptr > ;
+using formatter_ptr = std::shared_ptr<spdlog::formatter>;
+
+
+//Log level enum
+namespace level
+{
+typedef enum
+{
+    trace    = 0,
+    debug    = 1,
+    info     = 2,
+    notice   = 3,
+    warn     = 4,
+    err      = 5,
+    critical = 6,
+    alert    = 7,
+    emerg    = 8,
+    off      = 9
+} level_enum;
+
+static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
+
+static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
+
+inline const char* to_str(spdlog::level::level_enum l)
+{
+    return level_names[l];
+}
+
+inline const char* to_short_str(spdlog::level::level_enum l)
+{
+    return short_level_names[l];
+}
+} //level
+
+
+//
+// Async overflow policy - block by default.
+//
+enum class async_overflow_policy
+{
+    block_retry, // Block / yield / sleep until message can be enqueued
+    discard_log_msg // Discard the message it enqueue fails
+};
+
+
+//
+// Log exception
+//
+class spdlog_ex : public std::exception
+{
+public:
+    spdlog_ex(const std::string& msg) :_msg(msg) {}
+    const char* what() const SPDLOG_NOEXCEPT override
+    {
+        return _msg.c_str();
+    }
+private:
+    std::string _msg;
+
+};
+
+} //spdlog

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/async_log_helper.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h
new file mode 100644
index 0000000..59c1b2d
--- /dev/null
+++ b/include/spdlog/details/async_log_helper.h
@@ -0,0 +1,326 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+// async log helper :
+// Process logs asynchronously using a back thread.
+//
+// If the internal queue of log messages reaches its max size,
+// then the client call will block until there is more room.
+//
+// If the back thread throws during logging, a spdlog::spdlog_ex exception
+// will be thrown in client's thread when tries to log the next message
+
+#pragma once
+
+#include <chrono>
+#include <thread>
+#include <atomic>
+#include <functional>
+
+#include "../common.h"
+#include "../sinks/sink.h"
+#include "./mpmc_bounded_q.h"
+#include "./log_msg.h"
+#include "./format.h"
+#include "os.h"
+
+
+namespace spdlog
+{
+namespace details
+{
+
+class async_log_helper
+{
+    // Async msg to move to/from the queue
+    // Movable only. should never be copied
+    struct async_msg
+    {
+        std::string logger_name;
+        level::level_enum level;
+        log_clock::time_point time;
+        size_t thread_id;
+        std::string txt;
+
+        async_msg() = default;
+        ~async_msg() = default;
+
+async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
+        logger_name(std::move(other.logger_name)),
+                    level(std::move(other.level)),
+                    time(std::move(other.time)),
+                    txt(std::move(other.txt))
+        {}
+
+        async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
+        {
+            logger_name = std::move(other.logger_name);
+            level = other.level;
+            time = std::move(other.time);
+            thread_id = other.thread_id;
+            txt = std::move(other.txt);
+            return *this;
+        }
+        // never copy or assign. should only be moved..
+        async_msg(const async_msg&) = delete;
+        async_msg& operator=(async_msg& other) = delete;
+
+        // construct from log_msg
+        async_msg(const details::log_msg& m) :
+            logger_name(m.logger_name),
+            level(m.level),
+            time(m.time),
+            thread_id(m.thread_id),
+            txt(m.raw.data(), m.raw.size())
+        {}
+
+
+        // copy into log_msg
+        void fill_log_msg(log_msg &msg)
+        {
+            msg.clear();
+            msg.logger_name = logger_name;
+            msg.level = level;
+            msg.time = time;
+            msg.thread_id = thread_id;
+            msg.raw << txt;
+        }
+    };
+
+public:
+
+    using item_type = async_msg;
+    using q_type = details::mpmc_bounded_queue<item_type>;
+
+    using clock = std::chrono::steady_clock;
+
+
+    async_log_helper(formatter_ptr formatter,
+                     const std::vector<sink_ptr>& sinks,
+                     size_t queue_size,
+                     const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
+                     const std::function<void()>& worker_warmup_cb = nullptr,
+                     const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
+
+    void log(const details::log_msg& msg);
+
+    // stop logging and join the back thread
+    ~async_log_helper();
+
+    void set_formatter(formatter_ptr);
+
+
+private:
+    formatter_ptr _formatter;
+    std::vector<std::shared_ptr<sinks::sink>> _sinks;
+
+    // queue of messages to log
+    q_type _q;
+
+    // last exception thrown from the worker thread
+    std::shared_ptr<spdlog_ex> _last_workerthread_ex;
+
+    // overflow policy
+    const async_overflow_policy _overflow_policy;
+
+    // worker thread warmup callback - one can set thread priority, affinity, etc
+    const std::function<void()> _worker_warmup_cb;
+
+    // auto periodic sink flush parameter
+    const std::chrono::milliseconds _flush_interval_ms;
+
+    // worker thread
+    std::thread _worker_thread;
+
+    // throw last worker thread exception or if worker thread is not active
+    void throw_if_bad_worker();
+
+    // worker thread main loop
+    void worker_loop();
+
+    // pop next message from the queue and process it
+    // return true if a message was available (queue was not empty), will set the last_pop to the pop time
+    bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush);
+
+    void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush);
+
+    // sleep,yield or return immediatly using the time passed since last message as a hint
+    static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time);
+
+
+
+};
+}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// async_sink class implementation
+///////////////////////////////////////////////////////////////////////////////
+inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, const std::vector<sink_ptr>& sinks, size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms):
+    _formatter(formatter),
+    _sinks(sinks),
+    _q(queue_size),
+    _overflow_policy(overflow_policy),
+    _worker_warmup_cb(worker_warmup_cb),
+    _flush_interval_ms(flush_interval_ms),
+    _worker_thread(&async_log_helper::worker_loop, this)
+{}
+
+// Send to the worker thread termination message(level=off)
+// and wait for it to finish gracefully
+inline spdlog::details::async_log_helper::~async_log_helper()
+{
+
+    try
+    {
+        log(log_msg(level::off));
+        _worker_thread.join();
+    }
+    catch (...) //Dont crash if thread not joinable
+    {}
+}
+
+
+//Try to push and block until succeeded
+inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
+{
+    throw_if_bad_worker();
+    async_msg new_msg(msg);
+    if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
+    {
+        auto last_op_time = details::os::now();
+        auto now = last_op_time;
+        do
+        {
+            now = details::os::now();
+            sleep_or_yield(now, last_op_time);
+        }
+        while (!_q.enqueue(std::move(new_msg)));
+    }
+
+}
+
+inline void spdlog::details::async_log_helper::worker_loop()
+{
+    try
+    {
+        if (_worker_warmup_cb) _worker_warmup_cb();
+        auto last_pop = details::os::now();
+        auto last_flush = last_pop;
+        while(process_next_msg(last_pop, last_flush));
+    }
+    catch (const std::exception& ex)
+    {
+        _last_workerthread_ex = std::make_shared<spdlog_ex>(std::string("async_logger worker thread exception: ") + ex.what());
+    }
+    catch (...)
+    {
+        _last_workerthread_ex = std::make_shared<spdlog_ex>("async_logger worker thread exception");
+    }
+}
+
+// process next message in the queue
+// return true if this thread should still be active (no msg with level::off was received)
+inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
+{
+
+    async_msg incoming_async_msg;
+    log_msg incoming_log_msg;
+
+    if (_q.dequeue(incoming_async_msg))
+    {
+        last_pop = details::os::now();
+
+        if(incoming_async_msg.level == level::off)
+            return false;
+
+        incoming_async_msg.fill_log_msg(incoming_log_msg);
+        _formatter->format(incoming_log_msg);
+        for (auto &s : _sinks)
+            s->log(incoming_log_msg);
+    }
+    else //empty queue
+    {
+        auto now = details::os::now();
+        handle_flush_interval(now, last_flush);
+        sleep_or_yield(now, last_pop);
+    }
+    return true;
+}
+
+inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush)
+{
+    if (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms)
+    {
+        for (auto &s : _sinks)
+            s->flush();
+        now = last_flush = details::os::now();
+    }
+}
+inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
+{
+    _formatter = msg_formatter;
+}
+
+
+// sleep,yield or return immediatly using the time passed since last message as a hint
+inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time)
+{
+    using std::chrono::milliseconds;
+    using namespace std::this_thread;
+
+    auto time_since_op = now - last_op_time;
+
+    // spin upto 1 ms
+    if (time_since_op <= milliseconds(1))
+        return;
+
+    // yield upto 10ms
+    if (time_since_op <= milliseconds(10))
+        return yield();
+
+
+    // sleep for half of duration since last op
+    if (time_since_op <= milliseconds(100))
+        return sleep_for(time_since_op / 2);
+
+    return sleep_for(milliseconds(100));
+}
+
+// throw if the worker thread threw an exception or not active
+inline void spdlog::details::async_log_helper::throw_if_bad_worker()
+{
+    if (_last_workerthread_ex)
+    {
+        auto ex = std::move(_last_workerthread_ex);
+        throw *ex;
+    }
+}
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/async_logger_impl.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/async_logger_impl.h b/include/spdlog/details/async_logger_impl.h
new file mode 100644
index 0000000..f60407e
--- /dev/null
+++ b/include/spdlog/details/async_logger_impl.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+
+#include "./async_log_helper.h"
+
+//
+// Async Logger implementation
+// Use single async_sink (queue) to perform the logging in a worker thread
+//
+
+
+template<class It>
+inline spdlog::async_logger::async_logger(const std::string& logger_name,
+        const It& begin,
+        const It& end,
+        size_t queue_size,
+        const  async_overflow_policy overflow_policy,
+        const std::function<void()>& worker_warmup_cb,
+        const std::chrono::milliseconds& flush_interval_ms) :
+    logger(logger_name, begin, end),
+    _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms))
+{
+}
+
+inline spdlog::async_logger::async_logger(const std::string& logger_name,
+        sinks_init_list sinks,
+        size_t queue_size,
+        const  async_overflow_policy overflow_policy,
+        const std::function<void()>& worker_warmup_cb,
+        const std::chrono::milliseconds& flush_interval_ms) :
+    async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
+
+inline spdlog::async_logger::async_logger(const std::string& logger_name,
+        sink_ptr single_sink,
+        size_t queue_size,
+        const  async_overflow_policy overflow_policy,
+        const std::function<void()>& worker_warmup_cb,
+        const std::chrono::milliseconds& flush_interval_ms) :
+    async_logger(logger_name, { single_sink }, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms) {}
+
+
+inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
+{
+    _formatter = msg_formatter;
+    _async_log_helper->set_formatter(_formatter);
+}
+
+inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
+{
+    _formatter = std::make_shared<pattern_formatter>(pattern);
+    _async_log_helper->set_formatter(_formatter);
+}
+
+
+inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
+{
+    _async_log_helper->log(msg);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/details/file_helper.h
----------------------------------------------------------------------
diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h
new file mode 100644
index 0000000..8e1f600
--- /dev/null
+++ b/include/spdlog/details/file_helper.h
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+// Helper class for file sink
+// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
+// Can be set to auto flush on every line
+// Throw spdlog_ex exception on errors
+
+#include <string>
+#include <thread>
+#include <chrono>
+#include "os.h"
+
+
+
+
+namespace spdlog
+{
+namespace details
+{
+
+class file_helper
+{
+public:
+    const int open_tries = 5;
+    const int open_interval = 10;
+
+    explicit file_helper(bool force_flush):
+        _fd(nullptr),
+        _force_flush(force_flush)
+    {}
+
+    file_helper(const file_helper&) = delete;
+    file_helper& operator=(const file_helper&) = delete;
+
+    ~file_helper()
+    {
+        close();
+    }
+
+
+    void open(const std::string& fname, bool truncate=false)
+    {
+
+        close();
+        const char* mode = truncate ? "wb" : "ab";
+        _filename = fname;
+        for (int tries = 0; tries < open_tries; ++tries)
+        {
+            if(!os::fopen_s(&_fd, fname, mode))
+                return;
+
+            std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
+        }
+
+        throw spdlog_ex("Failed opening file " + fname + " for writing");
+    }
+
+    void reopen(bool truncate)
+    {
+        if(_filename.empty())
+            throw spdlog_ex("Failed re opening file - was not opened before");
+        open(_filename, truncate);
+
+    }
+
+    void flush() {
+        std::fflush(_fd);
+    }
+
+    void close()
+    {
+        if (_fd)
+        {
+            std::fclose(_fd);
+            _fd = nullptr;
+        }
+    }
+
+    void write(const log_msg& msg)
+    {
+
+        size_t size = msg.formatted.size();
+        auto data = msg.formatted.data();
+        if(std::fwrite(data, 1, size, _fd) != size)
+            throw spdlog_ex("Failed writing to file " + _filename);
+
+        if(_force_flush)
+            std::fflush(_fd);
+
+    }
+
+    const std::string& filename() const
+    {
+        return _filename;
+    }
+
+    static bool file_exists(const std::string& name)
+    {
+        FILE* file;
+        if (!os::fopen_s(&file, name.c_str(), "r"))
+        {
+            fclose(file);
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+private:
+    FILE* _fd;
+    std::string _filename;
+    bool _force_flush;
+
+
+};
+}
+}
+


[17/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/ProcessGroup.h
----------------------------------------------------------------------
diff --git a/inc/ProcessGroup.h b/inc/ProcessGroup.h
deleted file mode 100644
index 4dd26f8..0000000
--- a/inc/ProcessGroup.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/**
- * @file ProcessGroup.h
- * ProcessGroup class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __PROCESS_GROUP_H__
-#define __PROCESS_GROUP_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-#include <set>
-
-#include "Logger.h"
-#include "Processor.h"
-#include "Exception.h"
-#include "TimerDrivenSchedulingAgent.h"
-
-//! Process Group Type
-enum ProcessGroupType
-{
-	ROOT_PROCESS_GROUP = 0,
-	REMOTE_PROCESS_GROUP,
-	MAX_PROCESS_GROUP_TYPE
-};
-
-//! ProcessGroup Class
-class ProcessGroup
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new process group
-	 */
-	ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid = NULL, ProcessGroup *parent = NULL);
-	//! Destructor
-	virtual ~ProcessGroup();
-	//! Set Processor Name
-	void setName(std::string name) {
-		_name = name;
-	}
-	//! Get Process Name
-	std::string getName(void) {
-		return (_name);
-	}
-	//! Set URL
-	void setURL(std::string url) {
-		_url = url;
-	}
-	//! Get URL
-	std::string getURL(void) {
-		return (_url);
-	}
-	//! SetTransmitting
-	void setTransmitting(bool val)
-	{
-		_transmitting = val;
-	}
-	//! Get Transmitting
-	bool getTransmitting()
-	{
-		return _transmitting;
-	}
-	//! setTimeOut
-	void setTimeOut(uint64_t time)
-	{
-		_timeOut = time;
-	}
-	uint64_t getTimeOut()
-	{
-		return _timeOut;
-	}
-	//! Set Processor yield period in MilliSecond
-	void setYieldPeriodMsec(uint64_t period) {
-		_yieldPeriodMsec = period;
-	}
-	//! Get Processor yield period in MilliSecond
-	uint64_t getYieldPeriodMsec(void) {
-		return(_yieldPeriodMsec);
-	}
-	//! Set UUID
-	void setUUID(uuid_t uuid) {
-		uuid_copy(_uuid, uuid);
-	}
-	//! Get UUID
-	bool getUUID(uuid_t uuid) {
-		if (uuid)
-		{
-			uuid_copy(uuid, _uuid);
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Start Processing
-	void startProcessing(TimerDrivenSchedulingAgent *timeScheduler);
-	//! Stop Processing
-	void stopProcessing(TimerDrivenSchedulingAgent *timeScheduler);
-	//! Whether it is root process group
-	bool isRootProcessGroup();
-	//! set parent process group
-	void setParent(ProcessGroup *parent) {
-		std::lock_guard<std::mutex> lock(_mtx);
-		_parentProcessGroup = parent;
-	}
-	//! get parent process group
-	ProcessGroup *getParent(void) {
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _parentProcessGroup;
-	}
-	//! Add processor
-	void addProcessor(Processor *processor);
-	//! Remove processor
-	void removeProcessor(Processor *processor);
-	//! Add child processor group
-	void addProcessGroup(ProcessGroup *child);
-	//! Remove child processor group
-	void removeProcessGroup(ProcessGroup *child);
-	// ! Add connections
-	void addConnection(Connection *connection);
-	//! findProcessor based on UUID
-	Processor *findProcessor(uuid_t uuid);
-	//! findProcessor based on name
-	Processor *findProcessor(std::string processorName);
-	//! removeConnection
-	void removeConnection(Connection *connection);
-	//! update property value
-	void updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue);
-
-protected:
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! Processor Group Name
-	std::string _name;
-	//! Process Group Type
-	ProcessGroupType _type;
-	//! Processors (ProcessNode) inside this process group which include Input/Output Port, Remote Process Group input/Output port
-	std::set<Processor *> _processors;
-	std::set<ProcessGroup *> _childProcessGroups;
-	//! Connections between the processor inside the group;
-	std::set<Connection *> _connections;
-	//! Parent Process Group
-	ProcessGroup* _parentProcessGroup;
-	//! Yield Period in Milliseconds
-	std::atomic<uint64_t> _yieldPeriodMsec;
-	std::atomic<uint64_t> _timeOut;
-	//! URL
-	std::string _url;
-	//! Transmitting
-	std::atomic<bool> _transmitting;
-
-private:
-
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Logger
-	Logger *_logger;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	ProcessGroup(const ProcessGroup &parent);
-	ProcessGroup &operator=(const ProcessGroup &parent);
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/ProcessSession.h
----------------------------------------------------------------------
diff --git a/inc/ProcessSession.h b/inc/ProcessSession.h
deleted file mode 100644
index c8ec3a5..0000000
--- a/inc/ProcessSession.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file ProcessSession.h
- * ProcessSession class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __PROCESS_SESSION_H__
-#define __PROCESS_SESSION_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-#include <set>
-
-#include "Logger.h"
-#include "Processor.h"
-#include "ProcessContext.h"
-#include "FlowFileRecord.h"
-#include "Exception.h"
-
-//! ProcessSession Class
-class ProcessSession
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new process session
-	 */
-	ProcessSession(ProcessContext *processContext = NULL) : _processContext(processContext) {
-		_logger = Logger::getLogger();
-		_logger->log_trace("ProcessSession created for %s", _processContext->getProcessor()->getName().c_str());
-	}
-	//! Destructor
-	virtual ~ProcessSession() {}
-	//! Commit the session
-	void commit();
-	//! Roll Back the session
-	void rollback();
-	//!
-	//! Get the FlowFile from the highest priority queue
-	FlowFileRecord *get();
-	//! Create a new UUID FlowFile with no content resource claim and without parent
-	FlowFileRecord *create();
-	//! Create a new UUID FlowFile with no content resource claim and inherit all attributes from parent
-	FlowFileRecord *create(FlowFileRecord *parent);
-	//! Clone a new UUID FlowFile from parent both for content resource claim and attributes
-	FlowFileRecord *clone(FlowFileRecord *parent);
-	//! Clone a new UUID FlowFile from parent for attributes and sub set of parent content resource claim
-	FlowFileRecord *clone(FlowFileRecord *parent, long offset, long size);
-	//! Duplicate a FlowFile with the same UUID and all attributes and content resource claim for the roll back of the session
-	FlowFileRecord *duplicate(FlowFileRecord *orignal);
-	//! Transfer the FlowFile to the relationship
-	void transfer(FlowFileRecord *flow, Relationship relationship);
-	//! Put Attribute
-	void putAttribute(FlowFileRecord *flow, std::string key, std::string value);
-	//! Remove Attribute
-	void removeAttribute(FlowFileRecord *flow, std::string key);
-	//! Remove Flow File
-	void remove(FlowFileRecord *flow);
-	//! Execute the given read callback against the content
-	void read(FlowFileRecord *flow, InputStreamCallback *callback);
-	//! Execute the given write callback against the content
-	void write(FlowFileRecord *flow, OutputStreamCallback *callback);
-	//! Execute the given write/append callback against the content
-	void append(FlowFileRecord *flow, OutputStreamCallback *callback);
-	//! Penalize the flow
-	void penalize(FlowFileRecord *flow);
-	//! Import the existed file into the flow
-	void import(std::string source, FlowFileRecord *flow, bool keepSource = true, uint64_t offset = 0);
-
-protected:
-	//! FlowFiles being modified by current process session
-	std::map<std::string, FlowFileRecord *> _updatedFlowFiles;
-	//! Copy of the original FlowFiles being modified by current process session as above
-	std::map<std::string, FlowFileRecord *> _originalFlowFiles;
-	//! FlowFiles being added by current process session
-	std::map<std::string, FlowFileRecord *> _addedFlowFiles;
-	//! FlowFiles being deleted by current process session
-	std::map<std::string, FlowFileRecord *> _deletedFlowFiles;
-	//! FlowFiles being transfered to the relationship
-	std::map<std::string, Relationship> _transferRelationship;
-	//! FlowFiles being cloned for multiple connections per relationship
-	std::map<std::string, FlowFileRecord *> _clonedFlowFiles;
-
-private:
-	// Clone the flow file during transfer to multiple connections for a relationship
-	FlowFileRecord* cloneDuringTransfer(FlowFileRecord *parent);
-	//! ProcessContext
-	ProcessContext *_processContext;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	ProcessSession(const ProcessSession &parent);
-	ProcessSession &operator=(const ProcessSession &parent);
-	//! Logger
-	Logger *_logger;
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Processor.h
----------------------------------------------------------------------
diff --git a/inc/Processor.h b/inc/Processor.h
deleted file mode 100644
index db26ad0..0000000
--- a/inc/Processor.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/**
- * @file Processor.h
- * Processor class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __PROCESSOR_H__
-#define __PROCESSOR_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-#include <set>
-
-#include "TimeUtil.h"
-#include "Property.h"
-#include "Relationship.h"
-#include "Connection.h"
-
-//! Forwarder declaration
-class ProcessContext;
-class ProcessSession;
-
-//! Minimum scheduling period in Nano Second
-#define MINIMUM_SCHEDULING_NANOS 30000
-
-//! Default yield period in second
-#define DEFAULT_YIELD_PERIOD_SECONDS 1
-
-//! Default penalization period in second
-#define DEFAULT_PENALIZATION_PERIOD_SECONDS 30
-
-/*!
- * Indicates the valid values for the state of a entity
- * with respect to scheduling the entity to run.
- */
-enum ScheduledState {
-
-    /**
-     * Entity cannot be scheduled to run
-     */
-    DISABLED,
-    /**
-     * Entity can be scheduled to run but currently is not
-     */
-    STOPPED,
-    /**
-     * Entity is currently scheduled to run
-     */
-    RUNNING
-};
-
-/*!
- * Scheduling Strategy
- */
-enum SchedulingStrategy {
-	//! Event driven
-	EVENT_DRIVEN,
-	//! Timer driven
-	TIMER_DRIVEN,
-	//! Cron Driven
-	CRON_DRIVEN
-};
-
-//! Processor Class
-class Processor
-{
-	friend class ProcessContext;
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	Processor(std::string name, uuid_t uuid = NULL);
-	//! Destructor
-	virtual ~Processor();
-	//! Set Processor Name
-	void setName(std::string name) {
-		_name = name;
-	}
-	//! Get Process Name
-	std::string getName(void) {
-		return (_name);
-	}
-	//! Set UUID
-	void setUUID(uuid_t uuid) {
-		uuid_copy(_uuid, uuid);
-		char uuidStr[37];
-		uuid_unparse(_uuid, uuidStr);
-		_uuidStr = uuidStr;
-	}
-	//! Get UUID
-	bool getUUID(uuid_t uuid) {
-		if (uuid)
-		{
-			uuid_copy(uuid, _uuid);
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Set the supported processor properties while the process is not running
-	bool setSupportedProperties(std::set<Property> properties);
-	//! Set the supported relationships while the process is not running
-	bool setSupportedRelationships(std::set<Relationship> relationships);
-	//! Get the supported property value by name
-	bool getProperty(std::string name, std::string &value);
-	//! Set the supported property value by name wile the process is not running
-	bool setProperty(std::string name, std::string value);
-	//! Whether the relationship is supported
-	bool isSupportedRelationship(Relationship relationship);
-	//! Set the auto terminated relationships while the process is not running
-	bool setAutoTerminatedRelationships(std::set<Relationship> relationships);
-	//! Check whether the relationship is auto terminated
-	bool isAutoTerminated(Relationship relationship);
-	//! Check whether the processor is running
-	bool isRunning();
-	//! Set Processor Scheduled State
-	void setScheduledState(ScheduledState state) {
-		_state = state;
-	}
-	//! Get Processor Scheduled State
-	ScheduledState getScheduledState(void) {
-		return _state;
-	}
-	//! Set Processor Scheduling Strategy
-	void setSchedulingStrategy(SchedulingStrategy strategy) {
-		_strategy = strategy;
-	}
-	//! Get Processor Scheduling Strategy
-	SchedulingStrategy getSchedulingStrategy(void) {
-		return _strategy;
-	}
-	//! Set Processor Loss Tolerant
-	void setlossTolerant(bool lossTolerant) {
-		_lossTolerant = lossTolerant;
-	}
-	//! Get Processor Loss Tolerant
-	bool getlossTolerant(void) {
-		return _lossTolerant;
-	}
-	//! Set Processor Scheduling Period in Nano Second
-	void setSchedulingPeriodNano(uint64_t period) {
-		uint64_t minPeriod = MINIMUM_SCHEDULING_NANOS;
-		_schedulingPeriodNano = std::max(period, minPeriod);
-	}
-	//! Get Processor Scheduling Period in Nano Second
-	uint64_t getSchedulingPeriodNano(void) {
-		return _schedulingPeriodNano;
-	}
-	//! Set Processor Run Duration in Nano Second
-	void setRunDurationNano(uint64_t period) {
-		_runDurantionNano = period;
-	}
-	//! Get Processor Run Duration in Nano Second
-	uint64_t getRunDurationNano(void) {
-		return(_runDurantionNano);
-	}
-	//! Set Processor yield period in MilliSecond
-	void setYieldPeriodMsec(uint64_t period) {
-		_yieldPeriodMsec = period;
-	}
-	//! Get Processor yield period in MilliSecond
-	uint64_t getYieldPeriodMsec(void) {
-		return(_yieldPeriodMsec);
-	}
-	//! Set Processor penalization period in MilliSecond
-	void setPenalizationPeriodMsec(uint64_t period) {
-		_penalizationPeriodMsec = period;
-	}
-	//! Get Processor penalization period in MilliSecond
-	uint64_t getPenalizationPeriodMsec(void) {
-		return(_penalizationPeriodMsec);
-	}
-	//! Set Processor Maximum Concurrent Tasks
-	void setMaxConcurrentTasks(uint8_t tasks) {
-		_maxConcurrentTasks = tasks;
-	}
-	//! Get Processor Maximum Concurrent Tasks
-	uint8_t getMaxConcurrentTasks(void) {
-		return(_maxConcurrentTasks);
-	}
-	//! Set Trigger when empty
-	void setTriggerWhenEmpty(bool value) {
-		_triggerWhenEmpty = value;
-	}
-	//! Get Trigger when empty
-	bool getTriggerWhenEmpty(void) {
-		return(_triggerWhenEmpty);
-	}
-	//! Get Active Task Counts
-	uint8_t getActiveTasks(void) {
-		return(_activeTasks);
-	}
-	//! Increment Active Task Counts
-	void incrementActiveTasks(void) {
-		_activeTasks++;
-	}
-	//! decrement Active Task Counts
-	void decrementActiveTask(void) {
-		_activeTasks--;
-	}
-	void clearActiveTask(void) {
-		_activeTasks = 0;
-	}
-	//! Yield based on the yield period
-	void yield()
-	{
-		_yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
-	}
-	//! Yield based on the input time
-	void yield(uint64_t time)
-	{
-		_yieldExpiration = (getTimeMillis() + time);
-	}
-	//! whether need be to yield
-	bool isYield()
-	{
-		if (_yieldExpiration > 0)
-			return (_yieldExpiration >= getTimeMillis());
-		else
-			return false;
-	}
-	// clear yield expiration
-	void clearYield()
-	{
-		_yieldExpiration = 0;
-	}
-	// get yield time
-	uint64_t getYieldTime()
-	{
-		uint64_t curTime = getTimeMillis();
-		if (_yieldExpiration > curTime)
-			return (_yieldExpiration - curTime);
-		else
-			return 0;;
-	}
-	//! Whether flow file queued in incoming connection
-	bool flowFilesQueued();
-	//! Whether flow file queue full in any of the outgoin connection
-	bool flowFilesOutGoingFull();
-	//! Get incoming connections
-	std::set<Connection *> getIncomingConnections() {
-		return _incomingConnections;
-	}
-	//! Has Incoming Connection
-	bool hasIncomingConnections() {
-		return (_incomingConnections.size() > 0);
-	}
-	//! Get outgoing connections based on relationship name
-	std::set<Connection *> getOutGoingConnections(std::string relationship);
-	//! Add connection
-	bool addConnection(Connection *connection);
-	//! Remove connection
-	void removeConnection(Connection *connection);
-	//! Get the UUID as string
-	std::string getUUIDStr() {
-		return _uuidStr;
-	}
-	//! Get the Next RoundRobin incoming connection
-	Connection *getNextIncomingConnection();
-	//! On Trigger
-	void onTrigger();
-
-public:
-	//! OnTrigger method, implemented by NiFi Processor Designer
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session) = 0;
-	//! Initialize, over write by NiFi Process Designer
-	virtual void initialize(void) {
-		return;
-	}
-
-protected:
-
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! Processor Name
-	std::string _name;
-	//! Supported properties
-	std::map<std::string, Property> _properties;
-	//! Supported relationships
-	std::map<std::string, Relationship> _relationships;
-	//! Autoterminated relationships
-	std::map<std::string, Relationship> _autoTerminatedRelationships;
-	//! Processor state
-	std::atomic<ScheduledState> _state;
-	//! Scheduling Strategy
-	std::atomic<SchedulingStrategy> _strategy;
-	//! lossTolerant
-	std::atomic<bool> _lossTolerant;
-	//! SchedulePeriod in Nano Seconds
-	std::atomic<uint64_t> _schedulingPeriodNano;
-	//! Run Duration in Nano Seconds
-	std::atomic<uint64_t> _runDurantionNano;
-	//! Yield Period in Milliseconds
-	std::atomic<uint64_t> _yieldPeriodMsec;
-	//! Penalization Period in MilliSecond
-	std::atomic<uint64_t> _penalizationPeriodMsec;
-	//! Maximum Concurrent Tasks
-	std::atomic<uint8_t> _maxConcurrentTasks;
-	//! Active Tasks
-	std::atomic<uint8_t> _activeTasks;
-	//! Trigger the Processor even if the incoming connection is empty
-	std::atomic<bool> _triggerWhenEmpty;
-	//! Incoming connections
-	std::set<Connection *> _incomingConnections;
-	//! Outgoing connections map based on Relationship name
-	std::map<std::string, std::set<Connection *>> _outGoingConnections;
-	//! UUID string
-	std::string _uuidStr;
-
-private:
-
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Yield Expiration
-	std::atomic<uint64_t> _yieldExpiration;
-	//! Incoming connection Iterator
-	std::set<Connection *>::iterator _incomingConnectionsIter;
-	//! Logger
-	Logger *_logger;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Processor(const Processor &parent);
-	Processor &operator=(const Processor &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Property.h
----------------------------------------------------------------------
diff --git a/inc/Property.h b/inc/Property.h
deleted file mode 100644
index a724394..0000000
--- a/inc/Property.h
+++ /dev/null
@@ -1,344 +0,0 @@
-/**
- * @file Property.h
- * Processor Property class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __PROPERTY_H__
-#define __PROPERTY_H__
-
-#include <string>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <set>
-#include <stdlib.h>
-#include <math.h>
-
-//! Time Unit
-enum TimeUnit {
-	DAY,
-	HOUR,
-	MINUTE,
-	SECOND,
-	MILLISECOND,
-	NANOSECOND
-};
-
-//! Property Class
-class Property {
-
-public:
-	//! Constructor
-	/*!
-	 * Create a new property
-	 */
-	Property(const std::string name, const std::string description, const std::string value)
-		: _name(name), _description(description), _value(value) {
-	}
-	Property() {}
-	//! Destructor
-	virtual ~Property() {}
-	//! Get Name for the property
-	std::string getName() {
-		return _name;
-	}
-	//! Get Description for the property
-	std::string getDescription() {
-		return _description;
-	}
-	//! Get value for the property
-	std::string getValue() {
-		return _value;
-	}
-	//! Set value for the property
-	void setValue(std::string value) {
-		_value = value;
-	}
-	//! Compare
-	bool operator < (const Property & right) const {
-		return _name < right._name;
-	}
-
-	//! Convert TimeUnit to MilliSecond
-	static bool ConvertTimeUnitToMS(int64_t input, TimeUnit unit, int64_t &out)
-	{
-		if (unit == MILLISECOND)
-		{
-			out = input;
-			return true;
-		}
-		else if (unit == SECOND)
-		{
-			out = input * 1000;
-			return true;
-		}
-		else if (unit == MINUTE)
-		{
-			out = input * 60 * 1000;
-			return true;
-		}
-		else if (unit == HOUR)
-		{
-			out = input * 60 * 60 * 1000;
-			return true;
-		}
-		else if (unit == DAY)
-		{
-			out = 24 * 60 * 60 * 1000;
-			return true;
-		}
-		else if (unit == NANOSECOND)
-		{
-			out = input/1000/1000;
-			return true;
-		}
-		else
-		{
-			return false;
-		}
-	}
-	//! Convert TimeUnit to NanoSecond
-	static bool ConvertTimeUnitToNS(int64_t input, TimeUnit unit, int64_t &out)
-	{
-		if (unit == MILLISECOND)
-		{
-			out = input * 1000 * 1000;
-			return true;
-		}
-		else if (unit == SECOND)
-		{
-			out = input * 1000 * 1000 * 1000;
-			return true;
-		}
-		else if (unit == MINUTE)
-		{
-			out = input * 60 * 1000 * 1000 * 1000;
-			return true;
-		}
-		else if (unit == HOUR)
-		{
-			out = input * 60 * 60 * 1000 * 1000 * 1000;
-			return true;
-		}
-		else if (unit == NANOSECOND)
-		{
-			out = input;
-			return true;
-		}
-		else
-		{
-			return false;
-		}
-	}
-	//! Convert String
-	static bool StringToTime(std::string input, int64_t &output, TimeUnit &timeunit)
-	{
-		if (input.size() == 0) {
-			return false;
-		}
-
-		const char *cvalue = input.c_str();
-		char *pEnd;
-		long int ival = strtol(cvalue, &pEnd, 0);
-
-		if (pEnd[0] == '\0')
-		{
-			return false;
-		}
-
-		while (*pEnd == ' ')
-		{
-			// Skip the space
-			pEnd++;
-		}
-
-		std::string unit(pEnd);
-
-		if (unit == "sec" || unit == "s" || unit == "second" || unit == "seconds" || unit == "secs")
-		{
-			timeunit = SECOND;
-			output = ival;
-			return true;
-		}
-		else if (unit == "min" || unit == "m" || unit == "mins" || unit == "minute" || unit == "minutes")
-		{
-			timeunit = MINUTE;
-			output = ival;
-			return true;
-		}
-		else if (unit == "ns" || unit == "nano" || unit == "nanos" || unit == "nanoseconds")
-		{
-			timeunit = NANOSECOND;
-			output = ival;
-			return true;
-		}
-		else if (unit == "ms" || unit == "milli" || unit == "millis" || unit == "milliseconds")
-		{
-			timeunit = MILLISECOND;
-			output = ival;
-			return true;
-		}
-		else if (unit == "h" || unit == "hr" || unit == "hour" || unit == "hrs" || unit == "hours")
-		{
-			timeunit = HOUR;
-			output = ival;
-			return true;
-		}
-		else if (unit == "d" || unit == "day" || unit == "days")
-		{
-			timeunit = DAY;
-			output = ival;
-			return true;
-		}
-		else
-			return false;
-	}
-
-	//! Convert String to Integer
-	static bool StringToInt(std::string input, int64_t &output)
-	{
-		if (input.size() == 0) {
-			return false;
-		}
-
-		const char *cvalue = input.c_str();
-		char *pEnd;
-		long int ival = strtol(cvalue, &pEnd, 0);
-
-		if (pEnd[0] == '\0')
-		{
-			output = ival;
-			return true;
-		}
-
-		while (*pEnd == ' ')
-		{
-			// Skip the space
-			pEnd++;
-		}
-
-		char end0 = toupper(pEnd[0]);
-		if ( (end0 == 'K') || (end0 == 'M') || (end0 == 'G') || (end0 == 'T') || (end0 == 'P') )
-		{
-			if (pEnd[1] == '\0')
-			{
-				unsigned long int multiplier = 1000;
-
-				if ( (end0 != 'K') ) {
-					multiplier *= 1000;
-					if (end0 != 'M') {
-						multiplier *= 1000;
-						if (end0 != 'G') {
-							multiplier *= 1000;
-							if (end0 != 'T') {
-								multiplier *= 1000;
-							}
-						}
-					}
-				}
-				output = ival * multiplier;
-				return true;
-
-			} else if ((pEnd[1] == 'b' || pEnd[1] == 'B') && (pEnd[2] == '\0')) {
-
-				unsigned long int multiplier = 1024;
-
-				if ( (end0 != 'K') ) {
-					multiplier *= 1024;
-					if (end0 != 'M') {
-						multiplier *= 1024;
-						if (end0 != 'G') {
-							multiplier *= 1024;
-							if (end0 != 'T') {
-								multiplier *= 1024;
-							}
-						}
-					}
-				}
-				output = ival * multiplier;
-				return true;
-			}
-		}
-
-		return false;
-	}
-	//! Convert String to Float
-	static bool StringToFloat(std::string input, float &output)
-	{
-		const char *cvalue = input.c_str();
-		char *pEnd;
-		float val = strtof(cvalue, &pEnd);
-
-		if (pEnd[0] == '\0')
-		{
-			output = val;
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Convert String to Bool
-	static bool StringToBool(std::string input, bool &output)
-	{
-		if (input == "true" || input == "True" || input == "TRUE")
-		{
-			output = true;
-			return true;
-		}
-		if (input == "false" || input == "False" || input == "FALSE")
-		{
-			output = false;
-			return true;
-		}
-		return false;
-	}
-
-	// Trim String utils
-	static std::string trim(const std::string& s)
-	{
-	    return trimRight(trimLeft(s));
-	}
-
-	static std::string trimLeft(const std::string& s)
-	{
-		const char *WHITESPACE = " \n\r\t";
-	    size_t startpos = s.find_first_not_of(WHITESPACE);
-	    return (startpos == std::string::npos) ? "" : s.substr(startpos);
-	}
-
-	static std::string trimRight(const std::string& s)
-	{
-		const char *WHITESPACE = " \n\r\t";
-	    size_t endpos = s.find_last_not_of(WHITESPACE);
-	    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
-	}
-
-protected:
-	//! Name
-	std::string _name;
-	//! Description
-	std::string _description;
-	//! Value
-	std::string _value;
-
-private:
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/RealTimeDataCollector.h
----------------------------------------------------------------------
diff --git a/inc/RealTimeDataCollector.h b/inc/RealTimeDataCollector.h
deleted file mode 100644
index 760b566..0000000
--- a/inc/RealTimeDataCollector.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * @file RealTimeDataCollector.h
- * RealTimeDataCollector class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __REAL_TIME_DATA_COLLECTOR_H__
-#define __REAL_TIME_DATA_COLLECTOR_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <string>
-#include <errno.h>
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! RealTimeDataCollector Class
-class RealTimeDataCollector : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	RealTimeDataCollector(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_realTimeSocket = 0;
-		_batchSocket = 0;
-		_logger = Logger::getLogger();
-		_firstInvoking = false;
-		_realTimeAccumulated = 0;
-		_batchAcccumulated = 0;
-		_queuedDataSize = 0;
-	}
-	//! Destructor
-	virtual ~RealTimeDataCollector()
-	{
-		if (_realTimeSocket)
-			close(_realTimeSocket);
-		if (_batchSocket)
-			close(_batchSocket);
-		if (_fileStream.is_open())
-			_fileStream.close();
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property REALTIMESERVERNAME;
-	static Property REALTIMESERVERPORT;
-	static Property BATCHSERVERNAME;
-	static Property BATCHSERVERPORT;
-	static Property FILENAME;
-	static Property ITERATION;
-	static Property REALTIMEMSGID;
-	static Property BATCHMSGID;
-	static Property REALTIMEINTERVAL;
-	static Property BATCHINTERVAL;
-	static Property BATCHMAXBUFFERSIZE;
-	//! Supported Relationships
-	static Relationship Success;
-	//! Connect to the socket
-	int connectServer(const char *host, uint16_t port);
-	int sendData(int socket, const char *buf, int buflen);
-	void onTriggerRealTime(ProcessContext *context, ProcessSession *session);
-	void onTriggerBatch(ProcessContext *context, ProcessSession *session);
-
-public:
-	//! OnTrigger method, implemented by NiFi RealTimeDataCollector
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi RealTimeDataCollector
-	virtual void initialize(void);
-
-protected:
-
-private:
-	//! realtime server Name
-	std::string _realTimeServerName;
-	int64_t _realTimeServerPort;
-	std::string _batchServerName;
-	int64_t _batchServerPort;
-	int64_t _realTimeInterval;
-	int64_t _batchInterval;
-	int64_t _batchMaxBufferSize;
-	//! Match pattern for Real time Message ID
-	std::vector<std::string> _realTimeMsgID;
-	//! Match pattern for Batch Message ID
-	std::vector<std::string> _batchMsgID;
-	//! file for which the realTime collector will tail
-	std::string _fileName;
-	//! Whether we need to iterate from the beginning for demo
-	bool _iteration;
-	int _realTimeSocket;
-	int _batchSocket;
-	//! Logger
-	Logger *_logger;
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Queued data size
-	uint64_t _queuedDataSize;
-	//! Queue for the batch process
-	std::queue<std::string> _queue;
-	std::thread::id _realTimeThreadId;
-	std::thread::id _batchThreadId;
-	std::atomic<bool> _firstInvoking;
-	int64_t _realTimeAccumulated;
-	int64_t _batchAcccumulated;
-	std::ifstream _fileStream;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Relationship.h
----------------------------------------------------------------------
diff --git a/inc/Relationship.h b/inc/Relationship.h
deleted file mode 100644
index 3454ee5..0000000
--- a/inc/Relationship.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file Relationship.h
- * Relationship class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __RELATIONSHIP_H__
-#define __RELATIONSHIP_H__
-
-#include <string>
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-
-//! undefined relationship for remote process group outgoing port and root process group incoming port
-#define UNDEFINED_RELATIONSHIP "undefined"
-
-inline bool isRelationshipNameUndefined(std::string name)
-{
-	if (name == UNDEFINED_RELATIONSHIP)
-		return true;
-	else
-		return false;
-}
-
-//! Relationship Class
-class Relationship {
-
-public:
-	//! Constructor
-	/*!
-	 * Create a new relationship 
-	 */
-	Relationship(const std::string name, const std::string description)
-		: _name(name), _description(description) {
-	}
-	Relationship()
-		: _name(UNDEFINED_RELATIONSHIP) {
-	}
-	//! Destructor
-	virtual ~Relationship() {
-	}
-	//! Get Name for the relationship
-	std::string getName() {
-		return _name;
-	}
-	//! Get Description for the relationship
-	std::string getDescription() {
-		return _description;
-	}
-	//! Compare
-	bool operator < (const Relationship & right) const {
-		return _name < right._name;
-	}
-	//! Whether it is a undefined relationship
-	bool isRelationshipUndefined()
-	{
-		return isRelationshipNameUndefined(_name);
-	}
-
-protected:
-
-	//! Name
-	std::string _name;
-	//! Description
-	std::string _description;
-
-private:
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/RemoteProcessorGroupPort.h
----------------------------------------------------------------------
diff --git a/inc/RemoteProcessorGroupPort.h b/inc/RemoteProcessorGroupPort.h
deleted file mode 100644
index cd99e50..0000000
--- a/inc/RemoteProcessorGroupPort.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * @file RemoteProcessorGroupPort.h
- * RemoteProcessorGroupPort class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __REMOTE_PROCESSOR_GROUP_PORT_H__
-#define __REMOTE_PROCESSOR_GROUP_PORT_H__
-
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-#include "Site2SiteClientProtocol.h"
-
-//! RemoteProcessorGroupPort Class
-class RemoteProcessorGroupPort : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	RemoteProcessorGroupPort(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-		_peer = new Site2SitePeer("", 9999);
-		_protocol = new Site2SiteClientProtocol(_peer);
-		_protocol->setPortId(uuid);
-	}
-	//! Destructor
-	virtual ~RemoteProcessorGroupPort()
-	{
-		delete _protocol;
-		delete _peer;
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property hostName;
-	static Property port;
-	//! Supported Relationships
-	static Relationship relation;
-public:
-	//! OnTrigger method, implemented by NiFi RemoteProcessorGroupPort
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi RemoteProcessorGroupPort
-	virtual void initialize(void);
-	//! Set Direction
-	void setDirection(TransferDirection direction)
-	{
-		_direction = direction;
-		if (_direction == RECEIVE)
-			this->setTriggerWhenEmpty(true);
-	}
-	//! Set Timeout
-	void setTimeOut(uint64_t timeout)
-	{
-		_protocol->setTimeOut(timeout);
-	}
-	//! SetTransmitting
-	void setTransmitting(bool val)
-	{
-		_transmitting = val;
-	}
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-	//! Peer Connection
-	Site2SitePeer *_peer;
-	//! Peer Protocol
-	Site2SiteClientProtocol *_protocol;
-	//! Transaction Direction
-	TransferDirection _direction;
-	//! Transmitting
-	bool _transmitting;
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/ResourceClaim.h
----------------------------------------------------------------------
diff --git a/inc/ResourceClaim.h b/inc/ResourceClaim.h
deleted file mode 100644
index d8f9979..0000000
--- a/inc/ResourceClaim.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @file ResourceClaim.h
- * Resource Claim class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __RESOURCE_CLAIM_H__
-#define __RESOURCE_CLAIM_H__
-
-#include <string>
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include "Configure.h"
-
-//! Default content directory
-#define DEFAULT_CONTENT_DIRECTORY "."
-
-//! ResourceClaim Class
-class ResourceClaim {
-
-public:
-	//! Constructor
-	/*!
-	 * Create a new resource claim
-	 */
-	ResourceClaim(const std::string contentDirectory);
-	//! Destructor
-	virtual ~ResourceClaim() {}
-	//! increaseFlowFileRecordOwnedCount
-	void increaseFlowFileRecordOwnedCount()
-	{
-		++_flowFileRecordOwnedCount;
-	}
-	//! decreaseFlowFileRecordOwenedCount
-	void decreaseFlowFileRecordOwnedCount()
-	{
-		--_flowFileRecordOwnedCount;
-	}
-	//! getFlowFileRecordOwenedCount
-	uint64_t getFlowFileRecordOwnedCount()
-	{
-		return _flowFileRecordOwnedCount;
-	}
-	//! Get the content full path
-	std::string getContentFullPath()
-	{
-		return _contentFullPath;
-	}
-
-protected:
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! A local unique identifier
-	uint64_t _id;
-	//! Full path to the content
-	std::string _contentFullPath;
-
-	//! How many FlowFileRecord Own this cliam
-	std::atomic<uint64_t> _flowFileRecordOwnedCount;
-
-private:
-	//! Configure
-	Configure *_configure;
-	//! Logger
-	Logger *_logger;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	ResourceClaim(const ResourceClaim &parent);
-	ResourceClaim &operator=(const ResourceClaim &parent);
-
-	//! Local resource claim number
-	static std::atomic<uint64_t> _localResourceClaimNumber;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/SchedulingAgent.h
----------------------------------------------------------------------
diff --git a/inc/SchedulingAgent.h b/inc/SchedulingAgent.h
deleted file mode 100644
index 2e3f6b8..0000000
--- a/inc/SchedulingAgent.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file SchedulingAgent.h
- * SchedulingAgent class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __SCHEDULING_AGENT_H__
-#define __SCHEDULING_AGENT_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-#include <thread>
-#include "TimeUtil.h"
-#include "Logger.h"
-#include "Configure.h"
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessContext.h"
-
-//! SchedulingAgent Class
-class SchedulingAgent
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	SchedulingAgent() {
-		_configure = Configure::getConfigure();
-		_logger = Logger::getLogger();
-		_running = false;
-	}
-	//! Destructor
-	virtual ~SchedulingAgent()
-	{
-
-	}
-	//! onTrigger, return whether the yield is need
-	bool onTrigger(Processor *processor);
-	//! Whether agent has work to do
-	bool hasWorkToDo(Processor *processor);
-	//! Whether the outgoing need to be backpressure
-	bool hasTooMuchOutGoing(Processor *processor);
-	//! start
-	void start() {
-		_running = true;
-	}
-	//! stop
-	void stop() {
-		_running = false;
-	}
-
-public:
-	//! schedule, overwritten by different DrivenSchedulingAgent
-	virtual void schedule(Processor *processor) = 0;
-	//! unschedule, overwritten by different DrivenSchedulingAgent
-	virtual void unschedule(Processor *processor) = 0;
-
-protected:
-	//! Logger
-	Logger *_logger;
-	//! Configure
-	Configure *_configure;
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Whether it is running
-	std::atomic<bool> _running;
-	//! AdministrativeYieldDuration
-	int64_t _administrativeYieldDuration;
-	//! BoredYieldDuration
-	int64_t _boredYieldDuration;
-
-private:
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	SchedulingAgent(const SchedulingAgent &parent);
-	SchedulingAgent &operator=(const SchedulingAgent &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Site2SiteClientProtocol.h
----------------------------------------------------------------------
diff --git a/inc/Site2SiteClientProtocol.h b/inc/Site2SiteClientProtocol.h
deleted file mode 100644
index 5b72b11..0000000
--- a/inc/Site2SiteClientProtocol.h
+++ /dev/null
@@ -1,638 +0,0 @@
-/**
- * @file Site2SiteClientProtocol.h
- * Site2SiteClientProtocol class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __SITE2SITE_CLIENT_PROTOCOL_H__
-#define __SITE2SITE_CLIENT_PROTOCOL_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <string>
-#include <errno.h>
-#include <chrono>
-#include <thread>
-#include <algorithm>
-#include <uuid/uuid.h>
-#include "Logger.h"
-#include "Configure.h"
-#include "Property.h"
-#include "Site2SitePeer.h"
-#include "FlowFileRecord.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-//! Resource Negotiated Status Code
-#define RESOURCE_OK 20
-#define DIFFERENT_RESOURCE_VERSION 21
-#define NEGOTIATED_ABORT 255
-// ! Max attributes
-#define MAX_NUM_ATTRIBUTES 25000
-
-/**
- * An enumeration for specifying the direction in which data should be
- * transferred between a client and a remote NiFi instance.
- */
-typedef enum {
-	/**
-	 * * The client is to send data to the remote instance.
-	 * */
-	SEND,
-	/**
-	 * * The client is to receive data from the remote instance.
-	 * */
-	RECEIVE
-} TransferDirection;
-
-
-//! Peer State
-typedef enum {
-	/**
-	 * * IDLE
-	 * */
-	IDLE = 0,
-	/**
-	 * * Socket Established
-	 * */
-	ESTABLISHED,
-	/**
-	 * * HandShake Done
-	 * */
-	HANDSHAKED,
-	/**
-	 * * After CodeDec Completion
-	 * */
-	READY
-} PeerState;
-
-//! Transaction State
-typedef enum {
-	/**
-	 * * Transaction has been started but no data has been sent or received.
-	 * */
-	TRANSACTION_STARTED,
-	/**
-	 * * Transaction has been started and data has been sent or received.
-	 * */
-	DATA_EXCHANGED,
-	/**
-	 * * Data that has been transferred has been confirmed via its CRC.
-	 * * Transaction is ready to be completed.
-	 * */
-	TRANSACTION_CONFIRMED,
-	/**
-	 * * Transaction has been successfully completed.
-	 * */
-	TRANSACTION_COMPLETED,
-	/**
-	 * * The Transaction has been canceled.
-	 * */
-	TRANSACTION_CANCELED,
-	/**
-	 * * The Transaction ended in an error.
-	 * */
-	TRANSACTION_ERROR
-} TransactionState;
-
-//! Request Type
-typedef enum {
-    NEGOTIATE_FLOWFILE_CODEC = 0,
-    REQUEST_PEER_LIST,
-    SEND_FLOWFILES,
-    RECEIVE_FLOWFILES,
-    SHUTDOWN,
-	MAX_REQUEST_TYPE
-} RequestType;
-
-//! Request Type Str
-static const char *RequestTypeStr[MAX_REQUEST_TYPE] =
-{
-		"NEGOTIATE_FLOWFILE_CODEC",
-		"REQUEST_PEER_LIST",
-		"SEND_FLOWFILES",
-		"RECEIVE_FLOWFILES",
-		"SHUTDOWN"
-};
-
-//! Respond Code
-typedef enum {
-		RESERVED = 0,
-		// ResponseCode, so that we can indicate a 0 followed by some other bytes
-
-		// handshaking properties
-		PROPERTIES_OK = 1,
-		UNKNOWN_PROPERTY_NAME = 230,
-		ILLEGAL_PROPERTY_VALUE = 231,
-		MISSING_PROPERTY = 232,
-		// transaction indicators
-		CONTINUE_TRANSACTION = 10,
-		FINISH_TRANSACTION = 11,
-		CONFIRM_TRANSACTION = 12, // "Explanation" of this code is the checksum
-		TRANSACTION_FINISHED = 13,
-		TRANSACTION_FINISHED_BUT_DESTINATION_FULL = 14,
-		CANCEL_TRANSACTION = 15,
-		BAD_CHECKSUM = 19,
-		// data availability indicators
-		MORE_DATA = 20,
-		NO_MORE_DATA = 21,
-		// port state indicators
-		UNKNOWN_PORT = 200,
-		PORT_NOT_IN_VALID_STATE = 201,
-		PORTS_DESTINATION_FULL = 202,
-		// authorization
-		UNAUTHORIZED = 240,
-		// error indicators
-		ABORT = 250,
-		UNRECOGNIZED_RESPONSE_CODE = 254,
-		END_OF_STREAM = 255
-} RespondCode;
-
-//! Respond Code Class
-typedef struct {
-	RespondCode code;
-	const char *description;
-	bool hasDescription;
-} RespondCodeContext;
-
-//! Respond Code Context
-static RespondCodeContext respondCodeContext[]  =
-{
-		{RESERVED, "Reserved for Future Use", false},
-		{PROPERTIES_OK, "Properties OK", false},
-		{UNKNOWN_PROPERTY_NAME, "Unknown Property Name", true},
-		{ILLEGAL_PROPERTY_VALUE, "Illegal Property Value", true},
-		{MISSING_PROPERTY, "Missing Property", true},
-		{CONTINUE_TRANSACTION, "Continue Transaction", false},
-		{FINISH_TRANSACTION, "Finish Transaction", false},
-		{CONFIRM_TRANSACTION, "Confirm Transaction", true},
-		{TRANSACTION_FINISHED, "Transaction Finished", false},
-		{TRANSACTION_FINISHED_BUT_DESTINATION_FULL, "Transaction Finished But Destination is Full", false},
-		{CANCEL_TRANSACTION, "Cancel Transaction", true},
-		{BAD_CHECKSUM, "Bad Checksum", false},
-		{MORE_DATA, "More Data Exists", false},
-		{NO_MORE_DATA, "No More Data Exists", false},
-		{UNKNOWN_PORT, "Unknown Port", false},
-	    {PORT_NOT_IN_VALID_STATE, "Port Not in a Valid State", true},
-		{PORTS_DESTINATION_FULL, "Port's Destination is Full", false},
-		{UNAUTHORIZED, "User Not Authorized", true},
-		{ABORT, "Abort", true},
-		{UNRECOGNIZED_RESPONSE_CODE, "Unrecognized Response Code", false},
-		{END_OF_STREAM, "End of Stream", false}
-};
-
-//! Respond Code Sequence Pattern
-static const uint8_t CODE_SEQUENCE_VALUE_1 = (uint8_t) 'R';
-static const uint8_t CODE_SEQUENCE_VALUE_2 = (uint8_t) 'C';
-
-/**
- * Enumeration of Properties that can be used for the Site-to-Site Socket
- * Protocol.
- */
-typedef enum {
-		/**
-		 * Boolean value indicating whether or not the contents of a FlowFile should
-		 * be GZipped when transferred.
-		 */
-		GZIP,
-		/**
-		 * The unique identifier of the port to communicate with
-		 */
-		PORT_IDENTIFIER,
-		/**
-		 * Indicates the number of milliseconds after the request was made that the
-		 * client will wait for a response. If no response has been received by the
-		 * time this value expires, the server can move on without attempting to
-		 * service the request because the client will have already disconnected.
-		 */
-		REQUEST_EXPIRATION_MILLIS,
-		/**
-		 * The preferred number of FlowFiles that the server should send to the
-		 * client when pulling data. This property was introduced in version 5 of
-		 * the protocol.
-		 */
-		BATCH_COUNT,
-		/**
-		 * The preferred number of bytes that the server should send to the client
-		 * when pulling data. This property was introduced in version 5 of the
-		 * protocol.
-		 */
-		BATCH_SIZE,
-		/**
-		 * The preferred amount of time that the server should send data to the
-		 * client when pulling data. This property was introduced in version 5 of
-		 * the protocol. Value is in milliseconds.
-		 */
-		BATCH_DURATION,
-		MAX_HANDSHAKE_PROPERTY
-} HandshakeProperty;
-
-//! HandShakeProperty Str
-static const char *HandShakePropertyStr[MAX_HANDSHAKE_PROPERTY] =
-{
-		/**
-		 * Boolean value indicating whether or not the contents of a FlowFile should
-		 * be GZipped when transferred.
-		 */
-		"GZIP",
-		/**
-		 * The unique identifier of the port to communicate with
-		 */
-		"PORT_IDENTIFIER",
-		/**
-		 * Indicates the number of milliseconds after the request was made that the
-		 * client will wait for a response. If no response has been received by the
-		 * time this value expires, the server can move on without attempting to
-		 * service the request because the client will have already disconnected.
-		 */
-		"REQUEST_EXPIRATION_MILLIS",
-		/**
-		 * The preferred number of FlowFiles that the server should send to the
-		 * client when pulling data. This property was introduced in version 5 of
-		 * the protocol.
-		 */
-		"BATCH_COUNT",
-		/**
-		 * The preferred number of bytes that the server should send to the client
-		 * when pulling data. This property was introduced in version 5 of the
-		 * protocol.
-		 */
-		"BATCH_SIZE",
-		/**
-		 * The preferred amount of time that the server should send data to the
-		 * client when pulling data. This property was introduced in version 5 of
-		 * the protocol. Value is in milliseconds.
-		 */
-		"BATCH_DURATION"
-};
-
-class Site2SiteClientProtocol;
-
-//! Transaction Class
-class Transaction
-{
-	friend class Site2SiteClientProtocol;
-public:
-	//! Constructor
-	/*!
-	 * Create a new transaction
-	 */
-	Transaction(TransferDirection direction) {
-		_state = TRANSACTION_STARTED;
-		_direction = direction;
-		_dataAvailable = false;
-		_transfers = 0;
-		_bytes = 0;
-
-		char uuidStr[37];
-
-		// Generate the global UUID for the transaction
-		uuid_generate(_uuid);
-		uuid_unparse(_uuid, uuidStr);
-		_uuidStr = uuidStr;
-	}
-	//! Destructor
-	virtual ~Transaction()
-	{
-	}
-	//! getUUIDStr
-	std::string getUUIDStr()
-	{
-		return _uuidStr;
-	}
-	//! getState
-	TransactionState getState()
-	{
-		return _state;
-	}
-	//! isDataAvailable
-	bool isDataAvailable()
-	{
-		return _dataAvailable;
-	}
-	//! setDataAvailable()
-	void setDataAvailable(bool value)
-	{
-		_dataAvailable = value;
-	}
-	//! getDirection
-	TransferDirection getDirection()
-	{
-		return _direction;
-	}
-	//! getCRC
-	long getCRC()
-	{
-		return _crc.getCRC();
-	}
-	//! updateCRC
-	void updateCRC(uint8_t *buffer, uint32_t length)
-	{
-		_crc.update(buffer, length);
-	}
-
-protected:
-
-private:
-	//! Transaction State
-	TransactionState _state;
-	//! Transaction Direction
-	TransferDirection _direction;
-	//! Whether received data is available
-	bool _dataAvailable;
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! UUID string
-	std::string _uuidStr;
-	//! Number of transfer
-	int _transfers;
-	//! Number of content bytes
-	uint64_t _bytes;
-	//! CRC32
-	CRC32 _crc;
-
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Transaction(const Transaction &parent);
-	Transaction &operator=(const Transaction &parent);
-};
-
-/**
- * Represents a piece of data that is to be sent to or that was received from a
- * NiFi instance.
- */
-class DataPacket
-{
-public:
-	DataPacket(Site2SiteClientProtocol *protocol, Transaction *transaction,
-			std::map<std::string, std::string> attributes) {
-		_protocol = protocol;
-		_size = 0;
-		_transaction = transaction;
-		_attributes = attributes;
-	}
-	std::map<std::string, std::string> _attributes;
-	uint64_t _size;
-	Site2SiteClientProtocol *_protocol;
-	Transaction *_transaction;
-};
-
-//! Site2SiteClientProtocol Class
-class Site2SiteClientProtocol
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new control protocol
-	 */
-	Site2SiteClientProtocol(Site2SitePeer *peer) {
-		_logger = Logger::getLogger();
-		_configure = Configure::getConfigure();
-		_peer = peer;
-		_batchSize = 0;
-		_batchCount = 0;
-		_batchDuration = 0;
-		_batchSendNanos = 5000000000; // 5 seconds
-		_timeOut = 30000; // 30 seconds
-		_peerState = IDLE;
-		_supportedVersion[0] = 5;
-		_supportedVersion[1] = 4;
-		_supportedVersion[2] = 3;
-		_supportedVersion[3] = 2;
-		_supportedVersion[4] = 1;
-		_currentVersion = _supportedVersion[0];
-		_currentVersionIndex = 0;
-		_supportedCodecVersion[0] = 1;
-		_currentCodecVersion = _supportedCodecVersion[0];
-		_currentCodecVersionIndex = 0;
-	}
-	//! Destructor
-	virtual ~Site2SiteClientProtocol()
-	{
-	}
-
-public:
-	//! setBatchSize
-	void setBatchSize(uint64_t size)
-	{
-		_batchSize = size;
-	}
-	//! setBatchCount
-	void setBatchCount(uint64_t count)
-	{
-		_batchCount = count;
-	}
-	//! setBatchDuration
-	void setBatchDuration(uint64_t duration)
-	{
-		_batchDuration = duration;
-	}
-	//! setTimeOut
-	void setTimeOut(uint64_t time)
-	{
-		_timeOut = time;
-		if (_peer)
-			_peer->setTimeOut(time);
-
-	}
-	//! getTimeout
-	uint64_t getTimeOut()
-	{
-		return _timeOut;
-	}
-	//! setPortId
-	void setPortId(uuid_t id)
-	{
-		uuid_copy(_portId, id);
-		char idStr[37];
-		uuid_unparse(id, idStr);
-		_portIdStr = idStr;
-	}
-	//! getResourceName
-	std::string getResourceName()
-	{
-		return "SocketFlowFileProtocol";
-	}
-	//! getCodecResourceName
-	std::string getCodecResourceName()
-	{
-		return "StandardFlowFileCodec";
-	}
-	//! bootstrap the protocol to the ready for transaction state by going through the state machine
-	bool bootstrap();
-	//! establish
-	bool establish();
-	//! handShake
-	bool handShake();
-	//! negotiateCodec
-	bool negotiateCodec();
-	//! initiateResourceNegotiation
-	bool initiateResourceNegotiation();
-	//! initiateCodecResourceNegotiation
-	bool initiateCodecResourceNegotiation();
-	//! tearDown
-	void tearDown();
-	//! write Request Type
-	int writeRequestType(RequestType type);
-	//! read Request Type
-	int readRequestType(RequestType &type);
-	//! read Respond
-	int readRespond(RespondCode &code, std::string &message);
-	//! write respond
-	int writeRespond(RespondCode code, std::string message);
-	//! getRespondCodeContext
-	RespondCodeContext *getRespondCodeContext(RespondCode code)
-	{
-		for (unsigned int i = 0; i < sizeof(respondCodeContext)/sizeof(RespondCodeContext); i++)
-		{
-			if (respondCodeContext[i].code == code)
-			{
-				return &respondCodeContext[i];
-			}
-		}
-		return NULL;
-	}
-	//! getPeer
-	Site2SitePeer *getPeer()
-	{
-		return _peer;
-	}
-	//! Creation of a new transaction, return the transaction ID if success,
-	//! Return NULL when any error occurs
-	Transaction *createTransaction(std::string &transactionID, TransferDirection direction);
-	//! Receive the data packet from the transaction
-	//! Return false when any error occurs
-	bool receive(std::string transactionID, DataPacket *packet, bool &eof);
-	//! Send the data packet from the transaction
-	//! Return false when any error occurs
-	bool send(std::string transactionID, DataPacket *packet, FlowFileRecord *flowFile, ProcessSession *session);
-	//! Confirm the data that was sent or received by comparing CRC32's of the data sent and the data received.
-	bool confirm(std::string transactionID);
-	//! Cancel the transaction
-	void cancel(std::string transactionID);
-	//! Complete the transaction
-	bool complete(std::string transactionID);
-	//! Error the transaction
-	void error(std::string transactionID);
-	//! Receive flow files for the process session
-	void receiveFlowFiles(ProcessContext *context, ProcessSession *session);
-	//! Transfer flow files for the process session
-	void transferFlowFiles(ProcessContext *context, ProcessSession *session);
-	//! deleteTransaction
-	void deleteTransaction(std::string transactionID);
-	//! Nest Callback Class for write stream
-	class WriteCallback : public OutputStreamCallback
-	{
-		public:
-		WriteCallback(DataPacket *packet)
-		: _packet(packet) {}
-		DataPacket *_packet;
-		void process(std::ofstream *stream) {
-			uint8_t buffer[8192];
-			int len = _packet->_size;
-			while (len > 0)
-			{
-				int size = std::min(len, (int) sizeof(buffer));
-				int ret = _packet->_protocol->_peer->readData(buffer, size, &_packet->_transaction->_crc);
-				if (ret != size)
-				{
-					_packet->_protocol->_logger->log_error("Site2Site Receive Flow Size %d Failed %d", size, ret);
-					break;
-				}
-				stream->write((const char *) buffer, size);
-				len -= size;
-			}
-		}
-	};
-	//! Nest Callback Class for read stream
-	class ReadCallback : public InputStreamCallback
-	{
-		public:
-		ReadCallback(DataPacket *packet)
-		: _packet(packet) {}
-		DataPacket *_packet;
-		void process(std::ifstream *stream) {
-			_packet->_size = 0;
-			uint8_t buffer[8192];
-			int readSize;
-			while (stream->good())
-			{
-				if (!stream->read((char *)buffer, 8192))
-					readSize = stream->gcount();
-				else
-					readSize = 8192;
-				int ret = _packet->_protocol->_peer->write(buffer, readSize, &_packet->_transaction->_crc);
-				if (ret != readSize)
-				{
-					_packet->_protocol->_logger->log_error("Site2Site Send Flow Size %d Failed %d", readSize, ret);
-					break;
-				}
-				_packet->_size += readSize;
-			}
-		}
-	};
-
-protected:
-
-private:
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Logger
-	Logger *_logger;
-	//! Configure
-	Configure *_configure;
-	//! Batch Count
-	std::atomic<uint64_t> _batchCount;
-	//! Batch Size
-	std::atomic<uint64_t> _batchSize;
-	//! Batch Duration in msec
-	std::atomic<uint64_t> _batchDuration;
-	//! Timeout in msec
-	std::atomic<uint64_t> _timeOut;
-	//! Peer Connection
-	Site2SitePeer *_peer;
-	//! portId
-	uuid_t _portId;
-	//! portIDStr
-	std::string _portIdStr;
-	//! BATCH_SEND_NANOS
-	uint64_t _batchSendNanos;
-	//! Peer State
-	PeerState _peerState;
-	uint32_t _supportedVersion[5];
-	uint32_t _currentVersion;
-	int _currentVersionIndex;
-	uint32_t _supportedCodecVersion[1];
-	uint32_t _currentCodecVersion;
-	int _currentCodecVersionIndex;
-	//! commsIdentifier
-	std::string _commsIdentifier;
-	//! transaction map
-	std::map<std::string, Transaction *> _transactionMap;
-
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Site2SiteClientProtocol(const Site2SiteClientProtocol &parent);
-	Site2SiteClientProtocol &operator=(const Site2SiteClientProtocol &parent);
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Site2SitePeer.h
----------------------------------------------------------------------
diff --git a/inc/Site2SitePeer.h b/inc/Site2SitePeer.h
deleted file mode 100644
index ff11637..0000000
--- a/inc/Site2SitePeer.h
+++ /dev/null
@@ -1,364 +0,0 @@
-/**
- * @file Site2SitePeer.h
- * Site2SitePeer class declaration for site to site peer  
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __SITE2SITE_PEER_H__
-#define __SITE2SITE_PEER_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <string>
-#include <errno.h>
-#include <mutex>
-#include <atomic>
-#include "TimeUtil.h"
-#include "Logger.h"
-#include "Configure.h"
-#include "Property.h"
-
-class CRC32
-{
-public:
-    CRC32() {
-    	crc = 0;
-
-    	if (tableInit)
-    		return;
-
-    	tableInit = true;
-        unsigned int poly = 0xedb88320;
-        unsigned int temp = 0;
-        for(unsigned int i = 0; i < 256; ++i) {
-            temp = i;
-            for(int j = 8; j > 0; --j) {
-                if((temp & 1) == 1) {
-                    temp = (unsigned int)((temp >> 1) ^ poly);
-                }else {
-                    temp >>= 1;
-                }
-            }
-            table[i] = temp;
-        }
-    }
-
-    unsigned int update(uint8_t * bytes, size_t size) {
-    	crc = crc ^ ~0U;
-        for(unsigned int i = 0; i < size; ++i) {
-            uint8_t index = (uint8_t)(((crc) & 0xff) ^ bytes[i]);
-            crc = (unsigned int)((crc >> 8) ^ table[index]);
-        }
-        crc = crc ^ ~0U;
-        return crc;
-    }
-
-    long getCRC()
-    {
-    	return crc;
-    }
-
-private:
-    static unsigned int table[256];
-    static std::atomic<bool> tableInit;
-    unsigned int crc;
-};
-
-static const char MAGIC_BYTES[] = {'N', 'i', 'F', 'i'};
-
-//! Site2SitePeer Class
-class Site2SitePeer
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new site2site peer
-	 */
-	Site2SitePeer(std::string host, uint16_t port) {
-		_logger = Logger::getLogger();
-		_configure = Configure::getConfigure();
-		_socket = 0;
-		_host = host;
-		_port = port;
-		_yieldExpiration = 0;
-		_timeOut = 30000; // 30 seconds
-		_url = "nifi://" + _host + ":" + std::to_string(_port);
-	}
-	//! Destructor
-	virtual ~Site2SitePeer() { Close();}
-	//! Set Processor yield period in MilliSecond
-	void setYieldPeriodMsec(uint64_t period) {
-		_yieldPeriodMsec = period;
-	}
-	//! get URL
-	std::string getURL() {
-		return _url;
-	}
-	//! Get Processor yield period in MilliSecond
-	uint64_t getYieldPeriodMsec(void) {
-		return(_yieldPeriodMsec);
-	}
-	//! Yield based on the yield period
-	void yield()
-	{
-		_yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
-	}
-	//! setHostName
-	void setHostName(std::string host)
-	{
-		_host = host;
-		_url = "nifi://" + _host + ":" + std::to_string(_port);
-	}
-	//! setPort
-	void setPort(uint16_t port)
-	{
-		_port = port;
-		_url = "nifi://" + _host + ":" + std::to_string(_port);
-	}
-	//! getHostName
-	std::string getHostName()
-	{
-		return _host;
-	}
-	//! getPort
-	uint16_t getPort()
-	{
-		return _port;
-	}
-	//! Yield based on the input time
-	void yield(uint64_t time)
-	{
-		_yieldExpiration = (getTimeMillis() + time);
-	}
-	//! whether need be to yield
-	bool isYield()
-	{
-		if (_yieldExpiration > 0)
-			return (_yieldExpiration >= getTimeMillis());
-		else
-			return false;
-	}
-	// clear yield expiration
-	void clearYield()
-	{
-		_yieldExpiration = 0;
-	}
-	//! Yield based on the yield period
-	void yield(std::string portId)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		uint64_t yieldExpiration = (getTimeMillis() + _yieldPeriodMsec);
-		_yieldExpirationPortIdMap[portId] = yieldExpiration;
-	}
-	//! Yield based on the input time
-	void yield(std::string portId, uint64_t time)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		uint64_t yieldExpiration = (getTimeMillis() + time);
-		_yieldExpirationPortIdMap[portId] = yieldExpiration;
-	}
-	//! whether need be to yield
-	bool isYield(std::string portId)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		std::map<std::string, uint64_t>::iterator it = this->_yieldExpirationPortIdMap.find(portId);
-		if (it != _yieldExpirationPortIdMap.end())
-		{
-			uint64_t yieldExpiration = it->second;
-			return (yieldExpiration >= getTimeMillis());
-		}
-		else
-		{
-			return false;
-		}
-	}
-	//! clear yield expiration
-	void clearYield(std::string portId)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		std::map<std::string, uint64_t>::iterator it = this->_yieldExpirationPortIdMap.find(portId);
-		if (it != _yieldExpirationPortIdMap.end())
-		{
-			_yieldExpirationPortIdMap.erase(portId);
-		}
-	}
-	//! setTimeOut
-	void setTimeOut(uint64_t time)
-	{
-		_timeOut = time;
-	}
-	//! getTimeOut
-	uint64_t getTimeOut()
-	{
-		return _timeOut;
-	}
-	int write(uint8_t value, CRC32 *crc = NULL)
-	{
-		return sendData(&value, 1, crc);
-	}
-	int write(char value, CRC32 *crc = NULL)
-	{
-		return sendData((uint8_t *)&value, 1, crc);
-	}
-	int write(uint32_t value, CRC32 *crc = NULL)
-	{
-		uint8_t temp[4];
-
-		temp[0] = (value & 0xFF000000) >> 24;
-		temp[1] = (value & 0x00FF0000) >> 16;
-		temp[2] = (value & 0x0000FF00) >> 8;
-		temp[3] = (value & 0x000000FF);
-		return sendData(temp, 4, crc);
-	}
-	int write(uint16_t value, CRC32 *crc = NULL)
-	{
-		uint8_t temp[2];
-		temp[0] = (value & 0xFF00) >> 8;
-		temp[1] = (value & 0xFF);
-		return sendData(temp, 2, crc);
-	}
-	int write(uint8_t *value, int len, CRC32 *crc = NULL)
-	{
-		return sendData(value, len, crc);
-	}
-	int write(uint64_t value, CRC32 *crc = NULL)
-	{
-		uint8_t temp[8];
-
-		temp[0] = (value >> 56) & 0xFF;
-		temp[1] = (value >> 48) & 0xFF;
-		temp[2] = (value >> 40) & 0xFF;
-		temp[3] = (value >> 32) & 0xFF;
-		temp[4] = (value >> 24) & 0xFF;
-		temp[5] = (value >> 16) & 0xFF;
-		temp[6] = (value >>  8) & 0xFF;
-		temp[7] = (value >>  0) & 0xFF;
-		return sendData(temp, 8, crc);
-	}
-	int write(bool value, CRC32 *crc = NULL)
-	{
-		uint8_t temp = value;
-		return write(temp, crc);
-	}
-	int writeUTF(std::string str, bool widen = false, CRC32 *crc = NULL);
-	int read(uint8_t &value, CRC32 *crc = NULL)
-	{
-		uint8_t buf;
-
-		int ret = readData(&buf, 1, crc);
-		if (ret == 1)
-			value = buf;
-		return ret;
-	}
-	int read(uint16_t &value, CRC32 *crc = NULL)
-	{
-		uint8_t buf[2];
-
-		int ret = readData(buf, 2, crc);
-		if (ret == 2)
-			value = (buf[0] << 8) | buf[1];
-		return ret;
-	}
-	int read(char &value, CRC32 *crc = NULL)
-	{
-		uint8_t buf;
-
-		int ret = readData(&buf, 1, crc);
-		if (ret == 1)
-			value = (char) buf;
-		return ret;
-	}
-	int read(uint8_t *value, int len, CRC32 *crc = NULL)
-	{
-		return readData(value, len, crc);
-	}
-	int read(uint32_t &value, CRC32 *crc = NULL)
-	{
-		uint8_t buf[4];
-
-		int ret = readData(buf, 4, crc);
-		if (ret == 4)
-			value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-		return ret;
-	}
-	int read(uint64_t &value, CRC32 *crc = NULL)
-	{
-		uint8_t buf[8];
-
-		int ret = readData(buf, 8, crc);
-		if (ret == 8)
-		{
-			value = ((uint64_t) buf[0] << 56) |
-					((uint64_t) (buf[1] & 255) << 48) |
-					((uint64_t) (buf[2] & 255) << 40) |
-					((uint64_t) (buf[3] & 255) << 32) |
-					((uint64_t) (buf[4] & 255) << 24) |
-					((uint64_t) (buf[5] & 255) << 16) |
-					((uint64_t) (buf[6] & 255) <<  8) |
-					((uint64_t) (buf[7] & 255) <<  0);
-		}
-		return ret;
-	}
-	int readUTF(std::string &str, bool widen = false, CRC32 *crc = NULL);
-	//! open connection to the peer
-	bool Open();
-	//! close connection to the peer
-	void Close();
-	//! Send Data via the socket, return -1 for failure
-	int sendData(uint8_t *buf, int buflen, CRC32 *crc = NULL);
-	//! Read length into buf, return -1 for failure and 0 for EOF
-	int readData(uint8_t *buf, int buflen, CRC32 *crc = NULL);
-	//! Select on the socket
-	int Select(int msec);
-
-protected:
-
-private:
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! S2S server Name
-	std::string _host;
-	//! S2S server port
-	uint16_t _port;
-	//! socket to server
-	int _socket;
-	//! URL
-	std::string _url;
-	//! socket timeout;
-	std::atomic<uint64_t> _timeOut;
-	//! Logger
-	Logger *_logger;
-	//! Configure
-	Configure *_configure;
-	//! Yield Period in Milliseconds
-	std::atomic<uint64_t> _yieldPeriodMsec;
-	//! Yield Expiration
-	std::atomic<uint64_t> _yieldExpiration;
-	//! Yield Expiration per destination PortID
-	std::map<std::string, uint64_t> _yieldExpirationPortIdMap;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Site2SitePeer(const Site2SitePeer &parent);
-	Site2SitePeer &operator=(const Site2SitePeer &parent);
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/TailFile.h
----------------------------------------------------------------------
diff --git a/inc/TailFile.h b/inc/TailFile.h
deleted file mode 100644
index 5c4ba09..0000000
--- a/inc/TailFile.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * @file TailFile.h
- * TailFile class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __TAIL_FILE_H__
-#define __TAIL_FILE_H__
-
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! TailFile Class
-class TailFile : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	TailFile(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-		_stateRecovered = false;
-	}
-	//! Destructor
-	virtual ~TailFile()
-	{
-		storeState();
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property FileName;
-	static Property StateFile;
-	//! Supported Relationships
-	static Relationship Success;
-
-public:
-	//! OnTrigger method, implemented by NiFi TailFile
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi TailFile
-	virtual void initialize(void);
-	//! recoverState
-	void recoverState();
-	//! storeState
-	void storeState();
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-	std::string _fileLocation;
-	//! Property Specified Tailed File Name
-	std::string _fileName;
-	//! File to save state
-	std::string _stateFile;
-	//! State related to the tailed file
-	std::string _currentTailFileName;
-	uint64_t _currentTailFilePosition;
-	bool _stateRecovered;
-	uint64_t _currentTailFileCreatedTime;
-	//! Utils functions for parse state file
-	std::string trimLeft(const std::string& s);
-	std::string trimRight(const std::string& s);
-	void parseStateFileLine(char *buf);
-	void checkRollOver();
-
-};
-
-//! Matched File Item for Roll over check
-typedef struct {
-	std::string fileName;
-	uint64_t modifiedTime;
-} TailMatchedFileItem;
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/TimeUtil.h
----------------------------------------------------------------------
diff --git a/inc/TimeUtil.h b/inc/TimeUtil.h
deleted file mode 100644
index b024245..0000000
--- a/inc/TimeUtil.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * @file TimeUtil.h
- * Basic Time Utility 
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __TIME_UTIL_H__
-#define __TIME_UTIL_H__
-
-#include <time.h>
-#include <sys/time.h>
-#include <string.h>
-#include <unistd.h>
-#include <string.h>
-#include <iostream>
-
-#ifdef __MACH__
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
-inline uint64_t getTimeMillis()
-{
-	uint64_t value;
-
-	timeval time;
-	gettimeofday(&time, NULL);
-	value = ((uint64_t) (time.tv_sec) * 1000) + (time.tv_usec / 1000);
-
-	return value;
-}
-
-inline uint64_t getTimeNano()
-{
-	struct timespec ts;
-	
-#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
-	clock_serv_t cclock;
-	mach_timespec_t mts;
-	host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
-	clock_get_time(cclock, &mts);
-	mach_port_deallocate(mach_task_self(), cclock);
-	ts.tv_sec = mts.tv_sec;
-	ts.tv_nsec = mts.tv_nsec;
-#else
-	clock_gettime(CLOCK_REALTIME, &ts);
-#endif
-
-	return ((uint64_t) (ts.tv_sec) * 1000000000 + ts.tv_nsec);
-}
-
-//! Convert millisecond since UTC to a time display string
-inline std::string getTimeStr(uint64_t msec)
-{
-	char date[120];
-	time_t second = (time_t) (msec/1000);
-	msec = msec % 1000;
-	strftime(date, sizeof(date) / sizeof(*date), "%Y-%m-%d %H:%M:%S",
-	             localtime(&second));
-
-	std::string ret = date;
-	date[0] = '\0';
-	sprintf(date, ".%03llu", (unsigned long long) msec);
-
-	ret += date;
-	return ret;
-}
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/TimerDrivenSchedulingAgent.h
----------------------------------------------------------------------
diff --git a/inc/TimerDrivenSchedulingAgent.h b/inc/TimerDrivenSchedulingAgent.h
deleted file mode 100644
index 9195745..0000000
--- a/inc/TimerDrivenSchedulingAgent.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * @file TimerDrivenSchedulingAgent.h
- * TimerDrivenSchedulingAgent class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __TIMER_DRIVEN_SCHEDULING_AGENT_H__
-#define __TIMER_DRIVEN_SCHEDULING_AGENT_H__
-
-#include "Logger.h"
-#include "Configure.h"
-#include "Processor.h"
-#include "ProcessContext.h"
-#include "SchedulingAgent.h"
-
-//! TimerDrivenSchedulingAgent Class
-class TimerDrivenSchedulingAgent : public SchedulingAgent
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	TimerDrivenSchedulingAgent()
-	: SchedulingAgent()
-	{
-	}
-	//! Destructor
-	virtual ~TimerDrivenSchedulingAgent()
-	{
-	}
-	//! Run function for the thread
-	static void run(TimerDrivenSchedulingAgent *agent, Processor *processor);
-
-public:
-	//! schedule, overwritten by different DrivenTimerDrivenSchedulingAgent
-	virtual void schedule(Processor *processor);
-	//! unschedule, overwritten by different DrivenTimerDrivenSchedulingAgent
-	virtual void unschedule(Processor *processor);
-
-protected:
-
-private:
-	//! Threads
-	std::map<std::string, std::vector<std::thread *>> _threads;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	TimerDrivenSchedulingAgent(const TimerDrivenSchedulingAgent &parent);
-	TimerDrivenSchedulingAgent &operator=(const TimerDrivenSchedulingAgent &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/async_logger.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/async_logger.h b/inc/spdlog/async_logger.h
deleted file mode 100644
index 517ce92..0000000
--- a/inc/spdlog/async_logger.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-// Very fast asynchronous logger (millions of logs per second on an average desktop)
-// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
-// Creates a single back thread to pop messages from the queue and log them.
-//
-// Upon each log write the logger:
-//    1. Checks if its log level is enough to log the message
-//    2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
-//    3. will throw spdlog_ex upon log exceptions
-// Upong destruction, logs all remaining messages in the queue before destructing..
-
-#include <chrono>
-#include <functional>
-#include "common.h"
-#include "logger.h"
-#include "spdlog.h"
-
-
-namespace spdlog
-{
-
-namespace details
-{
-class async_log_helper;
-}
-
-class async_logger :public logger
-{
-public:
-    template<class It>
-    async_logger(const std::string& name,
-                 const It& begin,
-                 const It& end,
-                 size_t queue_size,
-                 const async_overflow_policy overflow_policy =  async_overflow_policy::block_retry,
-                 const std::function<void()>& worker_warmup_cb = nullptr,
-                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
-    async_logger(const std::string& logger_name,
-                 sinks_init_list sinks,
-                 size_t queue_size,
-                 const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
-                 const std::function<void()>& worker_warmup_cb = nullptr,
-                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
-    async_logger(const std::string& logger_name,
-                 sink_ptr single_sink,
-                 size_t queue_size,
-                 const async_overflow_policy overflow_policy =  async_overflow_policy::block_retry,
-                 const std::function<void()>& worker_warmup_cb = nullptr,
-                 const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
-
-
-protected:
-    void _log_msg(details::log_msg& msg) override;
-    void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
-    void _set_pattern(const std::string& pattern) override;
-
-private:
-    std::unique_ptr<details::async_log_helper> _async_log_helper;
-};
-}
-
-
-#include "./details/async_logger_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/common.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/common.h b/inc/spdlog/common.h
deleted file mode 100644
index cde5a9e..0000000
--- a/inc/spdlog/common.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <string>
-#include <initializer_list>
-#include <chrono>
-#include <memory>
-
-//visual studio does not support noexcept yet
-#ifndef _MSC_VER
-#define SPDLOG_NOEXCEPT noexcept
-#else
-#define SPDLOG_NOEXCEPT throw()
-#endif
-
-
-namespace spdlog
-{
-
-class formatter;
-
-namespace sinks
-{
-class sink;
-}
-
-// Common types across the lib
-using log_clock = std::chrono::system_clock;
-using sink_ptr = std::shared_ptr < sinks::sink > ;
-using sinks_init_list = std::initializer_list < sink_ptr > ;
-using formatter_ptr = std::shared_ptr<spdlog::formatter>;
-
-
-//Log level enum
-namespace level
-{
-typedef enum
-{
-    trace    = 0,
-    debug    = 1,
-    info     = 2,
-    notice   = 3,
-    warn     = 4,
-    err      = 5,
-    critical = 6,
-    alert    = 7,
-    emerg    = 8,
-    off      = 9
-} level_enum;
-
-static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
-
-static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
-
-inline const char* to_str(spdlog::level::level_enum l)
-{
-    return level_names[l];
-}
-
-inline const char* to_short_str(spdlog::level::level_enum l)
-{
-    return short_level_names[l];
-}
-} //level
-
-
-//
-// Async overflow policy - block by default.
-//
-enum class async_overflow_policy
-{
-    block_retry, // Block / yield / sleep until message can be enqueued
-    discard_log_msg // Discard the message it enqueue fails
-};
-
-
-//
-// Log exception
-//
-class spdlog_ex : public std::exception
-{
-public:
-    spdlog_ex(const std::string& msg) :_msg(msg) {}
-    const char* what() const SPDLOG_NOEXCEPT override
-    {
-        return _msg.c_str();
-    }
-private:
-    std::string _msg;
-
-};
-
-} //spdlog


[07/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Connection.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Connection.cpp b/libminifi/src/Connection.cpp
new file mode 100644
index 0000000..e036b89
--- /dev/null
+++ b/libminifi/src/Connection.cpp
@@ -0,0 +1,160 @@
+/**
+ * @file Connection.cpp
+ * Connection class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <iostream>
+
+#include "Connection.h"
+
+Connection::Connection(std::string name, uuid_t uuid, uuid_t srcUUID, uuid_t destUUID)
+: _name(name)
+{
+	if (!uuid)
+		// Generate the global UUID for the flow record
+		uuid_generate(_uuid);
+	else
+		uuid_copy(_uuid, uuid);
+
+	if (srcUUID)
+		uuid_copy(_srcUUID, srcUUID);
+	if (destUUID)
+		uuid_copy(_destUUID, destUUID);
+
+	_srcProcessor = NULL;
+	_destProcessor = NULL;
+	_maxQueueSize = 0;
+	_maxQueueDataSize = 0;
+	_expiredDuration = 0;
+	_queuedDataSize = 0;
+
+	_logger = Logger::getLogger();
+
+	_logger->log_info("Connection %s created", _name.c_str());
+}
+
+bool Connection::isEmpty()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	return _queue.empty();
+}
+
+bool Connection::isFull()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_maxQueueSize <= 0 && _maxQueueDataSize <= 0)
+		// No back pressure setting
+		return false;
+
+	if (_maxQueueSize > 0 && _queue.size() >= _maxQueueSize)
+		return true;
+
+	if (_maxQueueDataSize > 0 && _queuedDataSize >= _maxQueueDataSize)
+		return true;
+
+	return false;
+}
+
+void Connection::put(FlowFileRecord *flow)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_queue.push(flow);
+
+	_queuedDataSize += flow->getSize();
+
+	_logger->log_debug("Enqueue flow file UUID %s to connection %s",
+			flow->getUUIDStr().c_str(), _name.c_str());
+}
+
+FlowFileRecord* Connection::poll(std::set<FlowFileRecord *> &expiredFlowRecords)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	while (!_queue.empty())
+	{
+		FlowFileRecord *item = _queue.front();
+		_queue.pop();
+		_queuedDataSize -= item->getSize();
+
+		if (_expiredDuration > 0)
+		{
+			// We need to check for flow expiration
+			if (getTimeMillis() > (item->getEntryDate() + _expiredDuration))
+			{
+				// Flow record expired
+				expiredFlowRecords.insert(item);
+			}
+			else
+			{
+				// Flow record not expired
+				if (item->isPenalized())
+				{
+					// Flow record was penalized
+					_queue.push(item);
+					_queuedDataSize += item->getSize();
+					break;
+				}
+				item->setOriginalConnection(this);
+				_logger->log_debug("Dequeue flow file UUID %s from connection %s",
+						item->getUUIDStr().c_str(), _name.c_str());
+				return item;
+			}
+		}
+		else
+		{
+			// Flow record not expired
+			if (item->isPenalized())
+			{
+				// Flow record was penalized
+				_queue.push(item);
+				_queuedDataSize += item->getSize();
+				break;
+			}
+			item->setOriginalConnection(this);
+			_logger->log_debug("Dequeue flow file UUID %s from connection %s",
+					item->getUUIDStr().c_str(), _name.c_str());
+			return item;
+		}
+	}
+
+	return NULL;
+}
+
+void Connection::drain()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	while (!_queue.empty())
+	{
+		FlowFileRecord *item = _queue.front();
+		_queue.pop();
+		delete item;
+	}
+
+	_logger->log_debug("Drain connection %s", _name.c_str());
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/FlowControlProtocol.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/FlowControlProtocol.cpp b/libminifi/src/FlowControlProtocol.cpp
new file mode 100644
index 0000000..011ebcf
--- /dev/null
+++ b/libminifi/src/FlowControlProtocol.cpp
@@ -0,0 +1,541 @@
+/**
+ * @file FlowControlProtocol.cpp
+ * FlowControlProtocol class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/time.h>
+#include <stdio.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <random>
+#include <netinet/tcp.h>
+#include <iostream>
+#include "FlowController.h"
+#include "FlowControlProtocol.h"
+
+int FlowControlProtocol::connectServer(const char *host, uint16_t port)
+{
+	in_addr_t addr;
+	int sock = 0;
+	struct hostent *h;
+#ifdef __MACH__
+	h = gethostbyname(host);
+#else
+	char buf[1024];
+	struct hostent he;
+	int hh_errno;
+	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
+#endif
+	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0)
+	{
+		_logger->log_error("Could not create socket to hostName %s", host);
+		return 0;
+	}
+
+#ifndef __MACH__
+	int opt = 1;
+	bool nagle_off = true;
+
+	if (nagle_off)
+	{
+		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() TCP_NODELAY failed");
+			close(sock);
+			return 0;
+		}
+		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+				(char *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() SO_REUSEADDR failed");
+			close(sock);
+			return 0;
+		}
+	}
+
+	int sndsize = 256*1024;
+	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
+	{
+		_logger->log_error("setsockopt() SO_SNDBUF failed");
+		close(sock);
+		return 0;
+	}
+#endif
+
+	struct sockaddr_in sa;
+	socklen_t socklen;
+	int status;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = htonl(INADDR_ANY);
+	sa.sin_port = htons(0);
+	socklen = sizeof(sa);
+	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
+	{
+		_logger->log_error("socket bind failed");
+		close(sock);
+		return 0;
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = addr;
+	sa.sin_port = htons(port);
+	socklen = sizeof(sa);
+
+	status = connect(sock, (struct sockaddr *)&sa, socklen);
+
+	if (status < 0)
+	{
+		_logger->log_error("socket connect failed to %s %d", host, port);
+		close(sock);
+		return 0;
+	}
+
+	_logger->log_info("Flow Control Protocol socket %d connect to server %s port %d success", sock, host, port);
+
+	return sock;
+}
+
+int FlowControlProtocol::sendData(uint8_t *buf, int buflen)
+{
+	int ret = 0, bytes = 0;
+
+	while (bytes < buflen)
+	{
+		ret = send(_socket, buf+bytes, buflen-bytes, 0);
+		//check for errors
+		if (ret == -1)
+		{
+			return ret;
+		}
+		bytes+=ret;
+	}
+
+	return bytes;
+}
+
+int FlowControlProtocol::selectClient(int msec)
+{
+	fd_set fds;
+	struct timeval tv;
+    int retval;
+    int fd = _socket;
+
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+
+    tv.tv_sec = msec/1000;
+    tv.tv_usec = (msec % 1000) * 1000;
+
+    if (msec > 0)
+       retval = select(fd+1, &fds, NULL, NULL, &tv);
+    else
+       retval = select(fd+1, &fds, NULL, NULL, NULL);
+
+    if (retval <= 0)
+      return retval;
+    if (FD_ISSET(fd, &fds))
+      return retval;
+    else
+      return 0;
+}
+
+int FlowControlProtocol::readData(uint8_t *buf, int buflen)
+{
+	int sendSize = buflen;
+
+	while (buflen)
+	{
+		int status;
+		status = selectClient(MAX_READ_TIMEOUT);
+		if (status <= 0)
+		{
+			return status;
+		}
+#ifndef __MACH__
+		status = read(_socket, buf, buflen);
+#else
+		status = recv(_socket, buf, buflen, 0);
+#endif
+		if (status <= 0)
+		{
+			return status;
+		}
+		buflen -= status;
+		buf += status;
+	}
+
+	return sendSize;
+}
+
+int FlowControlProtocol::readHdr(FlowControlProtocolHeader *hdr)
+{
+	uint8_t buffer[sizeof(FlowControlProtocolHeader)];
+
+	uint8_t *data = buffer;
+
+	int status = readData(buffer, sizeof(FlowControlProtocolHeader));
+	if (status <= 0)
+		return status;
+
+	uint32_t value;
+	data = this->decode(data, value);
+	hdr->msgType = value;
+
+	data = this->decode(data, value);
+	hdr->seqNumber = value;
+
+	data = this->decode(data, value);
+	hdr->status = value;
+
+	data = this->decode(data, value);
+	hdr->payloadLen = value;
+
+	return sizeof(FlowControlProtocolHeader);
+}
+
+void FlowControlProtocol::start()
+{
+	if (_reportInterval <= 0)
+		return;
+	if (_running)
+		return;
+	_running = true;
+	_logger->log_info("FlowControl Protocol Start");
+	_thread = new std::thread(run, this);
+	_thread->detach();
+}
+
+void FlowControlProtocol::stop()
+{
+	if (!_running)
+		return;
+	_running = false;
+	_logger->log_info("FlowControl Protocol Stop");
+}
+
+void FlowControlProtocol::run(FlowControlProtocol *protocol)
+{
+	while (protocol->_running)
+	{
+		std::this_thread::sleep_for(std::chrono::milliseconds(protocol->_reportInterval));
+		if (!protocol->_registered)
+		{
+			// if it is not register yet
+			protocol->sendRegisterReq();
+			// protocol->_controller->reload("flow.xml");
+		}
+		else
+			protocol->sendReportReq();
+	}
+	return;
+}
+
+int FlowControlProtocol::sendRegisterReq()
+{
+	if (_registered)
+	{
+		_logger->log_info("Already registered");
+		return -1;
+	}
+
+	uint16_t port = this->_serverPort;
+
+	if (this->_socket <= 0)
+		this->_socket = connectServer(_serverName.c_str(), port);
+
+	if (this->_socket <= 0)
+		return -1;
+
+	// Calculate the total payload msg size
+	uint32_t payloadSize = FlowControlMsgIDEncodingLen(FLOW_SERIAL_NUMBER, 0) +
+			FlowControlMsgIDEncodingLen(FLOW_XML_NAME, this->_controller->getName().size()+1);
+	uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
+
+	uint8_t *data = new uint8_t[size];
+	uint8_t *start = data;
+
+	// encode the HDR
+	FlowControlProtocolHeader hdr;
+	hdr.msgType = REGISTER_REQ;
+	hdr.payloadLen = payloadSize;
+	hdr.seqNumber  = this->_seqNumber;
+	hdr.status = RESP_SUCCESS;
+	data = this->encode(data, hdr.msgType);
+	data = this->encode(data, hdr.seqNumber);
+	data = this->encode(data, hdr.status);
+	data = this->encode(data, hdr.payloadLen);
+
+	// encode the serial number
+	data = this->encode(data, FLOW_SERIAL_NUMBER);
+	data = this->encode(data, this->_serialNumber, 8);
+
+	// encode the XML name
+	data = this->encode(data, FLOW_XML_NAME);
+	data = this->encode(data, this->_controller->getName());
+
+	// send it
+	int status = sendData(start, size);
+	delete[] start;
+	if (status <= 0)
+	{
+		close(_socket);
+		_socket = 0;
+		_logger->log_error("Flow Control Protocol Send Register Req failed");
+		return -1;
+	}
+
+	// Looking for register respond
+	status = readHdr(&hdr);
+
+	if (status <= 0)
+	{
+		close(_socket);
+		_socket = 0;
+		_logger->log_error("Flow Control Protocol Read Register Resp header failed");
+		return -1;
+	}
+	_logger->log_info("Flow Control Protocol receive MsgType %s", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
+	_logger->log_info("Flow Control Protocol receive Seq Num %d", hdr.seqNumber);
+	_logger->log_info("Flow Control Protocol receive Resp Code %s", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
+	_logger->log_info("Flow Control Protocol receive Payload len %d", hdr.payloadLen);
+
+	if (hdr.status == RESP_SUCCESS && hdr.seqNumber == this->_seqNumber)
+	{
+		this->_registered = true;
+		this->_seqNumber++;
+		_logger->log_info("Flow Control Protocol Register success");
+		uint8_t *payload = new uint8_t[hdr.payloadLen];
+		uint8_t *payloadPtr = payload;
+		status = readData(payload, hdr.payloadLen);
+		if (status <= 0)
+		{
+			delete[] payload;
+			_logger->log_info("Flow Control Protocol Register Read Payload fail");
+			close(_socket);
+			_socket = 0;
+			return -1;
+		}
+		while (payloadPtr < (payload + hdr.payloadLen))
+		{
+			uint32_t msgID;
+			payloadPtr = this->decode(payloadPtr, msgID);
+			if (((FlowControlMsgID) msgID) == REPORT_INTERVAL)
+			{
+				// Fixed 4 bytes
+				uint32_t reportInterval;
+				payloadPtr = this->decode(payloadPtr, reportInterval);
+				_logger->log_info("Flow Control Protocol receive report interval %d ms", reportInterval);
+				this->_reportInterval = reportInterval;
+			}
+			else if (((FlowControlMsgID) msgID) == FLOW_XML_CONTENT)
+			{
+				uint32_t xmlLen;
+				payloadPtr = this->decode(payloadPtr, xmlLen);
+				_logger->log_info("Flow Control Protocol receive XML content length %d", xmlLen);
+				time_t rawtime;
+				struct tm *timeinfo;
+				time(&rawtime);
+				timeinfo = localtime(&rawtime);
+				std::string xmlFileName = "flow.";
+				xmlFileName += asctime(timeinfo);
+				xmlFileName += ".xml";
+				std::ofstream fs;
+				fs.open(xmlFileName.c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
+				if (fs.is_open())
+				{
+					fs.write((const char *)payloadPtr, xmlLen);
+					fs.close();
+					this->_controller->reload(xmlFileName.c_str());
+				}
+			}
+			else
+			{
+				break;
+			}
+		}
+		delete[] payload;
+		close(_socket);
+		_socket = 0;
+		return 0;
+	}
+	else
+	{
+		_logger->log_info("Flow Control Protocol Register fail");
+		close(_socket);
+		_socket = 0;
+		return -1;
+	}
+}
+
+
+int FlowControlProtocol::sendReportReq()
+{
+	uint16_t port = this->_serverPort;
+
+	if (this->_socket <= 0)
+		this->_socket = connectServer(_serverName.c_str(), port);
+
+	if (this->_socket <= 0)
+		return -1;
+
+	// Calculate the total payload msg size
+	uint32_t payloadSize =
+			FlowControlMsgIDEncodingLen(FLOW_XML_NAME, this->_controller->getName().size()+1);
+	uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
+
+	uint8_t *data = new uint8_t[size];
+	uint8_t *start = data;
+
+	// encode the HDR
+	FlowControlProtocolHeader hdr;
+	hdr.msgType = REPORT_REQ;
+	hdr.payloadLen = payloadSize;
+	hdr.seqNumber  = this->_seqNumber;
+	hdr.status = RESP_SUCCESS;
+	data = this->encode(data, hdr.msgType);
+	data = this->encode(data, hdr.seqNumber);
+	data = this->encode(data, hdr.status);
+	data = this->encode(data, hdr.payloadLen);
+
+	// encode the XML name
+	data = this->encode(data, FLOW_XML_NAME);
+	data = this->encode(data, this->_controller->getName());
+
+	// send it
+	int status = sendData(start, size);
+	delete[] start;
+	if (status <= 0)
+	{
+		close(_socket);
+		_socket = 0;
+		_logger->log_error("Flow Control Protocol Send Report Req failed");
+		return -1;
+	}
+
+	// Looking for report respond
+	status = readHdr(&hdr);
+
+	if (status <= 0)
+	{
+		close(_socket);
+		_socket = 0;
+		_logger->log_error("Flow Control Protocol Read Report Resp header failed");
+		return -1;
+	}
+	_logger->log_info("Flow Control Protocol receive MsgType %s", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
+	_logger->log_info("Flow Control Protocol receive Seq Num %d", hdr.seqNumber);
+	_logger->log_info("Flow Control Protocol receive Resp Code %s", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
+	_logger->log_info("Flow Control Protocol receive Payload len %d", hdr.payloadLen);
+
+	if (hdr.status == RESP_SUCCESS && hdr.seqNumber == this->_seqNumber)
+	{
+		this->_seqNumber++;
+		uint8_t *payload = new uint8_t[hdr.payloadLen];
+		uint8_t *payloadPtr = payload;
+		status = readData(payload, hdr.payloadLen);
+		if (status <= 0)
+		{
+			delete[] payload;
+			_logger->log_info("Flow Control Protocol Report Resp Read Payload fail");
+			close(_socket);
+			_socket = 0;
+			return -1;
+		}
+		std::string processor;
+		std::string propertyName;
+		std::string propertyValue;
+		while (payloadPtr < (payload + hdr.payloadLen))
+		{
+			uint32_t msgID;
+			payloadPtr = this->decode(payloadPtr, msgID);
+			if (((FlowControlMsgID) msgID) == PROCESSOR_NAME)
+			{
+				uint32_t len;
+				payloadPtr = this->decode(payloadPtr, len);
+				processor = (const char *) payloadPtr;
+				payloadPtr += len;
+				_logger->log_info("Flow Control Protocol receive report resp processor %s", processor.c_str());
+			}
+			else if (((FlowControlMsgID) msgID) == PROPERTY_NAME)
+			{
+				uint32_t len;
+				payloadPtr = this->decode(payloadPtr, len);
+				propertyName = (const char *) payloadPtr;
+				payloadPtr += len;
+				_logger->log_info("Flow Control Protocol receive report resp property name %s", propertyName.c_str());
+			}
+			else if (((FlowControlMsgID) msgID) == PROPERTY_VALUE)
+			{
+				uint32_t len;
+				payloadPtr = this->decode(payloadPtr, len);
+				propertyValue = (const char *) payloadPtr;
+				payloadPtr += len;
+				_logger->log_info("Flow Control Protocol receive report resp property value %s", propertyValue.c_str());
+				this->_controller->updatePropertyValue(processor, propertyName, propertyValue);
+			}
+			else
+			{
+				break;
+			}
+		}
+		delete[] payload;
+		close(_socket);
+		_socket = 0;
+		return 0;
+	}
+	else if (hdr.status == RESP_TRIGGER_REGISTER && hdr.seqNumber == this->_seqNumber)
+	{
+		_logger->log_info("Flow Control Protocol trigger reregister");
+		this->_registered = false;
+		this->_seqNumber++;
+		close(_socket);
+		_socket = 0;
+		return 0;
+	}
+	else if (hdr.status == RESP_STOP_FLOW_CONTROLLER && hdr.seqNumber == this->_seqNumber)
+	{
+		_logger->log_info("Flow Control Protocol stop flow controller");
+		this->_controller->stop(true);
+		this->_seqNumber++;
+		close(_socket);
+		_socket = 0;
+		return 0;
+	}
+	else if (hdr.status == RESP_START_FLOW_CONTROLLER && hdr.seqNumber == this->_seqNumber)
+	{
+		_logger->log_info("Flow Control Protocol start flow controller");
+		this->_controller->start();
+		this->_seqNumber++;
+		close(_socket);
+		_socket = 0;
+		return 0;
+	}
+	else
+	{
+		_logger->log_info("Flow Control Protocol Report fail");
+		close(_socket);
+		_socket = 0;
+		return -1;
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/FlowController.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/FlowController.cpp b/libminifi/src/FlowController.cpp
new file mode 100644
index 0000000..8fbe3dc
--- /dev/null
+++ b/libminifi/src/FlowController.cpp
@@ -0,0 +1,1190 @@
+/**
+ * @file FlowController.cpp
+ * FlowController class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "FlowController.h"
+#include "ProcessContext.h"
+
+FlowController::FlowController(std::string name)
+: _name(name)
+{
+	uuid_generate(_uuid);
+
+	// Setup the default values
+	_configurationFileName = DEFAULT_FLOW_YAML_FILE_NAME;
+	_maxEventDrivenThreads = DEFAULT_MAX_EVENT_DRIVEN_THREAD;
+	_maxTimerDrivenThreads = DEFAULT_MAX_TIMER_DRIVEN_THREAD;
+	_running = false;
+	_initialized = false;
+	_root = NULL;
+	_logger = Logger::getLogger();
+	_protocol = new FlowControlProtocol(this);
+
+	// NiFi config properties
+	_configure = Configure::getConfigure();
+
+	std::string rawConfigFileString;
+	_configure->get(Configure::nifi_flow_configuration_file, rawConfigFileString);
+
+	if (!rawConfigFileString.empty())
+	{
+		_configurationFileName = rawConfigFileString;
+	}
+
+	char *path = NULL;
+	char full_path[PATH_MAX];
+
+	std::string adjustedFilename;
+	if (!_configurationFileName.empty())
+	{
+		// perform a naive determination if this is a relative path
+		if (_configurationFileName.c_str()[0] != '/')
+		{
+			adjustedFilename = adjustedFilename + _configure->getHome() + "/" + _configurationFileName;
+		}
+		else
+		{
+			adjustedFilename = _configurationFileName;
+		}
+	}
+
+	path = realpath(adjustedFilename.c_str(), full_path);
+	if (!path)
+	{
+		_logger->log_error("Could not locate path from provided configuration file name.");
+	}
+
+	std::string pathString(path);
+	_configurationFileName = pathString;
+	_logger->log_info("FlowController NiFi Configuration file %s", pathString.c_str());
+
+	// Create repos for flow record and provenance
+
+	_logger->log_info("FlowController %s created", _name.c_str());
+}
+
+FlowController::~FlowController()
+{
+	stop(true);
+	unload();
+	delete _protocol;
+}
+
+bool FlowController::isRunning()
+{
+	return (_running);
+}
+
+bool FlowController::isInitialized()
+{
+	return (_initialized);
+}
+
+void FlowController::stop(bool force)
+{
+	if (_running)
+	{
+		_logger->log_info("Stop Flow Controller");
+		this->_timerScheduler.stop();
+		// Wait for sometime for thread stop
+		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+		if (this->_root)
+			this->_root->stopProcessing(&this->_timerScheduler);
+		_running = false;
+	}
+}
+
+void FlowController::unload()
+{
+	if (_running)
+	{
+		stop(true);
+	}
+	if (_initialized)
+	{
+		_logger->log_info("Unload Flow Controller");
+		if (_root)
+			delete _root;
+		_root = NULL;
+		_initialized = false;
+		_name = "";
+	}
+
+	return;
+}
+
+void FlowController::reload(std::string xmlFile)
+{
+	_logger->log_info("Starting to reload Flow Controller with xml %s", xmlFile.c_str());
+	stop(true);
+	unload();
+	std::string oldxmlFile = this->_configurationFileName;
+	this->_configurationFileName = xmlFile;
+	load(ConfigFormat::XML);
+	start();
+	if (!this->_root)
+	{
+		this->_configurationFileName = oldxmlFile;
+		_logger->log_info("Rollback Flow Controller to xml %s", oldxmlFile.c_str());
+		stop(true);
+		unload();
+		load(ConfigFormat::XML);
+		start();
+	}
+}
+
+Processor *FlowController::createProcessor(std::string name, uuid_t uuid)
+{
+	Processor *processor = NULL;
+	if (name == GenerateFlowFile::ProcessorName)
+	{
+		processor = new GenerateFlowFile(name, uuid);
+	}
+	else if (name == LogAttribute::ProcessorName)
+	{
+		processor = new LogAttribute(name, uuid);
+	}
+	else if (name == RealTimeDataCollector::ProcessorName)
+	{
+		processor = new RealTimeDataCollector(name, uuid);
+	}
+	else if (name == GetFile::ProcessorName)
+	{
+		processor = new GetFile(name, uuid);
+	}
+	else if (name == TailFile::ProcessorName)
+	{
+		processor = new TailFile(name, uuid);
+	}
+	else if (name == ListenSyslog::ProcessorName)
+	{
+		processor = new ListenSyslog(name, uuid);
+	}
+	else if (name == ExecuteProcess::ProcessorName)
+	{
+		processor = new ExecuteProcess(name, uuid);
+	}
+	else
+	{
+		_logger->log_error("No Processor defined for %s", name.c_str());
+		return NULL;
+	}
+
+	//! initialize the processor
+	processor->initialize();
+
+	return processor;
+}
+
+ProcessGroup *FlowController::createRootProcessGroup(std::string name, uuid_t uuid)
+{
+	return new ProcessGroup(ROOT_PROCESS_GROUP, name, uuid);
+}
+
+ProcessGroup *FlowController::createRemoteProcessGroup(std::string name, uuid_t uuid)
+{
+	return new ProcessGroup(REMOTE_PROCESS_GROUP, name, uuid);
+}
+
+Connection *FlowController::createConnection(std::string name, uuid_t uuid)
+{
+	return new Connection(name, uuid);
+}
+
+void FlowController::parseConnection(xmlDoc *doc, xmlNode *node, ProcessGroup *parent)
+{
+	uuid_t uuid;
+	xmlNode *currentNode;
+	Connection *connection = NULL;
+
+	if (!parent)
+	{
+		_logger->log_error("parseProcessNode: no parent group existed");
+		return;
+	}
+
+	// generate the random UIID
+	uuid_generate(uuid);
+
+	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next)
+	{
+		if (currentNode->type == XML_ELEMENT_NODE)
+		{
+			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0)
+			{
+				char *id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseConnection: id => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				char *name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseConnection: name => [%s]", name);
+					connection = this->createConnection(name, uuid);
+					if (connection == NULL) {
+						xmlFree(name);
+						return;
+					}
+					xmlFree(name);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "sourceId") == 0) {
+				char *id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseConnection: sourceId => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+					if (connection)
+						connection->setSourceProcessorUUID(uuid);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "destinationId") == 0) {
+				char *id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseConnection: destinationId => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+					if (connection)
+						connection->setDestinationProcessorUUID(uuid);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxWorkQueueSize") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				int64_t maxWorkQueueSize = 0;
+				if (temp) {
+					if (Property::StringToInt(temp, maxWorkQueueSize)) {
+						_logger->log_debug("parseConnection: maxWorkQueueSize => [%d]", maxWorkQueueSize);
+						if (connection)
+							connection->setMaxQueueSize(maxWorkQueueSize);
+
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxWorkQueueDataSize") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				int64_t maxWorkQueueDataSize = 0;
+				if (temp) {
+					if (Property::StringToInt(temp, maxWorkQueueDataSize)) {
+						_logger->log_debug("parseConnection: maxWorkQueueDataSize => [%d]", maxWorkQueueDataSize);
+						if (connection)
+							connection->setMaxQueueDataSize(maxWorkQueueDataSize);
+
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "relationship") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					std::string relationshipName = temp;
+					if (!relationshipName.empty()) {
+						Relationship relationship(relationshipName, "");
+						_logger->log_debug("parseConnection: relationship => [%s]", relationshipName.c_str());
+						if (connection)
+							connection->setRelationship(relationship);
+					} else {
+						Relationship empty;
+						_logger->log_debug("parseConnection: relationship => [%s]", empty.getName().c_str());
+						if (connection)
+							connection->setRelationship(empty);
+					}
+					xmlFree(temp);
+				}
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // for node
+
+	if (connection)
+		parent->addConnection(connection);
+
+	return;
+}
+
+void FlowController::parseRootProcessGroup(xmlDoc *doc, xmlNode *node) {
+	uuid_t uuid;
+	xmlNode *currentNode;
+	ProcessGroup *group = NULL;
+
+	// generate the random UIID
+	uuid_generate(uuid);
+
+	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+		if (currentNode->type == XML_ELEMENT_NODE) {
+			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
+				char *id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseRootProcessGroup: id => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				char *name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseRootProcessGroup: name => [%s]", name);
+					group = this->createRootProcessGroup(name, uuid);
+					if (group == NULL) {
+						xmlFree(name);
+						return;
+					}
+					// Set the root process group
+					this->_root = group;
+					this->_name = name;
+					xmlFree(name);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "processor") == 0) {
+				this->parseProcessorNode(doc, currentNode, group);
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "connection") == 0) {
+				this->parseConnection(doc, currentNode, group);
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "remoteProcessGroup") == 0) {
+				this->parseRemoteProcessGroup(doc, currentNode, group);
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // for node
+}
+
+void FlowController::parseRootProcessGroupYaml(YAML::Node rootFlowNode) {
+	uuid_t uuid;
+	ProcessGroup *group = NULL;
+
+	// generate the random UIID
+	uuid_generate(uuid);
+
+	std::string flowName = rootFlowNode["name"].as<std::string>();
+
+	char uuidStr[37];
+	uuid_unparse(_uuid, uuidStr);
+	_logger->log_debug("parseRootProcessGroup: id => [%s]", uuidStr);
+	_logger->log_debug("parseRootProcessGroup: name => [%s]", flowName.c_str());
+	group = this->createRootProcessGroup(flowName, uuid);
+	this->_root = group;
+	this->_name = flowName;
+}
+
+void FlowController::parseProcessorNodeYaml(YAML::Node processorsNode, ProcessGroup *parentGroup) {
+	int64_t schedulingPeriod = -1;
+	int64_t penalizationPeriod = -1;
+	int64_t yieldPeriod = -1;
+	int64_t runDurationNanos = -1;
+	uuid_t uuid;
+	Processor *processor = NULL;
+
+	if (!parentGroup) {
+		_logger->log_error("parseProcessNodeYaml: no parent group exists");
+		return;
+	}
+
+	if (processorsNode) {
+		// Evaluate sequence of processors
+		int numProcessors = processorsNode.size();
+		if (numProcessors < 1) {
+			throw new std::invalid_argument("There must be at least one processor configured.");
+		}
+
+		std::vector<ProcessorConfig> processorConfigs;
+
+		if (processorsNode.IsSequence()) {
+			for (YAML::const_iterator iter = processorsNode.begin(); iter != processorsNode.end(); ++iter) {
+				ProcessorConfig procCfg;
+				YAML::Node procNode = iter->as<YAML::Node>();
+
+				procCfg.name = procNode["name"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: name => [%s]", procCfg.name.c_str());
+				procCfg.javaClass = procNode["class"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: class => [%s]", procCfg.javaClass.c_str());
+
+				char uuidStr[37];
+				uuid_unparse(_uuid, uuidStr);
+
+				// generate the random UUID
+				uuid_generate(uuid);
+
+				// Determine the processor name only from the Java class
+				int lastOfIdx = procCfg.javaClass.find_last_of(".");
+				if (lastOfIdx != std::string::npos) {
+					lastOfIdx++; // if a value is found, increment to move beyond the .
+					int nameLength = procCfg.javaClass.length() - lastOfIdx;
+					std::string processorName = procCfg.javaClass.substr(lastOfIdx, nameLength);
+					processor = this->createProcessor(processorName, uuid);
+				}
+
+				if (!processor) {
+					_logger->log_error("Could not create a processor %s with name %s", procCfg.name.c_str(), uuidStr);
+					throw std::invalid_argument("Could not create processor " + procCfg.name);
+				}
+				processor->setName(procCfg.name);
+
+				procCfg.maxConcurrentTasks = procNode["max concurrent tasks"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: max concurrent tasks => [%s]", procCfg.maxConcurrentTasks.c_str());
+				procCfg.schedulingStrategy = procNode["scheduling strategy"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: scheduling strategy => [%s]",
+						procCfg.schedulingStrategy.c_str());
+				procCfg.schedulingPeriod = procNode["scheduling period"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: scheduling period => [%s]", procCfg.schedulingPeriod.c_str());
+				procCfg.penalizationPeriod = procNode["penalization period"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: penalization period => [%s]",
+						procCfg.penalizationPeriod.c_str());
+				procCfg.yieldPeriod = procNode["yield period"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: yield period => [%s]", procCfg.yieldPeriod.c_str());
+				procCfg.yieldPeriod = procNode["run duration nanos"].as<std::string>();
+				_logger->log_debug("parseProcessorNode: run duration nanos => [%s]", procCfg.runDurationNanos.c_str());
+
+				// handle auto-terminated relationships
+				YAML::Node autoTerminatedSequence = procNode["auto-terminated relationships list"];
+				std::vector<std::string> rawAutoTerminatedRelationshipValues;
+				if (autoTerminatedSequence.IsSequence() && !autoTerminatedSequence.IsNull()
+						&& autoTerminatedSequence.size() > 0) {
+					for (YAML::const_iterator relIter = autoTerminatedSequence.begin();
+							relIter != autoTerminatedSequence.end(); ++relIter) {
+						std::string autoTerminatedRel = relIter->as<std::string>();
+						rawAutoTerminatedRelationshipValues.push_back(autoTerminatedRel);
+					}
+				}
+				procCfg.autoTerminatedRelationships = rawAutoTerminatedRelationshipValues;
+
+				// handle processor properties
+				YAML::Node propertiesNode = procNode["Properties"];
+				parsePropertiesNodeYaml(&propertiesNode, processor);
+
+				// Take care of scheduling
+				TimeUnit unit;
+				if (Property::StringToTime(procCfg.schedulingPeriod, schedulingPeriod, unit)
+						&& Property::ConvertTimeUnitToNS(schedulingPeriod, unit, schedulingPeriod)) {
+					_logger->log_debug("convert: parseProcessorNode: schedulingPeriod => [%d] ns", schedulingPeriod);
+					processor->setSchedulingPeriodNano(schedulingPeriod);
+				}
+
+				if (Property::StringToTime(procCfg.penalizationPeriod, penalizationPeriod, unit)
+						&& Property::ConvertTimeUnitToMS(penalizationPeriod, unit, penalizationPeriod)) {
+					_logger->log_debug("convert: parseProcessorNode: penalizationPeriod => [%d] ms",
+							penalizationPeriod);
+					processor->setPenalizationPeriodMsec(penalizationPeriod);
+				}
+
+				if (Property::StringToTime(procCfg.yieldPeriod, yieldPeriod, unit)
+						&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod)) {
+					_logger->log_debug("convert: parseProcessorNode: yieldPeriod => [%d] ms", yieldPeriod);
+					processor->setYieldPeriodMsec(yieldPeriod);
+				}
+
+				// Default to running
+				processor->setScheduledState(RUNNING);
+
+				if (procCfg.schedulingStrategy == "TIMER_DRIVEN") {
+					processor->setSchedulingStrategy(TIMER_DRIVEN);
+					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
+				} else if (procCfg.schedulingStrategy == "EVENT_DRIVEN") {
+					processor->setSchedulingStrategy(EVENT_DRIVEN);
+					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
+				} else {
+					processor->setSchedulingStrategy(CRON_DRIVEN);
+					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
+
+				}
+
+				int64_t maxConcurrentTasks;
+				if (Property::StringToInt(procCfg.maxConcurrentTasks, maxConcurrentTasks)) {
+					_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
+					processor->setMaxConcurrentTasks(maxConcurrentTasks);
+				}
+
+				if (Property::StringToInt(procCfg.runDurationNanos, runDurationNanos)) {
+					_logger->log_debug("parseProcessorNode: runDurationNanos => [%d]", runDurationNanos);
+					processor->setRunDurationNano(runDurationNanos);
+				}
+
+				std::set<Relationship> autoTerminatedRelationships;
+				for (auto&& relString : procCfg.autoTerminatedRelationships) {
+					Relationship relationship(relString, "");
+					_logger->log_debug("parseProcessorNode: autoTerminatedRelationship  => [%s]", relString.c_str());
+					autoTerminatedRelationships.insert(relationship);
+				}
+
+				processor->setAutoTerminatedRelationships(autoTerminatedRelationships);
+
+				parentGroup->addProcessor(processor);
+			}
+		}
+	} else {
+		throw new std::invalid_argument(
+				"Cannot instantiate a MiNiFi instance without a defined Processors configuration node.");
+	}
+}
+
+void FlowController::parseRemoteProcessGroupYaml(YAML::Node *rpgNode, ProcessGroup *parentGroup) {
+	uuid_t uuid;
+
+	if (!parentGroup) {
+		_logger->log_error("parseRemoteProcessGroupYaml: no parent group exists");
+		return;
+	}
+
+	if (rpgNode) {
+		if (rpgNode->IsSequence()) {
+			for (YAML::const_iterator iter = rpgNode->begin(); iter != rpgNode->end(); ++iter) {
+				YAML::Node rpgNode = iter->as<YAML::Node>();
+
+				auto name = rpgNode["name"].as<std::string>();
+				_logger->log_debug("parseRemoteProcessGroupYaml: name => [%s]", name.c_str());
+
+				std::string url = rpgNode["url"].as<std::string>();
+				_logger->log_debug("parseRemoteProcessGroupYaml: url => [%s]", url.c_str());
+
+				std::string timeout = rpgNode["timeout"].as<std::string>();
+				_logger->log_debug("parseRemoteProcessGroupYaml: timeout => [%s]", timeout.c_str());
+
+				std::string yieldPeriod = rpgNode["yield period"].as<std::string>();
+				_logger->log_debug("parseRemoteProcessGroupYaml: yield period => [%s]", yieldPeriod.c_str());
+
+				YAML::Node inputPorts = rpgNode["Input Ports"].as<YAML::Node>();
+				ProcessGroup* group = NULL;
+
+				// generate the random UUID
+				uuid_generate(uuid);
+
+				char uuidStr[37];
+				uuid_unparse(_uuid, uuidStr);
+
+				int64_t timeoutValue = -1;
+				int64_t yieldPeriodValue = -1;
+
+				group = this->createRemoteProcessGroup(name.c_str(), uuid);
+				group->setParent(parentGroup);
+				parentGroup->addProcessGroup(group);
+
+				TimeUnit unit;
+
+				if (Property::StringToTime(yieldPeriod, yieldPeriodValue, unit)
+							&& Property::ConvertTimeUnitToMS(yieldPeriodValue, unit, yieldPeriodValue) && group) {
+					_logger->log_debug("parseRemoteProcessGroupYaml: yieldPeriod => [%d] ms", yieldPeriodValue);
+					group->setYieldPeriodMsec(yieldPeriodValue);
+				}
+
+				if (Property::StringToTime(timeout, timeoutValue, unit)
+					&& Property::ConvertTimeUnitToMS(timeoutValue, unit, timeoutValue) && group) {
+					_logger->log_debug("parseRemoteProcessGroupYaml: timeoutValue => [%d] ms", timeoutValue);
+					group->setTimeOut(timeoutValue);
+				}
+
+				group->setTransmitting(true);
+				group->setURL(url);
+
+				if (inputPorts.IsSequence()) {
+					for (YAML::const_iterator portIter = inputPorts.begin(); portIter != inputPorts.end(); ++portIter) {
+						_logger->log_debug("Got a current port, iterating...");
+
+						YAML::Node currPort = portIter->as<YAML::Node>();
+
+						this->parsePortYaml(&currPort, group, SEND);
+					} // for node
+				}
+			}
+		}
+	}
+}
+
+void FlowController::parseConnectionYaml(YAML::Node *connectionsNode, ProcessGroup *parent) {
+	uuid_t uuid;
+	Connection *connection = NULL;
+
+	if (!parent) {
+		_logger->log_error("parseProcessNode: no parent group was provided");
+		return;
+	}
+
+	if (connectionsNode) {
+		int numConnections = connectionsNode->size();
+		if (numConnections < 1) {
+			throw new std::invalid_argument("There must be at least one connection configured.");
+		}
+
+		if (connectionsNode->IsSequence()) {
+			for (YAML::const_iterator iter = connectionsNode->begin(); iter != connectionsNode->end(); ++iter) {
+				// generate the random UIID
+				uuid_generate(uuid);
+
+				YAML::Node connectionNode = iter->as<YAML::Node>();
+
+				std::string name = connectionNode["name"].as<std::string>();
+				std::string destName = connectionNode["destination name"].as<std::string>();
+
+				char uuidStr[37];
+				uuid_unparse(_uuid, uuidStr);
+
+				_logger->log_debug("Created connection with UUID %s and name %s", uuidStr, name.c_str());
+				connection = this->createConnection(name, uuid);
+				auto rawRelationship = connectionNode["source relationship name"].as<std::string>();
+				Relationship relationship(rawRelationship, "");
+				_logger->log_debug("parseConnection: relationship => [%s]", rawRelationship.c_str());
+				if (connection)
+					connection->setRelationship(relationship);
+				std::string connectionSrcProcName = connectionNode["source name"].as<std::string>();
+
+				Processor *srcProcessor = this->_root->findProcessor(connectionSrcProcName);
+
+				if (!srcProcessor) {
+					_logger->log_error("Could not locate a source with name %s to create a connection",
+							connectionSrcProcName.c_str());
+					throw std::invalid_argument(
+							"Could not locate a source with name %s to create a connection " + connectionSrcProcName);
+				}
+
+				Processor *destProcessor = this->_root->findProcessor(destName);
+				// If we could not find name, try by UUID
+				if (!destProcessor) {
+					uuid_t destUuid;
+					uuid_parse(destName.c_str(), destUuid);
+					destProcessor = this->_root->findProcessor(destUuid);
+				}
+				if (destProcessor) {
+					std::string destUuid = destProcessor->getUUIDStr();
+				}
+
+				uuid_t srcUuid;
+				uuid_t destUuid;
+				srcProcessor->getUUID(srcUuid);
+				connection->setSourceProcessorUUID(srcUuid);
+				destProcessor->getUUID(destUuid);
+				connection->setDestinationProcessorUUID(destUuid);
+
+				if (connection) {
+					parent->addConnection(connection);
+				}
+			}
+		}
+
+		if (connection)
+			parent->addConnection(connection);
+
+		return;
+	}
+}
+
+void FlowController::parseRemoteProcessGroup(xmlDoc *doc, xmlNode *node, ProcessGroup *parent) {
+	uuid_t uuid;
+	xmlNode *currentNode;
+	ProcessGroup *group = NULL;
+	int64_t yieldPeriod = -1;
+	int64_t timeOut = -1;
+
+// generate the random UIID
+	uuid_generate(uuid);
+
+	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+		if (currentNode->type == XML_ELEMENT_NODE) {
+			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
+				char *id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseRootProcessGroup: id => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				char *name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseRemoteProcessGroup: name => [%s]", name);
+					group = this->createRemoteProcessGroup(name, uuid);
+					if (group == NULL) {
+						xmlFree(name);
+						return;
+					}
+					group->setParent(parent);
+					parent->addProcessGroup(group);
+					xmlFree(name);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "yieldPeriod") == 0) {
+				TimeUnit unit;
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToTime(temp, yieldPeriod, unit)
+							&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod) && group) {
+						_logger->log_debug("parseRemoteProcessGroup: yieldPeriod => [%d] ms", yieldPeriod);
+						group->setYieldPeriodMsec(yieldPeriod);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "timeout") == 0) {
+				TimeUnit unit;
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToTime(temp, timeOut, unit)
+							&& Property::ConvertTimeUnitToMS(timeOut, unit, timeOut) && group) {
+						_logger->log_debug("parseRemoteProcessGroup: timeOut => [%d] ms", timeOut);
+						group->setTimeOut(timeOut);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "transmitting") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				bool transmitting;
+				if (temp) {
+					if (Property::StringToBool(temp, transmitting) && group) {
+						_logger->log_debug("parseRemoteProcessGroup: transmitting => [%d]", transmitting);
+						group->setTransmitting(transmitting);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "inputPort") == 0 && group) {
+				this->parsePort(doc, currentNode, group, SEND);
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "outputPort") == 0 && group) {
+				this->parsePort(doc, currentNode, group, RECEIVE);
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // for node
+}
+
+void FlowController::parseProcessorProperty(xmlDoc *doc, xmlNode *node, Processor *processor) {
+	xmlNode *currentNode;
+	std::string propertyValue;
+	std::string propertyName;
+
+	if (!processor) {
+		_logger->log_error("parseProcessorProperty: no parent processor existed");
+		return;
+	}
+
+	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+		if (currentNode->type == XML_ELEMENT_NODE) {
+			if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				char *name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseProcessorNode: name => [%s]", name);
+					propertyName = name;
+					xmlFree(name);
+				}
+			}
+			if (xmlStrcmp(currentNode->name, BAD_CAST "value") == 0) {
+				char *value = (char *) xmlNodeGetContent(currentNode);
+				if (value) {
+					_logger->log_debug("parseProcessorNode: value => [%s]", value);
+					propertyValue = value;
+					xmlFree(value);
+				}
+			}
+			if (!propertyName.empty() && !propertyValue.empty()) {
+				processor->setProperty(propertyName, propertyValue);
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // for node
+}
+
+void FlowController::parsePortYaml(YAML::Node *portNode, ProcessGroup *parent, TransferDirection direction) {
+	uuid_t uuid;
+	Processor *processor = NULL;
+	RemoteProcessorGroupPort *port = NULL;
+
+	if (!parent) {
+		_logger->log_error("parseProcessNode: no parent group existed");
+		return;
+	}
+
+	YAML::Node inputPortsObj = portNode->as<YAML::Node>();
+
+	// generate the random UIID
+	uuid_generate(uuid);
+
+	auto portId = inputPortsObj["id"].as<std::string>();
+	auto nameStr = inputPortsObj["name"].as<std::string>();
+	uuid_parse(portId.c_str(), uuid);
+
+	port = new RemoteProcessorGroupPort(nameStr.c_str(), uuid);
+
+	processor = (Processor *) port;
+	port->setDirection(direction);
+	port->setTimeOut(parent->getTimeOut());
+	port->setTransmitting(true);
+	processor->setYieldPeriodMsec(parent->getYieldPeriodMsec());
+	processor->initialize();
+
+	// handle port properties
+	YAML::Node nodeVal = portNode->as<YAML::Node>();
+	YAML::Node propertiesNode = nodeVal["Properties"];
+
+	parsePropertiesNodeYaml(&propertiesNode, processor);
+
+	// add processor to parent
+	parent->addProcessor(processor);
+	processor->setScheduledState(RUNNING);
+	auto rawMaxConcurrentTasks = inputPortsObj["max concurrent tasks"].as<std::string>();
+	int64_t maxConcurrentTasks;
+	if (Property::StringToInt(rawMaxConcurrentTasks, maxConcurrentTasks)) {
+		processor->setMaxConcurrentTasks(maxConcurrentTasks);
+	}
+	_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
+	processor->setMaxConcurrentTasks(maxConcurrentTasks);
+
+}
+
+void FlowController::parsePort(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent, TransferDirection direction) {
+	char *id = NULL;
+	char *name = NULL;
+	uuid_t uuid;
+	xmlNode *currentNode;
+	Processor *processor = NULL;
+	RemoteProcessorGroupPort *port = NULL;
+
+	if (!parent) {
+		_logger->log_error("parseProcessNode: no parent group existed");
+		return;
+	}
+// generate the random UIID
+	uuid_generate(uuid);
+
+	for (currentNode = processorNode->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+		if (currentNode->type == XML_ELEMENT_NODE) {
+			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
+				id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseProcessorNode: id => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseProcessorNode: name => [%s]", name);
+					port = new RemoteProcessorGroupPort(name, uuid);
+					processor = (Processor *) port;
+					if (processor == NULL) {
+						xmlFree(name);
+						return;
+					}
+					port->setDirection(direction);
+					port->setTimeOut(parent->getTimeOut());
+					port->setTransmitting(parent->getTransmitting());
+					processor->setYieldPeriodMsec(parent->getYieldPeriodMsec());
+					processor->initialize();
+					// add processor to parent
+					parent->addProcessor(processor);
+					xmlFree(name);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "scheduledState") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					std::string state = temp;
+					if (state == "DISABLED") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(DISABLED);
+					}
+					if (state == "STOPPED") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(STOPPED);
+					}
+					if (state == "RUNNING") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(RUNNING);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxConcurrentTasks") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					int64_t maxConcurrentTasks;
+					if (Property::StringToInt(temp, maxConcurrentTasks)) {
+						_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
+						processor->setMaxConcurrentTasks(maxConcurrentTasks);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "property") == 0) {
+				this->parseProcessorProperty(doc, currentNode, processor);
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // while node
+}
+
+void FlowController::parseProcessorNode(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent) {
+	char *id = NULL;
+	char *name = NULL;
+	int64_t schedulingPeriod = -1;
+	int64_t penalizationPeriod = -1;
+	int64_t yieldPeriod = -1;
+	bool lossTolerant = false;
+	int64_t runDurationNanos = -1;
+	uuid_t uuid;
+	xmlNode *currentNode;
+	Processor *processor = NULL;
+
+	if (!parent) {
+		_logger->log_error("parseProcessNode: no parent group existed");
+		return;
+	}
+// generate the random UIID
+	uuid_generate(uuid);
+
+	for (currentNode = processorNode->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+		if (currentNode->type == XML_ELEMENT_NODE) {
+			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
+				id = (char *) xmlNodeGetContent(currentNode);
+				if (id) {
+					_logger->log_debug("parseProcessorNode: id => [%s]", id);
+					uuid_parse(id, uuid);
+					xmlFree(id);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
+				name = (char *) xmlNodeGetContent(currentNode);
+				if (name) {
+					_logger->log_debug("parseProcessorNode: name => [%s]", name);
+					processor = this->createProcessor(name, uuid);
+					if (processor == NULL) {
+						xmlFree(name);
+						return;
+					}
+					// add processor to parent
+					parent->addProcessor(processor);
+					xmlFree(name);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "schedulingPeriod") == 0) {
+				TimeUnit unit;
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToTime(temp, schedulingPeriod, unit)
+							&& Property::ConvertTimeUnitToNS(schedulingPeriod, unit, schedulingPeriod)) {
+						_logger->log_debug("parseProcessorNode: schedulingPeriod => [%d] ns", schedulingPeriod);
+						processor->setSchedulingPeriodNano(schedulingPeriod);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "penalizationPeriod") == 0) {
+				TimeUnit unit;
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToTime(temp, penalizationPeriod, unit)
+							&& Property::ConvertTimeUnitToMS(penalizationPeriod, unit, penalizationPeriod)) {
+						_logger->log_debug("parseProcessorNode: penalizationPeriod => [%d] ms", penalizationPeriod);
+						processor->setPenalizationPeriodMsec(penalizationPeriod);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "yieldPeriod") == 0) {
+				TimeUnit unit;
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToTime(temp, yieldPeriod, unit)
+							&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod)) {
+						_logger->log_debug("parseProcessorNode: yieldPeriod => [%d] ms", yieldPeriod);
+						processor->setYieldPeriodMsec(yieldPeriod);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "lossTolerant") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToBool(temp, lossTolerant)) {
+						_logger->log_debug("parseProcessorNode: lossTolerant => [%d]", lossTolerant);
+						processor->setlossTolerant(lossTolerant);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "scheduledState") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					std::string state = temp;
+					if (state == "DISABLED") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(DISABLED);
+					}
+					if (state == "STOPPED") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(STOPPED);
+					}
+					if (state == "RUNNING") {
+						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
+						processor->setScheduledState(RUNNING);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "schedulingStrategy") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					std::string strategy = temp;
+					if (strategy == "TIMER_DRIVEN") {
+						_logger->log_debug("parseProcessorNode: scheduledStrategy  => [%s]", strategy.c_str());
+						processor->setSchedulingStrategy(TIMER_DRIVEN);
+					}
+					if (strategy == "EVENT_DRIVEN") {
+						_logger->log_debug("parseProcessorNode: scheduledStrategy  => [%s]", strategy.c_str());
+						processor->setSchedulingStrategy(EVENT_DRIVEN);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxConcurrentTasks") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					int64_t maxConcurrentTasks;
+					if (Property::StringToInt(temp, maxConcurrentTasks)) {
+						_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
+						processor->setMaxConcurrentTasks(maxConcurrentTasks);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "runDurationNanos") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					if (Property::StringToInt(temp, runDurationNanos)) {
+						_logger->log_debug("parseProcessorNode: runDurationNanos => [%d]", runDurationNanos);
+						processor->setRunDurationNano(runDurationNanos);
+					}
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "autoTerminatedRelationship") == 0) {
+				char *temp = (char *) xmlNodeGetContent(currentNode);
+				if (temp) {
+					std::string relationshipName = temp;
+					Relationship relationship(relationshipName, "");
+					std::set<Relationship> relationships;
+
+					relationships.insert(relationship);
+					processor->setAutoTerminatedRelationships(relationships);
+					_logger->log_debug("parseProcessorNode: autoTerminatedRelationship  => [%s]",
+							relationshipName.c_str());
+					xmlFree(temp);
+				}
+			} else if (xmlStrcmp(currentNode->name, BAD_CAST "property") == 0) {
+				this->parseProcessorProperty(doc, currentNode, processor);
+			}
+		} // if (currentNode->type == XML_ELEMENT_NODE)
+	} // while node
+}
+
+void FlowController::parsePropertiesNodeYaml(YAML::Node *propertiesNode, Processor *processor)
+{
+    // Treat generically as a YAML node so we can perform inspection on entries to ensure they are populated
+    for (YAML::const_iterator propsIter = propertiesNode->begin(); propsIter != propertiesNode->end(); ++propsIter)
+    {
+        std::string propertyName = propsIter->first.as<std::string>();
+        YAML::Node propertyValueNode = propsIter->second;
+        if (!propertyValueNode.IsNull() && propertyValueNode.IsDefined())
+        {
+            std::string rawValueString = propertyValueNode.as<std::string>();
+            if (!processor->setProperty(propertyName, rawValueString))
+            {
+                _logger->log_warn("Received property %s with value %s but is not one of the properties for %s", propertyName.c_str(), rawValueString.c_str(), processor->getName().c_str());
+            }
+        }
+    }
+}
+
+void FlowController::load(ConfigFormat configFormat) {
+	if (_running) {
+		stop(true);
+	}
+	if (!_initialized) {
+		_logger->log_info("Load Flow Controller from file %s", _configurationFileName.c_str());
+
+		if (ConfigFormat::XML == configFormat) {
+			_logger->log_info("Detected an XML configuration file for processing.");
+
+			xmlDoc *doc = xmlReadFile(_configurationFileName.c_str(), NULL, XML_PARSE_NONET);
+			if (doc == NULL) {
+				_logger->log_error("xmlReadFile returned NULL when reading [%s]", _configurationFileName.c_str());
+				_initialized = true;
+				return;
+			}
+
+			xmlNode *root = xmlDocGetRootElement(doc);
+
+			if (root == NULL) {
+				_logger->log_error("Can not get root from XML doc %s", _configurationFileName.c_str());
+				xmlFreeDoc(doc);
+				xmlCleanupParser();
+			}
+
+			if (xmlStrcmp(root->name, BAD_CAST "flowController") != 0) {
+				_logger->log_error("Root name is not flowController for XML doc %s", _configurationFileName.c_str());
+				xmlFreeDoc(doc);
+				xmlCleanupParser();
+				return;
+			}
+
+			xmlNode *currentNode;
+
+			for (currentNode = root->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
+				if (currentNode->type == XML_ELEMENT_NODE) {
+					if (xmlStrcmp(currentNode->name, BAD_CAST "rootGroup") == 0) {
+						this->parseRootProcessGroup(doc, currentNode);
+					} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxTimerDrivenThreadCount") == 0) {
+						char *temp = (char *) xmlNodeGetContent(currentNode);
+						int64_t maxTimerDrivenThreadCount;
+						if (temp) {
+							if (Property::StringToInt(temp, maxTimerDrivenThreadCount)) {
+								_logger->log_debug("maxTimerDrivenThreadCount => [%d]", maxTimerDrivenThreadCount);
+								this->_maxTimerDrivenThreads = maxTimerDrivenThreadCount;
+							}
+							xmlFree(temp);
+						}
+					} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxEventDrivenThreadCount") == 0) {
+						char *temp = (char *) xmlNodeGetContent(currentNode);
+						int64_t maxEventDrivenThreadCount;
+						if (temp) {
+							if (Property::StringToInt(temp, maxEventDrivenThreadCount)) {
+								_logger->log_debug("maxEventDrivenThreadCount => [%d]", maxEventDrivenThreadCount);
+								this->_maxEventDrivenThreads = maxEventDrivenThreadCount;
+							}
+							xmlFree(temp);
+						}
+					}
+				} // type == XML_ELEMENT_NODE
+			} // for
+
+			xmlFreeDoc(doc);
+			xmlCleanupParser();
+			_initialized = true;
+		} else if (ConfigFormat::YAML == configFormat) {
+			YAML::Node flow = YAML::LoadFile(_configurationFileName);
+
+			YAML::Node flowControllerNode = flow["Flow Controller"];
+			YAML::Node processorsNode = flow[CONFIG_YAML_PROCESSORS_KEY];
+			YAML::Node connectionsNode = flow["Connections"];
+			YAML::Node remoteProcessingGroupNode = flow["Remote Processing Groups"];
+
+			// Create the root process group
+			parseRootProcessGroupYaml(flowControllerNode);
+			parseProcessorNodeYaml(processorsNode, this->_root);
+			parseRemoteProcessGroupYaml(&remoteProcessingGroupNode, this->_root);
+			parseConnectionYaml(&connectionsNode, this->_root);
+
+			_initialized = true;
+		}
+	}
+}
+
+bool FlowController::start() {
+	if (!_initialized) {
+		_logger->log_error("Can not start Flow Controller because it has not been initialized");
+		return false;
+	} else {
+		if (!_running) {
+			_logger->log_info("Start Flow Controller");
+			this->_timerScheduler.start();
+			if (this->_root)
+				this->_root->startProcessing(&this->_timerScheduler);
+			_running = true;
+			this->_protocol->start();
+		}
+		return true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/FlowFileRecord.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/FlowFileRecord.cpp b/libminifi/src/FlowFileRecord.cpp
new file mode 100644
index 0000000..2dda47a
--- /dev/null
+++ b/libminifi/src/FlowFileRecord.cpp
@@ -0,0 +1,231 @@
+/**
+ * @file FlowFileRecord.cpp
+ * Flow file record class implementation 
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+#include <cstdio>
+
+#include "FlowFileRecord.h"
+#include "Relationship.h"
+#include "Logger.h"
+
+std::atomic<uint64_t> FlowFileRecord::_localFlowSeqNumber(0);
+
+FlowFileRecord::FlowFileRecord(std::map<std::string, std::string> attributes, ResourceClaim *claim)
+: _size(0),
+  _id(_localFlowSeqNumber.load()),
+  _offset(0),
+  _penaltyExpirationMs(0),
+  _claim(claim),
+  _markedDelete(false),
+  _connection(NULL),
+  _orginalConnection(NULL)
+{
+	_entryDate = getTimeMillis();
+	_lineageStartDate = _entryDate;
+
+	char uuidStr[37];
+
+	// Generate the global UUID for the flow record
+	uuid_generate(_uuid);
+	// Increase the local ID for the flow record
+	++_localFlowSeqNumber;
+	uuid_unparse(_uuid, uuidStr);
+	_uuidStr = uuidStr;
+
+	// Populate the default attributes
+    addAttribute(FILENAME, std::to_string(getTimeNano()));
+    addAttribute(PATH, DEFAULT_FLOWFILE_PATH);
+    addAttribute(UUID, uuidStr);
+	// Populate the attributes from the input
+    std::map<std::string, std::string>::iterator it;
+    for (it = attributes.begin(); it!= attributes.end(); it++)
+    {
+    	addAttribute(it->first, it->second);
+    }
+
+    _snapshot = false;
+
+	if (_claim)
+		// Increase the flow file record owned count for the resource claim
+		_claim->increaseFlowFileRecordOwnedCount();
+	_logger = Logger::getLogger();
+}
+
+FlowFileRecord::~FlowFileRecord()
+{
+	if (!_snapshot)
+		_logger->log_debug("Delete FlowFile UUID %s", _uuidStr.c_str());
+	else
+		_logger->log_debug("Delete SnapShot FlowFile UUID %s", _uuidStr.c_str());
+	if (_claim)
+	{
+		// Decrease the flow file record owned count for the resource claim
+		_claim->decreaseFlowFileRecordOwnedCount();
+		if (_claim->getFlowFileRecordOwnedCount() == 0)
+		{
+			_logger->log_debug("Delete Resource Claim %s", _claim->getContentFullPath().c_str());
+			std::remove(_claim->getContentFullPath().c_str());
+			delete _claim;
+		}
+	}
+}
+
+bool FlowFileRecord::addAttribute(FlowAttribute key, std::string value)
+{
+	const char *keyStr = FlowAttributeKey(key);
+	if (keyStr)
+	{
+		std::string keyString = keyStr;
+		return addAttribute(keyString, value);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::addAttribute(std::string key, std::string value)
+{
+	std::map<std::string, std::string>::iterator it = _attributes.find(key);
+	if (it != _attributes.end())
+	{
+		// attribute already there in the map
+		return false;
+	}
+	else
+	{
+		_attributes[key] = value;
+		return true;
+	}
+}
+
+bool FlowFileRecord::removeAttribute(FlowAttribute key)
+{
+	const char *keyStr = FlowAttributeKey(key);
+	if (keyStr)
+	{
+		std::string keyString = keyStr;
+		return removeAttribute(keyString);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::removeAttribute(std::string key)
+{
+	std::map<std::string, std::string>::iterator it = _attributes.find(key);
+	if (it != _attributes.end())
+	{
+		_attributes.erase(key);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::updateAttribute(FlowAttribute key, std::string value)
+{
+	const char *keyStr = FlowAttributeKey(key);
+	if (keyStr)
+	{
+		std::string keyString = keyStr;
+		return updateAttribute(keyString, value);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::updateAttribute(std::string key, std::string value)
+{
+	std::map<std::string, std::string>::iterator it = _attributes.find(key);
+	if (it != _attributes.end())
+	{
+		_attributes[key] = value;
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::getAttribute(FlowAttribute key, std::string &value)
+{
+	const char *keyStr = FlowAttributeKey(key);
+	if (keyStr)
+	{
+		std::string keyString = keyStr;
+		return getAttribute(keyString, value);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool FlowFileRecord::getAttribute(std::string key, std::string &value)
+{
+	std::map<std::string, std::string>::iterator it = _attributes.find(key);
+	if (it != _attributes.end())
+	{
+		value = it->second;
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void FlowFileRecord::duplicate(FlowFileRecord *original)
+{
+	uuid_copy(this->_uuid, original->_uuid);
+	this->_attributes = original->_attributes;
+	this->_entryDate = original->_entryDate;
+	this->_id = original->_id;
+	this->_lastQueueDate = original->_lastQueueDate;
+	this->_lineageStartDate = original->_lineageStartDate;
+	this->_offset = original->_offset;
+	this->_penaltyExpirationMs = original->_penaltyExpirationMs;
+	this->_size = original->_size;
+	this->_lineageIdentifiers = original->_lineageIdentifiers;
+	this->_orginalConnection = original->_orginalConnection;
+	this->_uuidStr = original->_uuidStr;
+	this->_connection = original->_connection;
+	this->_markedDelete = original->_markedDelete;
+
+	this->_claim = original->_claim;
+	if (this->_claim)
+		this->_claim->increaseFlowFileRecordOwnedCount();
+
+	this->_snapshot = true;
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/GenerateFlowFile.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/GenerateFlowFile.cpp b/libminifi/src/GenerateFlowFile.cpp
new file mode 100644
index 0000000..4b0603d
--- /dev/null
+++ b/libminifi/src/GenerateFlowFile.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file GenerateFlowFile.cpp
+ * GenerateFlowFile class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <random>
+
+#include "GenerateFlowFile.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const char *GenerateFlowFile::DATA_FORMAT_BINARY = "Binary";
+const char *GenerateFlowFile::DATA_FORMAT_TEXT = "Text";
+const std::string GenerateFlowFile::ProcessorName("GenerateFlowFile");
+Property GenerateFlowFile::FileSize("File Size", "The size of the file that will be used", "1 kB");
+Property GenerateFlowFile::BatchSize("Batch Size", "The number of FlowFiles to be transferred in each invocation", "1");
+Property GenerateFlowFile::DataFormat("Data Format", "Specifies whether the data should be Text or Binary", GenerateFlowFile::DATA_FORMAT_BINARY);
+Property GenerateFlowFile::UniqueFlowFiles("Unique FlowFiles",
+		"If true, each FlowFile that is generated will be unique. If false, a random value will be generated and all FlowFiles", "true");
+Relationship GenerateFlowFile::Success("success", "success operational on the flow record");
+
+void GenerateFlowFile::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(FileSize);
+	properties.insert(BatchSize);
+	properties.insert(DataFormat);
+	properties.insert(UniqueFlowFiles);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+}
+
+void GenerateFlowFile::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	int64_t batchSize = 1;
+	bool uniqueFlowFile = true;
+	int64_t fileSize = 1024;
+
+	std::string value;
+	if (context->getProperty(FileSize.getName(), value))
+	{
+		Property::StringToInt(value, fileSize);
+	}
+	if (context->getProperty(BatchSize.getName(), value))
+	{
+		Property::StringToInt(value, batchSize);
+	}
+	if (context->getProperty(UniqueFlowFiles.getName(), value))
+	{
+		Property::StringToBool(value, uniqueFlowFile);
+	}
+
+	if (!uniqueFlowFile)
+	{
+		char *data;
+		data = new char[fileSize];
+		if (!data)
+			return;
+		uint64_t dataSize = fileSize;
+		GenerateFlowFile::WriteCallback callback(data, dataSize);
+		char *current = data;
+		for (int i = 0; i < fileSize; i+= sizeof(int))
+		{
+			int randValue = random();
+			*((int *) current) = randValue;
+			current += sizeof(int);
+		}
+		for (int i = 0; i < batchSize; i++)
+		{
+			// For each batch
+			FlowFileRecord *flowFile = session->create();
+			if (!flowFile)
+				return;
+			if (fileSize > 0)
+				session->write(flowFile, &callback);
+			session->transfer(flowFile, Success);
+		}
+		delete[] data;
+	}
+	else
+	{
+		if (!_data)
+		{
+			// We have not create the unique data yet
+			_data = new char[fileSize];
+			_dataSize = fileSize;
+			char *current = _data;
+			for (int i = 0; i < fileSize; i+= sizeof(int))
+			{
+				int randValue = random();
+				*((int *) current) = randValue;
+				// *((int *) current) = (0xFFFFFFFF & i);
+				current += sizeof(int);
+			}
+		}
+		GenerateFlowFile::WriteCallback callback(_data, _dataSize);
+		for (int i = 0; i < batchSize; i++)
+		{
+			// For each batch
+			FlowFileRecord *flowFile = session->create();
+			if (!flowFile)
+				return;
+			if (fileSize > 0)
+				session->write(flowFile, &callback);
+			session->transfer(flowFile, Success);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/GetFile.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/GetFile.cpp b/libminifi/src/GetFile.cpp
new file mode 100644
index 0000000..02e196a
--- /dev/null
+++ b/libminifi/src/GetFile.cpp
@@ -0,0 +1,295 @@
+/**
+ * @file GetFile.cpp
+ * GetFile class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sstream>
+#include <stdio.h>
+#include <string>
+#include <iostream>
+#include <dirent.h>
+#include <limits.h>
+#include <unistd.h>
+#include <regex>
+
+#include "TimeUtil.h"
+#include "GetFile.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string GetFile::ProcessorName("GetFile");
+Property GetFile::BatchSize("Batch Size", "The maximum number of files to pull in each iteration", "10");
+Property GetFile::Directory("Input Directory", "The input directory from which to pull files", ".");
+Property GetFile::IgnoreHiddenFile("Ignore Hidden Files", "Indicates whether or not hidden files should be ignored", "true");
+Property GetFile::KeepSourceFile("Keep Source File",
+		"If true, the file is not deleted after it has been copied to the Content Repository", "false");
+Property GetFile::MaxAge("Maximum File Age",
+		"The minimum age that a file must be in order to be pulled; any file younger than this amount of time (according to last modification date) will be ignored", "0 sec");
+Property GetFile::MinAge("Minimum File Age",
+		"The maximum age that a file must be in order to be pulled; any file older than this amount of time (according to last modification date) will be ignored", "0 sec");
+Property GetFile::MaxSize("Maximum File Size", "The maximum size that a file can be in order to be pulled", "0 B");
+Property GetFile::MinSize("Minimum File Size", "The minimum size that a file must be in order to be pulled", "0 B");
+Property GetFile::PollInterval("Polling Interval", "Indicates how long to wait before performing a directory listing", "0 sec");
+Property GetFile::Recurse("Recurse Subdirectories", "Indicates whether or not to pull files from subdirectories", "true");
+Property GetFile::FileFilter("File Filter", "Only files whose names match the given regular expression will be picked up", "[^\\.].*");
+Relationship GetFile::Success("success", "All files are routed to success");
+
+void GetFile::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(BatchSize);
+	properties.insert(Directory);
+	properties.insert(IgnoreHiddenFile);
+	properties.insert(KeepSourceFile);
+	properties.insert(MaxAge);
+	properties.insert(MinAge);
+	properties.insert(MaxSize);
+	properties.insert(MinSize);
+	properties.insert(PollInterval);
+	properties.insert(Recurse);
+	properties.insert(FileFilter);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+}
+
+void GetFile::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string value;
+	if (context->getProperty(Directory.getName(), value))
+	{
+		_directory = value;
+	}
+	if (context->getProperty(BatchSize.getName(), value))
+	{
+		Property::StringToInt(value, _batchSize);
+	}
+	if (context->getProperty(IgnoreHiddenFile.getName(), value))
+	{
+		Property::StringToBool(value, _ignoreHiddenFile);
+	}
+	if (context->getProperty(KeepSourceFile.getName(), value))
+	{
+		Property::StringToBool(value, _keepSourceFile);
+	}
+	if (context->getProperty(MaxAge.getName(), value))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(value, _maxAge, unit) &&
+			Property::ConvertTimeUnitToMS(_maxAge, unit, _maxAge))
+		{
+
+		}
+	}
+	if (context->getProperty(MinAge.getName(), value))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(value, _minAge, unit) &&
+			Property::ConvertTimeUnitToMS(_minAge, unit, _minAge))
+		{
+
+		}
+	}
+	if (context->getProperty(MaxSize.getName(), value))
+	{
+		Property::StringToInt(value, _maxSize);
+	}
+	if (context->getProperty(MinSize.getName(), value))
+	{
+		Property::StringToInt(value, _minSize);
+	}
+	if (context->getProperty(PollInterval.getName(), value))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(value, _pollInterval, unit) &&
+			Property::ConvertTimeUnitToMS(_pollInterval, unit, _pollInterval))
+		{
+
+		}
+	}
+	if (context->getProperty(Recurse.getName(), value))
+	{
+		Property::StringToBool(value, _recursive);
+	}
+
+	if (context->getProperty(FileFilter.getName(), value))
+	{
+		_fileFilter = value;
+	}
+
+	// Perform directory list
+	if (isListingEmpty())
+	{
+		if (_pollInterval == 0 || (getTimeMillis() - _lastDirectoryListingTime) > _pollInterval)
+		{
+			performListing(_directory);
+		}
+	}
+
+	if (!isListingEmpty())
+	{
+		try
+		{
+			std::queue<std::string> list;
+			pollListing(list, _batchSize);
+			while (!list.empty())
+			{
+				std::string fileName = list.front();
+				list.pop();
+				_logger->log_info("GetFile process %s", fileName.c_str());
+				FlowFileRecord *flowFile = session->create();
+				if (!flowFile)
+					return;
+				std::size_t found = fileName.find_last_of("/\\");
+				std::string path = fileName.substr(0,found);
+				std::string name = fileName.substr(found+1);
+				flowFile->updateAttribute(FILENAME, name);
+				flowFile->updateAttribute(PATH, path);
+				flowFile->addAttribute(ABSOLUTE_PATH, fileName);
+				session->import(fileName, flowFile, _keepSourceFile);
+				session->transfer(flowFile, Success);
+			}
+		}
+		catch (std::exception &exception)
+		{
+			_logger->log_debug("GetFile Caught Exception %s", exception.what());
+			throw;
+		}
+		catch (...)
+		{
+			throw;
+		}
+	}
+}
+
+bool GetFile::isListingEmpty()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	return _dirList.empty();
+}
+
+void GetFile::putListing(std::string fileName)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_dirList.push(fileName);
+}
+
+void GetFile::pollListing(std::queue<std::string> &list, int maxSize)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	while (!_dirList.empty() && (maxSize == 0 || list.size() < maxSize))
+	{
+		std::string fileName = _dirList.front();
+		_dirList.pop();
+		list.push(fileName);
+	}
+
+	return;
+}
+
+bool GetFile::acceptFile(std::string fileName)
+{
+	struct stat statbuf;
+
+	if (stat(fileName.c_str(), &statbuf) == 0)
+	{
+		if (_minSize > 0 && statbuf.st_size <_minSize)
+			return false;
+
+		if (_maxSize > 0 && statbuf.st_size > _maxSize)
+			return false;
+
+		uint64_t modifiedTime = ((uint64_t) (statbuf.st_mtime) * 1000);
+		uint64_t fileAge = getTimeMillis() - modifiedTime;
+		if (_minAge > 0 && fileAge < _minAge)
+			return false;
+		if (_maxAge > 0 && fileAge > _maxAge)
+			return false;
+
+		if (_ignoreHiddenFile && fileName.c_str()[0] == '.')
+			return false;
+
+		if (access(fileName.c_str(), R_OK) != 0)
+			return false;
+
+		if (_keepSourceFile == false && access(fileName.c_str(), W_OK) != 0)
+			return false;
+
+		try {
+			std::regex re(_fileFilter);
+			if (!std::regex_match(fileName, re)) {
+				return false;
+	   		}
+		} catch (std::regex_error e) {
+			_logger->log_error("Invalid File Filter regex: %s.", e.what());
+			return false;
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+void GetFile::performListing(std::string dir)
+{
+	DIR *d;
+	d = opendir(dir.c_str());
+	if (!d)
+		return;
+	while (1)
+	{
+		struct dirent *entry;
+		entry = readdir(d);
+		if (!entry)
+			break;
+		std::string d_name = entry->d_name;
+		if ((entry->d_type & DT_DIR))
+		{
+			// if this is a directory
+			if (_recursive && strcmp(d_name.c_str(), "..") != 0 && strcmp(d_name.c_str(), ".") != 0)
+			{
+				std::string path = dir + "/" + d_name;
+				performListing(path);
+			}
+		}
+		else
+		{
+			std::string fileName = dir + "/" + d_name;
+			if (acceptFile(fileName))
+			{
+				// check whether we can take this file
+				putListing(fileName);
+			}
+		}
+	}
+	closedir(d);
+}


[05/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Site2SiteClientProtocol.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Site2SiteClientProtocol.cpp b/libminifi/src/Site2SiteClientProtocol.cpp
new file mode 100644
index 0000000..88ea78a
--- /dev/null
+++ b/libminifi/src/Site2SiteClientProtocol.cpp
@@ -0,0 +1,1313 @@
+/**
+ * @file Site2SiteProtocol.cpp
+ * Site2SiteProtocol class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/time.h>
+#include <stdio.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <random>
+#include <netinet/tcp.h>
+#include <iostream>
+#include "Site2SitePeer.h"
+#include "Site2SiteClientProtocol.h"
+
+bool Site2SiteClientProtocol::establish()
+{
+	if (_peerState != IDLE)
+	{
+		_logger->log_error("Site2Site peer state is not idle while try to establish");
+		return false;
+	}
+
+	bool ret = _peer->Open();
+
+	if (!ret)
+	{
+		_logger->log_error("Site2Site peer socket open failed");
+		return false;
+	}
+
+	// Negotiate the version
+	ret = initiateResourceNegotiation();
+
+	if (!ret)
+	{
+		_logger->log_error("Site2Site Protocol Version Negotiation failed");
+		/*
+		_peer->yield();
+		tearDown(); */
+		return false;
+	}
+
+	_logger->log_info("Site2Site socket established");
+	_peerState = ESTABLISHED;
+
+	return true;
+}
+
+bool Site2SiteClientProtocol::initiateResourceNegotiation()
+{
+	// Negotiate the version
+	if (_peerState != IDLE)
+	{
+		_logger->log_error("Site2Site peer state is not idle while initiateResourceNegotiation");
+		return false;
+	}
+
+	_logger->log_info("Negotiate protocol version with destination port %s current version %d", _portIdStr.c_str(), _currentVersion);
+
+	int ret = _peer->writeUTF(this->getResourceName());
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	ret = _peer->write(_currentVersion);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	uint8_t statusCode;
+	ret = _peer->read(statusCode);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	switch (statusCode)
+	{
+	case RESOURCE_OK:
+		_logger->log_info("Site2Site Protocol Negotiate protocol version OK");
+		return true;
+	case DIFFERENT_RESOURCE_VERSION:
+		uint32_t serverVersion;
+		ret = _peer->read(serverVersion);
+		if (ret <= 0)
+		{
+			// tearDown();
+			return false;
+		}
+		_logger->log_info("Site2Site Server Response asked for a different protocol version %d", serverVersion);
+		for (unsigned int i = (_currentVersionIndex + 1); i < sizeof(_supportedVersion)/sizeof(uint32_t); i++)
+		{
+			if (serverVersion >= _supportedVersion[i])
+			{
+				_currentVersion = _supportedVersion[i];
+				_currentVersionIndex = i;
+				return initiateResourceNegotiation();
+			}
+		}
+		ret = -1;
+		// tearDown();
+		return false;
+	case NEGOTIATED_ABORT:
+		_logger->log_info("Site2Site Negotiate protocol response ABORT");
+		ret = -1;
+		// tearDown();
+		return false;
+	default:
+		_logger->log_info("Negotiate protocol response unknown code %d", statusCode);
+		return true;
+	}
+
+	return true;
+}
+
+bool Site2SiteClientProtocol::initiateCodecResourceNegotiation()
+{
+	// Negotiate the version
+	if (_peerState != HANDSHAKED)
+	{
+		_logger->log_error("Site2Site peer state is not handshaked while initiateCodecResourceNegotiation");
+		return false;
+	}
+
+	_logger->log_info("Negotiate Codec version with destination port %s current version %d", _portIdStr.c_str(), _currentCodecVersion);
+
+	int ret = _peer->writeUTF(this->getCodecResourceName());
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	ret = _peer->write(_currentCodecVersion);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	uint8_t statusCode;
+	ret = _peer->read(statusCode);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	switch (statusCode)
+	{
+	case RESOURCE_OK:
+		_logger->log_info("Site2Site Codec Negotiate version OK");
+		return true;
+	case DIFFERENT_RESOURCE_VERSION:
+		uint32_t serverVersion;
+		ret = _peer->read(serverVersion);
+		if (ret <= 0)
+		{
+			// tearDown();
+			return false;
+		}
+		_logger->log_info("Site2Site Server Response asked for a different codec version %d", serverVersion);
+		for (unsigned int i = (_currentCodecVersionIndex + 1); i < sizeof(_supportedCodecVersion)/sizeof(uint32_t); i++)
+		{
+			if (serverVersion >= _supportedCodecVersion[i])
+			{
+				_currentCodecVersion = _supportedCodecVersion[i];
+				_currentCodecVersionIndex = i;
+				return initiateCodecResourceNegotiation();
+			}
+		}
+		ret = -1;
+		// tearDown();
+		return false;
+	case NEGOTIATED_ABORT:
+		_logger->log_info("Site2Site Codec Negotiate response ABORT");
+		ret = -1;
+		// tearDown();
+		return false;
+	default:
+		_logger->log_info("Negotiate Codec response unknown code %d", statusCode);
+		return true;
+	}
+
+	return true;
+}
+
+bool Site2SiteClientProtocol::handShake()
+{
+	if (_peerState != ESTABLISHED)
+	{
+		_logger->log_error("Site2Site peer state is not established while handshake");
+		return false;
+	}
+	_logger->log_info("Site2Site Protocol Perform hand shake with destination port %s", _portIdStr.c_str());
+	uuid_t uuid;
+	// Generate the global UUID for the com identify
+	uuid_generate(uuid);
+	char uuidStr[37];
+	uuid_unparse(uuid, uuidStr);
+	_commsIdentifier = uuidStr;
+
+	int ret = _peer->writeUTF(_commsIdentifier);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	std::map<std::string, std::string> properties;
+	properties[HandShakePropertyStr[GZIP]] = "false";
+	properties[HandShakePropertyStr[PORT_IDENTIFIER]] = _portIdStr;
+	properties[HandShakePropertyStr[REQUEST_EXPIRATION_MILLIS]] = std::to_string(this->_timeOut);
+	if (this->_currentVersion >= 5)
+	{
+		if (this->_batchCount > 0)
+			properties[HandShakePropertyStr[BATCH_COUNT]] = std::to_string(this->_batchCount);
+		if (this->_batchSize > 0)
+			properties[HandShakePropertyStr[BATCH_SIZE]] = std::to_string(this->_batchSize);
+		if (this->_batchDuration > 0)
+			properties[HandShakePropertyStr[BATCH_DURATION]] = std::to_string(this->_batchDuration);
+	}
+
+	if (_currentVersion >= 3)
+	{
+		ret = _peer->writeUTF(_peer->getURL());
+		if (ret <= 0)
+		{
+			// tearDown();
+			return false;
+		}
+	}
+
+	uint32_t size = properties.size();
+	ret = _peer->write(size);
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	std::map<std::string, std::string>::iterator it;
+	for (it = properties.begin(); it!= properties.end(); it++)
+	{
+		ret = _peer->writeUTF(it->first);
+		if (ret <= 0)
+		{
+			// tearDown();
+			return false;
+		}
+		ret = _peer->writeUTF(it->second);
+		if (ret <= 0)
+		{
+			// tearDown();
+			return false;
+		}
+		_logger->log_info("Site2Site Protocol Send handshake properties %s %s", it->first.c_str(), it->second.c_str());
+	}
+
+	RespondCode code;
+	std::string message;
+
+	ret = this->readRespond(code, message);
+
+	if (ret <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	switch (code)
+	{
+	case PROPERTIES_OK:
+		_logger->log_info("Site2Site HandShake Completed");
+		_peerState = HANDSHAKED;
+		return true;
+	case PORT_NOT_IN_VALID_STATE:
+    case UNKNOWN_PORT:
+    case PORTS_DESTINATION_FULL:
+    	_logger->log_error("Site2Site HandShake Failed because destination port is either invalid or full");
+		ret = -1;
+		/*
+		_peer->yield();
+		tearDown(); */
+		return false;
+	default:
+		_logger->log_info("HandShake Failed because of unknown respond code %d", code);
+		ret = -1;
+		/*
+		_peer->yield();
+		tearDown(); */
+		return false;
+	}
+
+	return false;
+}
+
+void Site2SiteClientProtocol::tearDown()
+{
+	if (_peerState >= ESTABLISHED)
+	{
+		_logger->log_info("Site2Site Protocol tearDown");
+		// need to write shutdown request
+		writeRequestType(SHUTDOWN);
+	}
+
+	std::map<std::string, Transaction *>::iterator it;
+	for (it = _transactionMap.begin(); it!= _transactionMap.end(); it++)
+	{
+		delete it->second;
+	}
+	_transactionMap.clear();
+	_peer->Close();
+	_peerState = IDLE;
+}
+
+int Site2SiteClientProtocol::writeRequestType(RequestType type)
+{
+	if (type >= MAX_REQUEST_TYPE)
+		return -1;
+
+	return _peer->writeUTF(RequestTypeStr[type]);
+}
+
+int Site2SiteClientProtocol::readRequestType(RequestType &type)
+{
+	std::string requestTypeStr;
+
+	int ret = _peer->readUTF(requestTypeStr);
+
+	if (ret <= 0)
+		return ret;
+
+	for (int i = (int) NEGOTIATE_FLOWFILE_CODEC; i <= (int) SHUTDOWN; i++)
+	{
+		if (RequestTypeStr[i] == requestTypeStr)
+		{
+			type = (RequestType) i;
+			return ret;
+		}
+	}
+
+	return -1;
+}
+
+int Site2SiteClientProtocol::readRespond(RespondCode &code, std::string &message)
+{
+	uint8_t firstByte;
+
+	int ret = _peer->read(firstByte);
+
+	if (ret <= 0 || firstByte != CODE_SEQUENCE_VALUE_1)
+		return -1;
+
+	uint8_t secondByte;
+
+	ret = _peer->read(secondByte);
+
+	if (ret <= 0 || secondByte != CODE_SEQUENCE_VALUE_2)
+		return -1;
+
+	uint8_t thirdByte;
+
+	ret = _peer->read(thirdByte);
+
+	if (ret <= 0)
+		return ret;
+
+	code = (RespondCode) thirdByte;
+
+	RespondCodeContext *resCode = this->getRespondCodeContext(code);
+
+	if ( resCode == NULL)
+	{
+		// Not a valid respond code
+		return -1;
+	}
+	if (resCode->hasDescription)
+	{
+		ret = _peer->readUTF(message);
+		if (ret <= 0)
+			return -1;
+	}
+	return 3 + message.size();
+}
+
+int Site2SiteClientProtocol::writeRespond(RespondCode code, std::string message)
+{
+	RespondCodeContext *resCode = this->getRespondCodeContext(code);
+
+	if (resCode == NULL)
+	{
+		// Not a valid respond code
+		return -1;
+	}
+
+	uint8_t codeSeq[3];
+	codeSeq[0] = CODE_SEQUENCE_VALUE_1;
+	codeSeq[1] = CODE_SEQUENCE_VALUE_2;
+	codeSeq[2] = (uint8_t) code;
+
+	int ret = _peer->write(codeSeq, 3);
+
+	if (ret != 3)
+		return -1;
+
+	if (resCode->hasDescription)
+	{
+		ret = _peer->writeUTF(message);
+		if (ret > 0)
+			return (3 + ret);
+		else
+			return ret;
+	}
+	else
+		return 3;
+}
+
+bool Site2SiteClientProtocol::negotiateCodec()
+{
+	if (_peerState != HANDSHAKED)
+	{
+		_logger->log_error("Site2Site peer state is not handshaked while negotiate codec");
+		return false;
+	}
+
+	_logger->log_info("Site2Site Protocol Negotiate Codec with destination port %s", _portIdStr.c_str());
+
+	int status = this->writeRequestType(NEGOTIATE_FLOWFILE_CODEC);
+
+	if (status <= 0)
+	{
+		// tearDown();
+		return false;
+	}
+
+	// Negotiate the codec version
+	bool ret = initiateCodecResourceNegotiation();
+
+	if (!ret)
+	{
+		_logger->log_error("Site2Site Codec Version Negotiation failed");
+		/*
+		_peer->yield();
+		tearDown(); */
+		return false;
+	}
+
+	_logger->log_info("Site2Site Codec Completed and move to READY state for data transfer");
+	_peerState = READY;
+
+	return true;
+}
+
+bool Site2SiteClientProtocol::bootstrap()
+{
+	if (_peerState == READY)
+		return true;
+
+	tearDown();
+
+	if (establish() && handShake() && negotiateCodec())
+	{
+		_logger->log_info("Site2Site Ready For data transaction");
+		return true;
+	}
+	else
+	{
+		_peer->yield();
+		tearDown();
+		return false;
+	}
+}
+
+Transaction* Site2SiteClientProtocol::createTransaction(std::string &transactionID, TransferDirection direction)
+{
+	int ret;
+	bool dataAvailable;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		return NULL;
+	}
+
+	if (direction == RECEIVE)
+	{
+		ret = writeRequestType(RECEIVE_FLOWFILES);
+
+		if (ret <= 0)
+		{
+			// tearDown();
+			return NULL;
+		}
+
+		RespondCode code;
+		std::string message;
+
+		ret = readRespond(code, message);
+
+		if (ret <= 0)
+		{
+			// tearDown();
+			return NULL;
+		}
+
+		switch (code)
+		{
+		case MORE_DATA:
+			dataAvailable = true;
+			_logger->log_info("Site2Site peer indicates that data is available");
+			transaction = new Transaction(direction);
+			_transactionMap[transaction->getUUIDStr()] = transaction;
+			transactionID = transaction->getUUIDStr();
+			transaction->setDataAvailable(dataAvailable);
+			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
+			return transaction;
+		case NO_MORE_DATA:
+			dataAvailable = false;
+			_logger->log_info("Site2Site peer indicates that no data is available");
+			transaction = new Transaction(direction);
+			_transactionMap[transaction->getUUIDStr()] = transaction;
+			transactionID = transaction->getUUIDStr();
+			transaction->setDataAvailable(dataAvailable);
+			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
+			return transaction;
+		default:
+			_logger->log_info("Site2Site got unexpected response %d when asking for data", code);
+			// tearDown();
+			return NULL;
+		}
+	}
+	else
+	{
+		ret = writeRequestType(SEND_FLOWFILES);
+
+		if (ret <= 0)
+		{
+			// tearDown();
+			return NULL;
+		}
+		else
+		{
+			transaction = new Transaction(direction);
+			_transactionMap[transaction->getUUIDStr()] = transaction;
+			transactionID = transaction->getUUIDStr();
+			_logger->log_info("Site2Site create transaction %s", transaction->getUUIDStr().c_str());
+			return transaction;
+		}
+	}
+}
+
+bool Site2SiteClientProtocol::receive(std::string transactionID, DataPacket *packet, bool &eof)
+{
+	int ret;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		return false;
+	}
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return false;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	if (transaction->getState() != TRANSACTION_STARTED && transaction->getState() != DATA_EXCHANGED)
+	{
+		_logger->log_info("Site2Site transaction %s is not at started or exchanged state", transactionID.c_str());
+		return false;
+	}
+
+	if (transaction->getDirection() != RECEIVE)
+	{
+		_logger->log_info("Site2Site transaction %s direction is wrong", transactionID.c_str());
+		return false;
+	}
+
+	if (!transaction->isDataAvailable())
+	{
+		eof = true;
+		return true;
+	}
+
+	if (transaction->_transfers > 0)
+	{
+		// if we already has transfer before, check to see whether another one is available
+		RespondCode code;
+		std::string message;
+
+		ret = readRespond(code, message);
+
+		if (ret <= 0)
+		{
+			return false;
+		}
+		if (code == CONTINUE_TRANSACTION)
+		{
+			_logger->log_info("Site2Site transaction %s peer indicate continue transaction", transactionID.c_str());
+			transaction->_dataAvailable = true;
+		}
+		else if (code == FINISH_TRANSACTION)
+		{
+			_logger->log_info("Site2Site transaction %s peer indicate finish transaction", transactionID.c_str());
+			transaction->_dataAvailable = false;
+		}
+		else
+		{
+			_logger->log_info("Site2Site transaction %s peer indicate wrong respond code %d", transactionID.c_str(), code);
+			return false;
+		}
+	}
+
+	if (!transaction->isDataAvailable())
+	{
+		eof = true;
+		return true;
+	}
+
+	// start to read the packet
+	uint32_t numAttributes;
+	ret = _peer->read(numAttributes, &transaction->_crc);
+	if (ret <= 0 || numAttributes > MAX_NUM_ATTRIBUTES)
+	{
+		return false;
+	}
+
+	// read the attributes
+	for (unsigned int i = 0; i < numAttributes; i++)
+	{
+		std::string key;
+		std::string value;
+		ret = _peer->readUTF(key, true, &transaction->_crc);
+		if (ret <= 0)
+		{
+			return false;
+		}
+		ret = _peer->readUTF(value, true, &transaction->_crc);
+		if (ret <= 0)
+		{
+			return false;
+		}
+		packet->_attributes[key] = value;
+		_logger->log_info("Site2Site transaction %s receives attribute key %s value %s", transactionID.c_str(), key.c_str(), value.c_str());
+	}
+
+	uint64_t len;
+	ret = _peer->read(len, &transaction->_crc);
+	if (ret <= 0)
+	{
+		return false;
+	}
+
+	packet->_size = len;
+	transaction->_transfers++;
+	transaction->_state = DATA_EXCHANGED;
+	transaction->_bytes += len;
+	_logger->log_info("Site2Site transaction %s receives flow record %d, total length %d", transactionID.c_str(),
+			transaction->_transfers, transaction->_bytes);
+
+	return true;
+}
+
+bool Site2SiteClientProtocol::send(std::string transactionID, DataPacket *packet, FlowFileRecord *flowFile, ProcessSession *session)
+{
+	int ret;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		return false;
+	}
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return false;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	if (transaction->getState() != TRANSACTION_STARTED && transaction->getState() != DATA_EXCHANGED)
+	{
+		_logger->log_info("Site2Site transaction %s is not at started or exchanged state", transactionID.c_str());
+		return false;
+	}
+
+	if (transaction->getDirection() != SEND)
+	{
+		_logger->log_info("Site2Site transaction %s direction is wrong", transactionID.c_str());
+		return false;
+	}
+
+	if (transaction->_transfers > 0)
+	{
+		ret = writeRespond(CONTINUE_TRANSACTION, "CONTINUE_TRANSACTION");
+		if (ret <= 0)
+		{
+			return false;
+		}
+	}
+
+	// start to read the packet
+	uint32_t numAttributes = packet->_attributes.size();
+	ret = _peer->write(numAttributes, &transaction->_crc);
+	if (ret != 4)
+	{
+		return false;
+	}
+
+	std::map<std::string, std::string>::iterator itAttribute;
+	for (itAttribute = packet->_attributes.begin(); itAttribute!= packet->_attributes.end(); itAttribute++)
+	{
+		ret = _peer->writeUTF(itAttribute->first, true, &transaction->_crc);
+		if (ret <= 0)
+		{
+			return false;
+		}
+		ret = _peer->writeUTF(itAttribute->second, true, &transaction->_crc);
+		if (ret <= 0)
+		{
+			return false;
+		}
+		_logger->log_info("Site2Site transaction %s send attribute key %s value %s", transactionID.c_str(),
+				itAttribute->first.c_str(), itAttribute->second.c_str());
+	}
+
+	uint64_t len = flowFile->getSize() ;
+	ret = _peer->write(len, &transaction->_crc);
+	if (ret != 8)
+	{
+		return false;
+	}
+
+	if (flowFile->getSize())
+	{
+		Site2SiteClientProtocol::ReadCallback callback(packet);
+		session->read(flowFile, &callback);
+		if (flowFile->getSize() != packet->_size)
+		{
+			return false;
+		}
+	}
+
+	transaction->_transfers++;
+	transaction->_state = DATA_EXCHANGED;
+	transaction->_bytes += len;
+	_logger->log_info("Site2Site transaction %s send flow record %d, total length %d", transactionID.c_str(),
+				transaction->_transfers, transaction->_bytes);
+
+	return true;
+}
+
+void Site2SiteClientProtocol::receiveFlowFiles(ProcessContext *context, ProcessSession *session)
+{
+	uint64_t bytes = 0;
+	int transfers = 0;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		context->yield();
+		tearDown();
+		throw Exception(SITE2SITE_EXCEPTION, "Can not establish handshake with peer");
+		return;
+	}
+
+	// Create the transaction
+	std::string transactionID;
+	transaction = createTransaction(transactionID, RECEIVE);
+
+	if (transaction == NULL)
+	{
+		context->yield();
+		tearDown();
+		throw Exception(SITE2SITE_EXCEPTION, "Can not create transaction");
+		return;
+	}
+
+	try
+	{
+		while (true)
+		{
+			std::map<std::string, std::string> empty;
+			DataPacket packet(this, transaction, empty);
+			bool eof = false;
+
+			if (!receive(transactionID, &packet, eof))
+			{
+				throw Exception(SITE2SITE_EXCEPTION, "Receive Failed");
+				return;
+			}
+			if (eof)
+			{
+				// transaction done
+				break;
+			}
+			FlowFileRecord *flowFile = session->create();
+			if (!flowFile)
+			{
+				throw Exception(SITE2SITE_EXCEPTION, "Flow File Creation Failed");
+				return;
+			}
+			std::map<std::string, std::string>::iterator it;
+			for (it = packet._attributes.begin(); it!= packet._attributes.end(); it++)
+			{
+				flowFile->addAttribute(it->first, it->second);
+			}
+
+			if (packet._size > 0)
+			{
+				Site2SiteClientProtocol::WriteCallback callback(&packet);
+				session->write(flowFile, &callback);
+				if (flowFile->getSize() != packet._size)
+				{
+					throw Exception(SITE2SITE_EXCEPTION, "Receive Size Not Right");
+					return;
+				}
+			}
+			Relationship relation; // undefined relationship
+			session->transfer(flowFile, relation);
+			// receive the transfer for the flow record
+			bytes += packet._size;
+			transfers++;
+		} // while true
+
+		if (!confirm(transactionID))
+		{
+			throw Exception(SITE2SITE_EXCEPTION, "Confirm Transaction Failed");
+			return;
+		}
+		if (!complete(transactionID))
+		{
+			throw Exception(SITE2SITE_EXCEPTION, "Complete Transaction Failed");
+			return;
+		}
+		_logger->log_info("Site2Site transaction %s successfully receive flow record %d, content bytes %d",
+				transactionID.c_str(), transfers, bytes);
+		// we yield the receive if we did not get anything
+		if (transfers == 0)
+			context->yield();
+	}
+	catch (std::exception &exception)
+	{
+		if (transaction)
+			deleteTransaction(transactionID);
+		context->yield();
+		tearDown();
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		if (transaction)
+			deleteTransaction(transactionID);
+		context->yield();
+		tearDown();
+		_logger->log_debug("Caught Exception during Site2SiteClientProtocol::receiveFlowFiles");
+		throw;
+	}
+
+	deleteTransaction(transactionID);
+
+	return;
+}
+
+bool Site2SiteClientProtocol::confirm(std::string transactionID)
+{
+	int ret;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		return false;
+	}
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return false;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	if (transaction->getState() == TRANSACTION_STARTED && !transaction->isDataAvailable() &&
+			transaction->getDirection() == RECEIVE)
+	{
+		transaction->_state = TRANSACTION_CONFIRMED;
+		return true;
+	}
+
+	if (transaction->getState() != DATA_EXCHANGED)
+		return false;
+
+	if (transaction->getDirection() == RECEIVE)
+	{
+		if (transaction->isDataAvailable())
+			return false;
+		// we received a FINISH_TRANSACTION indicator. Send back a CONFIRM_TRANSACTION message
+		// to peer so that we can verify that the connection is still open. This is a two-phase commit,
+		// which helps to prevent the chances of data duplication. Without doing this, we may commit the
+		// session and then when we send the response back to the peer, the peer may have timed out and may not
+		// be listening. As a result, it will re-send the data. By doing this two-phase commit, we narrow the
+		// Critical Section involved in this transaction so that rather than the Critical Section being the
+		// time window involved in the entire transaction, it is reduced to a simple round-trip conversation.
+		long crcValue = transaction->getCRC();
+		std::string crc = std::to_string(crcValue);
+		_logger->log_info("Site2Site Send confirm with CRC %d to transaction %s", transaction->getCRC(),
+						transactionID.c_str());
+		ret = writeRespond(CONFIRM_TRANSACTION, crc);
+		if (ret <= 0)
+			return false;
+		RespondCode code;
+		std::string message;
+		readRespond(code, message);
+		if (ret <= 0)
+			return false;
+
+		if (code == CONFIRM_TRANSACTION)
+		{
+			_logger->log_info("Site2Site transaction %s peer confirm transaction", transactionID.c_str());
+			transaction->_state = TRANSACTION_CONFIRMED;
+			return true;
+		}
+		else if (code == BAD_CHECKSUM)
+		{
+			_logger->log_info("Site2Site transaction %s peer indicate bad checksum", transactionID.c_str());
+			/*
+			transaction->_state = TRANSACTION_CONFIRMED;
+			return true; */
+			return false;
+		}
+		else
+		{
+			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
+					transactionID.c_str(), code);
+			return false;
+		}
+	}
+	else
+	{
+		_logger->log_info("Site2Site Send FINISH TRANSACTION for transaction %s",
+								transactionID.c_str());
+		ret = writeRespond(FINISH_TRANSACTION, "FINISH_TRANSACTION");
+		if (ret <= 0)
+			return false;
+		RespondCode code;
+		std::string message;
+		readRespond(code, message);
+		if (ret <= 0)
+			return false;
+
+		// we've sent a FINISH_TRANSACTION. Now we'll wait for the peer to send a 'Confirm Transaction' response
+		if (code == CONFIRM_TRANSACTION)
+		{
+			_logger->log_info("Site2Site transaction %s peer confirm transaction with CRC %s", transactionID.c_str(), message.c_str());
+			if (this->_currentVersion > 3)
+			{
+				long crcValue = transaction->getCRC();
+				std::string crc = std::to_string(crcValue);
+				if (message == crc)
+				{
+					_logger->log_info("Site2Site transaction %s CRC matched", transactionID.c_str());
+					ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
+					if (ret <= 0)
+						return false;
+					transaction->_state = TRANSACTION_CONFIRMED;
+					return true;
+				}
+				else
+				{
+					_logger->log_info("Site2Site transaction %s CRC not matched %s", transactionID.c_str(), crc.c_str());
+					ret = writeRespond(BAD_CHECKSUM, "BAD_CHECKSUM");
+					/*
+					ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
+										if (ret <= 0)
+											return false;
+										transaction->_state = TRANSACTION_CONFIRMED;
+					return true; */
+					return false;
+				}
+			}
+			ret = writeRespond(CONFIRM_TRANSACTION, "CONFIRM_TRANSACTION");
+			if (ret <= 0)
+				return false;
+			transaction->_state = TRANSACTION_CONFIRMED;
+			return true;
+		}
+		else
+		{
+			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
+					transactionID.c_str(), code);
+			return false;
+		}
+		return false;
+	}
+}
+
+void Site2SiteClientProtocol::cancel(std::string transactionID)
+{
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		return;
+	}
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	if (transaction->getState() == TRANSACTION_CANCELED || transaction->getState() == TRANSACTION_COMPLETED
+			|| transaction->getState() == TRANSACTION_ERROR)
+	{
+		return;
+	}
+
+	this->writeRespond(CANCEL_TRANSACTION, "Cancel");
+	transaction->_state = TRANSACTION_CANCELED;
+
+	tearDown();
+	return;
+}
+
+void Site2SiteClientProtocol::deleteTransaction(std::string transactionID)
+{
+	Transaction *transaction = NULL;
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	_logger->log_info("Site2Site delete transaction %s", transaction->getUUIDStr().c_str());
+	delete transaction;
+	_transactionMap.erase(transactionID);
+}
+
+void Site2SiteClientProtocol::error(std::string transactionID)
+{
+	Transaction *transaction = NULL;
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	transaction->_state = TRANSACTION_ERROR;
+	tearDown();
+	return;
+}
+
+//! Complete the transaction
+bool Site2SiteClientProtocol::complete(std::string transactionID)
+{
+	int ret;
+	Transaction *transaction = NULL;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		return false;
+	}
+
+	std::map<std::string, Transaction *>::iterator it = this->_transactionMap.find(transactionID);
+
+	if (it == _transactionMap.end())
+	{
+		return false;
+	}
+	else
+	{
+		transaction = it->second;
+	}
+
+	if (transaction->getState() != TRANSACTION_CONFIRMED)
+	{
+		return false;
+	}
+
+	if (transaction->getDirection() == RECEIVE)
+	{
+		if (transaction->_transfers == 0)
+		{
+			transaction->_state = TRANSACTION_COMPLETED;
+			return true;
+		}
+		else
+		{
+			_logger->log_info("Site2Site transaction %s send finished", transactionID.c_str());
+			ret = this->writeRespond(TRANSACTION_FINISHED, "Finished");
+			if (ret <= 0)
+				return false;
+			else
+			{
+				transaction->_state = TRANSACTION_COMPLETED;
+				return true;
+			}
+		}
+	}
+	else
+	{
+		RespondCode code;
+		std::string message;
+		int ret;
+
+		ret = readRespond(code, message);
+
+		if (ret <= 0)
+			return false;
+
+		if (code == TRANSACTION_FINISHED)
+		{
+			_logger->log_info("Site2Site transaction %s peer finished transaction", transactionID.c_str());
+			transaction->_state = TRANSACTION_COMPLETED;
+			return true;
+		}
+		else
+		{
+			_logger->log_info("Site2Site transaction %s peer unknown respond code %d",
+					transactionID.c_str(), code);
+			return false;
+		}
+	}
+}
+
+void Site2SiteClientProtocol::transferFlowFiles(ProcessContext *context, ProcessSession *session)
+{
+	FlowFileRecord *flow = session->get();
+	Transaction *transaction = NULL;
+
+	if (!flow)
+		return;
+
+	if (_peerState != READY)
+	{
+		bootstrap();
+	}
+
+	if (_peerState != READY)
+	{
+		context->yield();
+		tearDown();
+		throw Exception(SITE2SITE_EXCEPTION, "Can not establish handshake with peer");
+		return;
+	}
+
+	// Create the transaction
+	std::string transactionID;
+	transaction = createTransaction(transactionID, SEND);
+
+	if (transaction == NULL)
+	{
+		context->yield();
+		tearDown();
+		throw Exception(SITE2SITE_EXCEPTION, "Can not create transaction");
+		return;
+	}
+
+	bool continueTransaction = true;
+	uint64_t startSendingNanos = getTimeNano();
+
+	try
+	{
+		while (continueTransaction)
+		{
+			DataPacket packet(this, transaction, flow->getAttributes());
+
+			if (!send(transactionID, &packet, flow, session))
+			{
+				throw Exception(SITE2SITE_EXCEPTION, "Send Failed");
+				return;
+			}
+			_logger->log_info("Site2Site transaction %s send flow record %s",
+							transactionID.c_str(), flow->getUUIDStr().c_str());
+			session->remove(flow);
+
+			uint64_t transferNanos = getTimeNano() - startSendingNanos;
+			if (transferNanos > _batchSendNanos)
+				break;
+
+			flow = session->get();
+			if (!flow)
+			{
+				continueTransaction = false;
+			}
+		} // while true
+
+		if (!confirm(transactionID))
+		{
+			throw Exception(SITE2SITE_EXCEPTION, "Confirm Failed");
+			return;
+		}
+		if (!complete(transactionID))
+		{
+			throw Exception(SITE2SITE_EXCEPTION, "Complete Failed");
+			return;
+		}
+		_logger->log_info("Site2Site transaction %s successfully send flow record %d, content bytes %d",
+				transactionID.c_str(), transaction->_transfers, transaction->_bytes);
+	}
+	catch (std::exception &exception)
+	{
+		if (transaction)
+			deleteTransaction(transactionID);
+		context->yield();
+		tearDown();
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		if (transaction)
+			deleteTransaction(transactionID);
+		context->yield();
+		tearDown();
+		_logger->log_debug("Caught Exception during Site2SiteClientProtocol::transferFlowFiles");
+		throw;
+	}
+
+	deleteTransaction(transactionID);
+
+	return;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Site2SitePeer.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Site2SitePeer.cpp b/libminifi/src/Site2SitePeer.cpp
new file mode 100644
index 0000000..48e19d0
--- /dev/null
+++ b/libminifi/src/Site2SitePeer.cpp
@@ -0,0 +1,435 @@
+/**
+ * @file Site2SitePeer.cpp
+ * Site2SitePeer class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/time.h>
+#include <stdio.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <random>
+#include <netinet/tcp.h>
+#include <iostream>
+#include "Site2SitePeer.h"
+
+//! CRC tables
+std::atomic<bool> CRC32::tableInit(false);
+unsigned int CRC32::table[256];
+
+bool Site2SitePeer::Open()
+{
+	in_addr_t addr;
+	int sock = 0;
+	struct hostent *h;
+	const char *host;
+	uint16_t port;
+
+	host = this->_host.c_str();
+	port = this->_port;
+
+	if (strlen(host) == 0)
+		return false;
+
+#ifdef __MACH__
+	h = gethostbyname(host);
+#else
+	char buf[1024];
+	struct hostent he;
+	int hh_errno;
+	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
+#endif
+	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0)
+	{
+		_logger->log_error("Could not create socket to hostName %s", host);
+		this->yield();
+		return false;
+	}
+
+#ifndef __MACH__
+	int opt = 1;
+	bool nagle_off = true;
+
+	if (nagle_off)
+	{
+		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() TCP_NODELAY failed");
+			close(sock);
+			this->yield();
+			return false;
+		}
+		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+				(char *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() SO_REUSEADDR failed");
+			close(sock);
+			this->yield();
+			return false;
+		}
+	}
+
+	int sndsize = 256*1024;
+	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
+	{
+		_logger->log_error("setsockopt() SO_SNDBUF failed");
+		close(sock);
+		this->yield();
+		return false;
+	}
+	int rcvsize = 256*1024;
+	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcvsize, (int)sizeof(rcvsize)) < 0)
+	{
+		_logger->log_error("setsockopt() SO_RCVBUF failed");
+		close(sock);
+		this->yield();
+		return false;
+	}
+#endif
+
+	struct sockaddr_in sa;
+	socklen_t socklen;
+	int status;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = htonl(INADDR_ANY);
+	sa.sin_port = htons(0);
+	socklen = sizeof(sa);
+	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
+	{
+		_logger->log_error("socket bind failed");
+		close(sock);
+		this->yield();
+		return false;
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = addr;
+	sa.sin_port = htons(port);
+	socklen = sizeof(sa);
+
+	status = connect(sock, (struct sockaddr *)&sa, socklen);
+
+	if (status < 0)
+	{
+		_logger->log_error("socket connect failed to %s %d", host, port);
+		close(sock);
+		this->yield();
+		return false;
+	}
+
+	_logger->log_info("Site2Site Peer socket %d connect to server %s port %d success", sock, host, port);
+
+	_socket = sock;
+
+	status = sendData((uint8_t *) MAGIC_BYTES, sizeof(MAGIC_BYTES));
+
+	if (status <= 0)
+	{
+		Close();
+		return false;
+	}
+
+	return true;
+}
+
+void Site2SitePeer::Close()
+{
+	if (_socket)
+	{
+		_logger->log_info("Site2Site Peer socket %d close", _socket);
+		close(_socket);
+		_socket = 0;
+	}
+}
+
+int Site2SitePeer::sendData(uint8_t *buf, int buflen, CRC32 *crc)
+{
+	int ret = 0, bytes = 0;
+
+	if (_socket <= 0)
+	{
+		// this->yield();
+		return -1;
+	}
+
+	while (bytes < buflen)
+	{
+		ret = send(_socket, buf+bytes, buflen-bytes, 0);
+		//check for errors
+		if (ret == -1)
+		{
+			_logger->log_error("Site2Site Peer socket %d send failed %s", _socket, strerror(errno));
+			Close();
+			// this->yield();
+			return ret;
+		}
+		bytes+=ret;
+	}
+
+	if (crc)
+		crc->update(buf, buflen);
+
+	return bytes;
+}
+
+int Site2SitePeer::Select(int msec)
+{
+	fd_set fds;
+	struct timeval tv;
+    int retval;
+    int fd = _socket;
+
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+
+    tv.tv_sec = msec/1000;
+    tv.tv_usec = (msec % 1000) * 1000;
+
+    if (msec > 0)
+       retval = select(fd+1, &fds, NULL, NULL, &tv);
+    else
+       retval = select(fd+1, &fds, NULL, NULL, NULL);
+
+    if (retval <= 0)
+      return retval;
+    if (FD_ISSET(fd, &fds))
+      return retval;
+    else
+      return 0;
+}
+
+int Site2SitePeer::readData(uint8_t *buf, int buflen, CRC32 *crc)
+{
+	int sendSize = buflen;
+	uint8_t *start = buf;
+
+	if (_socket <= 0)
+	{
+		// this->yield();
+		return -1;
+	}
+
+	while (buflen)
+	{
+		int status;
+		status = Select((int) _timeOut);
+		if (status <= 0)
+		{
+			Close();
+			return status;
+		}
+		status = recv(_socket, buf, buflen, 0);
+		if (status <= 0)
+		{
+			Close();
+			// this->yield();
+			return status;
+		}
+		buflen -= status;
+		buf += status;
+	}
+
+	if (crc)
+		crc->update(start, sendSize);
+
+	return sendSize;
+}
+
+int Site2SitePeer::writeUTF(std::string str, bool widen, CRC32 *crc)
+{
+	int strlen = str.length();
+	int utflen = 0;
+	int c, count = 0;
+
+	/* use charAt instead of copying String to char array */
+	for (int i = 0; i < strlen; i++) {
+		c = str.at(i);
+		if ((c >= 0x0001) && (c <= 0x007F)) {
+			utflen++;
+		} else if (c > 0x07FF) {
+			utflen += 3;
+		} else {
+			utflen += 2;
+		}
+	}
+
+	if (utflen > 65535)
+		return -1;
+
+	uint8_t *bytearr = NULL;
+	if (!widen)
+	{
+		bytearr = new uint8_t[utflen+2];
+		bytearr[count++] = (uint8_t) ((utflen >> 8) & 0xFF);
+		bytearr[count++] = (uint8_t) ((utflen >> 0) & 0xFF);
+	}
+	else
+	{
+		bytearr = new uint8_t[utflen+4];
+		bytearr[count++] = (uint8_t) ((utflen >> 24) & 0xFF);
+		bytearr[count++] = (uint8_t) ((utflen >> 16) & 0xFF);
+		bytearr[count++] = (uint8_t) ((utflen >> 8) & 0xFF);
+		bytearr[count++] = (uint8_t) ((utflen >> 0) & 0xFF);
+	}
+
+	int i=0;
+	for (i=0; i<strlen; i++) {
+		c = str.at(i);
+		if (!((c >= 0x0001) && (c <= 0x007F))) break;
+		bytearr[count++] = (uint8_t) c;
+	}
+
+	for (;i < strlen; i++){
+		c = str.at(i);
+		if ((c >= 0x0001) && (c <= 0x007F)) {
+			bytearr[count++] = (uint8_t) c;
+		} else if (c > 0x07FF) {
+			bytearr[count++] = (uint8_t) (0xE0 | ((c >> 12) & 0x0F));
+			bytearr[count++] = (uint8_t) (0x80 | ((c >>  6) & 0x3F));
+			bytearr[count++] = (uint8_t) (0x80 | ((c >>  0) & 0x3F));
+		} else {
+			bytearr[count++] = (uint8_t) (0xC0 | ((c >>  6) & 0x1F));
+			bytearr[count++] = (uint8_t) (0x80 | ((c >>  0) & 0x3F));
+		}
+	}
+	int ret;
+	if (!widen)
+	{
+		ret = sendData(bytearr, utflen+2, crc);
+	}
+	else
+	{
+		ret = sendData(bytearr, utflen+4, crc);
+	}
+	delete[] bytearr;
+	return ret;
+}
+
+int Site2SitePeer::readUTF(std::string &str, bool widen, CRC32 *crc)
+{
+    uint16_t utflen;
+    int ret;
+
+    if (!widen)
+    {
+    	ret = read(utflen, crc);
+    	if (ret <= 0)
+    		return ret;
+    }
+    else
+    {
+    	uint32_t len;
+       	ret = read(len, crc);
+        if (ret <= 0)
+        	return ret;
+        utflen = len;
+    }
+
+    uint8_t *bytearr = NULL;
+    char *chararr = NULL;
+    bytearr = new uint8_t[utflen];
+    chararr = new char[utflen];
+    memset(chararr, 0, utflen);
+
+    int c, char2, char3;
+    int count = 0;
+    int chararr_count=0;
+
+    ret = read(bytearr, utflen, crc);
+    if (ret <= 0)
+    {
+    	delete[] bytearr;
+    	delete[] chararr;
+    	return ret;
+    }
+
+    while (count < utflen) {
+        c = (int) bytearr[count] & 0xff;
+        if (c > 127) break;
+        count++;
+        chararr[chararr_count++]=(char)c;
+    }
+
+    while (count < utflen) {
+        c = (int) bytearr[count] & 0xff;
+        switch (c >> 4) {
+            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+                /* 0xxxxxxx*/
+                count++;
+                chararr[chararr_count++]=(char)c;
+                break;
+            case 12: case 13:
+                /* 110x xxxx   10xx xxxx*/
+                count += 2;
+                if (count > utflen)
+                {
+                	delete[] bytearr;
+                	delete[] chararr;
+                	return -1;
+                }
+                char2 = (int) bytearr[count-1];
+                if ((char2 & 0xC0) != 0x80)
+                {
+                	delete[] bytearr;
+                	delete[] chararr;
+                	return -1;
+                }
+                chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
+                                                (char2 & 0x3F));
+                break;
+            case 14:
+                /* 1110 xxxx  10xx xxxx  10xx xxxx */
+                count += 3;
+                if (count > utflen)
+                {
+                	delete[] bytearr;
+                	delete[] chararr;
+                	return -1;
+                }
+                char2 = (int) bytearr[count-2];
+                char3 = (int) bytearr[count-1];
+                if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+                {
+                	delete[] bytearr;
+                	delete[] chararr;
+                	return -1;
+                }
+                chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
+                                                ((char2 & 0x3F) << 6)  |
+                                                ((char3 & 0x3F) << 0));
+                break;
+            default:
+            	delete[] bytearr;
+            	delete[] chararr;
+            	return -1;
+        }
+    }
+    // The number of chars produced may be less than utflen
+    std::string value(chararr, chararr_count);
+    str = value;
+    delete[] bytearr;
+    delete[] chararr;
+    if (!widen)
+    	return (2 + utflen);
+    else
+    	return (4 + utflen);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/TailFile.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/TailFile.cpp b/libminifi/src/TailFile.cpp
new file mode 100644
index 0000000..445255b
--- /dev/null
+++ b/libminifi/src/TailFile.cpp
@@ -0,0 +1,272 @@
+/**
+ * @file TailFile.cpp
+ * TailFile class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sstream>
+#include <stdio.h>
+#include <string>
+#include <iostream>
+#include <dirent.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "TimeUtil.h"
+#include "TailFile.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string TailFile::ProcessorName("TailFile");
+Property TailFile::FileName("File to Tail", "Fully-qualified filename of the file that should be tailed", "");
+Property TailFile::StateFile("State File",
+		"Specifies the file that should be used for storing state about what data has been ingested so that upon restart NiFi can resume from where it left off", "");
+Relationship TailFile::Success("success", "All files are routed to success");
+
+void TailFile::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(FileName);
+	properties.insert(StateFile);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+}
+
+std::string TailFile::trimLeft(const std::string& s)
+{
+	const char *WHITESPACE = " \n\r\t";
+    size_t startpos = s.find_first_not_of(WHITESPACE);
+    return (startpos == std::string::npos) ? "" : s.substr(startpos);
+}
+
+std::string TailFile::trimRight(const std::string& s)
+{
+	const char *WHITESPACE = " \n\r\t";
+    size_t endpos = s.find_last_not_of(WHITESPACE);
+    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
+}
+
+void TailFile::parseStateFileLine(char *buf)
+{
+	char *line = buf;
+
+    while ((line[0] == ' ') || (line[0] =='\t'))
+    	++line;
+
+    char first = line[0];
+    if ((first == '\0') || (first == '#')  || (first == '\r') || (first == '\n') || (first == '='))
+    {
+    	return;
+    }
+
+    char *equal = strchr(line, '=');
+    if (equal == NULL)
+    {
+    	return;
+    }
+
+    equal[0] = '\0';
+    std::string key = line;
+
+    equal++;
+    while ((equal[0] == ' ') || (equal[0] == '\t'))
+    	++equal;
+
+    first = equal[0];
+    if ((first == '\0') || (first == '\r') || (first== '\n'))
+    {
+    	return;
+    }
+
+    std::string value = equal;
+    key = trimRight(key);
+    value = trimRight(value);
+
+    if (key == "FILENAME")
+    	this->_currentTailFileName = value;
+    if (key == "POSITION")
+    	this->_currentTailFilePosition = std::stoi(value);
+
+    return;
+}
+
+void TailFile::recoverState()
+{
+	std::ifstream file(_stateFile.c_str(), std::ifstream::in);
+	if (!file.good())
+	{
+		_logger->log_error("load state file failed %s", _stateFile.c_str());
+		return;
+	}
+	const unsigned int bufSize = 512;
+	char buf[bufSize];
+	for (file.getline(buf,bufSize); file.good(); file.getline(buf,bufSize))
+	{
+		parseStateFileLine(buf);
+	}
+}
+
+void TailFile::storeState()
+{
+	std::ofstream file(_stateFile.c_str());
+	if (!file.is_open())
+	{
+		_logger->log_error("store state file failed %s", _stateFile.c_str());
+		return;
+	}
+	file << "FILENAME=" << this->_currentTailFileName << "\n";
+	file << "POSITION=" << this->_currentTailFilePosition << "\n";
+	file.close();
+}
+
+static bool sortTailMatchedFileItem(TailMatchedFileItem i, TailMatchedFileItem j)
+{
+	return (i.modifiedTime < j.modifiedTime);
+}
+void TailFile::checkRollOver()
+{
+	struct stat statbuf;
+	std::vector<TailMatchedFileItem> matchedFiles;
+	std::string fullPath = this->_fileLocation + "/" + _currentTailFileName;
+
+	if (stat(fullPath.c_str(), &statbuf) == 0)
+	{
+		if (statbuf.st_size > this->_currentTailFilePosition)
+			// there are new input for the current tail file
+			return;
+
+		uint64_t modifiedTimeCurrentTailFile = ((uint64_t) (statbuf.st_mtime) * 1000);
+		std::string pattern = _fileName;
+		std::size_t found = _fileName.find_last_of(".");
+		if (found != std::string::npos)
+			pattern = _fileName.substr(0,found);
+		DIR *d;
+		d = opendir(this->_fileLocation.c_str());
+		if (!d)
+			return;
+		while (1)
+		{
+			struct dirent *entry;
+			entry = readdir(d);
+			if (!entry)
+				break;
+			std::string d_name = entry->d_name;
+			if (!(entry->d_type & DT_DIR))
+			{
+				std::string fileName = d_name;
+				std::string fileFullName = this->_fileLocation + "/" + d_name;
+				if (fileFullName.find(pattern) != std::string::npos && stat(fileFullName.c_str(), &statbuf) == 0)
+				{
+					if (((uint64_t) (statbuf.st_mtime) * 1000) >= modifiedTimeCurrentTailFile)
+					{
+						TailMatchedFileItem item;
+						item.fileName = fileName;
+						item.modifiedTime = ((uint64_t) (statbuf.st_mtime) * 1000);
+						matchedFiles.push_back(item);
+					}
+				}
+			}
+		}
+		closedir(d);
+
+		// Sort the list based on modified time
+		std::sort(matchedFiles.begin(), matchedFiles.end(), sortTailMatchedFileItem);
+		for (std::vector<TailMatchedFileItem>::iterator it = matchedFiles.begin(); it!=matchedFiles.end(); ++it)
+		{
+			TailMatchedFileItem item = *it;
+			if (item.fileName == _currentTailFileName)
+			{
+				++it;
+				if (it!=matchedFiles.end())
+				{
+					TailMatchedFileItem nextItem = *it;
+					_logger->log_info("TailFile File Roll Over from %s to %s", _currentTailFileName.c_str(), nextItem.fileName.c_str());
+					_currentTailFileName = nextItem.fileName;
+					_currentTailFilePosition = 0;
+					storeState();
+				}
+				break;
+			}
+		}
+	}
+	else
+		return;
+}
+
+
+void TailFile::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string value;
+	if (context->getProperty(FileName.getName(), value))
+	{
+		std::size_t found = value.find_last_of("/\\");
+		this->_fileLocation = value.substr(0,found);
+		this->_fileName = value.substr(found+1);
+	}
+	if (context->getProperty(StateFile.getName(), value))
+	{
+		_stateFile = value;
+	}
+	if (!this->_stateRecovered)
+	{
+		_stateRecovered = true;
+		this->_currentTailFileName = _fileName;
+		this->_currentTailFilePosition = 0;
+		// recover the state if we have not done so
+		this->recoverState();
+	}
+	checkRollOver();
+	std::string fullPath = this->_fileLocation + "/" + _currentTailFileName;
+	struct stat statbuf;
+	if (stat(fullPath.c_str(), &statbuf) == 0)
+	{
+		if (statbuf.st_size <= this->_currentTailFilePosition)
+			// there are no new input for the current tail file
+		{
+			context->yield();
+			return;
+		}
+		FlowFileRecord *flowFile = session->create();
+		if (!flowFile)
+			return;
+		std::size_t found = _currentTailFileName.find_last_of(".");
+		std::string baseName = _currentTailFileName.substr(0,found);
+		std::string extension = _currentTailFileName.substr(found+1);
+		flowFile->updateAttribute(PATH, _fileLocation);
+		flowFile->addAttribute(ABSOLUTE_PATH, fullPath);
+		session->import(fullPath, flowFile, true, this->_currentTailFilePosition);
+		session->transfer(flowFile, Success);
+		_logger->log_info("TailFile %s for %d bytes", _currentTailFileName.c_str(), flowFile->getSize());
+		std::string logName = baseName + "." + std::to_string(_currentTailFilePosition) + "-" +
+				std::to_string(_currentTailFilePosition + flowFile->getSize()) + "." + extension;
+		flowFile->updateAttribute(FILENAME, logName);
+		this->_currentTailFilePosition += flowFile->getSize();
+		storeState();
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/TimerDrivenSchedulingAgent.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/TimerDrivenSchedulingAgent.cpp b/libminifi/src/TimerDrivenSchedulingAgent.cpp
new file mode 100644
index 0000000..3ce57ae
--- /dev/null
+++ b/libminifi/src/TimerDrivenSchedulingAgent.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file TimerDrivenSchedulingAgent.cpp
+ * TimerDrivenSchedulingAgent class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <chrono>
+#include <thread>
+#include <iostream>
+#include "Property.h"
+#include "TimerDrivenSchedulingAgent.h"
+
+void TimerDrivenSchedulingAgent::schedule(Processor *processor)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_administrativeYieldDuration = 0;
+	std::string yieldValue;
+
+	if (_configure->get(Configure::nifi_administrative_yield_duration, yieldValue))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(yieldValue, _administrativeYieldDuration, unit) &&
+					Property::ConvertTimeUnitToMS(_administrativeYieldDuration, unit, _administrativeYieldDuration))
+		{
+			_logger->log_debug("nifi_administrative_yield_duration: [%d] ms", _administrativeYieldDuration);
+		}
+	}
+
+	_boredYieldDuration = 0;
+	if (_configure->get(Configure::nifi_bored_yield_duration, yieldValue))
+	{
+		TimeUnit unit;
+		if (Property::StringToTime(yieldValue, _boredYieldDuration, unit) &&
+					Property::ConvertTimeUnitToMS(_boredYieldDuration, unit, _boredYieldDuration))
+		{
+			_logger->log_debug("nifi_bored_yield_duration: [%d] ms", _boredYieldDuration);
+		}
+	}
+
+	if (processor->getScheduledState() != RUNNING)
+	{
+		_logger->log_info("Can not schedule threads for processor %s because it is not running", processor->getName().c_str());
+		return;
+	}
+
+	std::map<std::string, std::vector<std::thread *>>::iterator it =
+			_threads.find(processor->getUUIDStr());
+	if (it != _threads.end())
+	{
+		_logger->log_info("Can not schedule threads for processor %s because there are existed thread running");
+		return;
+	}
+
+	std::vector<std::thread *> threads;
+	for (int i = 0; i < processor->getMaxConcurrentTasks(); i++)
+	{
+		std::thread *thread = new std::thread(run, this, processor);
+		thread->detach();
+		threads.push_back(thread);
+		_logger->log_info("Scheduled Time Driven thread %d running for process %s", thread->get_id(),
+				processor->getName().c_str());
+	}
+	_threads[processor->getUUIDStr().c_str()] = threads;
+
+	return;
+}
+
+void TimerDrivenSchedulingAgent::unschedule(Processor *processor)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (processor->getScheduledState() != RUNNING)
+	{
+		_logger->log_info("Can not unschedule threads for processor %s because it is not running", processor->getName().c_str());
+		return;
+	}
+
+	std::map<std::string, std::vector<std::thread *>>::iterator it =
+			_threads.find(processor->getUUIDStr());
+
+	if (it == _threads.end())
+	{
+		_logger->log_info("Can not unschedule threads for processor %s because there are no existed thread running");
+		return;
+	}
+	for (std::vector<std::thread *>::iterator itThread = it->second.begin(); itThread != it->second.end(); ++itThread)
+	{
+		std::thread *thread = *itThread;
+		_logger->log_info("Scheduled Time Driven thread %d deleted for process %s", thread->get_id(),
+				processor->getName().c_str());
+		delete thread;
+	}
+	_threads.erase(processor->getUUIDStr());
+	processor->clearActiveTask();
+
+	return;
+}
+
+void TimerDrivenSchedulingAgent::run(TimerDrivenSchedulingAgent *agent, Processor *processor)
+{
+	while (agent->_running)
+	{
+		bool shouldYield = agent->onTrigger(processor);
+
+		if (processor->isYield())
+		{
+			// Honor the yield
+			std::this_thread::sleep_for(std::chrono::milliseconds(processor->getYieldTime()));
+		}
+		else if (shouldYield && agent->_boredYieldDuration > 0)
+		{
+			// No work to do or need to apply back pressure
+			std::this_thread::sleep_for(std::chrono::milliseconds(agent->_boredYieldDuration));
+		}
+		std::this_thread::sleep_for(std::chrono::nanoseconds(processor->getSchedulingPeriodNano()));
+	}
+	return;
+}
+
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/test/FlowFileRecordTest.cpp
----------------------------------------------------------------------
diff --git a/libminifi/test/FlowFileRecordTest.cpp b/libminifi/test/FlowFileRecordTest.cpp
new file mode 100644
index 0000000..09a3d33
--- /dev/null
+++ b/libminifi/test/FlowFileRecordTest.cpp
@@ -0,0 +1,28 @@
+/**
+ * @file MiNiFiMain.cpp 
+ * MiNiFiMain implementation 
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+
+#include "FlowFileRecord.h"
+
+int main(int argc, char **argv)
+{
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/test/Server.cpp
----------------------------------------------------------------------
diff --git a/libminifi/test/Server.cpp b/libminifi/test/Server.cpp
new file mode 100644
index 0000000..e7b3452
--- /dev/null
+++ b/libminifi/test/Server.cpp
@@ -0,0 +1,607 @@
+/* A simple server in the internet domain using TCP
+   The port number is passed as an argument */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string>
+#include <errno.h>
+#include <chrono>
+#include <thread>
+#include <iostream>     // std::cout
+#include <fstream>      // std::ifstream
+#include <signal.h>
+
+#define DEFAULT_NIFI_SERVER_PORT 9000
+#define DEFAULT_REPORT_INTERVAL 1000 // 1 sec
+#define MAX_READ_TIMEOUT 30000 // 30 seconds
+
+//! FlowControl Protocol Msg Type
+typedef enum {
+	REGISTER_REQ, // Device Register Request from device to server which contain device serial number, current running flow xml version
+	REGISTER_RESP, // Device Register Respond from server to device, may contain new flow.xml from server ask device to apply and also device report interval
+	REPORT_REQ, // Period Device Report from device to server which contain device serial number, current running flow xml name/version and other period report info
+	REPORT_RESP, // Report Respond from server to device, may ask device to update flow xml or processor property
+	MAX_FLOW_CONTROL_MSG_TYPE
+} FlowControlMsgType;
+
+//! FlowControl Protocol Msg Type String
+static const char *FlowControlMsgTypeStr[MAX_FLOW_CONTROL_MSG_TYPE] =
+{
+		"REGISTER_REQ",
+		"REGISTER_RESP",
+		"REPORT_REQ",
+		"REPORT_RESP"
+};
+
+//! Flow Control Msg Type to String
+inline const char *FlowControlMsgTypeToStr(FlowControlMsgType type)
+{
+	if (type < MAX_FLOW_CONTROL_MSG_TYPE)
+		return FlowControlMsgTypeStr[type];
+	else
+		return NULL;
+}
+
+//! FlowControll Protocol Msg ID (Some Messages are fix length, Some are variable length (TLV)
+typedef enum {
+	//Fix length 8 bytes: client to server in register request, required field
+	FLOW_SERIAL_NUMBER,
+	// Flow XML name TLV: client to server in register request and report request, required field
+	FLOW_XML_NAME,
+	// Flow XML content, TLV: server to client in register respond, option field in case server want to ask client to load xml from server
+	FLOW_XML_CONTENT,
+	// Fix length, 4 bytes Report interval in msec: server to client in register respond, option field
+	REPORT_INTERVAL,
+	// Processor Name TLV:  server to client in report respond, option field in case server want to ask client to update processor property
+	PROCESSOR_NAME,
+	// Processor Property Name TLV: server to client in report respond, option field in case server want to ask client to update processor property
+	PROPERTY_NAME,
+	// Processor Property Value TLV: server to client in report respond, option field in case server want to ask client to update processor property
+	PROPERTY_VALUE,
+	// Report Blob TLV: client to server in report request, option field in case client want to pickyback the report blob in report request to server
+	REPORT_BLOB,
+	MAX_FLOW_MSG_ID
+} FlowControlMsgID;
+
+//! FlowControl Protocol Msg ID String
+static const char *FlowControlMsgIDStr[MAX_FLOW_MSG_ID] =
+{
+		"FLOW_SERIAL_NUMBER",
+		"FLOW_XML_NAME",
+		"FLOW_XML_CONTENT",
+		"REPORT_INTERVAL",
+		"PROCESSOR_NAME"
+		"PROPERTY_NAME",
+		"PROPERTY_VALUE",
+		"REPORT_BLOB"
+};
+
+#define TYPE_HDR_LEN 4 // Fix Hdr Type
+#define TLV_HDR_LEN 8 // Type 4 bytes and Len 4 bytes
+
+//! FlowControl Protocol Msg Len
+inline int FlowControlMsgIDEncodingLen(FlowControlMsgID id, int payLoadLen)
+{
+	if (id == FLOW_SERIAL_NUMBER)
+		return (TYPE_HDR_LEN + 8);
+	else if (id == REPORT_INTERVAL)
+		return (TYPE_HDR_LEN + 4);
+	else if (id < MAX_FLOW_MSG_ID)
+		return (TLV_HDR_LEN + payLoadLen);
+	else
+		return -1;
+}
+
+//! Flow Control Msg Id to String
+inline const char *FlowControlMsgIdToStr(FlowControlMsgID id)
+{
+	if (id < MAX_FLOW_MSG_ID)
+		return FlowControlMsgIDStr[id];
+	else
+		return NULL;
+}
+
+//! Flow Control Respond status code
+typedef enum {
+	RESP_SUCCESS,
+	RESP_TRIGGER_REGISTER, // Server respond to client report to re trigger register
+	RESP_START_FLOW_CONTROLLER, // Server respond to client to start flow controller
+	RESP_STOP_FLOW_CONTROLLER, // Server respond to client to stop flow controller
+	RESP_FAILURE,
+	MAX_RESP_CODE
+} FlowControlRespCode;
+
+//! FlowControl Resp Code str
+static const char *FlowControlRespCodeStr[MAX_RESP_CODE] =
+{
+		"RESP_SUCCESS",
+		"RESP_TRIGGER_REGISTER",
+		"RESP_START_FLOW_CONTROLLER",
+		"RESP_STOP_FLOW_CONTROLLER",
+		"RESP_FAILURE"
+};
+
+//! Flow Control Resp Code to String
+inline const char *FlowControlRespCodeToStr(FlowControlRespCode code)
+{
+	if (code < MAX_RESP_CODE)
+		return FlowControlRespCodeStr[code];
+	else
+		return NULL;
+}
+
+//! Common FlowControlProtocol Header
+typedef struct {
+	uint32_t msgType; //! Msg Type
+	uint32_t seqNumber; //! Seq Number to match Req with Resp
+	uint32_t status; //! Resp Code, see FlowControlRespCode
+	uint32_t payloadLen; //! Msg Payload length
+} FlowControlProtocolHeader;
+
+
+//! encode uint32_t
+uint8_t *encode(uint8_t *buf, uint32_t value)
+{
+		*buf++ = (value & 0xFF000000) >> 24;
+		*buf++ = (value & 0x00FF0000) >> 16;
+		*buf++ = (value & 0x0000FF00) >> 8;
+		*buf++ = (value & 0x000000FF);
+		return buf;
+}
+
+//! encode uint32_t
+uint8_t *decode(uint8_t *buf, uint32_t &value)
+{
+		value = ((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3]));
+		return (buf + 4);
+}
+
+//! encode byte array
+uint8_t *encode(uint8_t *buf, uint8_t *bufArray, int size)
+{
+		memcpy(buf, bufArray, size);
+		buf += size;
+		return buf;
+}
+
+//! encode std::string
+uint8_t *encode(uint8_t *buf, std::string value)
+{
+		// add the \0 for size
+		buf = encode(buf, value.size()+1);
+		buf = encode(buf, (uint8_t *) value.c_str(), value.size()+1);
+		return buf;
+}
+
+int sendData(int socket, uint8_t *buf, int buflen)
+{
+	int ret = 0, bytes = 0;
+
+	while (bytes < buflen)
+	{
+		ret = send(socket, buf+bytes, buflen-bytes, 0);
+		//check for errors
+		if (ret == -1)
+		{
+			return ret;
+		}
+		bytes+=ret;
+	}
+
+	return bytes;
+}
+
+void error(const char *msg)
+{
+    perror(msg);
+    exit(1);
+}
+
+/* readline - read a '\n' terminated line from socket fd 
+              into buffer bufptr of size len. The line in the
+              buffer is terminated with '\0'.
+              It returns -1 in case of error or if
+              the capacity of the buffer is exceeded.
+	      It returns 0 if EOF is encountered before reading '\n'.
+ */
+int readline( int fd, char *bufptr, size_t len )
+{
+  /* Note that this function is very tricky.  It uses the
+     static variables bp, cnt, and b to establish a local buffer.
+     The recv call requests large chunks of data (the size of the buffer).
+     Then if the recv call reads more than one line, the overflow
+     remains in the buffer and it is made available to the next call
+     to readline. 
+     Notice also that this routine reads up to '\n' and overwrites
+     it with '\0'. Thus if the line is really terminated with
+     "\r\n", the '\r' will remain unchanged.
+  */
+  char *bufx = bufptr;
+  static char *bp;
+  static int cnt = 0;
+  static char b[ 4096 ];
+  char c;
+  
+  while ( --len > 0 )
+    {
+      if ( --cnt <= 0 )
+	{
+	  cnt = recv( fd, b, sizeof( b ), 0 );
+	  if ( cnt < 0 )
+	    {
+	      if ( errno == EINTR )
+		{
+		  len++;		/* the while will decrement */
+		  continue;
+		}
+	      return -1;
+	    }
+	  if ( cnt == 0 )
+	    return 0;
+	  bp = b;
+	}
+      c = *bp++;
+      *bufptr++ = c;
+      if ( c == '\n' )
+	{
+	  *bufptr = '\0';
+	  return bufptr - bufx;
+	}
+    }
+  return -1;
+}
+
+int readData(int socket, uint8_t *buf, int buflen)
+{
+	int sendSize = buflen;
+	int status;
+
+	while (buflen)
+	{
+#ifndef __MACH__
+		status = read(socket, buf, buflen);
+#else
+		status = recv(socket, buf, buflen, 0);
+#endif
+		if (status <= 0)
+		{
+			return status;
+		}
+		buflen -= status;
+		buf += status;
+	}
+
+	return sendSize;
+}
+
+int readHdr(int socket, FlowControlProtocolHeader *hdr)
+{
+	uint8_t buffer[sizeof(FlowControlProtocolHeader)];
+
+	uint8_t *data = buffer;
+
+	int status = readData(socket, buffer, sizeof(FlowControlProtocolHeader));
+	if (status <= 0)
+		return status;
+
+	uint32_t value;
+	data = decode(data, value);
+	hdr->msgType = value;
+
+	data = decode(data, value);
+	hdr->seqNumber = value;
+
+	data = decode(data, value);
+	hdr->status = value;
+
+	data = decode(data, value);
+	hdr->payloadLen = value;
+
+	return sizeof(FlowControlProtocolHeader);
+}
+
+int readXML(char **xmlContent)
+{
+	  std::ifstream is ("conf/flowServer.xml", std::ifstream::binary);
+	  if (is) {
+	    // get length of file:
+	    is.seekg (0, is.end);
+	    int length = is.tellg();
+	    is.seekg (0, is.beg);
+
+	    char * buffer = new char [length];
+
+	    printf("Reading %s len %d\n", "conf/flowServer.xml", length);
+	    // read data as a block:
+	    is.read (buffer,length);
+
+	    is.close();
+
+	    // ...buffer contains the entire file...
+	    *xmlContent = buffer;
+
+	    return length;
+	  }
+	  return 0;
+}
+
+static int sockfd = 0, newsockfd = 0;
+void sigHandler(int signal)
+{
+	if (signal == SIGINT || signal == SIGTERM)
+	{
+		close(newsockfd);
+		close(sockfd);
+		exit(1);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+     int portno;
+     socklen_t clilen;
+     struct sockaddr_in serv_addr, cli_addr;
+     char buffer[4096];
+     int flag = 0;
+     int number = 0;
+     
+     int n;
+     if (argc < 2) {
+         fprintf(stderr,"ERROR, no port provided\n");
+         exit(1);
+     }
+
+ 	 if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) == SIG_ERR)
+ 	 {
+
+ 		return -1;
+ 	 }
+     sockfd = socket(AF_INET, SOCK_STREAM, 0);
+     if (sockfd < 0) 
+        error("ERROR opening socket");
+     bzero((char *) &serv_addr, sizeof(serv_addr));
+     portno = atoi(argv[1]);
+     serv_addr.sin_family = AF_INET;
+     serv_addr.sin_addr.s_addr = INADDR_ANY;
+     serv_addr.sin_port = htons(portno);
+     if (bind(sockfd, (struct sockaddr *) &serv_addr,
+              sizeof(serv_addr)) < 0) 
+              error("ERROR on binding");
+     listen(sockfd,5);
+     if (portno == DEFAULT_NIFI_SERVER_PORT)
+     {
+    	 while (true)
+    	 {
+    		 clilen = sizeof(cli_addr);
+    		 newsockfd = accept(sockfd,
+                 (struct sockaddr *) &cli_addr, 
+                 &clilen);
+    		 if (newsockfd < 0)
+    		 {
+    			 error("ERROR on accept");
+    			 break;
+    		 }
+    		 // process request
+    		 FlowControlProtocolHeader hdr;
+    		 int status = readHdr(newsockfd, &hdr);
+    		 if (status > 0)
+    		 {
+    			 printf("Flow Control Protocol receive MsgType %s\n", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
+    		     printf("Flow Control Protocol receive Seq Num %d\n", hdr.seqNumber);
+    		     printf("Flow Control Protocol receive Resp Code %s\n", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
+    		     printf("Flow Control Protocol receive Payload len %d\n", hdr.payloadLen);
+    		 	 if (((FlowControlMsgType) hdr.msgType) == REGISTER_REQ)
+    		 	 {
+    		 		printf("Flow Control Protocol Register Req receive\n");
+    		 		uint8_t *payload = new uint8_t[hdr.payloadLen];
+    		 		uint8_t *payloadPtr = payload;
+    		 		status = readData(newsockfd, payload, hdr.payloadLen);
+    		 		while (status > 0 && payloadPtr < (payload + hdr.payloadLen))
+    		 		{
+    		 			uint32_t msgID = 0xFFFFFFFF;
+    		 			payloadPtr = decode(payloadPtr, msgID);
+    		 			if (((FlowControlMsgID) msgID) == FLOW_SERIAL_NUMBER)
+    		 			{
+    		 				// Fixed 8 bytes
+    		 				uint8_t seqNum[8];
+    		 				memcpy(seqNum, payloadPtr, 8);
+    		 				printf("Flow Control Protocol Register Req receive serial num\n");
+    		 				payloadPtr += 8;
+    		 			}
+    		 			else if (((FlowControlMsgID) msgID) == FLOW_XML_NAME)
+    		 			{
+    		 				uint32_t len;
+    		 				payloadPtr = decode(payloadPtr, len);
+    		 				printf("Flow Control Protocol receive XML name length %d\n", len);
+    		 				std::string flowName = (const char *) payloadPtr;
+    		 				payloadPtr += len;
+    		 				printf("Flow Control Protocol receive XML name %s\n", flowName.c_str());
+    		 			}
+    		 			else
+    		 			{
+    		 				break;
+    		 			}
+    		 		}
+    		 		delete[] payload;
+    		 		// Send Register Respond
+    		 		// Calculate the total payload msg size
+    		 		char *xmlContent;
+    		 		uint32_t xmlLen = readXML(&xmlContent);
+    		 		uint32_t payloadSize = FlowControlMsgIDEncodingLen(REPORT_INTERVAL, 0);
+    		 		if (xmlLen > 0)
+    		 			payloadSize += FlowControlMsgIDEncodingLen(FLOW_XML_CONTENT, xmlLen);
+
+    		 		uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
+    		 		uint8_t *data = new uint8_t[size];
+    		 		uint8_t *start = data;
+
+    		 		// encode the HDR
+    		 		hdr.msgType = REGISTER_RESP;
+    		 		hdr.payloadLen = payloadSize;
+    		 		hdr.status = RESP_SUCCESS;
+    		 		data = encode(data, hdr.msgType);
+    		 		data = encode(data, hdr.seqNumber);
+    		 		data = encode(data, hdr.status);
+    		 		data = encode(data, hdr.payloadLen);
+
+    		 		// encode the report interval
+    		 		data = encode(data, REPORT_INTERVAL);
+    		 		data = encode(data, DEFAULT_REPORT_INTERVAL);
+
+    		 		// encode the XML content
+    		 		if (xmlLen > 0)
+    		 		{
+    		 			data = encode(data, FLOW_XML_CONTENT);
+    		 			data = encode(data, xmlLen);
+    		 			data = encode(data, (uint8_t *) xmlContent, xmlLen);
+    		 			delete[] xmlContent;
+    		 		}
+
+    		 		// send it
+    		 		status = sendData(newsockfd, start, size);
+    		 		delete[] start;
+    		 	 }
+    		 	 else if (((FlowControlMsgType) hdr.msgType) == REPORT_REQ)
+        		 {
+        		 		printf("Flow Control Protocol Report Req receive\n");
+        		 		uint8_t *payload = new uint8_t[hdr.payloadLen];
+        		 		uint8_t *payloadPtr = payload;
+        		 		status = readData(newsockfd, payload, hdr.payloadLen);
+        		 		while (status > 0 && payloadPtr < (payload + hdr.payloadLen))
+        		 		{
+        		 			uint32_t msgID = 0xFFFFFFFF;
+        		 			payloadPtr = decode(payloadPtr, msgID);
+        		 			if (((FlowControlMsgID) msgID) == FLOW_XML_NAME)
+        		 			{
+        		 				uint32_t len;
+        		 				payloadPtr = decode(payloadPtr, len);
+        		 				printf("Flow Control Protocol receive XML name length %d\n", len);
+        		 				std::string flowName = (const char *) payloadPtr;
+        		 				payloadPtr += len;
+        		 				printf("Flow Control Protocol receive XML name %s\n", flowName.c_str());
+        		 			}
+        		 			else
+        		 			{
+        		 				break;
+        		 			}
+        		 		}
+        		 		delete[] payload;
+        		 		// Send Register Respond
+        		 		// Calculate the total payload msg size
+        		 		std::string processor = "RealTimeDataCollector";
+        		 		std::string propertyName1 = "real Time Message ID";
+        		 		std::string propertyValue1 = "41";
+        		 		std::string propertyName2 = "Batch Message ID";
+        		 		std::string propertyValue2 = "172,30,48";
+        		 		if (flag == 0)
+        		 		{
+              		 		propertyName1 = "Real Time Message ID";
+              		 		propertyValue1 = "41";
+                		    propertyName2 = "Batch Message ID";
+                		    propertyValue2 = "172,48";
+        		 			flag = 1;
+        		 		}
+        		 		else if (flag == 1)
+        		 		{
+        		 			propertyName1 = "Real Time Message ID";
+        		 			propertyValue1 = "172,48";
+        		 			propertyName2 = "Batch Message ID";
+        		 			propertyValue2 = "41";
+        		 			flag = 0;
+        		 		}
+        		 		uint32_t payloadSize = FlowControlMsgIDEncodingLen(PROCESSOR_NAME, processor.size()+1);
+        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_NAME, propertyName1.size()+1);
+        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_VALUE, propertyValue1.size()+1);
+        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_NAME, propertyName2.size()+1);
+        		 		payloadSize += FlowControlMsgIDEncodingLen(PROPERTY_VALUE, propertyValue2.size()+1);
+
+        		 		uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
+        		 		uint8_t *data = new uint8_t[size];
+        		 		uint8_t *start = data;
+
+        		 		// encode the HDR
+        		 		hdr.msgType = REPORT_RESP;
+        		 		hdr.payloadLen = payloadSize;
+        		 		hdr.status = RESP_SUCCESS;
+
+        		 		if (number >= 10 && number < 20)
+        		 	    {
+        		 	        // After 10 second report, stop the flow controller for 10 second
+        		 	       hdr.status = RESP_STOP_FLOW_CONTROLLER;
+        		 	    }
+        		 		else if (number == 20)
+        		 		{
+        		 			// restart the flow controller after 10 second
+        		 			hdr.status = RESP_START_FLOW_CONTROLLER;
+        		 		}
+        		 		else if (number == 30)
+        		 		{
+        		 			// retrigger register
+        		 			hdr.status = RESP_TRIGGER_REGISTER;
+        		 			number = 0;
+        		 		}
+
+        		 	    number++;
+
+        		 		data = encode(data, hdr.msgType);
+        		 		data = encode(data, hdr.seqNumber);
+        		 		data = encode(data, hdr.status);
+        		 		data = encode(data, hdr.payloadLen);
+
+        		 		// encode the processorName
+        		 		data = encode(data, PROCESSOR_NAME);
+        		 		data = encode(data, processor);
+
+        		 		// encode the propertyName and value TLV
+        		 		data = encode(data, PROPERTY_NAME);
+            		 	data = encode(data, propertyName1);
+            		 	data = encode(data, PROPERTY_VALUE);
+            		 	data = encode(data, propertyValue1);
+            		 	data = encode(data, PROPERTY_NAME);
+            		 	data = encode(data, propertyName2);
+            		 	data = encode(data, PROPERTY_VALUE);
+            		 	data = encode(data, propertyValue2);
+        		 		// send it
+        		 		status = sendData(newsockfd, start, size);
+        		 		delete[] start;
+        		 	 }
+    		 }
+    		 close(newsockfd);
+    	 }
+    	 close(sockfd);
+     }
+     else
+     {
+    	 clilen = sizeof(cli_addr);
+    	 newsockfd = accept(sockfd,
+    	                (struct sockaddr *) &cli_addr,
+    	                 &clilen);
+    	 if (newsockfd < 0)
+    	    	error("ERROR on accept");
+    	 while (1)
+    	 {
+    	    	bzero(buffer,4096);
+    	    	n = readline(newsockfd,buffer,4095);
+    	    	if (n <= 0 )
+    	        {
+    	    		close(newsockfd);
+    	    		newsockfd = accept(sockfd,
+    	    		    	                (struct sockaddr *) &cli_addr,
+    	    		    	                 &clilen);
+    	    		continue;
+    	    	}
+    	    	printf("%s",buffer);
+    	  }
+    	  close(newsockfd);
+    	  close(sockfd);
+     }
+     return 0; 
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/main/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
new file mode 100644
index 0000000..2f470a5
--- /dev/null
+++ b/main/CMakeLists.txt
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+cmake_minimum_required(VERSION 2.6)
+
+cmake_policy(SET CMP0048 NEW)
+
+include_directories(../include ../libminifi/include ../thirdparty/yaml-cpp-yaml-cpp-0.5.3/include)
+
+# Include libxml2
+find_package(LibXml2)
+if (LIBXML2_FOUND)
+    include_directories(${LIBXML2_INCLUDE_DIR})
+else ()
+    # Build from our local version
+endif (LIBXML2_FOUND)
+
+add_executable(minifiexe MiNiFiMain.cpp)
+
+# Link against minifi and yaml-cpp
+target_link_libraries(minifiexe minifi yaml-cpp)
+set_target_properties(minifiexe
+        PROPERTIES OUTPUT_NAME minifi)
+
+install(TARGETS minifiexe
+        RUNTIME
+        DESTINATION bin
+        COMPONENT bin)

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Configure.cpp
----------------------------------------------------------------------
diff --git a/src/Configure.cpp b/src/Configure.cpp
deleted file mode 100644
index d7fd95b..0000000
--- a/src/Configure.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * @file Configure.cpp
- * Configure class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "Configure.h"
-
-Configure *Configure::_configure(NULL);
-const char *Configure::nifi_flow_configuration_file = "nifi.flow.configuration.file";
-const char *Configure::nifi_administrative_yield_duration = "nifi.administrative.yield.duration";
-const char *Configure::nifi_bored_yield_duration = "nifi.bored.yield.duration";
-const char *Configure::nifi_server_name = "nifi.server.name";
-const char *Configure::nifi_server_port = "nifi.server.port";
-const char *Configure::nifi_server_report_interval= "nifi.server.report.interval";
-
-
-//! Get the config value
-bool Configure::get(std::string key, std::string &value)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-	std::map<std::string,std::string>::iterator it = _properties.find(key);
-
-	if (it != _properties.end())
-	{
-		value = it->second;
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-// Trim String utils
-std::string Configure::trim(const std::string& s)
-{
-    return trimRight(trimLeft(s));
-}
-
-std::string Configure::trimLeft(const std::string& s)
-{
-	const char *WHITESPACE = " \n\r\t";
-    size_t startpos = s.find_first_not_of(WHITESPACE);
-    return (startpos == std::string::npos) ? "" : s.substr(startpos);
-}
-
-std::string Configure::trimRight(const std::string& s)
-{
-	const char *WHITESPACE = " \n\r\t";
-    size_t endpos = s.find_last_not_of(WHITESPACE);
-    return (endpos == std::string::npos) ? "" : s.substr(0, endpos+1);
-}
-
-//! Parse one line in configure file like key=value
-void Configure::parseConfigureFileLine(char *buf)
-{
-	char *line = buf;
-
-    while ((line[0] == ' ') || (line[0] =='\t'))
-    	++line;
-
-    char first = line[0];
-    if ((first == '\0') || (first == '#')  || (first == '\r') || (first == '\n') || (first == '='))
-    {
-    	return;
-    }
-
-    char *equal = strchr(line, '=');
-    if (equal == NULL)
-    {
-    	return;
-    }
-
-    equal[0] = '\0';
-    std::string key = line;
-
-    equal++;
-    while ((equal[0] == ' ') || (equal[0] == '\t'))
-    	++equal;
-
-    first = equal[0];
-    if ((first == '\0') || (first == '\r') || (first== '\n'))
-    {
-    	return;
-    }
-
-    std::string value = equal;
-    key = trimRight(key);
-    value = trimRight(value);
-    set(key, value);
-}
-
-//! Load Configure File
-void Configure::loadConfigureFile(const char *fileName)
-{
-
-    std::string adjustedFilename;
-    if (fileName)
-    {
-        // perform a naive determination if this is a relative path
-        if (fileName[0] != '/')
-        {
-            adjustedFilename = adjustedFilename + _configure->getHome() + "/" + fileName;
-        }
-        else
-        {
-            adjustedFilename += fileName;
-        }
-    }
-    char *path = NULL;
-    char full_path[PATH_MAX];
-    path = realpath(adjustedFilename.c_str(), full_path);
-    _logger->log_info("Using configuration file located at %s", path);
-
-    std::ifstream file(path, std::ifstream::in);
-    if (!file.good())
-    {
-        _logger->log_error("load configure file failed %s", path);
-        return;
-    }
-    this->clear();
-    const unsigned int bufSize = 512;
-    char buf[bufSize];
-    for (file.getline(buf, bufSize); file.good(); file.getline(buf, bufSize))
-    {
-        parseConfigureFileLine(buf);
-    }
-}
-
-//! Parse Command Line
-void Configure::parseCommandLine(int argc, char **argv)
-{
-	int i;
-	bool keyFound = false;
-	std::string key, value;
-
-	for (i = 1; i < argc; i++)
-	{
-		if (argv[i][0] == '-' && argv[i][1] != '\0')
-		{
-			keyFound = true;
-			key = &argv[i][1];
-			continue;
-		}
-		if (keyFound)
-		{
-			value = argv[i];
-			set(key,value);
-			keyFound = false;
-		}
-	}
-	return;
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/Connection.cpp
----------------------------------------------------------------------
diff --git a/src/Connection.cpp b/src/Connection.cpp
deleted file mode 100644
index e036b89..0000000
--- a/src/Connection.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * @file Connection.cpp
- * Connection class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <iostream>
-
-#include "Connection.h"
-
-Connection::Connection(std::string name, uuid_t uuid, uuid_t srcUUID, uuid_t destUUID)
-: _name(name)
-{
-	if (!uuid)
-		// Generate the global UUID for the flow record
-		uuid_generate(_uuid);
-	else
-		uuid_copy(_uuid, uuid);
-
-	if (srcUUID)
-		uuid_copy(_srcUUID, srcUUID);
-	if (destUUID)
-		uuid_copy(_destUUID, destUUID);
-
-	_srcProcessor = NULL;
-	_destProcessor = NULL;
-	_maxQueueSize = 0;
-	_maxQueueDataSize = 0;
-	_expiredDuration = 0;
-	_queuedDataSize = 0;
-
-	_logger = Logger::getLogger();
-
-	_logger->log_info("Connection %s created", _name.c_str());
-}
-
-bool Connection::isEmpty()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	return _queue.empty();
-}
-
-bool Connection::isFull()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	if (_maxQueueSize <= 0 && _maxQueueDataSize <= 0)
-		// No back pressure setting
-		return false;
-
-	if (_maxQueueSize > 0 && _queue.size() >= _maxQueueSize)
-		return true;
-
-	if (_maxQueueDataSize > 0 && _queuedDataSize >= _maxQueueDataSize)
-		return true;
-
-	return false;
-}
-
-void Connection::put(FlowFileRecord *flow)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_queue.push(flow);
-
-	_queuedDataSize += flow->getSize();
-
-	_logger->log_debug("Enqueue flow file UUID %s to connection %s",
-			flow->getUUIDStr().c_str(), _name.c_str());
-}
-
-FlowFileRecord* Connection::poll(std::set<FlowFileRecord *> &expiredFlowRecords)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	while (!_queue.empty())
-	{
-		FlowFileRecord *item = _queue.front();
-		_queue.pop();
-		_queuedDataSize -= item->getSize();
-
-		if (_expiredDuration > 0)
-		{
-			// We need to check for flow expiration
-			if (getTimeMillis() > (item->getEntryDate() + _expiredDuration))
-			{
-				// Flow record expired
-				expiredFlowRecords.insert(item);
-			}
-			else
-			{
-				// Flow record not expired
-				if (item->isPenalized())
-				{
-					// Flow record was penalized
-					_queue.push(item);
-					_queuedDataSize += item->getSize();
-					break;
-				}
-				item->setOriginalConnection(this);
-				_logger->log_debug("Dequeue flow file UUID %s from connection %s",
-						item->getUUIDStr().c_str(), _name.c_str());
-				return item;
-			}
-		}
-		else
-		{
-			// Flow record not expired
-			if (item->isPenalized())
-			{
-				// Flow record was penalized
-				_queue.push(item);
-				_queuedDataSize += item->getSize();
-				break;
-			}
-			item->setOriginalConnection(this);
-			_logger->log_debug("Dequeue flow file UUID %s from connection %s",
-					item->getUUIDStr().c_str(), _name.c_str());
-			return item;
-		}
-	}
-
-	return NULL;
-}
-
-void Connection::drain()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	while (!_queue.empty())
-	{
-		FlowFileRecord *item = _queue.front();
-		_queue.pop();
-		delete item;
-	}
-
-	_logger->log_debug("Drain connection %s", _name.c_str());
-}


[04/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/FlowControlProtocol.cpp
----------------------------------------------------------------------
diff --git a/src/FlowControlProtocol.cpp b/src/FlowControlProtocol.cpp
deleted file mode 100644
index 011ebcf..0000000
--- a/src/FlowControlProtocol.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/**
- * @file FlowControlProtocol.cpp
- * FlowControlProtocol class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <sys/time.h>
-#include <stdio.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <random>
-#include <netinet/tcp.h>
-#include <iostream>
-#include "FlowController.h"
-#include "FlowControlProtocol.h"
-
-int FlowControlProtocol::connectServer(const char *host, uint16_t port)
-{
-	in_addr_t addr;
-	int sock = 0;
-	struct hostent *h;
-#ifdef __MACH__
-	h = gethostbyname(host);
-#else
-	char buf[1024];
-	struct hostent he;
-	int hh_errno;
-	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
-#endif
-	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock < 0)
-	{
-		_logger->log_error("Could not create socket to hostName %s", host);
-		return 0;
-	}
-
-#ifndef __MACH__
-	int opt = 1;
-	bool nagle_off = true;
-
-	if (nagle_off)
-	{
-		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() TCP_NODELAY failed");
-			close(sock);
-			return 0;
-		}
-		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-				(char *)&opt, sizeof(opt)) < 0)
-		{
-			_logger->log_error("setsockopt() SO_REUSEADDR failed");
-			close(sock);
-			return 0;
-		}
-	}
-
-	int sndsize = 256*1024;
-	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
-	{
-		_logger->log_error("setsockopt() SO_SNDBUF failed");
-		close(sock);
-		return 0;
-	}
-#endif
-
-	struct sockaddr_in sa;
-	socklen_t socklen;
-	int status;
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = htonl(INADDR_ANY);
-	sa.sin_port = htons(0);
-	socklen = sizeof(sa);
-	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
-	{
-		_logger->log_error("socket bind failed");
-		close(sock);
-		return 0;
-	}
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = addr;
-	sa.sin_port = htons(port);
-	socklen = sizeof(sa);
-
-	status = connect(sock, (struct sockaddr *)&sa, socklen);
-
-	if (status < 0)
-	{
-		_logger->log_error("socket connect failed to %s %d", host, port);
-		close(sock);
-		return 0;
-	}
-
-	_logger->log_info("Flow Control Protocol socket %d connect to server %s port %d success", sock, host, port);
-
-	return sock;
-}
-
-int FlowControlProtocol::sendData(uint8_t *buf, int buflen)
-{
-	int ret = 0, bytes = 0;
-
-	while (bytes < buflen)
-	{
-		ret = send(_socket, buf+bytes, buflen-bytes, 0);
-		//check for errors
-		if (ret == -1)
-		{
-			return ret;
-		}
-		bytes+=ret;
-	}
-
-	return bytes;
-}
-
-int FlowControlProtocol::selectClient(int msec)
-{
-	fd_set fds;
-	struct timeval tv;
-    int retval;
-    int fd = _socket;
-
-    FD_ZERO(&fds);
-    FD_SET(fd, &fds);
-
-    tv.tv_sec = msec/1000;
-    tv.tv_usec = (msec % 1000) * 1000;
-
-    if (msec > 0)
-       retval = select(fd+1, &fds, NULL, NULL, &tv);
-    else
-       retval = select(fd+1, &fds, NULL, NULL, NULL);
-
-    if (retval <= 0)
-      return retval;
-    if (FD_ISSET(fd, &fds))
-      return retval;
-    else
-      return 0;
-}
-
-int FlowControlProtocol::readData(uint8_t *buf, int buflen)
-{
-	int sendSize = buflen;
-
-	while (buflen)
-	{
-		int status;
-		status = selectClient(MAX_READ_TIMEOUT);
-		if (status <= 0)
-		{
-			return status;
-		}
-#ifndef __MACH__
-		status = read(_socket, buf, buflen);
-#else
-		status = recv(_socket, buf, buflen, 0);
-#endif
-		if (status <= 0)
-		{
-			return status;
-		}
-		buflen -= status;
-		buf += status;
-	}
-
-	return sendSize;
-}
-
-int FlowControlProtocol::readHdr(FlowControlProtocolHeader *hdr)
-{
-	uint8_t buffer[sizeof(FlowControlProtocolHeader)];
-
-	uint8_t *data = buffer;
-
-	int status = readData(buffer, sizeof(FlowControlProtocolHeader));
-	if (status <= 0)
-		return status;
-
-	uint32_t value;
-	data = this->decode(data, value);
-	hdr->msgType = value;
-
-	data = this->decode(data, value);
-	hdr->seqNumber = value;
-
-	data = this->decode(data, value);
-	hdr->status = value;
-
-	data = this->decode(data, value);
-	hdr->payloadLen = value;
-
-	return sizeof(FlowControlProtocolHeader);
-}
-
-void FlowControlProtocol::start()
-{
-	if (_reportInterval <= 0)
-		return;
-	if (_running)
-		return;
-	_running = true;
-	_logger->log_info("FlowControl Protocol Start");
-	_thread = new std::thread(run, this);
-	_thread->detach();
-}
-
-void FlowControlProtocol::stop()
-{
-	if (!_running)
-		return;
-	_running = false;
-	_logger->log_info("FlowControl Protocol Stop");
-}
-
-void FlowControlProtocol::run(FlowControlProtocol *protocol)
-{
-	while (protocol->_running)
-	{
-		std::this_thread::sleep_for(std::chrono::milliseconds(protocol->_reportInterval));
-		if (!protocol->_registered)
-		{
-			// if it is not register yet
-			protocol->sendRegisterReq();
-			// protocol->_controller->reload("flow.xml");
-		}
-		else
-			protocol->sendReportReq();
-	}
-	return;
-}
-
-int FlowControlProtocol::sendRegisterReq()
-{
-	if (_registered)
-	{
-		_logger->log_info("Already registered");
-		return -1;
-	}
-
-	uint16_t port = this->_serverPort;
-
-	if (this->_socket <= 0)
-		this->_socket = connectServer(_serverName.c_str(), port);
-
-	if (this->_socket <= 0)
-		return -1;
-
-	// Calculate the total payload msg size
-	uint32_t payloadSize = FlowControlMsgIDEncodingLen(FLOW_SERIAL_NUMBER, 0) +
-			FlowControlMsgIDEncodingLen(FLOW_XML_NAME, this->_controller->getName().size()+1);
-	uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
-
-	uint8_t *data = new uint8_t[size];
-	uint8_t *start = data;
-
-	// encode the HDR
-	FlowControlProtocolHeader hdr;
-	hdr.msgType = REGISTER_REQ;
-	hdr.payloadLen = payloadSize;
-	hdr.seqNumber  = this->_seqNumber;
-	hdr.status = RESP_SUCCESS;
-	data = this->encode(data, hdr.msgType);
-	data = this->encode(data, hdr.seqNumber);
-	data = this->encode(data, hdr.status);
-	data = this->encode(data, hdr.payloadLen);
-
-	// encode the serial number
-	data = this->encode(data, FLOW_SERIAL_NUMBER);
-	data = this->encode(data, this->_serialNumber, 8);
-
-	// encode the XML name
-	data = this->encode(data, FLOW_XML_NAME);
-	data = this->encode(data, this->_controller->getName());
-
-	// send it
-	int status = sendData(start, size);
-	delete[] start;
-	if (status <= 0)
-	{
-		close(_socket);
-		_socket = 0;
-		_logger->log_error("Flow Control Protocol Send Register Req failed");
-		return -1;
-	}
-
-	// Looking for register respond
-	status = readHdr(&hdr);
-
-	if (status <= 0)
-	{
-		close(_socket);
-		_socket = 0;
-		_logger->log_error("Flow Control Protocol Read Register Resp header failed");
-		return -1;
-	}
-	_logger->log_info("Flow Control Protocol receive MsgType %s", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
-	_logger->log_info("Flow Control Protocol receive Seq Num %d", hdr.seqNumber);
-	_logger->log_info("Flow Control Protocol receive Resp Code %s", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
-	_logger->log_info("Flow Control Protocol receive Payload len %d", hdr.payloadLen);
-
-	if (hdr.status == RESP_SUCCESS && hdr.seqNumber == this->_seqNumber)
-	{
-		this->_registered = true;
-		this->_seqNumber++;
-		_logger->log_info("Flow Control Protocol Register success");
-		uint8_t *payload = new uint8_t[hdr.payloadLen];
-		uint8_t *payloadPtr = payload;
-		status = readData(payload, hdr.payloadLen);
-		if (status <= 0)
-		{
-			delete[] payload;
-			_logger->log_info("Flow Control Protocol Register Read Payload fail");
-			close(_socket);
-			_socket = 0;
-			return -1;
-		}
-		while (payloadPtr < (payload + hdr.payloadLen))
-		{
-			uint32_t msgID;
-			payloadPtr = this->decode(payloadPtr, msgID);
-			if (((FlowControlMsgID) msgID) == REPORT_INTERVAL)
-			{
-				// Fixed 4 bytes
-				uint32_t reportInterval;
-				payloadPtr = this->decode(payloadPtr, reportInterval);
-				_logger->log_info("Flow Control Protocol receive report interval %d ms", reportInterval);
-				this->_reportInterval = reportInterval;
-			}
-			else if (((FlowControlMsgID) msgID) == FLOW_XML_CONTENT)
-			{
-				uint32_t xmlLen;
-				payloadPtr = this->decode(payloadPtr, xmlLen);
-				_logger->log_info("Flow Control Protocol receive XML content length %d", xmlLen);
-				time_t rawtime;
-				struct tm *timeinfo;
-				time(&rawtime);
-				timeinfo = localtime(&rawtime);
-				std::string xmlFileName = "flow.";
-				xmlFileName += asctime(timeinfo);
-				xmlFileName += ".xml";
-				std::ofstream fs;
-				fs.open(xmlFileName.c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
-				if (fs.is_open())
-				{
-					fs.write((const char *)payloadPtr, xmlLen);
-					fs.close();
-					this->_controller->reload(xmlFileName.c_str());
-				}
-			}
-			else
-			{
-				break;
-			}
-		}
-		delete[] payload;
-		close(_socket);
-		_socket = 0;
-		return 0;
-	}
-	else
-	{
-		_logger->log_info("Flow Control Protocol Register fail");
-		close(_socket);
-		_socket = 0;
-		return -1;
-	}
-}
-
-
-int FlowControlProtocol::sendReportReq()
-{
-	uint16_t port = this->_serverPort;
-
-	if (this->_socket <= 0)
-		this->_socket = connectServer(_serverName.c_str(), port);
-
-	if (this->_socket <= 0)
-		return -1;
-
-	// Calculate the total payload msg size
-	uint32_t payloadSize =
-			FlowControlMsgIDEncodingLen(FLOW_XML_NAME, this->_controller->getName().size()+1);
-	uint32_t size = sizeof(FlowControlProtocolHeader) + payloadSize;
-
-	uint8_t *data = new uint8_t[size];
-	uint8_t *start = data;
-
-	// encode the HDR
-	FlowControlProtocolHeader hdr;
-	hdr.msgType = REPORT_REQ;
-	hdr.payloadLen = payloadSize;
-	hdr.seqNumber  = this->_seqNumber;
-	hdr.status = RESP_SUCCESS;
-	data = this->encode(data, hdr.msgType);
-	data = this->encode(data, hdr.seqNumber);
-	data = this->encode(data, hdr.status);
-	data = this->encode(data, hdr.payloadLen);
-
-	// encode the XML name
-	data = this->encode(data, FLOW_XML_NAME);
-	data = this->encode(data, this->_controller->getName());
-
-	// send it
-	int status = sendData(start, size);
-	delete[] start;
-	if (status <= 0)
-	{
-		close(_socket);
-		_socket = 0;
-		_logger->log_error("Flow Control Protocol Send Report Req failed");
-		return -1;
-	}
-
-	// Looking for report respond
-	status = readHdr(&hdr);
-
-	if (status <= 0)
-	{
-		close(_socket);
-		_socket = 0;
-		_logger->log_error("Flow Control Protocol Read Report Resp header failed");
-		return -1;
-	}
-	_logger->log_info("Flow Control Protocol receive MsgType %s", FlowControlMsgTypeToStr((FlowControlMsgType) hdr.msgType));
-	_logger->log_info("Flow Control Protocol receive Seq Num %d", hdr.seqNumber);
-	_logger->log_info("Flow Control Protocol receive Resp Code %s", FlowControlRespCodeToStr((FlowControlRespCode) hdr.status));
-	_logger->log_info("Flow Control Protocol receive Payload len %d", hdr.payloadLen);
-
-	if (hdr.status == RESP_SUCCESS && hdr.seqNumber == this->_seqNumber)
-	{
-		this->_seqNumber++;
-		uint8_t *payload = new uint8_t[hdr.payloadLen];
-		uint8_t *payloadPtr = payload;
-		status = readData(payload, hdr.payloadLen);
-		if (status <= 0)
-		{
-			delete[] payload;
-			_logger->log_info("Flow Control Protocol Report Resp Read Payload fail");
-			close(_socket);
-			_socket = 0;
-			return -1;
-		}
-		std::string processor;
-		std::string propertyName;
-		std::string propertyValue;
-		while (payloadPtr < (payload + hdr.payloadLen))
-		{
-			uint32_t msgID;
-			payloadPtr = this->decode(payloadPtr, msgID);
-			if (((FlowControlMsgID) msgID) == PROCESSOR_NAME)
-			{
-				uint32_t len;
-				payloadPtr = this->decode(payloadPtr, len);
-				processor = (const char *) payloadPtr;
-				payloadPtr += len;
-				_logger->log_info("Flow Control Protocol receive report resp processor %s", processor.c_str());
-			}
-			else if (((FlowControlMsgID) msgID) == PROPERTY_NAME)
-			{
-				uint32_t len;
-				payloadPtr = this->decode(payloadPtr, len);
-				propertyName = (const char *) payloadPtr;
-				payloadPtr += len;
-				_logger->log_info("Flow Control Protocol receive report resp property name %s", propertyName.c_str());
-			}
-			else if (((FlowControlMsgID) msgID) == PROPERTY_VALUE)
-			{
-				uint32_t len;
-				payloadPtr = this->decode(payloadPtr, len);
-				propertyValue = (const char *) payloadPtr;
-				payloadPtr += len;
-				_logger->log_info("Flow Control Protocol receive report resp property value %s", propertyValue.c_str());
-				this->_controller->updatePropertyValue(processor, propertyName, propertyValue);
-			}
-			else
-			{
-				break;
-			}
-		}
-		delete[] payload;
-		close(_socket);
-		_socket = 0;
-		return 0;
-	}
-	else if (hdr.status == RESP_TRIGGER_REGISTER && hdr.seqNumber == this->_seqNumber)
-	{
-		_logger->log_info("Flow Control Protocol trigger reregister");
-		this->_registered = false;
-		this->_seqNumber++;
-		close(_socket);
-		_socket = 0;
-		return 0;
-	}
-	else if (hdr.status == RESP_STOP_FLOW_CONTROLLER && hdr.seqNumber == this->_seqNumber)
-	{
-		_logger->log_info("Flow Control Protocol stop flow controller");
-		this->_controller->stop(true);
-		this->_seqNumber++;
-		close(_socket);
-		_socket = 0;
-		return 0;
-	}
-	else if (hdr.status == RESP_START_FLOW_CONTROLLER && hdr.seqNumber == this->_seqNumber)
-	{
-		_logger->log_info("Flow Control Protocol start flow controller");
-		this->_controller->start();
-		this->_seqNumber++;
-		close(_socket);
-		_socket = 0;
-		return 0;
-	}
-	else
-	{
-		_logger->log_info("Flow Control Protocol Report fail");
-		close(_socket);
-		_socket = 0;
-		return -1;
-	}
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/FlowController.cpp
----------------------------------------------------------------------
diff --git a/src/FlowController.cpp b/src/FlowController.cpp
deleted file mode 100644
index 8fbe3dc..0000000
--- a/src/FlowController.cpp
+++ /dev/null
@@ -1,1190 +0,0 @@
-/**
- * @file FlowController.cpp
- * FlowController class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-#include "FlowController.h"
-#include "ProcessContext.h"
-
-FlowController::FlowController(std::string name)
-: _name(name)
-{
-	uuid_generate(_uuid);
-
-	// Setup the default values
-	_configurationFileName = DEFAULT_FLOW_YAML_FILE_NAME;
-	_maxEventDrivenThreads = DEFAULT_MAX_EVENT_DRIVEN_THREAD;
-	_maxTimerDrivenThreads = DEFAULT_MAX_TIMER_DRIVEN_THREAD;
-	_running = false;
-	_initialized = false;
-	_root = NULL;
-	_logger = Logger::getLogger();
-	_protocol = new FlowControlProtocol(this);
-
-	// NiFi config properties
-	_configure = Configure::getConfigure();
-
-	std::string rawConfigFileString;
-	_configure->get(Configure::nifi_flow_configuration_file, rawConfigFileString);
-
-	if (!rawConfigFileString.empty())
-	{
-		_configurationFileName = rawConfigFileString;
-	}
-
-	char *path = NULL;
-	char full_path[PATH_MAX];
-
-	std::string adjustedFilename;
-	if (!_configurationFileName.empty())
-	{
-		// perform a naive determination if this is a relative path
-		if (_configurationFileName.c_str()[0] != '/')
-		{
-			adjustedFilename = adjustedFilename + _configure->getHome() + "/" + _configurationFileName;
-		}
-		else
-		{
-			adjustedFilename = _configurationFileName;
-		}
-	}
-
-	path = realpath(adjustedFilename.c_str(), full_path);
-	if (!path)
-	{
-		_logger->log_error("Could not locate path from provided configuration file name.");
-	}
-
-	std::string pathString(path);
-	_configurationFileName = pathString;
-	_logger->log_info("FlowController NiFi Configuration file %s", pathString.c_str());
-
-	// Create repos for flow record and provenance
-
-	_logger->log_info("FlowController %s created", _name.c_str());
-}
-
-FlowController::~FlowController()
-{
-	stop(true);
-	unload();
-	delete _protocol;
-}
-
-bool FlowController::isRunning()
-{
-	return (_running);
-}
-
-bool FlowController::isInitialized()
-{
-	return (_initialized);
-}
-
-void FlowController::stop(bool force)
-{
-	if (_running)
-	{
-		_logger->log_info("Stop Flow Controller");
-		this->_timerScheduler.stop();
-		// Wait for sometime for thread stop
-		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
-		if (this->_root)
-			this->_root->stopProcessing(&this->_timerScheduler);
-		_running = false;
-	}
-}
-
-void FlowController::unload()
-{
-	if (_running)
-	{
-		stop(true);
-	}
-	if (_initialized)
-	{
-		_logger->log_info("Unload Flow Controller");
-		if (_root)
-			delete _root;
-		_root = NULL;
-		_initialized = false;
-		_name = "";
-	}
-
-	return;
-}
-
-void FlowController::reload(std::string xmlFile)
-{
-	_logger->log_info("Starting to reload Flow Controller with xml %s", xmlFile.c_str());
-	stop(true);
-	unload();
-	std::string oldxmlFile = this->_configurationFileName;
-	this->_configurationFileName = xmlFile;
-	load(ConfigFormat::XML);
-	start();
-	if (!this->_root)
-	{
-		this->_configurationFileName = oldxmlFile;
-		_logger->log_info("Rollback Flow Controller to xml %s", oldxmlFile.c_str());
-		stop(true);
-		unload();
-		load(ConfigFormat::XML);
-		start();
-	}
-}
-
-Processor *FlowController::createProcessor(std::string name, uuid_t uuid)
-{
-	Processor *processor = NULL;
-	if (name == GenerateFlowFile::ProcessorName)
-	{
-		processor = new GenerateFlowFile(name, uuid);
-	}
-	else if (name == LogAttribute::ProcessorName)
-	{
-		processor = new LogAttribute(name, uuid);
-	}
-	else if (name == RealTimeDataCollector::ProcessorName)
-	{
-		processor = new RealTimeDataCollector(name, uuid);
-	}
-	else if (name == GetFile::ProcessorName)
-	{
-		processor = new GetFile(name, uuid);
-	}
-	else if (name == TailFile::ProcessorName)
-	{
-		processor = new TailFile(name, uuid);
-	}
-	else if (name == ListenSyslog::ProcessorName)
-	{
-		processor = new ListenSyslog(name, uuid);
-	}
-	else if (name == ExecuteProcess::ProcessorName)
-	{
-		processor = new ExecuteProcess(name, uuid);
-	}
-	else
-	{
-		_logger->log_error("No Processor defined for %s", name.c_str());
-		return NULL;
-	}
-
-	//! initialize the processor
-	processor->initialize();
-
-	return processor;
-}
-
-ProcessGroup *FlowController::createRootProcessGroup(std::string name, uuid_t uuid)
-{
-	return new ProcessGroup(ROOT_PROCESS_GROUP, name, uuid);
-}
-
-ProcessGroup *FlowController::createRemoteProcessGroup(std::string name, uuid_t uuid)
-{
-	return new ProcessGroup(REMOTE_PROCESS_GROUP, name, uuid);
-}
-
-Connection *FlowController::createConnection(std::string name, uuid_t uuid)
-{
-	return new Connection(name, uuid);
-}
-
-void FlowController::parseConnection(xmlDoc *doc, xmlNode *node, ProcessGroup *parent)
-{
-	uuid_t uuid;
-	xmlNode *currentNode;
-	Connection *connection = NULL;
-
-	if (!parent)
-	{
-		_logger->log_error("parseProcessNode: no parent group existed");
-		return;
-	}
-
-	// generate the random UIID
-	uuid_generate(uuid);
-
-	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next)
-	{
-		if (currentNode->type == XML_ELEMENT_NODE)
-		{
-			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0)
-			{
-				char *id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseConnection: id => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				char *name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseConnection: name => [%s]", name);
-					connection = this->createConnection(name, uuid);
-					if (connection == NULL) {
-						xmlFree(name);
-						return;
-					}
-					xmlFree(name);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "sourceId") == 0) {
-				char *id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseConnection: sourceId => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-					if (connection)
-						connection->setSourceProcessorUUID(uuid);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "destinationId") == 0) {
-				char *id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseConnection: destinationId => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-					if (connection)
-						connection->setDestinationProcessorUUID(uuid);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxWorkQueueSize") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				int64_t maxWorkQueueSize = 0;
-				if (temp) {
-					if (Property::StringToInt(temp, maxWorkQueueSize)) {
-						_logger->log_debug("parseConnection: maxWorkQueueSize => [%d]", maxWorkQueueSize);
-						if (connection)
-							connection->setMaxQueueSize(maxWorkQueueSize);
-
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxWorkQueueDataSize") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				int64_t maxWorkQueueDataSize = 0;
-				if (temp) {
-					if (Property::StringToInt(temp, maxWorkQueueDataSize)) {
-						_logger->log_debug("parseConnection: maxWorkQueueDataSize => [%d]", maxWorkQueueDataSize);
-						if (connection)
-							connection->setMaxQueueDataSize(maxWorkQueueDataSize);
-
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "relationship") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					std::string relationshipName = temp;
-					if (!relationshipName.empty()) {
-						Relationship relationship(relationshipName, "");
-						_logger->log_debug("parseConnection: relationship => [%s]", relationshipName.c_str());
-						if (connection)
-							connection->setRelationship(relationship);
-					} else {
-						Relationship empty;
-						_logger->log_debug("parseConnection: relationship => [%s]", empty.getName().c_str());
-						if (connection)
-							connection->setRelationship(empty);
-					}
-					xmlFree(temp);
-				}
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // for node
-
-	if (connection)
-		parent->addConnection(connection);
-
-	return;
-}
-
-void FlowController::parseRootProcessGroup(xmlDoc *doc, xmlNode *node) {
-	uuid_t uuid;
-	xmlNode *currentNode;
-	ProcessGroup *group = NULL;
-
-	// generate the random UIID
-	uuid_generate(uuid);
-
-	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-		if (currentNode->type == XML_ELEMENT_NODE) {
-			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
-				char *id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseRootProcessGroup: id => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				char *name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseRootProcessGroup: name => [%s]", name);
-					group = this->createRootProcessGroup(name, uuid);
-					if (group == NULL) {
-						xmlFree(name);
-						return;
-					}
-					// Set the root process group
-					this->_root = group;
-					this->_name = name;
-					xmlFree(name);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "processor") == 0) {
-				this->parseProcessorNode(doc, currentNode, group);
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "connection") == 0) {
-				this->parseConnection(doc, currentNode, group);
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "remoteProcessGroup") == 0) {
-				this->parseRemoteProcessGroup(doc, currentNode, group);
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // for node
-}
-
-void FlowController::parseRootProcessGroupYaml(YAML::Node rootFlowNode) {
-	uuid_t uuid;
-	ProcessGroup *group = NULL;
-
-	// generate the random UIID
-	uuid_generate(uuid);
-
-	std::string flowName = rootFlowNode["name"].as<std::string>();
-
-	char uuidStr[37];
-	uuid_unparse(_uuid, uuidStr);
-	_logger->log_debug("parseRootProcessGroup: id => [%s]", uuidStr);
-	_logger->log_debug("parseRootProcessGroup: name => [%s]", flowName.c_str());
-	group = this->createRootProcessGroup(flowName, uuid);
-	this->_root = group;
-	this->_name = flowName;
-}
-
-void FlowController::parseProcessorNodeYaml(YAML::Node processorsNode, ProcessGroup *parentGroup) {
-	int64_t schedulingPeriod = -1;
-	int64_t penalizationPeriod = -1;
-	int64_t yieldPeriod = -1;
-	int64_t runDurationNanos = -1;
-	uuid_t uuid;
-	Processor *processor = NULL;
-
-	if (!parentGroup) {
-		_logger->log_error("parseProcessNodeYaml: no parent group exists");
-		return;
-	}
-
-	if (processorsNode) {
-		// Evaluate sequence of processors
-		int numProcessors = processorsNode.size();
-		if (numProcessors < 1) {
-			throw new std::invalid_argument("There must be at least one processor configured.");
-		}
-
-		std::vector<ProcessorConfig> processorConfigs;
-
-		if (processorsNode.IsSequence()) {
-			for (YAML::const_iterator iter = processorsNode.begin(); iter != processorsNode.end(); ++iter) {
-				ProcessorConfig procCfg;
-				YAML::Node procNode = iter->as<YAML::Node>();
-
-				procCfg.name = procNode["name"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: name => [%s]", procCfg.name.c_str());
-				procCfg.javaClass = procNode["class"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: class => [%s]", procCfg.javaClass.c_str());
-
-				char uuidStr[37];
-				uuid_unparse(_uuid, uuidStr);
-
-				// generate the random UUID
-				uuid_generate(uuid);
-
-				// Determine the processor name only from the Java class
-				int lastOfIdx = procCfg.javaClass.find_last_of(".");
-				if (lastOfIdx != std::string::npos) {
-					lastOfIdx++; // if a value is found, increment to move beyond the .
-					int nameLength = procCfg.javaClass.length() - lastOfIdx;
-					std::string processorName = procCfg.javaClass.substr(lastOfIdx, nameLength);
-					processor = this->createProcessor(processorName, uuid);
-				}
-
-				if (!processor) {
-					_logger->log_error("Could not create a processor %s with name %s", procCfg.name.c_str(), uuidStr);
-					throw std::invalid_argument("Could not create processor " + procCfg.name);
-				}
-				processor->setName(procCfg.name);
-
-				procCfg.maxConcurrentTasks = procNode["max concurrent tasks"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: max concurrent tasks => [%s]", procCfg.maxConcurrentTasks.c_str());
-				procCfg.schedulingStrategy = procNode["scheduling strategy"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: scheduling strategy => [%s]",
-						procCfg.schedulingStrategy.c_str());
-				procCfg.schedulingPeriod = procNode["scheduling period"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: scheduling period => [%s]", procCfg.schedulingPeriod.c_str());
-				procCfg.penalizationPeriod = procNode["penalization period"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: penalization period => [%s]",
-						procCfg.penalizationPeriod.c_str());
-				procCfg.yieldPeriod = procNode["yield period"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: yield period => [%s]", procCfg.yieldPeriod.c_str());
-				procCfg.yieldPeriod = procNode["run duration nanos"].as<std::string>();
-				_logger->log_debug("parseProcessorNode: run duration nanos => [%s]", procCfg.runDurationNanos.c_str());
-
-				// handle auto-terminated relationships
-				YAML::Node autoTerminatedSequence = procNode["auto-terminated relationships list"];
-				std::vector<std::string> rawAutoTerminatedRelationshipValues;
-				if (autoTerminatedSequence.IsSequence() && !autoTerminatedSequence.IsNull()
-						&& autoTerminatedSequence.size() > 0) {
-					for (YAML::const_iterator relIter = autoTerminatedSequence.begin();
-							relIter != autoTerminatedSequence.end(); ++relIter) {
-						std::string autoTerminatedRel = relIter->as<std::string>();
-						rawAutoTerminatedRelationshipValues.push_back(autoTerminatedRel);
-					}
-				}
-				procCfg.autoTerminatedRelationships = rawAutoTerminatedRelationshipValues;
-
-				// handle processor properties
-				YAML::Node propertiesNode = procNode["Properties"];
-				parsePropertiesNodeYaml(&propertiesNode, processor);
-
-				// Take care of scheduling
-				TimeUnit unit;
-				if (Property::StringToTime(procCfg.schedulingPeriod, schedulingPeriod, unit)
-						&& Property::ConvertTimeUnitToNS(schedulingPeriod, unit, schedulingPeriod)) {
-					_logger->log_debug("convert: parseProcessorNode: schedulingPeriod => [%d] ns", schedulingPeriod);
-					processor->setSchedulingPeriodNano(schedulingPeriod);
-				}
-
-				if (Property::StringToTime(procCfg.penalizationPeriod, penalizationPeriod, unit)
-						&& Property::ConvertTimeUnitToMS(penalizationPeriod, unit, penalizationPeriod)) {
-					_logger->log_debug("convert: parseProcessorNode: penalizationPeriod => [%d] ms",
-							penalizationPeriod);
-					processor->setPenalizationPeriodMsec(penalizationPeriod);
-				}
-
-				if (Property::StringToTime(procCfg.yieldPeriod, yieldPeriod, unit)
-						&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod)) {
-					_logger->log_debug("convert: parseProcessorNode: yieldPeriod => [%d] ms", yieldPeriod);
-					processor->setYieldPeriodMsec(yieldPeriod);
-				}
-
-				// Default to running
-				processor->setScheduledState(RUNNING);
-
-				if (procCfg.schedulingStrategy == "TIMER_DRIVEN") {
-					processor->setSchedulingStrategy(TIMER_DRIVEN);
-					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
-				} else if (procCfg.schedulingStrategy == "EVENT_DRIVEN") {
-					processor->setSchedulingStrategy(EVENT_DRIVEN);
-					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
-				} else {
-					processor->setSchedulingStrategy(CRON_DRIVEN);
-					_logger->log_debug("setting scheduling strategy as %s", procCfg.schedulingStrategy.c_str());
-
-				}
-
-				int64_t maxConcurrentTasks;
-				if (Property::StringToInt(procCfg.maxConcurrentTasks, maxConcurrentTasks)) {
-					_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
-					processor->setMaxConcurrentTasks(maxConcurrentTasks);
-				}
-
-				if (Property::StringToInt(procCfg.runDurationNanos, runDurationNanos)) {
-					_logger->log_debug("parseProcessorNode: runDurationNanos => [%d]", runDurationNanos);
-					processor->setRunDurationNano(runDurationNanos);
-				}
-
-				std::set<Relationship> autoTerminatedRelationships;
-				for (auto&& relString : procCfg.autoTerminatedRelationships) {
-					Relationship relationship(relString, "");
-					_logger->log_debug("parseProcessorNode: autoTerminatedRelationship  => [%s]", relString.c_str());
-					autoTerminatedRelationships.insert(relationship);
-				}
-
-				processor->setAutoTerminatedRelationships(autoTerminatedRelationships);
-
-				parentGroup->addProcessor(processor);
-			}
-		}
-	} else {
-		throw new std::invalid_argument(
-				"Cannot instantiate a MiNiFi instance without a defined Processors configuration node.");
-	}
-}
-
-void FlowController::parseRemoteProcessGroupYaml(YAML::Node *rpgNode, ProcessGroup *parentGroup) {
-	uuid_t uuid;
-
-	if (!parentGroup) {
-		_logger->log_error("parseRemoteProcessGroupYaml: no parent group exists");
-		return;
-	}
-
-	if (rpgNode) {
-		if (rpgNode->IsSequence()) {
-			for (YAML::const_iterator iter = rpgNode->begin(); iter != rpgNode->end(); ++iter) {
-				YAML::Node rpgNode = iter->as<YAML::Node>();
-
-				auto name = rpgNode["name"].as<std::string>();
-				_logger->log_debug("parseRemoteProcessGroupYaml: name => [%s]", name.c_str());
-
-				std::string url = rpgNode["url"].as<std::string>();
-				_logger->log_debug("parseRemoteProcessGroupYaml: url => [%s]", url.c_str());
-
-				std::string timeout = rpgNode["timeout"].as<std::string>();
-				_logger->log_debug("parseRemoteProcessGroupYaml: timeout => [%s]", timeout.c_str());
-
-				std::string yieldPeriod = rpgNode["yield period"].as<std::string>();
-				_logger->log_debug("parseRemoteProcessGroupYaml: yield period => [%s]", yieldPeriod.c_str());
-
-				YAML::Node inputPorts = rpgNode["Input Ports"].as<YAML::Node>();
-				ProcessGroup* group = NULL;
-
-				// generate the random UUID
-				uuid_generate(uuid);
-
-				char uuidStr[37];
-				uuid_unparse(_uuid, uuidStr);
-
-				int64_t timeoutValue = -1;
-				int64_t yieldPeriodValue = -1;
-
-				group = this->createRemoteProcessGroup(name.c_str(), uuid);
-				group->setParent(parentGroup);
-				parentGroup->addProcessGroup(group);
-
-				TimeUnit unit;
-
-				if (Property::StringToTime(yieldPeriod, yieldPeriodValue, unit)
-							&& Property::ConvertTimeUnitToMS(yieldPeriodValue, unit, yieldPeriodValue) && group) {
-					_logger->log_debug("parseRemoteProcessGroupYaml: yieldPeriod => [%d] ms", yieldPeriodValue);
-					group->setYieldPeriodMsec(yieldPeriodValue);
-				}
-
-				if (Property::StringToTime(timeout, timeoutValue, unit)
-					&& Property::ConvertTimeUnitToMS(timeoutValue, unit, timeoutValue) && group) {
-					_logger->log_debug("parseRemoteProcessGroupYaml: timeoutValue => [%d] ms", timeoutValue);
-					group->setTimeOut(timeoutValue);
-				}
-
-				group->setTransmitting(true);
-				group->setURL(url);
-
-				if (inputPorts.IsSequence()) {
-					for (YAML::const_iterator portIter = inputPorts.begin(); portIter != inputPorts.end(); ++portIter) {
-						_logger->log_debug("Got a current port, iterating...");
-
-						YAML::Node currPort = portIter->as<YAML::Node>();
-
-						this->parsePortYaml(&currPort, group, SEND);
-					} // for node
-				}
-			}
-		}
-	}
-}
-
-void FlowController::parseConnectionYaml(YAML::Node *connectionsNode, ProcessGroup *parent) {
-	uuid_t uuid;
-	Connection *connection = NULL;
-
-	if (!parent) {
-		_logger->log_error("parseProcessNode: no parent group was provided");
-		return;
-	}
-
-	if (connectionsNode) {
-		int numConnections = connectionsNode->size();
-		if (numConnections < 1) {
-			throw new std::invalid_argument("There must be at least one connection configured.");
-		}
-
-		if (connectionsNode->IsSequence()) {
-			for (YAML::const_iterator iter = connectionsNode->begin(); iter != connectionsNode->end(); ++iter) {
-				// generate the random UIID
-				uuid_generate(uuid);
-
-				YAML::Node connectionNode = iter->as<YAML::Node>();
-
-				std::string name = connectionNode["name"].as<std::string>();
-				std::string destName = connectionNode["destination name"].as<std::string>();
-
-				char uuidStr[37];
-				uuid_unparse(_uuid, uuidStr);
-
-				_logger->log_debug("Created connection with UUID %s and name %s", uuidStr, name.c_str());
-				connection = this->createConnection(name, uuid);
-				auto rawRelationship = connectionNode["source relationship name"].as<std::string>();
-				Relationship relationship(rawRelationship, "");
-				_logger->log_debug("parseConnection: relationship => [%s]", rawRelationship.c_str());
-				if (connection)
-					connection->setRelationship(relationship);
-				std::string connectionSrcProcName = connectionNode["source name"].as<std::string>();
-
-				Processor *srcProcessor = this->_root->findProcessor(connectionSrcProcName);
-
-				if (!srcProcessor) {
-					_logger->log_error("Could not locate a source with name %s to create a connection",
-							connectionSrcProcName.c_str());
-					throw std::invalid_argument(
-							"Could not locate a source with name %s to create a connection " + connectionSrcProcName);
-				}
-
-				Processor *destProcessor = this->_root->findProcessor(destName);
-				// If we could not find name, try by UUID
-				if (!destProcessor) {
-					uuid_t destUuid;
-					uuid_parse(destName.c_str(), destUuid);
-					destProcessor = this->_root->findProcessor(destUuid);
-				}
-				if (destProcessor) {
-					std::string destUuid = destProcessor->getUUIDStr();
-				}
-
-				uuid_t srcUuid;
-				uuid_t destUuid;
-				srcProcessor->getUUID(srcUuid);
-				connection->setSourceProcessorUUID(srcUuid);
-				destProcessor->getUUID(destUuid);
-				connection->setDestinationProcessorUUID(destUuid);
-
-				if (connection) {
-					parent->addConnection(connection);
-				}
-			}
-		}
-
-		if (connection)
-			parent->addConnection(connection);
-
-		return;
-	}
-}
-
-void FlowController::parseRemoteProcessGroup(xmlDoc *doc, xmlNode *node, ProcessGroup *parent) {
-	uuid_t uuid;
-	xmlNode *currentNode;
-	ProcessGroup *group = NULL;
-	int64_t yieldPeriod = -1;
-	int64_t timeOut = -1;
-
-// generate the random UIID
-	uuid_generate(uuid);
-
-	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-		if (currentNode->type == XML_ELEMENT_NODE) {
-			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
-				char *id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseRootProcessGroup: id => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				char *name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseRemoteProcessGroup: name => [%s]", name);
-					group = this->createRemoteProcessGroup(name, uuid);
-					if (group == NULL) {
-						xmlFree(name);
-						return;
-					}
-					group->setParent(parent);
-					parent->addProcessGroup(group);
-					xmlFree(name);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "yieldPeriod") == 0) {
-				TimeUnit unit;
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToTime(temp, yieldPeriod, unit)
-							&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod) && group) {
-						_logger->log_debug("parseRemoteProcessGroup: yieldPeriod => [%d] ms", yieldPeriod);
-						group->setYieldPeriodMsec(yieldPeriod);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "timeout") == 0) {
-				TimeUnit unit;
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToTime(temp, timeOut, unit)
-							&& Property::ConvertTimeUnitToMS(timeOut, unit, timeOut) && group) {
-						_logger->log_debug("parseRemoteProcessGroup: timeOut => [%d] ms", timeOut);
-						group->setTimeOut(timeOut);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "transmitting") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				bool transmitting;
-				if (temp) {
-					if (Property::StringToBool(temp, transmitting) && group) {
-						_logger->log_debug("parseRemoteProcessGroup: transmitting => [%d]", transmitting);
-						group->setTransmitting(transmitting);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "inputPort") == 0 && group) {
-				this->parsePort(doc, currentNode, group, SEND);
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "outputPort") == 0 && group) {
-				this->parsePort(doc, currentNode, group, RECEIVE);
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // for node
-}
-
-void FlowController::parseProcessorProperty(xmlDoc *doc, xmlNode *node, Processor *processor) {
-	xmlNode *currentNode;
-	std::string propertyValue;
-	std::string propertyName;
-
-	if (!processor) {
-		_logger->log_error("parseProcessorProperty: no parent processor existed");
-		return;
-	}
-
-	for (currentNode = node->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-		if (currentNode->type == XML_ELEMENT_NODE) {
-			if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				char *name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseProcessorNode: name => [%s]", name);
-					propertyName = name;
-					xmlFree(name);
-				}
-			}
-			if (xmlStrcmp(currentNode->name, BAD_CAST "value") == 0) {
-				char *value = (char *) xmlNodeGetContent(currentNode);
-				if (value) {
-					_logger->log_debug("parseProcessorNode: value => [%s]", value);
-					propertyValue = value;
-					xmlFree(value);
-				}
-			}
-			if (!propertyName.empty() && !propertyValue.empty()) {
-				processor->setProperty(propertyName, propertyValue);
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // for node
-}
-
-void FlowController::parsePortYaml(YAML::Node *portNode, ProcessGroup *parent, TransferDirection direction) {
-	uuid_t uuid;
-	Processor *processor = NULL;
-	RemoteProcessorGroupPort *port = NULL;
-
-	if (!parent) {
-		_logger->log_error("parseProcessNode: no parent group existed");
-		return;
-	}
-
-	YAML::Node inputPortsObj = portNode->as<YAML::Node>();
-
-	// generate the random UIID
-	uuid_generate(uuid);
-
-	auto portId = inputPortsObj["id"].as<std::string>();
-	auto nameStr = inputPortsObj["name"].as<std::string>();
-	uuid_parse(portId.c_str(), uuid);
-
-	port = new RemoteProcessorGroupPort(nameStr.c_str(), uuid);
-
-	processor = (Processor *) port;
-	port->setDirection(direction);
-	port->setTimeOut(parent->getTimeOut());
-	port->setTransmitting(true);
-	processor->setYieldPeriodMsec(parent->getYieldPeriodMsec());
-	processor->initialize();
-
-	// handle port properties
-	YAML::Node nodeVal = portNode->as<YAML::Node>();
-	YAML::Node propertiesNode = nodeVal["Properties"];
-
-	parsePropertiesNodeYaml(&propertiesNode, processor);
-
-	// add processor to parent
-	parent->addProcessor(processor);
-	processor->setScheduledState(RUNNING);
-	auto rawMaxConcurrentTasks = inputPortsObj["max concurrent tasks"].as<std::string>();
-	int64_t maxConcurrentTasks;
-	if (Property::StringToInt(rawMaxConcurrentTasks, maxConcurrentTasks)) {
-		processor->setMaxConcurrentTasks(maxConcurrentTasks);
-	}
-	_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
-	processor->setMaxConcurrentTasks(maxConcurrentTasks);
-
-}
-
-void FlowController::parsePort(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent, TransferDirection direction) {
-	char *id = NULL;
-	char *name = NULL;
-	uuid_t uuid;
-	xmlNode *currentNode;
-	Processor *processor = NULL;
-	RemoteProcessorGroupPort *port = NULL;
-
-	if (!parent) {
-		_logger->log_error("parseProcessNode: no parent group existed");
-		return;
-	}
-// generate the random UIID
-	uuid_generate(uuid);
-
-	for (currentNode = processorNode->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-		if (currentNode->type == XML_ELEMENT_NODE) {
-			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
-				id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseProcessorNode: id => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseProcessorNode: name => [%s]", name);
-					port = new RemoteProcessorGroupPort(name, uuid);
-					processor = (Processor *) port;
-					if (processor == NULL) {
-						xmlFree(name);
-						return;
-					}
-					port->setDirection(direction);
-					port->setTimeOut(parent->getTimeOut());
-					port->setTransmitting(parent->getTransmitting());
-					processor->setYieldPeriodMsec(parent->getYieldPeriodMsec());
-					processor->initialize();
-					// add processor to parent
-					parent->addProcessor(processor);
-					xmlFree(name);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "scheduledState") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					std::string state = temp;
-					if (state == "DISABLED") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(DISABLED);
-					}
-					if (state == "STOPPED") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(STOPPED);
-					}
-					if (state == "RUNNING") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(RUNNING);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxConcurrentTasks") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					int64_t maxConcurrentTasks;
-					if (Property::StringToInt(temp, maxConcurrentTasks)) {
-						_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
-						processor->setMaxConcurrentTasks(maxConcurrentTasks);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "property") == 0) {
-				this->parseProcessorProperty(doc, currentNode, processor);
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // while node
-}
-
-void FlowController::parseProcessorNode(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent) {
-	char *id = NULL;
-	char *name = NULL;
-	int64_t schedulingPeriod = -1;
-	int64_t penalizationPeriod = -1;
-	int64_t yieldPeriod = -1;
-	bool lossTolerant = false;
-	int64_t runDurationNanos = -1;
-	uuid_t uuid;
-	xmlNode *currentNode;
-	Processor *processor = NULL;
-
-	if (!parent) {
-		_logger->log_error("parseProcessNode: no parent group existed");
-		return;
-	}
-// generate the random UIID
-	uuid_generate(uuid);
-
-	for (currentNode = processorNode->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-		if (currentNode->type == XML_ELEMENT_NODE) {
-			if (xmlStrcmp(currentNode->name, BAD_CAST "id") == 0) {
-				id = (char *) xmlNodeGetContent(currentNode);
-				if (id) {
-					_logger->log_debug("parseProcessorNode: id => [%s]", id);
-					uuid_parse(id, uuid);
-					xmlFree(id);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "name") == 0) {
-				name = (char *) xmlNodeGetContent(currentNode);
-				if (name) {
-					_logger->log_debug("parseProcessorNode: name => [%s]", name);
-					processor = this->createProcessor(name, uuid);
-					if (processor == NULL) {
-						xmlFree(name);
-						return;
-					}
-					// add processor to parent
-					parent->addProcessor(processor);
-					xmlFree(name);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "schedulingPeriod") == 0) {
-				TimeUnit unit;
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToTime(temp, schedulingPeriod, unit)
-							&& Property::ConvertTimeUnitToNS(schedulingPeriod, unit, schedulingPeriod)) {
-						_logger->log_debug("parseProcessorNode: schedulingPeriod => [%d] ns", schedulingPeriod);
-						processor->setSchedulingPeriodNano(schedulingPeriod);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "penalizationPeriod") == 0) {
-				TimeUnit unit;
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToTime(temp, penalizationPeriod, unit)
-							&& Property::ConvertTimeUnitToMS(penalizationPeriod, unit, penalizationPeriod)) {
-						_logger->log_debug("parseProcessorNode: penalizationPeriod => [%d] ms", penalizationPeriod);
-						processor->setPenalizationPeriodMsec(penalizationPeriod);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "yieldPeriod") == 0) {
-				TimeUnit unit;
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToTime(temp, yieldPeriod, unit)
-							&& Property::ConvertTimeUnitToMS(yieldPeriod, unit, yieldPeriod)) {
-						_logger->log_debug("parseProcessorNode: yieldPeriod => [%d] ms", yieldPeriod);
-						processor->setYieldPeriodMsec(yieldPeriod);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "lossTolerant") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToBool(temp, lossTolerant)) {
-						_logger->log_debug("parseProcessorNode: lossTolerant => [%d]", lossTolerant);
-						processor->setlossTolerant(lossTolerant);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "scheduledState") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					std::string state = temp;
-					if (state == "DISABLED") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(DISABLED);
-					}
-					if (state == "STOPPED") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(STOPPED);
-					}
-					if (state == "RUNNING") {
-						_logger->log_debug("parseProcessorNode: scheduledState  => [%s]", state.c_str());
-						processor->setScheduledState(RUNNING);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "schedulingStrategy") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					std::string strategy = temp;
-					if (strategy == "TIMER_DRIVEN") {
-						_logger->log_debug("parseProcessorNode: scheduledStrategy  => [%s]", strategy.c_str());
-						processor->setSchedulingStrategy(TIMER_DRIVEN);
-					}
-					if (strategy == "EVENT_DRIVEN") {
-						_logger->log_debug("parseProcessorNode: scheduledStrategy  => [%s]", strategy.c_str());
-						processor->setSchedulingStrategy(EVENT_DRIVEN);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxConcurrentTasks") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					int64_t maxConcurrentTasks;
-					if (Property::StringToInt(temp, maxConcurrentTasks)) {
-						_logger->log_debug("parseProcessorNode: maxConcurrentTasks => [%d]", maxConcurrentTasks);
-						processor->setMaxConcurrentTasks(maxConcurrentTasks);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "runDurationNanos") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					if (Property::StringToInt(temp, runDurationNanos)) {
-						_logger->log_debug("parseProcessorNode: runDurationNanos => [%d]", runDurationNanos);
-						processor->setRunDurationNano(runDurationNanos);
-					}
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "autoTerminatedRelationship") == 0) {
-				char *temp = (char *) xmlNodeGetContent(currentNode);
-				if (temp) {
-					std::string relationshipName = temp;
-					Relationship relationship(relationshipName, "");
-					std::set<Relationship> relationships;
-
-					relationships.insert(relationship);
-					processor->setAutoTerminatedRelationships(relationships);
-					_logger->log_debug("parseProcessorNode: autoTerminatedRelationship  => [%s]",
-							relationshipName.c_str());
-					xmlFree(temp);
-				}
-			} else if (xmlStrcmp(currentNode->name, BAD_CAST "property") == 0) {
-				this->parseProcessorProperty(doc, currentNode, processor);
-			}
-		} // if (currentNode->type == XML_ELEMENT_NODE)
-	} // while node
-}
-
-void FlowController::parsePropertiesNodeYaml(YAML::Node *propertiesNode, Processor *processor)
-{
-    // Treat generically as a YAML node so we can perform inspection on entries to ensure they are populated
-    for (YAML::const_iterator propsIter = propertiesNode->begin(); propsIter != propertiesNode->end(); ++propsIter)
-    {
-        std::string propertyName = propsIter->first.as<std::string>();
-        YAML::Node propertyValueNode = propsIter->second;
-        if (!propertyValueNode.IsNull() && propertyValueNode.IsDefined())
-        {
-            std::string rawValueString = propertyValueNode.as<std::string>();
-            if (!processor->setProperty(propertyName, rawValueString))
-            {
-                _logger->log_warn("Received property %s with value %s but is not one of the properties for %s", propertyName.c_str(), rawValueString.c_str(), processor->getName().c_str());
-            }
-        }
-    }
-}
-
-void FlowController::load(ConfigFormat configFormat) {
-	if (_running) {
-		stop(true);
-	}
-	if (!_initialized) {
-		_logger->log_info("Load Flow Controller from file %s", _configurationFileName.c_str());
-
-		if (ConfigFormat::XML == configFormat) {
-			_logger->log_info("Detected an XML configuration file for processing.");
-
-			xmlDoc *doc = xmlReadFile(_configurationFileName.c_str(), NULL, XML_PARSE_NONET);
-			if (doc == NULL) {
-				_logger->log_error("xmlReadFile returned NULL when reading [%s]", _configurationFileName.c_str());
-				_initialized = true;
-				return;
-			}
-
-			xmlNode *root = xmlDocGetRootElement(doc);
-
-			if (root == NULL) {
-				_logger->log_error("Can not get root from XML doc %s", _configurationFileName.c_str());
-				xmlFreeDoc(doc);
-				xmlCleanupParser();
-			}
-
-			if (xmlStrcmp(root->name, BAD_CAST "flowController") != 0) {
-				_logger->log_error("Root name is not flowController for XML doc %s", _configurationFileName.c_str());
-				xmlFreeDoc(doc);
-				xmlCleanupParser();
-				return;
-			}
-
-			xmlNode *currentNode;
-
-			for (currentNode = root->xmlChildrenNode; currentNode != NULL; currentNode = currentNode->next) {
-				if (currentNode->type == XML_ELEMENT_NODE) {
-					if (xmlStrcmp(currentNode->name, BAD_CAST "rootGroup") == 0) {
-						this->parseRootProcessGroup(doc, currentNode);
-					} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxTimerDrivenThreadCount") == 0) {
-						char *temp = (char *) xmlNodeGetContent(currentNode);
-						int64_t maxTimerDrivenThreadCount;
-						if (temp) {
-							if (Property::StringToInt(temp, maxTimerDrivenThreadCount)) {
-								_logger->log_debug("maxTimerDrivenThreadCount => [%d]", maxTimerDrivenThreadCount);
-								this->_maxTimerDrivenThreads = maxTimerDrivenThreadCount;
-							}
-							xmlFree(temp);
-						}
-					} else if (xmlStrcmp(currentNode->name, BAD_CAST "maxEventDrivenThreadCount") == 0) {
-						char *temp = (char *) xmlNodeGetContent(currentNode);
-						int64_t maxEventDrivenThreadCount;
-						if (temp) {
-							if (Property::StringToInt(temp, maxEventDrivenThreadCount)) {
-								_logger->log_debug("maxEventDrivenThreadCount => [%d]", maxEventDrivenThreadCount);
-								this->_maxEventDrivenThreads = maxEventDrivenThreadCount;
-							}
-							xmlFree(temp);
-						}
-					}
-				} // type == XML_ELEMENT_NODE
-			} // for
-
-			xmlFreeDoc(doc);
-			xmlCleanupParser();
-			_initialized = true;
-		} else if (ConfigFormat::YAML == configFormat) {
-			YAML::Node flow = YAML::LoadFile(_configurationFileName);
-
-			YAML::Node flowControllerNode = flow["Flow Controller"];
-			YAML::Node processorsNode = flow[CONFIG_YAML_PROCESSORS_KEY];
-			YAML::Node connectionsNode = flow["Connections"];
-			YAML::Node remoteProcessingGroupNode = flow["Remote Processing Groups"];
-
-			// Create the root process group
-			parseRootProcessGroupYaml(flowControllerNode);
-			parseProcessorNodeYaml(processorsNode, this->_root);
-			parseRemoteProcessGroupYaml(&remoteProcessingGroupNode, this->_root);
-			parseConnectionYaml(&connectionsNode, this->_root);
-
-			_initialized = true;
-		}
-	}
-}
-
-bool FlowController::start() {
-	if (!_initialized) {
-		_logger->log_error("Can not start Flow Controller because it has not been initialized");
-		return false;
-	} else {
-		if (!_running) {
-			_logger->log_info("Start Flow Controller");
-			this->_timerScheduler.start();
-			if (this->_root)
-				this->_root->startProcessing(&this->_timerScheduler);
-			_running = true;
-			this->_protocol->start();
-		}
-		return true;
-	}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/FlowFileRecord.cpp
----------------------------------------------------------------------
diff --git a/src/FlowFileRecord.cpp b/src/FlowFileRecord.cpp
deleted file mode 100644
index 2dda47a..0000000
--- a/src/FlowFileRecord.cpp
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @file FlowFileRecord.cpp
- * Flow file record class implementation 
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <sys/time.h>
-#include <time.h>
-#include <iostream>
-#include <fstream>
-#include <cstdio>
-
-#include "FlowFileRecord.h"
-#include "Relationship.h"
-#include "Logger.h"
-
-std::atomic<uint64_t> FlowFileRecord::_localFlowSeqNumber(0);
-
-FlowFileRecord::FlowFileRecord(std::map<std::string, std::string> attributes, ResourceClaim *claim)
-: _size(0),
-  _id(_localFlowSeqNumber.load()),
-  _offset(0),
-  _penaltyExpirationMs(0),
-  _claim(claim),
-  _markedDelete(false),
-  _connection(NULL),
-  _orginalConnection(NULL)
-{
-	_entryDate = getTimeMillis();
-	_lineageStartDate = _entryDate;
-
-	char uuidStr[37];
-
-	// Generate the global UUID for the flow record
-	uuid_generate(_uuid);
-	// Increase the local ID for the flow record
-	++_localFlowSeqNumber;
-	uuid_unparse(_uuid, uuidStr);
-	_uuidStr = uuidStr;
-
-	// Populate the default attributes
-    addAttribute(FILENAME, std::to_string(getTimeNano()));
-    addAttribute(PATH, DEFAULT_FLOWFILE_PATH);
-    addAttribute(UUID, uuidStr);
-	// Populate the attributes from the input
-    std::map<std::string, std::string>::iterator it;
-    for (it = attributes.begin(); it!= attributes.end(); it++)
-    {
-    	addAttribute(it->first, it->second);
-    }
-
-    _snapshot = false;
-
-	if (_claim)
-		// Increase the flow file record owned count for the resource claim
-		_claim->increaseFlowFileRecordOwnedCount();
-	_logger = Logger::getLogger();
-}
-
-FlowFileRecord::~FlowFileRecord()
-{
-	if (!_snapshot)
-		_logger->log_debug("Delete FlowFile UUID %s", _uuidStr.c_str());
-	else
-		_logger->log_debug("Delete SnapShot FlowFile UUID %s", _uuidStr.c_str());
-	if (_claim)
-	{
-		// Decrease the flow file record owned count for the resource claim
-		_claim->decreaseFlowFileRecordOwnedCount();
-		if (_claim->getFlowFileRecordOwnedCount() == 0)
-		{
-			_logger->log_debug("Delete Resource Claim %s", _claim->getContentFullPath().c_str());
-			std::remove(_claim->getContentFullPath().c_str());
-			delete _claim;
-		}
-	}
-}
-
-bool FlowFileRecord::addAttribute(FlowAttribute key, std::string value)
-{
-	const char *keyStr = FlowAttributeKey(key);
-	if (keyStr)
-	{
-		std::string keyString = keyStr;
-		return addAttribute(keyString, value);
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::addAttribute(std::string key, std::string value)
-{
-	std::map<std::string, std::string>::iterator it = _attributes.find(key);
-	if (it != _attributes.end())
-	{
-		// attribute already there in the map
-		return false;
-	}
-	else
-	{
-		_attributes[key] = value;
-		return true;
-	}
-}
-
-bool FlowFileRecord::removeAttribute(FlowAttribute key)
-{
-	const char *keyStr = FlowAttributeKey(key);
-	if (keyStr)
-	{
-		std::string keyString = keyStr;
-		return removeAttribute(keyString);
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::removeAttribute(std::string key)
-{
-	std::map<std::string, std::string>::iterator it = _attributes.find(key);
-	if (it != _attributes.end())
-	{
-		_attributes.erase(key);
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::updateAttribute(FlowAttribute key, std::string value)
-{
-	const char *keyStr = FlowAttributeKey(key);
-	if (keyStr)
-	{
-		std::string keyString = keyStr;
-		return updateAttribute(keyString, value);
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::updateAttribute(std::string key, std::string value)
-{
-	std::map<std::string, std::string>::iterator it = _attributes.find(key);
-	if (it != _attributes.end())
-	{
-		_attributes[key] = value;
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::getAttribute(FlowAttribute key, std::string &value)
-{
-	const char *keyStr = FlowAttributeKey(key);
-	if (keyStr)
-	{
-		std::string keyString = keyStr;
-		return getAttribute(keyString, value);
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool FlowFileRecord::getAttribute(std::string key, std::string &value)
-{
-	std::map<std::string, std::string>::iterator it = _attributes.find(key);
-	if (it != _attributes.end())
-	{
-		value = it->second;
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-void FlowFileRecord::duplicate(FlowFileRecord *original)
-{
-	uuid_copy(this->_uuid, original->_uuid);
-	this->_attributes = original->_attributes;
-	this->_entryDate = original->_entryDate;
-	this->_id = original->_id;
-	this->_lastQueueDate = original->_lastQueueDate;
-	this->_lineageStartDate = original->_lineageStartDate;
-	this->_offset = original->_offset;
-	this->_penaltyExpirationMs = original->_penaltyExpirationMs;
-	this->_size = original->_size;
-	this->_lineageIdentifiers = original->_lineageIdentifiers;
-	this->_orginalConnection = original->_orginalConnection;
-	this->_uuidStr = original->_uuidStr;
-	this->_connection = original->_connection;
-	this->_markedDelete = original->_markedDelete;
-
-	this->_claim = original->_claim;
-	if (this->_claim)
-		this->_claim->increaseFlowFileRecordOwnedCount();
-
-	this->_snapshot = true;
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/GenerateFlowFile.cpp
----------------------------------------------------------------------
diff --git a/src/GenerateFlowFile.cpp b/src/GenerateFlowFile.cpp
deleted file mode 100644
index 4b0603d..0000000
--- a/src/GenerateFlowFile.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @file GenerateFlowFile.cpp
- * GenerateFlowFile class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <time.h>
-#include <chrono>
-#include <thread>
-#include <random>
-
-#include "GenerateFlowFile.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const char *GenerateFlowFile::DATA_FORMAT_BINARY = "Binary";
-const char *GenerateFlowFile::DATA_FORMAT_TEXT = "Text";
-const std::string GenerateFlowFile::ProcessorName("GenerateFlowFile");
-Property GenerateFlowFile::FileSize("File Size", "The size of the file that will be used", "1 kB");
-Property GenerateFlowFile::BatchSize("Batch Size", "The number of FlowFiles to be transferred in each invocation", "1");
-Property GenerateFlowFile::DataFormat("Data Format", "Specifies whether the data should be Text or Binary", GenerateFlowFile::DATA_FORMAT_BINARY);
-Property GenerateFlowFile::UniqueFlowFiles("Unique FlowFiles",
-		"If true, each FlowFile that is generated will be unique. If false, a random value will be generated and all FlowFiles", "true");
-Relationship GenerateFlowFile::Success("success", "success operational on the flow record");
-
-void GenerateFlowFile::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(FileSize);
-	properties.insert(BatchSize);
-	properties.insert(DataFormat);
-	properties.insert(UniqueFlowFiles);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-}
-
-void GenerateFlowFile::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	int64_t batchSize = 1;
-	bool uniqueFlowFile = true;
-	int64_t fileSize = 1024;
-
-	std::string value;
-	if (context->getProperty(FileSize.getName(), value))
-	{
-		Property::StringToInt(value, fileSize);
-	}
-	if (context->getProperty(BatchSize.getName(), value))
-	{
-		Property::StringToInt(value, batchSize);
-	}
-	if (context->getProperty(UniqueFlowFiles.getName(), value))
-	{
-		Property::StringToBool(value, uniqueFlowFile);
-	}
-
-	if (!uniqueFlowFile)
-	{
-		char *data;
-		data = new char[fileSize];
-		if (!data)
-			return;
-		uint64_t dataSize = fileSize;
-		GenerateFlowFile::WriteCallback callback(data, dataSize);
-		char *current = data;
-		for (int i = 0; i < fileSize; i+= sizeof(int))
-		{
-			int randValue = random();
-			*((int *) current) = randValue;
-			current += sizeof(int);
-		}
-		for (int i = 0; i < batchSize; i++)
-		{
-			// For each batch
-			FlowFileRecord *flowFile = session->create();
-			if (!flowFile)
-				return;
-			if (fileSize > 0)
-				session->write(flowFile, &callback);
-			session->transfer(flowFile, Success);
-		}
-		delete[] data;
-	}
-	else
-	{
-		if (!_data)
-		{
-			// We have not create the unique data yet
-			_data = new char[fileSize];
-			_dataSize = fileSize;
-			char *current = _data;
-			for (int i = 0; i < fileSize; i+= sizeof(int))
-			{
-				int randValue = random();
-				*((int *) current) = randValue;
-				// *((int *) current) = (0xFFFFFFFF & i);
-				current += sizeof(int);
-			}
-		}
-		GenerateFlowFile::WriteCallback callback(_data, _dataSize);
-		for (int i = 0; i < batchSize; i++)
-		{
-			// For each batch
-			FlowFileRecord *flowFile = session->create();
-			if (!flowFile)
-				return;
-			if (fileSize > 0)
-				session->write(flowFile, &callback);
-			session->transfer(flowFile, Success);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/GetFile.cpp
----------------------------------------------------------------------
diff --git a/src/GetFile.cpp b/src/GetFile.cpp
deleted file mode 100644
index 02e196a..0000000
--- a/src/GetFile.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/**
- * @file GetFile.cpp
- * GetFile class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include <queue>
-#include <map>
-#include <set>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <sstream>
-#include <stdio.h>
-#include <string>
-#include <iostream>
-#include <dirent.h>
-#include <limits.h>
-#include <unistd.h>
-#include <regex>
-
-#include "TimeUtil.h"
-#include "GetFile.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string GetFile::ProcessorName("GetFile");
-Property GetFile::BatchSize("Batch Size", "The maximum number of files to pull in each iteration", "10");
-Property GetFile::Directory("Input Directory", "The input directory from which to pull files", ".");
-Property GetFile::IgnoreHiddenFile("Ignore Hidden Files", "Indicates whether or not hidden files should be ignored", "true");
-Property GetFile::KeepSourceFile("Keep Source File",
-		"If true, the file is not deleted after it has been copied to the Content Repository", "false");
-Property GetFile::MaxAge("Maximum File Age",
-		"The minimum age that a file must be in order to be pulled; any file younger than this amount of time (according to last modification date) will be ignored", "0 sec");
-Property GetFile::MinAge("Minimum File Age",
-		"The maximum age that a file must be in order to be pulled; any file older than this amount of time (according to last modification date) will be ignored", "0 sec");
-Property GetFile::MaxSize("Maximum File Size", "The maximum size that a file can be in order to be pulled", "0 B");
-Property GetFile::MinSize("Minimum File Size", "The minimum size that a file must be in order to be pulled", "0 B");
-Property GetFile::PollInterval("Polling Interval", "Indicates how long to wait before performing a directory listing", "0 sec");
-Property GetFile::Recurse("Recurse Subdirectories", "Indicates whether or not to pull files from subdirectories", "true");
-Property GetFile::FileFilter("File Filter", "Only files whose names match the given regular expression will be picked up", "[^\\.].*");
-Relationship GetFile::Success("success", "All files are routed to success");
-
-void GetFile::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(BatchSize);
-	properties.insert(Directory);
-	properties.insert(IgnoreHiddenFile);
-	properties.insert(KeepSourceFile);
-	properties.insert(MaxAge);
-	properties.insert(MinAge);
-	properties.insert(MaxSize);
-	properties.insert(MinSize);
-	properties.insert(PollInterval);
-	properties.insert(Recurse);
-	properties.insert(FileFilter);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	setSupportedRelationships(relationships);
-}
-
-void GetFile::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string value;
-	if (context->getProperty(Directory.getName(), value))
-	{
-		_directory = value;
-	}
-	if (context->getProperty(BatchSize.getName(), value))
-	{
-		Property::StringToInt(value, _batchSize);
-	}
-	if (context->getProperty(IgnoreHiddenFile.getName(), value))
-	{
-		Property::StringToBool(value, _ignoreHiddenFile);
-	}
-	if (context->getProperty(KeepSourceFile.getName(), value))
-	{
-		Property::StringToBool(value, _keepSourceFile);
-	}
-	if (context->getProperty(MaxAge.getName(), value))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(value, _maxAge, unit) &&
-			Property::ConvertTimeUnitToMS(_maxAge, unit, _maxAge))
-		{
-
-		}
-	}
-	if (context->getProperty(MinAge.getName(), value))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(value, _minAge, unit) &&
-			Property::ConvertTimeUnitToMS(_minAge, unit, _minAge))
-		{
-
-		}
-	}
-	if (context->getProperty(MaxSize.getName(), value))
-	{
-		Property::StringToInt(value, _maxSize);
-	}
-	if (context->getProperty(MinSize.getName(), value))
-	{
-		Property::StringToInt(value, _minSize);
-	}
-	if (context->getProperty(PollInterval.getName(), value))
-	{
-		TimeUnit unit;
-		if (Property::StringToTime(value, _pollInterval, unit) &&
-			Property::ConvertTimeUnitToMS(_pollInterval, unit, _pollInterval))
-		{
-
-		}
-	}
-	if (context->getProperty(Recurse.getName(), value))
-	{
-		Property::StringToBool(value, _recursive);
-	}
-
-	if (context->getProperty(FileFilter.getName(), value))
-	{
-		_fileFilter = value;
-	}
-
-	// Perform directory list
-	if (isListingEmpty())
-	{
-		if (_pollInterval == 0 || (getTimeMillis() - _lastDirectoryListingTime) > _pollInterval)
-		{
-			performListing(_directory);
-		}
-	}
-
-	if (!isListingEmpty())
-	{
-		try
-		{
-			std::queue<std::string> list;
-			pollListing(list, _batchSize);
-			while (!list.empty())
-			{
-				std::string fileName = list.front();
-				list.pop();
-				_logger->log_info("GetFile process %s", fileName.c_str());
-				FlowFileRecord *flowFile = session->create();
-				if (!flowFile)
-					return;
-				std::size_t found = fileName.find_last_of("/\\");
-				std::string path = fileName.substr(0,found);
-				std::string name = fileName.substr(found+1);
-				flowFile->updateAttribute(FILENAME, name);
-				flowFile->updateAttribute(PATH, path);
-				flowFile->addAttribute(ABSOLUTE_PATH, fileName);
-				session->import(fileName, flowFile, _keepSourceFile);
-				session->transfer(flowFile, Success);
-			}
-		}
-		catch (std::exception &exception)
-		{
-			_logger->log_debug("GetFile Caught Exception %s", exception.what());
-			throw;
-		}
-		catch (...)
-		{
-			throw;
-		}
-	}
-}
-
-bool GetFile::isListingEmpty()
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	return _dirList.empty();
-}
-
-void GetFile::putListing(std::string fileName)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	_dirList.push(fileName);
-}
-
-void GetFile::pollListing(std::queue<std::string> &list, int maxSize)
-{
-	std::lock_guard<std::mutex> lock(_mtx);
-
-	while (!_dirList.empty() && (maxSize == 0 || list.size() < maxSize))
-	{
-		std::string fileName = _dirList.front();
-		_dirList.pop();
-		list.push(fileName);
-	}
-
-	return;
-}
-
-bool GetFile::acceptFile(std::string fileName)
-{
-	struct stat statbuf;
-
-	if (stat(fileName.c_str(), &statbuf) == 0)
-	{
-		if (_minSize > 0 && statbuf.st_size <_minSize)
-			return false;
-
-		if (_maxSize > 0 && statbuf.st_size > _maxSize)
-			return false;
-
-		uint64_t modifiedTime = ((uint64_t) (statbuf.st_mtime) * 1000);
-		uint64_t fileAge = getTimeMillis() - modifiedTime;
-		if (_minAge > 0 && fileAge < _minAge)
-			return false;
-		if (_maxAge > 0 && fileAge > _maxAge)
-			return false;
-
-		if (_ignoreHiddenFile && fileName.c_str()[0] == '.')
-			return false;
-
-		if (access(fileName.c_str(), R_OK) != 0)
-			return false;
-
-		if (_keepSourceFile == false && access(fileName.c_str(), W_OK) != 0)
-			return false;
-
-		try {
-			std::regex re(_fileFilter);
-			if (!std::regex_match(fileName, re)) {
-				return false;
-	   		}
-		} catch (std::regex_error e) {
-			_logger->log_error("Invalid File Filter regex: %s.", e.what());
-			return false;
-		}
-
-		return true;
-	}
-
-	return false;
-}
-
-void GetFile::performListing(std::string dir)
-{
-	DIR *d;
-	d = opendir(dir.c_str());
-	if (!d)
-		return;
-	while (1)
-	{
-		struct dirent *entry;
-		entry = readdir(d);
-		if (!entry)
-			break;
-		std::string d_name = entry->d_name;
-		if ((entry->d_type & DT_DIR))
-		{
-			// if this is a directory
-			if (_recursive && strcmp(d_name.c_str(), "..") != 0 && strcmp(d_name.c_str(), ".") != 0)
-			{
-				std::string path = dir + "/" + d_name;
-				performListing(path);
-			}
-		}
-		else
-		{
-			std::string fileName = dir + "/" + d_name;
-			if (acceptFile(fileName))
-			{
-				// check whether we can take this file
-				putListing(fileName);
-			}
-		}
-	}
-	closedir(d);
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/src/ListenSyslog.cpp
----------------------------------------------------------------------
diff --git a/src/ListenSyslog.cpp b/src/ListenSyslog.cpp
deleted file mode 100644
index ace37d7..0000000
--- a/src/ListenSyslog.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/**
- * @file ListenSyslog.cpp
- * ListenSyslog class implementation
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <queue>
-#include <stdio.h>
-#include <string>
-#include "TimeUtil.h"
-#include "ListenSyslog.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-
-const std::string ListenSyslog::ProcessorName("ListenSyslog");
-Property ListenSyslog::RecvBufSize("Receive Buffer Size", "The size of each buffer used to receive Syslog messages.", "65507 B");
-Property ListenSyslog::MaxSocketBufSize("Max Size of Socket Buffer", "The maximum size of the socket buffer that should be used.", "1 MB");
-Property ListenSyslog::MaxConnections("Max Number of TCP Connections", "The maximum number of concurrent connections to accept Syslog messages in TCP mode.", "2");
-Property ListenSyslog::MaxBatchSize("Max Batch Size",
-		"The maximum number of Syslog events to add to a single FlowFile.", "1");
-Property ListenSyslog::MessageDelimiter("Message Delimiter",
-		"Specifies the delimiter to place between Syslog messages when multiple messages are bundled together (see <Max Batch Size> property).", "\n");
-Property ListenSyslog::ParseMessages("Parse Messages",
-		"Indicates if the processor should parse the Syslog messages. If set to false, each outgoing FlowFile will only.", "false");
-Property ListenSyslog::Protocol("Protocol", "The protocol for Syslog communication.", "UDP");
-Property ListenSyslog::Port("Port", "The port for Syslog communication.", "514");
-Relationship ListenSyslog::Success("success", "All files are routed to success");
-Relationship ListenSyslog::Invalid("invalid", "SysLog message format invalid");
-
-void ListenSyslog::initialize()
-{
-	//! Set the supported properties
-	std::set<Property> properties;
-	properties.insert(RecvBufSize);
-	properties.insert(MaxSocketBufSize);
-	properties.insert(MaxConnections);
-	properties.insert(MaxBatchSize);
-	properties.insert(MessageDelimiter);
-	properties.insert(ParseMessages);
-	properties.insert(Protocol);
-	properties.insert(Port);
-	setSupportedProperties(properties);
-	//! Set the supported relationships
-	std::set<Relationship> relationships;
-	relationships.insert(Success);
-	relationships.insert(Invalid);
-	setSupportedRelationships(relationships);
-}
-
-void ListenSyslog::startSocketThread()
-{
-	if (_thread != NULL)
-		return;
-
-	_logger->log_info("ListenSysLog Socket Thread Start");
-	_serverTheadRunning = true;
-	_thread = new std::thread(run, this);
-	_thread->detach();
-}
-
-void ListenSyslog::run(ListenSyslog *process)
-{
-	process->runThread();
-}
-
-void ListenSyslog::runThread()
-{
-	while (_serverTheadRunning)
-	{
-		if (_resetServerSocket)
-		{
-			_resetServerSocket = false;
-			// need to reset the socket
-			std::vector<int>::iterator it;
-			for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
-			{
-				int clientSocket = *it;
-				close(clientSocket);
-			}
-			_clientSockets.clear();
-			if (_serverSocket > 0)
-			{
-				close(_serverSocket);
-				_serverSocket = 0;
-			}
-		}
-
-		if (_serverSocket <= 0)
-		{
-			uint16_t portno = _port;
-			struct sockaddr_in serv_addr;
-			int sockfd;
-			if (_protocol == "TCP")
-				sockfd = socket(AF_INET, SOCK_STREAM, 0);
-			else
-				sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-			if (sockfd < 0)
-			{
-				_logger->log_info("ListenSysLog Server socket creation failed");
-				break;
-			}
-			bzero((char *) &serv_addr, sizeof(serv_addr));
-			serv_addr.sin_family = AF_INET;
-			serv_addr.sin_addr.s_addr = INADDR_ANY;
-			serv_addr.sin_port = htons(portno);
-			if (bind(sockfd, (struct sockaddr *) &serv_addr,
-					sizeof(serv_addr)) < 0)
-			{
-				_logger->log_error("ListenSysLog Server socket bind failed");
-				break;
-			}
-			if (_protocol == "TCP")
-				listen(sockfd,5);
-			_serverSocket = sockfd;
-			_logger->log_error("ListenSysLog Server socket %d bind OK to port %d", _serverSocket, portno);
-		}
-		FD_ZERO(&_readfds);
-		FD_SET(_serverSocket, &_readfds);
-		_maxFds = _serverSocket;
-		std::vector<int>::iterator it;
-		for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
-		{
-			int clientSocket = *it;
-			if (clientSocket >= _maxFds)
-				_maxFds = clientSocket;
-			FD_SET(clientSocket, &_readfds);
-		}
-		fd_set fds;
-		struct timeval tv;
-		int retval;
-		fds = _readfds;
-		tv.tv_sec = 0;
-		// 100 msec
-		tv.tv_usec = 100000;
-		retval = select(_maxFds+1, &fds, NULL, NULL, &tv);
-		if (retval < 0)
-			break;
-		if (retval == 0)
-			continue;
-		if (FD_ISSET(_serverSocket, &fds))
-		{
-			// server socket, either we have UDP datagram or TCP connection request
-			if (_protocol == "TCP")
-			{
-				socklen_t clilen;
-				struct sockaddr_in cli_addr;
-				clilen = sizeof(cli_addr);
-				int newsockfd = accept(_serverSocket,
-						(struct sockaddr *) &cli_addr,
-						&clilen);
-				if (newsockfd > 0)
-				{
-					if (_clientSockets.size() < _maxConnections)
-					{
-						_clientSockets.push_back(newsockfd);
-						_logger->log_info("ListenSysLog new client socket %d connection", newsockfd);
-						continue;
-					}
-					else
-					{
-						close(newsockfd);
-					}
-				}
-			}
-			else
-			{
-				socklen_t clilen;
-				struct sockaddr_in cli_addr;
-				clilen = sizeof(cli_addr);
-				int recvlen = recvfrom(_serverSocket, _buffer, sizeof(_buffer), 0,
-						(struct sockaddr *)&cli_addr, &clilen);
-				if (recvlen > 0 && (recvlen + getEventQueueByteSize()) <= _recvBufSize)
-				{
-					uint8_t *payload = new uint8_t[recvlen];
-					memcpy(payload, _buffer, recvlen);
-					putEvent(payload, recvlen);
-				}
-			}
-		}
-		it = _clientSockets.begin();
-		while (it != _clientSockets.end())
-		{
-			int clientSocket = *it;
-			if (FD_ISSET(clientSocket, &fds))
-			{
-				int recvlen = readline(clientSocket, (char *)_buffer, sizeof(_buffer));
-				if (recvlen <= 0)
-				{
-					close(clientSocket);
-					_logger->log_info("ListenSysLog client socket %d close", clientSocket);
-					it = _clientSockets.erase(it);
-				}
-				else
-				{
-					if ((recvlen + getEventQueueByteSize()) <= _recvBufSize)
-					{
-						uint8_t *payload = new uint8_t[recvlen];
-						memcpy(payload, _buffer, recvlen);
-						putEvent(payload, recvlen);
-					}
-					++it;
-				}
-			}
-		}
-	}
-	return;
-}
-
-
-int ListenSyslog::readline( int fd, char *bufptr, size_t len )
-{
-	char *bufx = bufptr;
-	static char *bp;
-	static int cnt = 0;
-	static char b[ 2048 ];
-	char c;
-
-	while ( --len > 0 )
-    {
-      if ( --cnt <= 0 )
-      {
-    	  cnt = recv( fd, b, sizeof( b ), 0 );
-    	  if ( cnt < 0 )
-    	  {
-    		  if ( errno == EINTR )
-    		  {
-    			  len++;		/* the while will decrement */
-    			  continue;
-    		  }
-    		  return -1;
-    	  }
-    	  if ( cnt == 0 )
-    		  return 0;
-    	  bp = b;
-      }
-      c = *bp++;
-      *bufptr++ = c;
-      if ( c == '\n' )
-      {
-    	  *bufptr = '\n';
-    	  return bufptr - bufx + 1;
-      }
-    }
-	return -1;
-}
-
-void ListenSyslog::onTrigger(ProcessContext *context, ProcessSession *session)
-{
-	std::string value;
-	bool needResetServerSocket = false;
-	if (context->getProperty(Protocol.getName(), value))
-	{
-		if (_protocol != value)
-			needResetServerSocket = true;
-		_protocol = value;
-	}
-	if (context->getProperty(RecvBufSize.getName(), value))
-	{
-		Property::StringToInt(value, _recvBufSize);
-	}
-	if (context->getProperty(MaxSocketBufSize.getName(), value))
-	{
-		Property::StringToInt(value, _maxSocketBufSize);
-	}
-	if (context->getProperty(MaxConnections.getName(), value))
-	{
-		Property::StringToInt(value, _maxConnections);
-	}
-	if (context->getProperty(MessageDelimiter.getName(), value))
-	{
-		_messageDelimiter = value;
-	}
-	if (context->getProperty(ParseMessages.getName(), value))
-	{
-		Property::StringToBool(value, _parseMessages);
-	}
-	if (context->getProperty(Port.getName(), value))
-	{
-		int64_t oldPort = _port;
-		Property::StringToInt(value, _port);
-		if (_port != oldPort)
-			needResetServerSocket = true;
-	}
-	if (context->getProperty(MaxBatchSize.getName(), value))
-	{
-		Property::StringToInt(value, _maxBatchSize);
-	}
-
-	if (needResetServerSocket)
-		_resetServerSocket = true;
-
-	startSocketThread();
-
-	// read from the event queue
-	if (isEventQueueEmpty())
-	{
-		context->yield();
-		return;
-	}
-
-	std::queue<SysLogEvent> eventQueue;
-	pollEvent(eventQueue, _maxBatchSize);
-	bool firstEvent = true;
-	FlowFileRecord *flowFile = NULL;
-	while(!eventQueue.empty())
-	{
-		SysLogEvent event = eventQueue.front();
-		eventQueue.pop();
-		if (firstEvent)
-		{
-			flowFile = session->create();
-			if (!flowFile)
-				return;
-			ListenSyslog::WriteCallback callback((char *)event.payload, event.len);
-			session->write(flowFile, &callback);
-			delete[] event.payload;
-			firstEvent = false;
-		}
-		else
-		{
-			ListenSyslog::WriteCallback callback((char *)event.payload, event.len);
-			session->append(flowFile, &callback);
-			delete[] event.payload;
-		}
-	}
-	flowFile->addAttribute("syslog.protocol", _protocol);
-	flowFile->addAttribute("syslog.port", std::to_string(_port));
-	session->transfer(flowFile, Success);
-}


[06/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/ListenSyslog.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/ListenSyslog.cpp b/libminifi/src/ListenSyslog.cpp
new file mode 100644
index 0000000..ace37d7
--- /dev/null
+++ b/libminifi/src/ListenSyslog.cpp
@@ -0,0 +1,342 @@
+/**
+ * @file ListenSyslog.cpp
+ * ListenSyslog class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <queue>
+#include <stdio.h>
+#include <string>
+#include "TimeUtil.h"
+#include "ListenSyslog.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string ListenSyslog::ProcessorName("ListenSyslog");
+Property ListenSyslog::RecvBufSize("Receive Buffer Size", "The size of each buffer used to receive Syslog messages.", "65507 B");
+Property ListenSyslog::MaxSocketBufSize("Max Size of Socket Buffer", "The maximum size of the socket buffer that should be used.", "1 MB");
+Property ListenSyslog::MaxConnections("Max Number of TCP Connections", "The maximum number of concurrent connections to accept Syslog messages in TCP mode.", "2");
+Property ListenSyslog::MaxBatchSize("Max Batch Size",
+		"The maximum number of Syslog events to add to a single FlowFile.", "1");
+Property ListenSyslog::MessageDelimiter("Message Delimiter",
+		"Specifies the delimiter to place between Syslog messages when multiple messages are bundled together (see <Max Batch Size> property).", "\n");
+Property ListenSyslog::ParseMessages("Parse Messages",
+		"Indicates if the processor should parse the Syslog messages. If set to false, each outgoing FlowFile will only.", "false");
+Property ListenSyslog::Protocol("Protocol", "The protocol for Syslog communication.", "UDP");
+Property ListenSyslog::Port("Port", "The port for Syslog communication.", "514");
+Relationship ListenSyslog::Success("success", "All files are routed to success");
+Relationship ListenSyslog::Invalid("invalid", "SysLog message format invalid");
+
+void ListenSyslog::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(RecvBufSize);
+	properties.insert(MaxSocketBufSize);
+	properties.insert(MaxConnections);
+	properties.insert(MaxBatchSize);
+	properties.insert(MessageDelimiter);
+	properties.insert(ParseMessages);
+	properties.insert(Protocol);
+	properties.insert(Port);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	relationships.insert(Invalid);
+	setSupportedRelationships(relationships);
+}
+
+void ListenSyslog::startSocketThread()
+{
+	if (_thread != NULL)
+		return;
+
+	_logger->log_info("ListenSysLog Socket Thread Start");
+	_serverTheadRunning = true;
+	_thread = new std::thread(run, this);
+	_thread->detach();
+}
+
+void ListenSyslog::run(ListenSyslog *process)
+{
+	process->runThread();
+}
+
+void ListenSyslog::runThread()
+{
+	while (_serverTheadRunning)
+	{
+		if (_resetServerSocket)
+		{
+			_resetServerSocket = false;
+			// need to reset the socket
+			std::vector<int>::iterator it;
+			for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
+			{
+				int clientSocket = *it;
+				close(clientSocket);
+			}
+			_clientSockets.clear();
+			if (_serverSocket > 0)
+			{
+				close(_serverSocket);
+				_serverSocket = 0;
+			}
+		}
+
+		if (_serverSocket <= 0)
+		{
+			uint16_t portno = _port;
+			struct sockaddr_in serv_addr;
+			int sockfd;
+			if (_protocol == "TCP")
+				sockfd = socket(AF_INET, SOCK_STREAM, 0);
+			else
+				sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+			if (sockfd < 0)
+			{
+				_logger->log_info("ListenSysLog Server socket creation failed");
+				break;
+			}
+			bzero((char *) &serv_addr, sizeof(serv_addr));
+			serv_addr.sin_family = AF_INET;
+			serv_addr.sin_addr.s_addr = INADDR_ANY;
+			serv_addr.sin_port = htons(portno);
+			if (bind(sockfd, (struct sockaddr *) &serv_addr,
+					sizeof(serv_addr)) < 0)
+			{
+				_logger->log_error("ListenSysLog Server socket bind failed");
+				break;
+			}
+			if (_protocol == "TCP")
+				listen(sockfd,5);
+			_serverSocket = sockfd;
+			_logger->log_error("ListenSysLog Server socket %d bind OK to port %d", _serverSocket, portno);
+		}
+		FD_ZERO(&_readfds);
+		FD_SET(_serverSocket, &_readfds);
+		_maxFds = _serverSocket;
+		std::vector<int>::iterator it;
+		for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
+		{
+			int clientSocket = *it;
+			if (clientSocket >= _maxFds)
+				_maxFds = clientSocket;
+			FD_SET(clientSocket, &_readfds);
+		}
+		fd_set fds;
+		struct timeval tv;
+		int retval;
+		fds = _readfds;
+		tv.tv_sec = 0;
+		// 100 msec
+		tv.tv_usec = 100000;
+		retval = select(_maxFds+1, &fds, NULL, NULL, &tv);
+		if (retval < 0)
+			break;
+		if (retval == 0)
+			continue;
+		if (FD_ISSET(_serverSocket, &fds))
+		{
+			// server socket, either we have UDP datagram or TCP connection request
+			if (_protocol == "TCP")
+			{
+				socklen_t clilen;
+				struct sockaddr_in cli_addr;
+				clilen = sizeof(cli_addr);
+				int newsockfd = accept(_serverSocket,
+						(struct sockaddr *) &cli_addr,
+						&clilen);
+				if (newsockfd > 0)
+				{
+					if (_clientSockets.size() < _maxConnections)
+					{
+						_clientSockets.push_back(newsockfd);
+						_logger->log_info("ListenSysLog new client socket %d connection", newsockfd);
+						continue;
+					}
+					else
+					{
+						close(newsockfd);
+					}
+				}
+			}
+			else
+			{
+				socklen_t clilen;
+				struct sockaddr_in cli_addr;
+				clilen = sizeof(cli_addr);
+				int recvlen = recvfrom(_serverSocket, _buffer, sizeof(_buffer), 0,
+						(struct sockaddr *)&cli_addr, &clilen);
+				if (recvlen > 0 && (recvlen + getEventQueueByteSize()) <= _recvBufSize)
+				{
+					uint8_t *payload = new uint8_t[recvlen];
+					memcpy(payload, _buffer, recvlen);
+					putEvent(payload, recvlen);
+				}
+			}
+		}
+		it = _clientSockets.begin();
+		while (it != _clientSockets.end())
+		{
+			int clientSocket = *it;
+			if (FD_ISSET(clientSocket, &fds))
+			{
+				int recvlen = readline(clientSocket, (char *)_buffer, sizeof(_buffer));
+				if (recvlen <= 0)
+				{
+					close(clientSocket);
+					_logger->log_info("ListenSysLog client socket %d close", clientSocket);
+					it = _clientSockets.erase(it);
+				}
+				else
+				{
+					if ((recvlen + getEventQueueByteSize()) <= _recvBufSize)
+					{
+						uint8_t *payload = new uint8_t[recvlen];
+						memcpy(payload, _buffer, recvlen);
+						putEvent(payload, recvlen);
+					}
+					++it;
+				}
+			}
+		}
+	}
+	return;
+}
+
+
+int ListenSyslog::readline( int fd, char *bufptr, size_t len )
+{
+	char *bufx = bufptr;
+	static char *bp;
+	static int cnt = 0;
+	static char b[ 2048 ];
+	char c;
+
+	while ( --len > 0 )
+    {
+      if ( --cnt <= 0 )
+      {
+    	  cnt = recv( fd, b, sizeof( b ), 0 );
+    	  if ( cnt < 0 )
+    	  {
+    		  if ( errno == EINTR )
+    		  {
+    			  len++;		/* the while will decrement */
+    			  continue;
+    		  }
+    		  return -1;
+    	  }
+    	  if ( cnt == 0 )
+    		  return 0;
+    	  bp = b;
+      }
+      c = *bp++;
+      *bufptr++ = c;
+      if ( c == '\n' )
+      {
+    	  *bufptr = '\n';
+    	  return bufptr - bufx + 1;
+      }
+    }
+	return -1;
+}
+
+void ListenSyslog::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string value;
+	bool needResetServerSocket = false;
+	if (context->getProperty(Protocol.getName(), value))
+	{
+		if (_protocol != value)
+			needResetServerSocket = true;
+		_protocol = value;
+	}
+	if (context->getProperty(RecvBufSize.getName(), value))
+	{
+		Property::StringToInt(value, _recvBufSize);
+	}
+	if (context->getProperty(MaxSocketBufSize.getName(), value))
+	{
+		Property::StringToInt(value, _maxSocketBufSize);
+	}
+	if (context->getProperty(MaxConnections.getName(), value))
+	{
+		Property::StringToInt(value, _maxConnections);
+	}
+	if (context->getProperty(MessageDelimiter.getName(), value))
+	{
+		_messageDelimiter = value;
+	}
+	if (context->getProperty(ParseMessages.getName(), value))
+	{
+		Property::StringToBool(value, _parseMessages);
+	}
+	if (context->getProperty(Port.getName(), value))
+	{
+		int64_t oldPort = _port;
+		Property::StringToInt(value, _port);
+		if (_port != oldPort)
+			needResetServerSocket = true;
+	}
+	if (context->getProperty(MaxBatchSize.getName(), value))
+	{
+		Property::StringToInt(value, _maxBatchSize);
+	}
+
+	if (needResetServerSocket)
+		_resetServerSocket = true;
+
+	startSocketThread();
+
+	// read from the event queue
+	if (isEventQueueEmpty())
+	{
+		context->yield();
+		return;
+	}
+
+	std::queue<SysLogEvent> eventQueue;
+	pollEvent(eventQueue, _maxBatchSize);
+	bool firstEvent = true;
+	FlowFileRecord *flowFile = NULL;
+	while(!eventQueue.empty())
+	{
+		SysLogEvent event = eventQueue.front();
+		eventQueue.pop();
+		if (firstEvent)
+		{
+			flowFile = session->create();
+			if (!flowFile)
+				return;
+			ListenSyslog::WriteCallback callback((char *)event.payload, event.len);
+			session->write(flowFile, &callback);
+			delete[] event.payload;
+			firstEvent = false;
+		}
+		else
+		{
+			ListenSyslog::WriteCallback callback((char *)event.payload, event.len);
+			session->append(flowFile, &callback);
+			delete[] event.payload;
+		}
+	}
+	flowFile->addAttribute("syslog.protocol", _protocol);
+	flowFile->addAttribute("syslog.port", std::to_string(_port));
+	session->transfer(flowFile, Success);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/LogAttribute.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/LogAttribute.cpp b/libminifi/src/LogAttribute.cpp
new file mode 100644
index 0000000..82130f8
--- /dev/null
+++ b/libminifi/src/LogAttribute.cpp
@@ -0,0 +1,158 @@
+/**
+ * @file LogAttribute.cpp
+ * LogAttribute class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <sstream>
+#include <string.h>
+#include <iostream>
+
+#include "TimeUtil.h"
+#include "LogAttribute.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string LogAttribute::ProcessorName("LogAttribute");
+Property LogAttribute::LogLevel("Log Level", "The Log Level to use when logging the Attributes", "info");
+Property LogAttribute::AttributesToLog("Attributes to Log", "A comma-separated list of Attributes to Log. If not specified, all attributes will be logged.", "");
+Property LogAttribute::AttributesToIgnore("Attributes to Ignore", "A comma-separated list of Attributes to ignore. If not specified, no attributes will be ignored.", "");
+Property LogAttribute::LogPayload("Log Payload",
+		"If true, the FlowFile's payload will be logged, in addition to its attributes; otherwise, just the Attributes will be logged.", "false");
+Property LogAttribute::LogPrefix("Log prefix",
+		"Log prefix appended to the log lines. It helps to distinguish the output of multiple LogAttribute processors.", "");
+Relationship LogAttribute::Success("success", "success operational on the flow record");
+
+void LogAttribute::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(LogLevel);
+	properties.insert(AttributesToLog);
+	properties.insert(AttributesToIgnore);
+	properties.insert(LogPayload);
+	properties.insert(LogPrefix);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+}
+
+void LogAttribute::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string dashLine = "--------------------------------------------------";
+	LogAttrLevel level = LogAttrLevelInfo;
+	bool logPayload = false;
+	std::ostringstream message;
+
+	FlowFileRecord *flow = session->get();
+
+	if (!flow)
+		return;
+
+	std::string value;
+	if (context->getProperty(LogLevel.getName(), value))
+	{
+		logLevelStringToEnum(value, level);
+	}
+	if (context->getProperty(LogPrefix.getName(), value))
+	{
+		dashLine = "-----" + value + "-----";
+	}
+	if (context->getProperty(LogPayload.getName(), value))
+	{
+		Property::StringToBool(value, logPayload);
+	}
+
+	message << "Logging for flow file " << "\n";
+	message << dashLine;
+	message << "\nStandard FlowFile Attributes";
+	message << "\n" << "UUID:" << flow->getUUIDStr();
+	message << "\n" << "EntryDate:" << getTimeStr(flow->getEntryDate());
+	message << "\n" << "lineageStartDate:" << getTimeStr(flow->getlineageStartDate());
+	message << "\n" << "Size:" << flow->getSize() << " Offset:" << flow->getOffset();
+	message << "\nFlowFile Attributes Map Content";
+	std::map<std::string, std::string> attrs = flow->getAttributes();
+    std::map<std::string, std::string>::iterator it;
+    for (it = attrs.begin(); it!= attrs.end(); it++)
+    {
+    	message << "\n" << "key:" << it->first << " value:" << it->second;
+    }
+    message << "\nFlowFile Resource Claim Content";
+    ResourceClaim *claim = flow->getResourceClaim();
+    if (claim)
+    {
+    	message << "\n" << "Content Claim:" << claim->getContentFullPath();
+    }
+    if (logPayload && flow->getSize() <= 1024*1024)
+    {
+    	message << "\n" << "Payload:" << "\n";
+    	ReadCallback callback(flow->getSize());
+    	session->read(flow, &callback);
+    	for (unsigned int i = 0, j = 0; i < callback._readSize; i++)
+    	{
+    		char temp[8];
+    		sprintf(temp, "%02x ", (unsigned char) (callback._buffer[i]));
+    		message << temp;
+    		j++;
+    		if (j == 16)
+    		{
+    			message << '\n';
+    			j = 0;
+    		}
+    	}
+    }
+    message << "\n" << dashLine << std::ends;
+    std::string output = message.str();
+
+    switch (level)
+    {
+    case LogAttrLevelInfo:
+    	_logger->log_info("%s", output.c_str());
+		break;
+    case LogAttrLevelDebug:
+    	_logger->log_debug("%s", output.c_str());
+		break;
+    case LogAttrLevelError:
+    	_logger->log_error("%s", output.c_str());
+		break;
+    case LogAttrLevelTrace:
+    	_logger->log_trace("%s", output.c_str());
+    	break;
+    case LogAttrLevelWarn:
+    	_logger->log_warn("%s", output.c_str());
+    	break;
+    default:
+    	break;
+    }
+
+    // Test Import
+    /*
+    FlowFileRecord *importRecord = session->create();
+    session->import(claim->getContentFullPath(), importRecord);
+    session->transfer(importRecord, Success); */
+
+
+    // Transfer to the relationship
+    session->transfer(flow, Success);
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Logger.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Logger.cpp b/libminifi/src/Logger.cpp
new file mode 100644
index 0000000..984f609
--- /dev/null
+++ b/libminifi/src/Logger.cpp
@@ -0,0 +1,27 @@
+/**
+ * @file Logger.cpp
+ * Logger class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+
+#include "Logger.h"
+
+Logger *Logger::_logger(NULL);
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/ProcessGroup.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/ProcessGroup.cpp b/libminifi/src/ProcessGroup.cpp
new file mode 100644
index 0000000..70ee9d7
--- /dev/null
+++ b/libminifi/src/ProcessGroup.cpp
@@ -0,0 +1,314 @@
+/**
+ * @file ProcessGroup.cpp
+ * ProcessGroup class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+
+#include "ProcessGroup.h"
+#include "Processor.h"
+
+ProcessGroup::ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid, ProcessGroup *parent)
+: _name(name),
+  _type(type),
+  _parentProcessGroup(parent)
+{
+	if (!uuid)
+		// Generate the global UUID for the flow record
+		uuid_generate(_uuid);
+	else
+		uuid_copy(_uuid, uuid);
+
+	_yieldPeriodMsec = 0;
+	_transmitting = false;
+
+	_logger = Logger::getLogger();
+	_logger->log_info("ProcessGroup %s created", _name.c_str());
+}
+
+ProcessGroup::~ProcessGroup()
+{
+	for (std::set<Connection *>::iterator it = _connections.begin(); it != _connections.end(); ++it)
+	{
+		Connection *connection = *it;
+		connection->drain();
+		delete connection;
+	}
+
+	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+	{
+		ProcessGroup *processGroup(*it);
+		delete processGroup;
+	}
+
+	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+	{
+		Processor *processor(*it);
+		delete processor;
+	}
+}
+
+bool ProcessGroup::isRootProcessGroup()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+	return (_type == ROOT_PROCESS_GROUP);
+}
+
+void ProcessGroup::addProcessor(Processor *processor)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_processors.find(processor) == _processors.end())
+	{
+		// We do not have the same processor in this process group yet
+		_processors.insert(processor);
+		_logger->log_info("Add processor %s into process group %s",
+				processor->getName().c_str(), _name.c_str());
+	}
+}
+
+void ProcessGroup::removeProcessor(Processor *processor)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_processors.find(processor) != _processors.end())
+	{
+		// We do have the same processor in this process group yet
+		_processors.erase(processor);
+		_logger->log_info("Remove processor %s from process group %s",
+				processor->getName().c_str(), _name.c_str());
+	}
+}
+
+void ProcessGroup::addProcessGroup(ProcessGroup *child)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_childProcessGroups.find(child) == _childProcessGroups.end())
+	{
+		// We do not have the same child process group in this process group yet
+		_childProcessGroups.insert(child);
+		_logger->log_info("Add child process group %s into process group %s",
+				child->getName().c_str(), _name.c_str());
+	}
+}
+
+void ProcessGroup::removeProcessGroup(ProcessGroup *child)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_childProcessGroups.find(child) != _childProcessGroups.end())
+	{
+		// We do have the same child process group in this process group yet
+		_childProcessGroups.erase(child);
+		_logger->log_info("Remove child process group %s from process group %s",
+				child->getName().c_str(), _name.c_str());
+	}
+}
+
+void ProcessGroup::startProcessing(TimerDrivenSchedulingAgent *timeScheduler)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	try
+	{
+		// Start all the processor node, input and output ports
+		for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+		{
+			Processor *processor(*it);
+			if (!processor->isRunning() && processor->getScheduledState() != DISABLED)
+			{
+				if (processor->getSchedulingStrategy() == TIMER_DRIVEN)
+					timeScheduler->schedule(processor);
+			}
+		}
+
+		for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+		{
+			ProcessGroup *processGroup(*it);
+			processGroup->startProcessing(timeScheduler);
+		}
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process group start processing");
+		throw;
+	}
+}
+
+void ProcessGroup::stopProcessing(TimerDrivenSchedulingAgent *timeScheduler)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	try
+	{
+		// Stop all the processor node, input and output ports
+		for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+		{
+			Processor *processor(*it);
+			if (processor->getSchedulingStrategy() == TIMER_DRIVEN)
+					timeScheduler->unschedule(processor);
+		}
+
+		for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+		{
+			ProcessGroup *processGroup(*it);
+			processGroup->stopProcessing(timeScheduler);
+		}
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process group stop processing");
+		throw;
+	}
+}
+
+Processor *ProcessGroup::findProcessor(uuid_t uuid)
+{
+	Processor *ret = NULL;
+	// std::lock_guard<std::mutex> lock(_mtx);
+
+	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+	{
+		Processor *processor(*it);
+		uuid_t processorUUID;
+		if (processor->getUUID(processorUUID) && uuid_compare(processorUUID, uuid) == 0)
+			return processor;
+	}
+
+	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+	{
+		ProcessGroup *processGroup(*it);
+		Processor *processor = processGroup->findProcessor(uuid);
+		if (processor)
+			return processor;
+	}
+
+	return ret;
+}
+
+Processor *ProcessGroup::findProcessor(std::string processorName)
+{
+	Processor *ret = NULL;
+
+	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+	{
+		Processor *processor(*it);
+		_logger->log_debug("Current processor is %s", processor->getName().c_str());
+		if (processor->getName() == processorName)
+			return processor;
+	}
+
+	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+	{
+		ProcessGroup *processGroup(*it);
+		Processor *processor = processGroup->findProcessor(processorName);
+		if (processor)
+			return processor;
+	}
+
+	return ret;
+}
+
+void ProcessGroup::updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	for (std::set<Processor *>::iterator it = _processors.begin(); it != _processors.end(); ++it)
+	{
+		Processor *processor(*it);
+		if (processor->getName() == processorName)
+		{
+			processor->setProperty(propertyName, propertyValue);
+		}
+	}
+
+	for (std::set<ProcessGroup *>::iterator it = _childProcessGroups.begin(); it != _childProcessGroups.end(); ++it)
+	{
+		ProcessGroup *processGroup(*it);
+		processGroup->updatePropertyValue(processorName, propertyName, propertyValue);
+	}
+
+	return;
+}
+
+void ProcessGroup::addConnection(Connection *connection)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_connections.find(connection) == _connections.end())
+	{
+		// We do not have the same connection in this process group yet
+		_connections.insert(connection);
+		_logger->log_info("Add connection %s into process group %s",
+				connection->getName().c_str(), _name.c_str());
+		uuid_t sourceUUID;
+		Processor *source = NULL;
+		connection->getSourceProcessorUUID(sourceUUID);
+		source = this->findProcessor(sourceUUID);
+		if (source)
+			source->addConnection(connection);
+		Processor *destination = NULL;
+		uuid_t destinationUUID;
+		connection->getDestinationProcessorUUID(destinationUUID);
+		destination = this->findProcessor(destinationUUID);
+		if (destination && destination != source)
+			destination->addConnection(connection);
+	}
+}
+
+void ProcessGroup::removeConnection(Connection *connection)
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_connections.find(connection) != _connections.end())
+	{
+		// We do not have the same connection in this process group yet
+		_connections.erase(connection);
+		_logger->log_info("Remove connection %s into process group %s",
+				connection->getName().c_str(), _name.c_str());
+		uuid_t sourceUUID;
+		Processor *source = NULL;
+		connection->getSourceProcessorUUID(sourceUUID);
+		source = this->findProcessor(sourceUUID);
+		if (source)
+			source->removeConnection(connection);
+		Processor *destination = NULL;
+		uuid_t destinationUUID;
+		connection->getDestinationProcessorUUID(destinationUUID);
+		destination = this->findProcessor(destinationUUID);
+		if (destination && destination != source)
+			destination->removeConnection(connection);
+	}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/ProcessSession.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/ProcessSession.cpp b/libminifi/src/ProcessSession.cpp
new file mode 100644
index 0000000..4f526c3
--- /dev/null
+++ b/libminifi/src/ProcessSession.cpp
@@ -0,0 +1,731 @@
+/**
+ * @file ProcessSession.cpp
+ * ProcessSession class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <iostream>
+
+#include "ProcessSession.h"
+
+FlowFileRecord* ProcessSession::create()
+{
+	std::map<std::string, std::string> empty;
+	FlowFileRecord *record = new FlowFileRecord(empty);
+
+	if (record)
+	{
+		_addedFlowFiles[record->getUUIDStr()] = record;
+		_logger->log_debug("Create FlowFile with UUID %s", record->getUUIDStr().c_str());
+	}
+
+	return record;
+}
+
+FlowFileRecord* ProcessSession::create(FlowFileRecord *parent)
+{
+	FlowFileRecord *record = this->create();
+	if (record)
+	{
+		// Copy attributes
+		std::map<std::string, std::string> parentAttributes = parent->getAttributes();
+	    std::map<std::string, std::string>::iterator it;
+	    for (it = parentAttributes.begin(); it!= parentAttributes.end(); it++)
+	    {
+	    	if (it->first == FlowAttributeKey(ALTERNATE_IDENTIFIER) ||
+	    			it->first == FlowAttributeKey(DISCARD_REASON) ||
+					it->first == FlowAttributeKey(UUID))
+	    		// Do not copy special attributes from parent
+	    		continue;
+	    	record->setAttribute(it->first, it->second);
+	    }
+	    record->_lineageStartDate = parent->_lineageStartDate;
+	    record->_lineageIdentifiers = parent->_lineageIdentifiers;
+	    record->_lineageIdentifiers.insert(parent->_uuidStr);
+
+	}
+	return record;
+}
+
+FlowFileRecord* ProcessSession::clone(FlowFileRecord *parent)
+{
+	FlowFileRecord *record = this->create(parent);
+	if (record)
+	{
+		// Copy Resource Claim
+		record->_claim = parent->_claim;
+		if (record->_claim)
+		{
+			record->_offset = parent->_offset;
+			record->_size = parent->_size;
+			record->_claim->increaseFlowFileRecordOwnedCount();
+		}
+	}
+	return record;
+}
+
+FlowFileRecord* ProcessSession::cloneDuringTransfer(FlowFileRecord *parent)
+{
+	std::map<std::string, std::string> empty;
+	FlowFileRecord *record = new FlowFileRecord(empty);
+
+	if (record)
+	{
+		this->_clonedFlowFiles[record->getUUIDStr()] = record;
+		_logger->log_debug("Clone FlowFile with UUID %s during transfer", record->getUUIDStr().c_str());
+		// Copy attributes
+		std::map<std::string, std::string> parentAttributes = parent->getAttributes();
+		std::map<std::string, std::string>::iterator it;
+		for (it = parentAttributes.begin(); it!= parentAttributes.end(); it++)
+		{
+			if (it->first == FlowAttributeKey(ALTERNATE_IDENTIFIER) ||
+	    			it->first == FlowAttributeKey(DISCARD_REASON) ||
+					it->first == FlowAttributeKey(UUID))
+	    		// Do not copy special attributes from parent
+	    		continue;
+	    	record->setAttribute(it->first, it->second);
+	    }
+	    record->_lineageStartDate = parent->_lineageStartDate;
+	    record->_lineageIdentifiers = parent->_lineageIdentifiers;
+	    record->_lineageIdentifiers.insert(parent->_uuidStr);
+
+	    // Copy Resource Claim
+	    record->_claim = parent->_claim;
+	    if (record->_claim)
+	    {
+	    	record->_offset = parent->_offset;
+	    	record->_size = parent->_size;
+	    	record->_claim->increaseFlowFileRecordOwnedCount();
+	    }
+	}
+
+	return record;
+}
+
+FlowFileRecord* ProcessSession::clone(FlowFileRecord *parent, long offset, long size)
+{
+	FlowFileRecord *record = this->create(parent);
+	if (record)
+	{
+		if (parent->_claim)
+		{
+			if ((offset + size) > (long) parent->_size)
+			{
+				// Set offset and size
+				_logger->log_error("clone offset %d and size %d exceed parent size %d",
+						offset, size, parent->_size);
+				// Remove the Add FlowFile for the session
+				std::map<std::string, FlowFileRecord *>::iterator it =
+						this->_addedFlowFiles.find(record->getUUIDStr());
+				if (it != this->_addedFlowFiles.end())
+					this->_addedFlowFiles.erase(record->getUUIDStr());
+				delete record;
+				return NULL;
+			}
+			record->_offset = parent->_offset + parent->_offset;
+			record->_size = size;
+			// Copy Resource Claim
+			record->_claim = parent->_claim;
+			record->_claim->increaseFlowFileRecordOwnedCount();
+		}
+	}
+	return record;
+}
+
+void ProcessSession::remove(FlowFileRecord *flow)
+{
+	flow->_markedDelete = true;
+	_deletedFlowFiles[flow->getUUIDStr()] = flow;
+}
+
+void ProcessSession::putAttribute(FlowFileRecord *flow, std::string key, std::string value)
+{
+	flow->setAttribute(key, value);
+}
+
+void ProcessSession::removeAttribute(FlowFileRecord *flow, std::string key)
+{
+	flow->removeAttribute(key);
+}
+
+void ProcessSession::penalize(FlowFileRecord *flow)
+{
+	flow->_penaltyExpirationMs = getTimeMillis() + this->_processContext->getProcessor()->getPenalizationPeriodMsec();
+}
+
+void ProcessSession::transfer(FlowFileRecord *flow, Relationship relationship)
+{
+	_transferRelationship[flow->getUUIDStr()] = relationship;
+}
+
+void ProcessSession::write(FlowFileRecord *flow, OutputStreamCallback *callback)
+{
+	ResourceClaim *claim = NULL;
+
+	claim = new ResourceClaim(DEFAULT_CONTENT_DIRECTORY);
+
+	try
+	{
+		std::ofstream fs;
+		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
+		if (fs.is_open())
+		{
+			// Call the callback to write the content
+			callback->process(&fs);
+			if (fs.good() && fs.tellp() >= 0)
+			{
+				flow->_size = fs.tellp();
+				flow->_offset = 0;
+				if (flow->_claim)
+				{
+					// Remove the old claim
+					flow->_claim->decreaseFlowFileRecordOwnedCount();
+					flow->_claim = NULL;
+				}
+				flow->_claim = claim;
+				claim->increaseFlowFileRecordOwnedCount();
+				/*
+				_logger->log_debug("Write offset %d length %d into content %s for FlowFile UUID %s",
+						flow->_offset, flow->_size, flow->_claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
+				fs.close();
+			}
+			else
+			{
+				fs.close();
+				throw Exception(FILE_OPERATION_EXCEPTION, "File Write Error");
+			}
+		}
+		else
+		{
+			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
+		}
+	}
+	catch (std::exception &exception)
+	{
+		if (flow && flow->_claim == claim)
+		{
+			flow->_claim->decreaseFlowFileRecordOwnedCount();
+			flow->_claim = NULL;
+		}
+		if (claim)
+			delete claim;
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		if (flow && flow->_claim == claim)
+		{
+			flow->_claim->decreaseFlowFileRecordOwnedCount();
+			flow->_claim = NULL;
+		}
+		if (claim)
+			delete claim;
+		_logger->log_debug("Caught Exception during process session write");
+		throw;
+	}
+}
+
+void ProcessSession::append(FlowFileRecord *flow, OutputStreamCallback *callback)
+{
+	ResourceClaim *claim = NULL;
+
+	if (flow->_claim == NULL)
+	{
+		// No existed claim for append, we need to create new claim
+		return write(flow, callback);
+	}
+
+	claim = flow->_claim;
+
+	try
+	{
+		std::ofstream fs;
+		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::app);
+		if (fs.is_open())
+		{
+			// Call the callback to write the content
+			std::streampos oldPos = fs.tellp();
+			callback->process(&fs);
+			if (fs.good() && fs.tellp() >= 0)
+			{
+				uint64_t appendSize = fs.tellp() - oldPos;
+				flow->_size += appendSize;
+				/*
+				_logger->log_debug("Append offset %d extra length %d to new size %d into content %s for FlowFile UUID %s",
+						flow->_offset, appendSize, flow->_size, claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
+				fs.close();
+			}
+			else
+			{
+				fs.close();
+				throw Exception(FILE_OPERATION_EXCEPTION, "File Write Error");
+			}
+		}
+		else
+		{
+			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
+		}
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process session append");
+		throw;
+	}
+}
+
+void ProcessSession::read(FlowFileRecord *flow, InputStreamCallback *callback)
+{
+	try
+	{
+		ResourceClaim *claim = NULL;
+		if (flow->_claim == NULL)
+		{
+			// No existed claim for read, we throw exception
+			throw Exception(FILE_OPERATION_EXCEPTION, "No Content Claim existed for read");
+		}
+
+		claim = flow->_claim;
+		std::ifstream fs;
+		fs.open(claim->getContentFullPath().c_str(), std::fstream::in | std::fstream::binary);
+		if (fs.is_open())
+		{
+			fs.seekg(flow->_offset, fs.beg);
+
+			if (fs.good())
+			{
+				callback->process(&fs);
+				/*
+				_logger->log_debug("Read offset %d size %d content %s for FlowFile UUID %s",
+						flow->_offset, flow->_size, claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
+				fs.close();
+			}
+			else
+			{
+				fs.close();
+				throw Exception(FILE_OPERATION_EXCEPTION, "File Read Error");
+			}
+		}
+		else
+		{
+			throw Exception(FILE_OPERATION_EXCEPTION, "File Open Error");
+		}
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process session read");
+		throw;
+	}
+}
+
+void ProcessSession::import(std::string source, FlowFileRecord *flow, bool keepSource, uint64_t offset)
+{
+	ResourceClaim *claim = NULL;
+
+	claim = new ResourceClaim(DEFAULT_CONTENT_DIRECTORY);
+	char *buf = NULL;
+	int size = 4096;
+	buf = new char [size];
+
+	try
+	{
+		std::ofstream fs;
+		fs.open(claim->getContentFullPath().c_str(), std::fstream::out | std::fstream::binary | std::fstream::trunc);
+		std::ifstream input;
+		input.open(source.c_str(), std::fstream::in | std::fstream::binary);
+
+		if (fs.is_open() && input.is_open())
+		{
+			// Open the source file and stream to the flow file
+			input.seekg(offset, fs.beg);
+			while (input.good())
+			{
+				input.read(buf, size);
+				if (input)
+					fs.write(buf, size);
+				else
+					fs.write(buf, input.gcount());
+			}
+
+			if (fs.good() && fs.tellp() >= 0)
+			{
+				flow->_size = fs.tellp();
+				flow->_offset = 0;
+				if (flow->_claim)
+				{
+					// Remove the old claim
+					flow->_claim->decreaseFlowFileRecordOwnedCount();
+					flow->_claim = NULL;
+				}
+				flow->_claim = claim;
+				claim->increaseFlowFileRecordOwnedCount();
+				/*
+				_logger->log_debug("Import offset %d length %d into content %s for FlowFile UUID %s",
+						flow->_offset, flow->_size, flow->_claim->getContentFullPath().c_str(), flow->getUUIDStr().c_str()); */
+				fs.close();
+				input.close();
+				if (!keepSource)
+					std::remove(source.c_str());
+			}
+			else
+			{
+				fs.close();
+				input.close();
+				throw Exception(FILE_OPERATION_EXCEPTION, "File Import Error");
+			}
+		}
+		else
+		{
+			throw Exception(FILE_OPERATION_EXCEPTION, "File Import Error");
+		}
+
+		delete[] buf;
+	}
+	catch (std::exception &exception)
+	{
+		if (flow && flow->_claim == claim)
+		{
+			flow->_claim->decreaseFlowFileRecordOwnedCount();
+			flow->_claim = NULL;
+		}
+		if (claim)
+			delete claim;
+		_logger->log_debug("Caught Exception %s", exception.what());
+		delete[] buf;
+		throw;
+	}
+	catch (...)
+	{
+		if (flow && flow->_claim == claim)
+		{
+			flow->_claim->decreaseFlowFileRecordOwnedCount();
+			flow->_claim = NULL;
+		}
+		if (claim)
+			delete claim;
+		_logger->log_debug("Caught Exception during process session write");
+		delete[] buf;
+		throw;
+	}
+}
+
+void ProcessSession::commit()
+{
+	try
+	{
+		// First we clone the flow record based on the transfered relationship for updated flow record
+		std::map<std::string, FlowFileRecord *>::iterator it;
+		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_markedDelete)
+				continue;
+			std::map<std::string, Relationship>::iterator itRelationship =
+					this->_transferRelationship.find(record->getUUIDStr());
+			if (itRelationship != _transferRelationship.end())
+			{
+				Relationship relationship = itRelationship->second;
+				// Find the relationship, we need to find the connections for that relationship
+				std::set<Connection *> connections =
+						_processContext->getProcessor()->getOutGoingConnections(relationship.getName());
+				if (connections.empty())
+				{
+					// No connection
+					if (!_processContext->getProcessor()->isAutoTerminated(relationship))
+					{
+						// Not autoterminate, we should have the connect
+						std::string message = "Connect empty for non auto terminated relationship" + relationship.getName();
+						throw Exception(PROCESS_SESSION_EXCEPTION, message.c_str());
+					}
+					else
+					{
+						// Autoterminated
+						remove(record);
+					}
+				}
+				else
+				{
+					// We connections, clone the flow and assign the connection accordingly
+					for (std::set<Connection *>::iterator itConnection = connections.begin(); itConnection != connections.end(); ++itConnection)
+					{
+						Connection *connection(*itConnection);
+						if (itConnection == connections.begin())
+						{
+							// First connection which the flow need be routed to
+							record->_connection = connection;
+						}
+						else
+						{
+							// Clone the flow file and route to the connection
+							FlowFileRecord *cloneRecord;
+							cloneRecord = this->cloneDuringTransfer(record);
+							if (cloneRecord)
+								cloneRecord->_connection = connection;
+							else
+								throw Exception(PROCESS_SESSION_EXCEPTION, "Can not clone the flow for transfer");
+						}
+					}
+				}
+			}
+			else
+			{
+				// Can not find relationship for the flow
+				throw Exception(PROCESS_SESSION_EXCEPTION, "Can not find the transfer relationship for the flow");
+			}
+		}
+
+		// Do the samething for added flow file
+		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_markedDelete)
+				continue;
+			std::map<std::string, Relationship>::iterator itRelationship =
+					this->_transferRelationship.find(record->getUUIDStr());
+			if (itRelationship != _transferRelationship.end())
+			{
+				Relationship relationship = itRelationship->second;
+				// Find the relationship, we need to find the connections for that relationship
+				std::set<Connection *> connections =
+						_processContext->getProcessor()->getOutGoingConnections(relationship.getName());
+				if (connections.empty())
+				{
+					// No connection
+					if (!_processContext->getProcessor()->isAutoTerminated(relationship))
+					{
+						// Not autoterminate, we should have the connect
+						std::string message = "Connect empty for non auto terminated relationship " + relationship.getName();
+						throw Exception(PROCESS_SESSION_EXCEPTION, message.c_str());
+					}
+					else
+					{
+						// Autoterminated
+						remove(record);
+					}
+				}
+				else
+				{
+					// We connections, clone the flow and assign the connection accordingly
+					for (std::set<Connection *>::iterator itConnection = connections.begin(); itConnection != connections.end(); ++itConnection)
+					{
+						Connection *connection(*itConnection);
+						if (itConnection == connections.begin())
+						{
+							// First connection which the flow need be routed to
+							record->_connection = connection;
+						}
+						else
+						{
+							// Clone the flow file and route to the connection
+							FlowFileRecord *cloneRecord;
+							cloneRecord = this->cloneDuringTransfer(record);
+							if (cloneRecord)
+								cloneRecord->_connection = connection;
+							else
+								throw Exception(PROCESS_SESSION_EXCEPTION, "Can not clone the flow for transfer");
+						}
+					}
+				}
+			}
+			else
+			{
+				// Can not find relationship for the flow
+				throw Exception(PROCESS_SESSION_EXCEPTION, "Can not find the transfer relationship for the flow");
+			}
+		}
+
+		// Complete process the added and update flow files for the session, send the flow file to its queue
+		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_markedDelete)
+			{
+				continue;
+			}
+			if (record->_connection)
+				record->_connection->put(record);
+			else
+				delete record;
+		}
+		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_markedDelete)
+			{
+				continue;
+			}
+			if (record->_connection)
+				record->_connection->put(record);
+			else
+				delete record;
+		}
+		// Process the clone flow files
+		for (it = _clonedFlowFiles.begin(); it!= _clonedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_markedDelete)
+			{
+				continue;
+			}
+			if (record->_connection)
+				record->_connection->put(record);
+			else
+				delete record;
+		}
+		// Delete the deleted flow files
+		for (it = _deletedFlowFiles.begin(); it!= _deletedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			delete record;
+		}
+		// Delete the snapshot
+		for (it = _originalFlowFiles.begin(); it!= _originalFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			delete record;
+		}
+		// All done
+		_updatedFlowFiles.clear();
+		_addedFlowFiles.clear();
+		_clonedFlowFiles.clear();
+		_deletedFlowFiles.clear();
+		_originalFlowFiles.clear();
+		_logger->log_trace("ProcessSession committed for %s", _processContext->getProcessor()->getName().c_str());
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process session commit");
+		throw;
+	}
+}
+
+
+void ProcessSession::rollback()
+{
+	try
+	{
+		std::map<std::string, FlowFileRecord *>::iterator it;
+		// Requeue the snapshot of the flowfile back
+		for (it = _originalFlowFiles.begin(); it!= _originalFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			if (record->_orginalConnection)
+			{
+				record->_snapshot = false;
+				record->_orginalConnection->put(record);
+			}
+			else
+				delete record;
+		}
+		_originalFlowFiles.clear();
+		// Process the clone flow files
+		for (it = _clonedFlowFiles.begin(); it!= _clonedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			delete record;
+		}
+		_clonedFlowFiles.clear();
+		for (it = _addedFlowFiles.begin(); it!= _addedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			delete record;
+		}
+		_addedFlowFiles.clear();
+		for (it = _updatedFlowFiles.begin(); it!= _updatedFlowFiles.end(); it++)
+		{
+			FlowFileRecord *record = it->second;
+			delete record;
+		}
+		_updatedFlowFiles.clear();
+		_deletedFlowFiles.clear();
+		_logger->log_trace("ProcessSession rollback for %s", _processContext->getProcessor()->getName().c_str());
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during process session roll back");
+		throw;
+	}
+}
+
+FlowFileRecord *ProcessSession::get()
+{
+	Connection *first = _processContext->getProcessor()->getNextIncomingConnection();
+
+	if (first == NULL)
+		return NULL;
+
+	Connection *current = first;
+
+	do
+	{
+		std::set<FlowFileRecord *> expired;
+		FlowFileRecord *ret = current->poll(expired);
+		if (expired.size() > 0)
+		{
+			// Remove expired flow record
+			for (std::set<FlowFileRecord *>::iterator it = expired.begin(); it != expired.end(); ++it)
+			{
+				delete (*it);
+			}
+		}
+		if (ret)
+		{
+			// add the flow record to the current process session update map
+			ret->_markedDelete = false;
+			_updatedFlowFiles[ret->getUUIDStr()] = ret;
+			std::map<std::string, std::string> empty;
+			FlowFileRecord *snapshot = new FlowFileRecord(empty);
+			_logger->log_debug("Create Snapshot FlowFile with UUID %s", snapshot->getUUIDStr().c_str());
+			snapshot->duplicate(ret);
+			// save a snapshot
+			_originalFlowFiles[snapshot->getUUIDStr()] = snapshot;
+			return ret;
+		}
+		current = _processContext->getProcessor()->getNextIncomingConnection();
+	}
+	while (current != NULL && current != first);
+
+	return NULL;
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/Processor.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/Processor.cpp b/libminifi/src/Processor.cpp
new file mode 100644
index 0000000..cc136dc
--- /dev/null
+++ b/libminifi/src/Processor.cpp
@@ -0,0 +1,451 @@
+/**
+ * @file Processor.cpp
+ * Processor class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+
+#include "Processor.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+Processor::Processor(std::string name, uuid_t uuid)
+: _name(name)
+{
+	if (!uuid)
+		// Generate the global UUID for the flow record
+		uuid_generate(_uuid);
+	else
+		uuid_copy(_uuid, uuid);
+
+	char uuidStr[37];
+	uuid_unparse(_uuid, uuidStr);
+	_uuidStr = uuidStr;
+
+	// Setup the default values
+	_state = DISABLED;
+	_strategy = TIMER_DRIVEN;
+	_lossTolerant = false;
+	_triggerWhenEmpty = false;
+	_schedulingPeriodNano = MINIMUM_SCHEDULING_NANOS;
+	_runDurantionNano = 0;
+	_yieldPeriodMsec = DEFAULT_YIELD_PERIOD_SECONDS * 1000;
+	_penalizationPeriodMsec = DEFAULT_PENALIZATION_PERIOD_SECONDS * 1000;
+	_maxConcurrentTasks = 1;
+	_activeTasks = 0;
+	_yieldExpiration = 0;
+	_incomingConnectionsIter = this->_incomingConnections.begin();
+	_logger = Logger::getLogger();
+
+	_logger->log_info("Processor %s created UUID %s", _name.c_str(), _uuidStr.c_str());
+}
+
+Processor::~Processor()
+{
+
+}
+
+bool Processor::isRunning()
+{
+	return (_state == RUNNING && _activeTasks > 0);
+}
+
+bool Processor::setSupportedProperties(std::set<Property> properties)
+{
+	if (isRunning())
+	{
+		_logger->log_info("Can not set processor property while the process %s is running",
+				_name.c_str());
+		return false;
+	}
+
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_properties.clear();
+	for (std::set<Property>::iterator it = properties.begin(); it != properties.end(); ++it)
+	{
+		Property item(*it);
+		_properties[item.getName()] = item;
+		_logger->log_info("Processor %s supported property name %s", _name.c_str(), item.getName().c_str());
+	}
+
+	return true;
+}
+
+bool Processor::setSupportedRelationships(std::set<Relationship> relationships)
+{
+	if (isRunning())
+	{
+		_logger->log_info("Can not set processor supported relationship while the process %s is running",
+				_name.c_str());
+		return false;
+	}
+
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_relationships.clear();
+	for (std::set<Relationship>::iterator it = relationships.begin(); it != relationships.end(); ++it)
+	{
+		Relationship item(*it);
+		_relationships[item.getName()] = item;
+		_logger->log_info("Processor %s supported relationship name %s", _name.c_str(), item.getName().c_str());
+	}
+
+	return true;
+}
+
+bool Processor::setAutoTerminatedRelationships(std::set<Relationship> relationships)
+{
+	if (isRunning())
+	{
+		_logger->log_info("Can not set processor auto terminated relationship while the process %s is running",
+				_name.c_str());
+		return false;
+	}
+
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	_autoTerminatedRelationships.clear();
+	for (std::set<Relationship>::iterator it = relationships.begin(); it != relationships.end(); ++it)
+	{
+		Relationship item(*it);
+		_autoTerminatedRelationships[item.getName()] = item;
+		_logger->log_info("Processor %s auto terminated relationship name %s", _name.c_str(), item.getName().c_str());
+	}
+
+	return true;
+}
+
+bool Processor::isAutoTerminated(Relationship relationship)
+{
+	bool isRun = isRunning();
+
+	if (!isRun)
+		_mtx.lock();
+
+	std::map<std::string, Relationship>::iterator it = _autoTerminatedRelationships.find(relationship.getName());
+	if (it != _autoTerminatedRelationships.end())
+	{
+		if (!isRun)
+			_mtx.unlock();
+		return true;
+	}
+	else
+	{
+		if (!isRun)
+			_mtx.unlock();
+		return false;
+	}
+}
+
+bool Processor::isSupportedRelationship(Relationship relationship)
+{
+	bool isRun = isRunning();
+
+	if (!isRun)
+		_mtx.lock();
+
+	std::map<std::string, Relationship>::iterator it = _relationships.find(relationship.getName());
+	if (it != _relationships.end())
+	{
+		if (!isRun)
+			_mtx.unlock();
+		return true;
+	}
+	else
+	{
+		if (!isRun)
+			_mtx.unlock();
+		return false;
+	}
+}
+
+bool Processor::getProperty(std::string name, std::string &value)
+{
+	bool isRun = isRunning();
+
+	if (!isRun)
+		// Because set property only allowed in non running state, we need to obtain lock avoid rack condition
+		_mtx.lock();
+
+	std::map<std::string, Property>::iterator it = _properties.find(name);
+	if (it != _properties.end())
+	{
+		Property item = it->second;
+		value = item.getValue();
+		if (!isRun)
+			_mtx.unlock();
+		return true;
+	}
+	else
+	{
+		if (!isRun)
+			_mtx.unlock();
+		return false;
+	}
+}
+
+bool Processor::setProperty(std::string name, std::string value)
+{
+
+	std::lock_guard<std::mutex> lock(_mtx);
+	std::map<std::string, Property>::iterator it = _properties.find(name);
+
+	if (it != _properties.end())
+	{
+		Property item = it->second;
+		item.setValue(value);
+		_properties[item.getName()] = item;
+		_logger->log_info("Processor %s property name %s value %s", _name.c_str(), item.getName().c_str(), value.c_str());
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+std::set<Connection *> Processor::getOutGoingConnections(std::string relationship)
+{
+	std::set<Connection *> empty;
+
+	std::map<std::string, std::set<Connection *>>::iterator it = _outGoingConnections.find(relationship);
+	if (it != _outGoingConnections.end())
+	{
+		return _outGoingConnections[relationship];
+	}
+	else
+	{
+		return empty;
+	}
+}
+
+bool Processor::addConnection(Connection *connection)
+{
+	bool ret = false;
+
+	if (isRunning())
+	{
+		_logger->log_info("Can not add connection while the process %s is running",
+				_name.c_str());
+		return false;
+	}
+
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	uuid_t srcUUID;
+	uuid_t destUUID;
+
+	connection->getSourceProcessorUUID(srcUUID);
+	connection->getDestinationProcessorUUID(destUUID);
+
+	if (uuid_compare(_uuid, destUUID) == 0)
+	{
+		// Connection is destination to the current processor
+		if (_incomingConnections.find(connection) == _incomingConnections.end())
+		{
+			_incomingConnections.insert(connection);
+			connection->setDestinationProcessor(this);
+			_logger->log_info("Add connection %s into Processor %s incoming connection",
+					connection->getName().c_str(), _name.c_str());
+			_incomingConnectionsIter = this->_incomingConnections.begin();
+			ret = true;
+		}
+	}
+
+	if (uuid_compare(_uuid, srcUUID) == 0)
+	{
+		std::string relationship = connection->getRelationship().getName();
+		// Connection is source from the current processor
+		std::map<std::string, std::set<Connection *>>::iterator it =
+				_outGoingConnections.find(relationship);
+		if (it != _outGoingConnections.end())
+		{
+			// We already has connection for this relationship
+			std::set<Connection *> existedConnection = it->second;
+			if (existedConnection.find(connection) == existedConnection.end())
+			{
+				// We do not have the same connection for this relationship yet
+				existedConnection.insert(connection);
+				connection->setSourceProcessor(this);
+				_outGoingConnections[relationship] = existedConnection;
+				_logger->log_info("Add connection %s into Processor %s outgoing connection for relationship %s",
+												connection->getName().c_str(), _name.c_str(), relationship.c_str());
+				ret = true;
+			}
+		}
+		else
+		{
+			// We do not have any outgoing connection for this relationship yet
+			std::set<Connection *> newConnection;
+			newConnection.insert(connection);
+			connection->setSourceProcessor(this);
+			_outGoingConnections[relationship] = newConnection;
+			_logger->log_info("Add connection %s into Processor %s outgoing connection for relationship %s",
+								connection->getName().c_str(), _name.c_str(), relationship.c_str());
+			ret = true;
+		}
+	}
+
+	return ret;
+}
+
+void Processor::removeConnection(Connection *connection)
+{
+	if (isRunning())
+	{
+		_logger->log_info("Can not remove connection while the process %s is running",
+				_name.c_str());
+		return;
+	}
+
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	uuid_t srcUUID;
+	uuid_t destUUID;
+
+	connection->getSourceProcessorUUID(srcUUID);
+	connection->getDestinationProcessorUUID(destUUID);
+
+	if (uuid_compare(_uuid, destUUID) == 0)
+	{
+		// Connection is destination to the current processor
+		if (_incomingConnections.find(connection) != _incomingConnections.end())
+		{
+			_incomingConnections.erase(connection);
+			connection->setDestinationProcessor(NULL);
+			_logger->log_info("Remove connection %s into Processor %s incoming connection",
+					connection->getName().c_str(), _name.c_str());
+			_incomingConnectionsIter = this->_incomingConnections.begin();
+		}
+	}
+
+	if (uuid_compare(_uuid, srcUUID) == 0)
+	{
+		std::string relationship = connection->getRelationship().getName();
+		// Connection is source from the current processor
+		std::map<std::string, std::set<Connection *>>::iterator it =
+				_outGoingConnections.find(relationship);
+		if (it == _outGoingConnections.end())
+		{
+			return;
+		}
+		else
+		{
+			if (_outGoingConnections[relationship].find(connection) != _outGoingConnections[relationship].end())
+			{
+				_outGoingConnections[relationship].erase(connection);
+				connection->setSourceProcessor(NULL);
+				_logger->log_info("Remove connection %s into Processor %s outgoing connection for relationship %s",
+								connection->getName().c_str(), _name.c_str(), relationship.c_str());
+			}
+		}
+	}
+}
+
+Connection *Processor::getNextIncomingConnection()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_incomingConnections.size() == 0)
+		return NULL;
+
+	if (_incomingConnectionsIter == _incomingConnections.end())
+		_incomingConnectionsIter = _incomingConnections.begin();
+
+	Connection *ret = *_incomingConnectionsIter;
+	_incomingConnectionsIter++;
+
+	if (_incomingConnectionsIter == _incomingConnections.end())
+		_incomingConnectionsIter = _incomingConnections.begin();
+
+	return ret;
+}
+
+bool Processor::flowFilesQueued()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	if (_incomingConnections.size() == 0)
+		return false;
+
+	for (std::set<Connection *>::iterator it = _incomingConnections.begin(); it != _incomingConnections.end(); ++it)
+	{
+		Connection *connection = *it;
+		if (connection->getQueueSize() > 0)
+			return true;
+	}
+
+	return false;
+}
+
+bool Processor::flowFilesOutGoingFull()
+{
+	std::lock_guard<std::mutex> lock(_mtx);
+
+	std::map<std::string, std::set<Connection *>>::iterator it;
+
+	for (it = _outGoingConnections.begin(); it != _outGoingConnections.end(); ++it)
+	{
+		// We already has connection for this relationship
+		std::set<Connection *> existedConnection = it->second;
+		for (std::set<Connection *>::iterator itConnection = existedConnection.begin(); itConnection != existedConnection.end(); ++itConnection)
+		{
+			Connection *connection = *itConnection;
+			if (connection->isFull())
+				return true;
+		}
+	}
+
+	return false;
+}
+
+void Processor::onTrigger()
+{
+	ProcessContext *context = new ProcessContext(this);
+	ProcessSession *session = new ProcessSession(context);
+	try {
+		// Call the child onTrigger function
+		this->onTrigger(context, session);
+		session->commit();
+		delete session;
+		delete context;
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		session->rollback();
+		delete session;
+		delete context;
+		throw;
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception Processor::onTrigger");
+		session->rollback();
+		delete session;
+		delete context;
+		throw;
+	}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/RealTimeDataCollector.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/RealTimeDataCollector.cpp b/libminifi/src/RealTimeDataCollector.cpp
new file mode 100644
index 0000000..c7118ff
--- /dev/null
+++ b/libminifi/src/RealTimeDataCollector.cpp
@@ -0,0 +1,482 @@
+/**
+ * @file RealTimeDataCollector.cpp
+ * RealTimeDataCollector class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <chrono>
+#include <thread>
+#include <random>
+#include <netinet/tcp.h>
+
+#include "RealTimeDataCollector.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string RealTimeDataCollector::ProcessorName("RealTimeDataCollector");
+Property RealTimeDataCollector::FILENAME("File Name", "File Name for the real time processor to process", "data.osp");
+Property RealTimeDataCollector::REALTIMESERVERNAME("Real Time Server Name", "Real Time Server Name", "localhost");
+Property RealTimeDataCollector::REALTIMESERVERPORT("Real Time Server Port", "Real Time Server Port", "10000");
+Property RealTimeDataCollector::BATCHSERVERNAME("Batch Server Name", "Batch Server Name", "localhost");
+Property RealTimeDataCollector::BATCHSERVERPORT("Batch Server Port", "Batch Server Port", "10001");
+Property RealTimeDataCollector::ITERATION("Iteration",
+		"If true, sample osp file will be iterated", "true");
+Property RealTimeDataCollector::REALTIMEMSGID("Real Time Message ID", "Real Time Message ID", "41");
+Property RealTimeDataCollector::BATCHMSGID("Batch Message ID", "Batch Message ID", "172, 30, 48");
+Property RealTimeDataCollector::REALTIMEINTERVAL("Real Time Interval", "Real Time Data Collection Interval in msec", "10 ms");
+Property RealTimeDataCollector::BATCHINTERVAL("Batch Time Interval", "Batch Processing Interval in msec", "100 ms");
+Property RealTimeDataCollector::BATCHMAXBUFFERSIZE("Batch Max Buffer Size", "Batch Buffer Maximum size in bytes", "262144");
+Relationship RealTimeDataCollector::Success("success", "success operational on the flow record");
+
+void RealTimeDataCollector::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(FILENAME);
+	properties.insert(REALTIMESERVERNAME);
+	properties.insert(REALTIMESERVERPORT);
+	properties.insert(BATCHSERVERNAME);
+	properties.insert(BATCHSERVERPORT);
+	properties.insert(ITERATION);
+	properties.insert(REALTIMEMSGID);
+	properties.insert(BATCHMSGID);
+	properties.insert(REALTIMEINTERVAL);
+	properties.insert(BATCHINTERVAL);
+	properties.insert(BATCHMAXBUFFERSIZE);
+
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(Success);
+	setSupportedRelationships(relationships);
+
+}
+
+int RealTimeDataCollector::connectServer(const char *host, uint16_t port)
+{
+	in_addr_t addr;
+	int sock = 0;
+	struct hostent *h;
+#ifdef __MACH__
+	h = gethostbyname(host);
+#else
+	char buf[1024];
+	struct hostent he;
+	int hh_errno;
+	gethostbyname_r(host, &he, buf, sizeof(buf), &h, &hh_errno);
+#endif
+	memcpy((char *) &addr, h->h_addr_list[0], h->h_length);
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0)
+	{
+		_logger->log_error("Could not create socket to hostName %s", host);
+		return 0;
+	}
+
+#ifndef __MACH__
+	int opt = 1;
+	bool nagle_off = true;
+
+	if (nagle_off)
+	{
+		if (setsockopt(sock, SOL_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() TCP_NODELAY failed");
+			close(sock);
+			return 0;
+		}
+		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+				(char *)&opt, sizeof(opt)) < 0)
+		{
+			_logger->log_error("setsockopt() SO_REUSEADDR failed");
+			close(sock);
+			return 0;
+		}
+	}
+
+	int sndsize = 256*1024;
+	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, (int)sizeof(sndsize)) < 0)
+	{
+		_logger->log_error("setsockopt() SO_SNDBUF failed");
+		close(sock);
+		return 0;
+	}
+#endif
+
+	struct sockaddr_in sa;
+	socklen_t socklen;
+	int status;
+
+	//TODO bind socket to the interface
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = htonl(INADDR_ANY);
+	sa.sin_port = htons(0);
+	socklen = sizeof(sa);
+	if (bind(sock, (struct sockaddr *)&sa, socklen) < 0)
+	{
+		_logger->log_error("socket bind failed");
+		close(sock);
+		return 0;
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sin_family = AF_INET;
+	sa.sin_addr.s_addr = addr;
+	sa.sin_port = htons(port);
+	socklen = sizeof(sa);
+
+	status = connect(sock, (struct sockaddr *)&sa, socklen);
+
+	if (status < 0)
+	{
+		_logger->log_error("socket connect failed to %s %d", host, port);
+		close(sock);
+		return 0;
+	}
+
+	_logger->log_info("socket %d connect to server %s port %d success", sock, host, port);
+
+	return sock;
+}
+
+int RealTimeDataCollector::sendData(int socket, const char *buf, int buflen)
+{
+	int ret = 0, bytes = 0;
+
+	while (bytes < buflen)
+	{
+		ret = send(socket, buf+bytes, buflen-bytes, 0);
+		//check for errors
+		if (ret == -1)
+		{
+			return ret;
+		}
+		bytes+=ret;
+	}
+
+	if (ret)
+		_logger->log_debug("Send data size %d over socket %d", buflen, socket);
+
+	return ret;
+}
+
+void RealTimeDataCollector::onTriggerRealTime(ProcessContext *context, ProcessSession *session)
+{
+	if (_realTimeAccumulated >= this->_realTimeInterval)
+	{
+		std::string value;
+		if (this->getProperty(REALTIMEMSGID.getName(), value))
+		{
+			this->_realTimeMsgID.clear();
+			this->_logger->log_info("Real Time Msg IDs %s", value.c_str());
+			std::stringstream lineStream(value);
+			std::string cell;
+
+			while(std::getline(lineStream, cell, ','))
+		    {
+		        this->_realTimeMsgID.push_back(cell);
+		        // this->_logger->log_debug("Real Time Msg ID %s", cell.c_str());
+		    }
+		}
+		if (this->getProperty(BATCHMSGID.getName(), value))
+		{
+			this->_batchMsgID.clear();
+			this->_logger->log_info("Batch Msg IDs %s", value.c_str());
+			std::stringstream lineStream(value);
+			std::string cell;
+
+			while(std::getline(lineStream, cell, ','))
+		    {
+				cell = Property::trim(cell);
+		        this->_batchMsgID.push_back(cell);
+		        // this->_logger->log_debug("Batch Msg ID %s", cell.c_str());
+		    }
+		}
+		// _logger->log_info("onTriggerRealTime");
+		// Open the file
+		if (!this->_fileStream.is_open())
+		{
+			_fileStream.open(this->_fileName.c_str(), std::ifstream::in);
+			if (this->_fileStream.is_open())
+				_logger->log_debug("open %s", _fileName.c_str());
+		}
+		if (!_fileStream.good())
+		{
+			_logger->log_error("load data file failed %s", _fileName.c_str());
+			return;
+		}
+		if (this->_fileStream.is_open())
+		{
+			std::string line;
+
+			while (std::getline(_fileStream, line))
+			{
+				line += "\n";
+				std::stringstream lineStream(line);
+				std::string cell;
+				if (std::getline(lineStream, cell, ','))
+				{
+					cell = Property::trim(cell);
+					// Check whether it match to the batch traffic
+					for (std::vector<std::string>::iterator it = _batchMsgID.begin(); it != _batchMsgID.end(); ++it)
+					{
+						if (cell == *it)
+						{
+							// push the batch data to the queue
+							std::lock_guard<std::mutex> lock(_mtx);
+							while ((_queuedDataSize + line.size()) > _batchMaxBufferSize)
+							{
+								std::string item = _queue.front();
+								_queuedDataSize -= item.size();
+								_logger->log_debug("Pop item size %d from batch queue, queue buffer size %d", item.size(), _queuedDataSize);
+								_queue.pop();
+							}
+							_queue.push(line);
+							_queuedDataSize += line.size();
+							_logger->log_debug("Push batch msg ID %s into batch queue, queue buffer size %d", cell.c_str(), _queuedDataSize);
+						}
+					}
+					bool findRealTime = false;
+					// Check whether it match to the real time traffic
+					for (std::vector<std::string>::iterator it = _realTimeMsgID.begin(); it != _realTimeMsgID.end(); ++it)
+					{
+						if (cell == *it)
+						{
+							int status = 0;
+							if (this->_realTimeSocket <= 0)
+							{
+								// Connect the LTE socket
+								uint16_t port = _realTimeServerPort;
+								this->_realTimeSocket = connectServer(_realTimeServerName.c_str(), port);
+							}
+							if (this->_realTimeSocket)
+							{
+								// try to send the data
+								status = sendData(_realTimeSocket, line.data(), line.size());
+								if (status < 0)
+								{
+									close(_realTimeSocket);
+									_realTimeSocket = 0;
+								}
+							}
+							if (this->_realTimeSocket <= 0 || status < 0)
+							{
+								// push the batch data to the queue
+								std::lock_guard<std::mutex> lock(_mtx);
+								while ((_queuedDataSize + line.size()) > _batchMaxBufferSize)
+								{
+									std::string item = _queue.front();
+									_queuedDataSize -= item.size();
+									_logger->log_debug("Pop item size %d from batch queue, queue buffer size %d", item.size(), _queuedDataSize);
+									_queue.pop();
+								}
+								_queue.push(line);
+								_queuedDataSize += line.size();
+								_logger->log_debug("Push real time msg ID %s into batch queue, queue buffer size %d", cell.c_str(), _queuedDataSize);
+							}
+							// find real time
+							findRealTime = true;
+						} // cell
+					} // for real time pattern
+					if (findRealTime)
+						// we break the while once we find the first real time
+						break;
+				}  // if get line
+			} // while
+			if (_fileStream.eof())
+			{
+				_fileStream.close();
+			}
+		} // if open
+		_realTimeAccumulated = 0;
+	}
+	_realTimeAccumulated += context->getProcessor()->getSchedulingPeriodNano();
+}
+
+void RealTimeDataCollector::onTriggerBatch(ProcessContext *context, ProcessSession *session)
+{
+	if (_batchAcccumulated >= this->_batchInterval)
+	{
+		// _logger->log_info("onTriggerBatch");
+		// dequeue the batch and send over WIFI
+		int status = 0;
+		if (this->_batchSocket <= 0)
+		{
+			// Connect the WIFI socket
+			uint16_t port = _batchServerPort;
+			this->_batchSocket = connectServer(_batchServerName.c_str(), port);
+		}
+		if (this->_batchSocket)
+		{
+			std::lock_guard<std::mutex> lock(_mtx);
+
+			while (!_queue.empty())
+			{
+				std::string line = _queue.front();
+				status = sendData(_batchSocket, line.data(), line.size());
+				_queue.pop();
+				_queuedDataSize -= line.size();
+				if (status < 0)
+				{
+					close(_batchSocket);
+					_batchSocket = 0;
+					break;
+				}
+			}
+		}
+		_batchAcccumulated = 0;
+	}
+	_batchAcccumulated += context->getProcessor()->getSchedulingPeriodNano();
+}
+
+void RealTimeDataCollector::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::thread::id id = std::this_thread::get_id();
+
+	if (id == _realTimeThreadId)
+		return onTriggerRealTime(context, session);
+	else if (id == _batchThreadId)
+		return onTriggerBatch(context, session);
+	else
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		if (!this->_firstInvoking)
+		{
+			this->_fileName = "data.osp";
+			std::string value;
+			if (this->getProperty(FILENAME.getName(), value))
+			{
+				this->_fileName = value;
+				this->_logger->log_info("Data Collector File Name %s", _fileName.c_str());
+			}
+			this->_realTimeServerName = "localhost";
+			if (this->getProperty(REALTIMESERVERNAME.getName(), value))
+			{
+				this->_realTimeServerName = value;
+				this->_logger->log_info("Real Time Server Name %s", this->_realTimeServerName.c_str());
+			}
+			this->_realTimeServerPort = 10000;
+			if (this->getProperty(REALTIMESERVERPORT.getName(), value))
+			{
+				Property::StringToInt(value, _realTimeServerPort);
+				this->_logger->log_info("Real Time Server Port %d", _realTimeServerPort);
+			}
+			if (this->getProperty(BATCHSERVERNAME.getName(), value))
+			{
+				this->_batchServerName = value;
+				this->_logger->log_info("Batch Server Name %s", this->_batchServerName.c_str());
+			}
+			this->_batchServerPort = 10001;
+			if (this->getProperty(BATCHSERVERPORT.getName(), value))
+			{
+				Property::StringToInt(value, _batchServerPort);
+				this->_logger->log_info("Batch Server Port %d", _batchServerPort);
+			}
+			if (this->getProperty(ITERATION.getName(), value))
+			{
+				Property::StringToBool(value, this->_iteration);
+				_logger->log_info("Iteration %d", _iteration);
+			}
+			this->_realTimeInterval = 10000000; //10 msec
+			if (this->getProperty(REALTIMEINTERVAL.getName(), value))
+			{
+				TimeUnit unit;
+				if (Property::StringToTime(value, _realTimeInterval, unit) &&
+								Property::ConvertTimeUnitToNS(_realTimeInterval, unit, _realTimeInterval))
+				{
+					_logger->log_info("Real Time Interval: [%d] ns", _realTimeInterval);
+				}
+			}
+			this->_batchInterval = 100000000; //100 msec
+			if (this->getProperty(BATCHINTERVAL.getName(), value))
+			{
+				TimeUnit unit;
+				if (Property::StringToTime(value, _batchInterval, unit) &&
+								Property::ConvertTimeUnitToNS(_batchInterval, unit, _batchInterval))
+				{
+					_logger->log_info("Batch Time Interval: [%d] ns", _batchInterval);
+				}
+			}
+			this->_batchMaxBufferSize = 256*1024;
+			if (this->getProperty(BATCHMAXBUFFERSIZE.getName(), value))
+			{
+				Property::StringToInt(value, _batchMaxBufferSize);
+				this->_logger->log_info("Batch Max Buffer Size %d", _batchMaxBufferSize);
+			}
+			if (this->getProperty(REALTIMEMSGID.getName(), value))
+			{
+				this->_logger->log_info("Real Time Msg IDs %s", value.c_str());
+				std::stringstream lineStream(value);
+				std::string cell;
+
+				while(std::getline(lineStream, cell, ','))
+			    {
+			        this->_realTimeMsgID.push_back(cell);
+			        this->_logger->log_info("Real Time Msg ID %s", cell.c_str());
+			    }
+			}
+			if (this->getProperty(BATCHMSGID.getName(), value))
+			{
+				this->_logger->log_info("Batch Msg IDs %s", value.c_str());
+				std::stringstream lineStream(value);
+				std::string cell;
+
+				while(std::getline(lineStream, cell, ','))
+			    {
+					cell = Property::trim(cell);
+			        this->_batchMsgID.push_back(cell);
+			        this->_logger->log_info("Batch Msg ID %s", cell.c_str());
+			    }
+			}
+			// Connect the LTE socket
+			uint16_t port = _realTimeServerPort;
+
+			this->_realTimeSocket = connectServer(_realTimeServerName.c_str(), port);
+
+			// Connect the WIFI socket
+			port = _batchServerPort;
+
+			this->_batchSocket = connectServer(_batchServerName.c_str(), port);
+
+			// Open the file
+			_fileStream.open(this->_fileName.c_str(), std::ifstream::in);
+			if (!_fileStream.good())
+			{
+				_logger->log_error("load data file failed %s", _fileName.c_str());
+				return;
+			}
+			else
+			{
+				_logger->log_debug("open %s", _fileName.c_str());
+			}
+			_realTimeThreadId = id;
+			this->_firstInvoking = true;
+		}
+		else
+		{
+			if (id != _realTimeThreadId)
+				_batchThreadId = id;
+			this->_firstInvoking = false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/RemoteProcessorGroupPort.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/RemoteProcessorGroupPort.cpp b/libminifi/src/RemoteProcessorGroupPort.cpp
new file mode 100644
index 0000000..9d849ae
--- /dev/null
+++ b/libminifi/src/RemoteProcessorGroupPort.cpp
@@ -0,0 +1,100 @@
+/**
+ * @file RemoteProcessorGroupPort.cpp
+ * RemoteProcessorGroupPort class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+#include <sys/time.h>
+#include <time.h>
+#include <sstream>
+#include <string.h>
+#include <iostream>
+
+#include "TimeUtil.h"
+#include "RemoteProcessorGroupPort.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+
+const std::string RemoteProcessorGroupPort::ProcessorName("RemoteProcessorGroupPort");
+Property RemoteProcessorGroupPort::hostName("Host Name", "Remote Host Name.", "localhost");
+Property RemoteProcessorGroupPort::port("Port", "Remote Port", "9999");
+Relationship RemoteProcessorGroupPort::relation;
+
+void RemoteProcessorGroupPort::initialize()
+{
+	//! Set the supported properties
+	std::set<Property> properties;
+	properties.insert(hostName);
+	properties.insert(port);
+	setSupportedProperties(properties);
+	//! Set the supported relationships
+	std::set<Relationship> relationships;
+	relationships.insert(relation);
+	setSupportedRelationships(relationships);
+}
+
+void RemoteProcessorGroupPort::onTrigger(ProcessContext *context, ProcessSession *session)
+{
+	std::string value;
+
+	if (!_transmitting)
+		return;
+
+	std::string host = _peer->getHostName();
+	uint16_t sport = _peer->getPort();
+	int64_t lvalue;
+	bool needReset = false;
+
+	if (context->getProperty(hostName.getName(), value))
+	{
+		host = value;
+	}
+	if (context->getProperty(port.getName(), value) && Property::StringToInt(value, lvalue))
+	{
+		sport = (uint16_t) lvalue;
+	}
+	if (host != _peer->getHostName())
+	{
+		_peer->setHostName(host);
+		needReset= true;
+	}
+	if (sport != _peer->getPort())
+	{
+		_peer->setPort(sport);
+		needReset = true;
+	}
+	if (needReset)
+		_protocol->tearDown();
+
+	if (!_protocol->bootstrap())
+	{
+		// bootstrap the client protocol if needeed
+		context->yield();
+		_logger->log_error("Site2Site bootstrap failed yield period %d peer timeout %d", context->getProcessor()->getYieldPeriodMsec(), _protocol->getPeer()->getTimeOut());
+		return;
+	}
+
+	if (_direction == RECEIVE)
+		_protocol->receiveFlowFiles(context, session);
+	else
+		_protocol->transferFlowFiles(context, session);
+
+	return;
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/ResourceClaim.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/ResourceClaim.cpp b/libminifi/src/ResourceClaim.cpp
new file mode 100644
index 0000000..3c22ac9
--- /dev/null
+++ b/libminifi/src/ResourceClaim.cpp
@@ -0,0 +1,45 @@
+/**
+ * @file ResourceClaim.cpp
+ * ResourceClaim class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vector>
+#include <queue>
+#include <map>
+
+#include "ResourceClaim.h"
+
+std::atomic<uint64_t> ResourceClaim::_localResourceClaimNumber(0);
+
+ResourceClaim::ResourceClaim(const std::string contentDirectory)
+: _id(_localResourceClaimNumber.load()),
+  _flowFileRecordOwnedCount(0)
+{
+	char uuidStr[37];
+
+	// Generate the global UUID for the resource claim
+	uuid_generate(_uuid);
+	// Increase the local ID for the resource claim
+	++_localResourceClaimNumber;
+	uuid_unparse(_uuid, uuidStr);
+	// Create the full content path for the content
+	_contentFullPath = contentDirectory + "/" + uuidStr;
+
+	_configure = Configure::getConfigure();
+	_logger = Logger::getLogger();
+	_logger->log_debug("Resource Claim created %s", _contentFullPath.c_str());
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/src/SchedulingAgent.cpp
----------------------------------------------------------------------
diff --git a/libminifi/src/SchedulingAgent.cpp b/libminifi/src/SchedulingAgent.cpp
new file mode 100644
index 0000000..211c328
--- /dev/null
+++ b/libminifi/src/SchedulingAgent.cpp
@@ -0,0 +1,86 @@
+/**
+ * @file SchedulingAgent.cpp
+ * SchedulingAgent class implementation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <chrono>
+#include <thread>
+#include <iostream>
+#include "Exception.h"
+#include "SchedulingAgent.h"
+
+bool SchedulingAgent::hasWorkToDo(Processor *processor)
+{
+	// Whether it has work to do
+	if (processor->getTriggerWhenEmpty() || !processor->hasIncomingConnections() ||
+			processor->flowFilesQueued())
+		return true;
+	else
+		return false;
+}
+
+bool SchedulingAgent::hasTooMuchOutGoing(Processor *processor)
+{
+	return processor->flowFilesOutGoingFull();
+}
+
+bool SchedulingAgent::onTrigger(Processor *processor)
+{
+	if (processor->isYield())
+		return false;
+
+	// No need to yield, reset yield expiration to 0
+	processor->clearYield();
+
+	if (!hasWorkToDo(processor))
+		// No work to do, yield
+		return true;
+
+	if(hasTooMuchOutGoing(processor))
+		// need to apply backpressure
+		return true;
+
+	//TODO runDuration
+
+	processor->incrementActiveTasks();
+	try
+	{
+		processor->onTrigger();
+		processor->decrementActiveTask();
+	}
+	catch (Exception &exception)
+	{
+		// Normal exception
+		_logger->log_debug("Caught Exception %s", exception.what());
+		processor->decrementActiveTask();
+	}
+	catch (std::exception &exception)
+	{
+		_logger->log_debug("Caught Exception %s", exception.what());
+		processor->yield(_administrativeYieldDuration);
+		processor->decrementActiveTask();
+	}
+	catch (...)
+	{
+		_logger->log_debug("Caught Exception during SchedulingAgent::onTrigger");
+		processor->yield(_administrativeYieldDuration);
+		processor->decrementActiveTask();
+	}
+
+	return false;
+}
+


[14/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/line_logger.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/line_logger.h b/inc/spdlog/details/line_logger.h
deleted file mode 100644
index 80d7cc1..0000000
--- a/inc/spdlog/details/line_logger.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-#include <type_traits>
-#include "../common.h"
-#include "../logger.h"
-
-// Line logger class - aggregates operator<< calls to fast ostream
-// and logs upon destruction
-
-namespace spdlog
-{
-namespace details
-{
-class line_logger
-{
-public:
-    line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
-        _callback_logger(callback_logger),
-        _log_msg(msg_level),
-        _enabled(enabled)
-    {}
-
-    // No copy intended. Only move
-    line_logger(const line_logger& other) = delete;
-    line_logger& operator=(const line_logger&) = delete;
-    line_logger& operator=(line_logger&&) = delete;
-
-
-    line_logger(line_logger&& other) :
-        _callback_logger(other._callback_logger),
-        _log_msg(std::move(other._log_msg)),
-        _enabled(other._enabled)
-    {
-        other.disable();
-    }
-
-    //Log the log message using the callback logger
-    ~line_logger()
-    {
-        if (_enabled)
-        {
-#ifndef SPDLOG_NO_NAME
-            _log_msg.logger_name = _callback_logger->name();
-#endif
-#ifndef SPDLOG_NO_DATETIME
-            _log_msg.time = os::now();
-#endif
-
-#ifndef SPDLOG_NO_THREAD_ID
-            _log_msg.thread_id = os::thread_id();
-#endif
-            _callback_logger->_log_msg(_log_msg);
-        }
-    }
-
-    //
-    // Support for format string with variadic args
-    //
-
-
-    void write(const char* what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-    }
-
-    template <typename... Args>
-    void write(const char* fmt, const Args&... args)
-    {
-        if (!_enabled)
-            return;
-        try
-        {
-            _log_msg.raw.write(fmt, args...);
-        }
-        catch (const fmt::FormatError& e)
-        {
-            throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
-        }
-    }
-
-
-    //
-    // Support for operator<<
-    //
-    line_logger& operator<<(const char* what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(const std::string& what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(int what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(unsigned int what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-
-    line_logger& operator<<(long what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(unsigned long what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(long long what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(unsigned long long what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(double what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(long double what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(float what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    line_logger& operator<<(char what)
-    {
-        if (_enabled)
-            _log_msg.raw << what;
-        return *this;
-    }
-
-    //Support user types which implements operator<<
-    template<typename T>
-    line_logger& operator<<(const T& what)
-    {
-        if (_enabled)
-            _log_msg.raw.write("{}", what);
-        return *this;
-    }
-
-
-    void disable()
-    {
-        _enabled = false;
-    }
-
-    bool is_enabled() const
-    {
-        return _enabled;
-    }
-
-
-private:
-    logger* _callback_logger;
-    log_msg _log_msg;
-    bool _enabled;
-};
-} //Namespace details
-} // Namespace spdlog

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/log_msg.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/log_msg.h b/inc/spdlog/details/log_msg.h
deleted file mode 100644
index bf58aca..0000000
--- a/inc/spdlog/details/log_msg.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <thread>
-#include "../common.h"
-#include "./format.h"
-
-namespace spdlog
-{
-namespace details
-{
-struct log_msg
-{
-    log_msg() = default;
-    log_msg(level::level_enum l):
-        logger_name(),
-        level(l),
-        raw(),
-        formatted() {}
-
-
-    log_msg(const log_msg& other) :
-        logger_name(other.logger_name),
-        level(other.level),
-        time(other.time),
-        thread_id(other.thread_id)
-    {
-        if (other.raw.size())
-            raw << fmt::BasicStringRef<char>(other.raw.data(), other.raw.size());
-        if (other.formatted.size())
-            formatted << fmt::BasicStringRef<char>(other.formatted.data(), other.formatted.size());
-    }
-
-    log_msg(log_msg&& other) :
-        logger_name(std::move(other.logger_name)),
-        level(other.level),
-        time(std::move(other.time)),
-        thread_id(other.thread_id),
-        raw(std::move(other.raw)),
-        formatted(std::move(other.formatted))
-    {
-        other.clear();
-    }
-
-    log_msg& operator=(log_msg&& other)
-    {
-        if (this == &other)
-            return *this;
-
-        logger_name = std::move(other.logger_name);
-        level = other.level;
-        time = std::move(other.time);
-        thread_id = other.thread_id;
-        raw = std::move(other.raw);
-        formatted = std::move(other.formatted);
-        other.clear();
-        return *this;
-    }
-
-    void clear()
-    {
-        level = level::off;
-        raw.clear();
-        formatted.clear();
-    }
-
-    std::string logger_name;
-    level::level_enum level;
-    log_clock::time_point time;
-    size_t thread_id;
-    fmt::MemoryWriter raw;
-    fmt::MemoryWriter formatted;
-};
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/logger_impl.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/logger_impl.h b/inc/spdlog/details/logger_impl.h
deleted file mode 100644
index d658ac0..0000000
--- a/inc/spdlog/details/logger_impl.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-//
-// Logger implementation
-//
-
-#include "./line_logger.h"
-
-
-// create logger with given name, sinks and the default pattern formatter
-// all other ctors will call this one
-template<class It>
-inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
-    _name(logger_name),
-    _sinks(begin, end),
-    _formatter(std::make_shared<pattern_formatter>("%+"))
-{
-
-    // no support under vs2013 for member initialization for std::atomic
-    _level = level::info;
-}
-
-// ctor with sinks as init list
-inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
-    logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
-
-
-// ctor with single sink
-inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
-    logger(logger_name, {
-    single_sink
-}) {}
-
-
-inline spdlog::logger::~logger() = default;
-
-
-inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
-{
-    _set_formatter(msg_formatter);
-}
-
-inline void spdlog::logger::set_pattern(const std::string& pattern)
-{
-    _set_pattern(pattern);
-}
-
-//
-// log only if given level>=logger's log level
-//
-
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
-{
-    bool msg_enabled = should_log(lvl);
-    details::line_logger l(this, lvl, msg_enabled);
-    l.write(fmt, args...);
-    return l;
-}
-
-inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
-{
-    return details::line_logger(this, lvl, should_log(lvl));
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
-{
-    bool msg_enabled = should_log(lvl);
-    details::line_logger l(this, lvl, msg_enabled);
-    l << msg;
-    return l;
-}
-
-//
-// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
-//
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::trace, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::debug, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::info, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::notice, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::warn, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::err, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::critical, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::alert, fmt, args...);
-}
-
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
-{
-    return _log_if_enabled(level::emerg, fmt, args...);
-}
-
-//
-// logger.info(msg) << ".." call style
-//
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
-{
-    return _log_if_enabled(level::trace, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
-{
-    return _log_if_enabled(level::debug, msg);
-}
-
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
-{
-    return _log_if_enabled(level::info, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
-{
-    return _log_if_enabled(level::notice, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
-{
-    return _log_if_enabled(level::warn, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
-{
-    return _log_if_enabled(level::err, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
-{
-    return _log_if_enabled(level::critical, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
-{
-    return _log_if_enabled(level::alert, msg);
-}
-
-template<typename T>
-inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
-{
-    return _log_if_enabled(level::emerg, msg);
-}
-
-
-
-
-//
-// logger.info() << ".." call  style
-//
-inline spdlog::details::line_logger spdlog::logger::trace()
-{
-    return _log_if_enabled(level::trace);
-}
-
-inline spdlog::details::line_logger spdlog::logger::debug()
-{
-    return _log_if_enabled(level::debug);
-}
-
-inline spdlog::details::line_logger spdlog::logger::info()
-{
-    return _log_if_enabled(level::info);
-}
-
-inline spdlog::details::line_logger spdlog::logger::notice()
-{
-    return _log_if_enabled(level::notice);
-}
-
-inline spdlog::details::line_logger spdlog::logger::warn()
-{
-    return _log_if_enabled(level::warn);
-}
-
-inline spdlog::details::line_logger spdlog::logger::error()
-{
-    return _log_if_enabled(level::err);
-}
-
-inline spdlog::details::line_logger spdlog::logger::critical()
-{
-    return _log_if_enabled(level::critical);
-}
-
-inline spdlog::details::line_logger spdlog::logger::alert()
-{
-    return _log_if_enabled(level::alert);
-}
-
-inline spdlog::details::line_logger spdlog::logger::emerg()
-{
-    return _log_if_enabled(level::emerg);
-}
-
-
-// always log, no matter what is the actual logger's log level
-template <typename... Args>
-inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
-{
-    details::line_logger l(this, lvl, true);
-    l.write(fmt, args...);
-    return l;
-}
-
-//
-// name and level
-//
-inline const std::string& spdlog::logger::name() const
-{
-    return _name;
-}
-
-inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
-{
-    _level.store(log_level);
-}
-
-inline spdlog::level::level_enum spdlog::logger::level() const
-{
-    return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));
-}
-
-inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
-{
-    return msg_level >= _level.load(std::memory_order_relaxed);
-}
-
-//
-// protected virtual called at end of each user log call (if enabled) by the line_logger
-//
-inline void spdlog::logger::_log_msg(details::log_msg& msg)
-{
-    _formatter->format(msg);
-    for (auto &sink : _sinks)
-        sink->log(msg);
-}
-
-inline void spdlog::logger::_set_pattern(const std::string& pattern)
-{
-    _formatter = std::make_shared<pattern_formatter>(pattern);
-}
-inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
-{
-    _formatter = msg_formatter;
-}
-
-inline void spdlog::logger::flush() {
-    for (auto& sink : _sinks)
-        sink->flush();
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/mpmc_bounded_q.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/mpmc_bounded_q.h b/inc/spdlog/details/mpmc_bounded_q.h
deleted file mode 100644
index 7cbcfd7..0000000
--- a/inc/spdlog/details/mpmc_bounded_q.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
-A modified version of Bounded MPMC queue by Dmitry Vyukov.
-
-Original code from:
-http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
-
-licensed by Dmitry Vyukov under the terms below:
-
-Simplified BSD license
-
-Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright notice, this list of
-conditions and the following disclaimer.
-
-2. 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.
-
-THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "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 DMITRY VYUKOV 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.
-
-The views and conclusions contained in the software and documentation are those of the authors and
-should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
-*/
-
-/*
-The code in its current form adds the license below:
-
-spdlog - an extremely fast and easy to use c++11 logging library.
-Copyright (c) 2014 Gabi Melman.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#pragma once
-
-#include <atomic>
-#include "../common.h"
-
-namespace spdlog
-{
-namespace details
-{
-
-template<typename T>
-class mpmc_bounded_queue
-{
-public:
-
-    using item_type = T;
-    mpmc_bounded_queue(size_t buffer_size)
-        : buffer_(new cell_t [buffer_size]),
-          buffer_mask_(buffer_size - 1)
-    {
-        //queue size must be power of two
-        if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
-            throw spdlog_ex("async logger queue size must be power of two");
-
-        for (size_t i = 0; i != buffer_size; i += 1)
-            buffer_[i].sequence_.store(i, std::memory_order_relaxed);
-        enqueue_pos_.store(0, std::memory_order_relaxed);
-        dequeue_pos_.store(0, std::memory_order_relaxed);
-    }
-
-    ~mpmc_bounded_queue()
-    {
-        delete [] buffer_;
-    }
-
-
-    bool enqueue(T&& data)
-    {
-        cell_t* cell;
-        size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
-        for (;;)
-        {
-            cell = &buffer_[pos & buffer_mask_];
-            size_t seq = cell->sequence_.load(std::memory_order_acquire);
-            intptr_t dif = (intptr_t)seq - (intptr_t)pos;
-            if (dif == 0)
-            {
-                if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
-                    break;
-            }
-            else if (dif < 0)
-            {
-                return false;
-            }
-            else
-            {
-                pos = enqueue_pos_.load(std::memory_order_relaxed);
-            }
-        }
-        cell->data_ = std::move(data);
-        cell->sequence_.store(pos + 1, std::memory_order_release);
-        return true;
-    }
-
-    bool dequeue(T& data)
-    {
-        cell_t* cell;
-        size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
-        for (;;)
-        {
-            cell = &buffer_[pos & buffer_mask_];
-            size_t seq =
-                cell->sequence_.load(std::memory_order_acquire);
-            intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
-            if (dif == 0)
-            {
-                if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
-                    break;
-            }
-            else if (dif < 0)
-                return false;
-            else
-                pos = dequeue_pos_.load(std::memory_order_relaxed);
-        }
-        data = std::move(cell->data_);
-        cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
-        return true;
-    }
-
-private:
-    struct cell_t
-    {
-        std::atomic<size_t>   sequence_;
-        T                     data_;
-    };
-
-    static size_t const     cacheline_size = 64;
-    typedef char            cacheline_pad_t [cacheline_size];
-
-    cacheline_pad_t         pad0_;
-    cell_t* const           buffer_;
-    size_t const            buffer_mask_;
-    cacheline_pad_t         pad1_;
-    std::atomic<size_t>     enqueue_pos_;
-    cacheline_pad_t         pad2_;
-    std::atomic<size_t>     dequeue_pos_;
-    cacheline_pad_t         pad3_;
-
-    mpmc_bounded_queue(mpmc_bounded_queue const&);
-    void operator = (mpmc_bounded_queue const&);
-};
-
-} // ns details
-} // ns spdlog

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/null_mutex.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/null_mutex.h b/inc/spdlog/details/null_mutex.h
deleted file mode 100644
index ebb56a5..0000000
--- a/inc/spdlog/details/null_mutex.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-// null, no cost mutex
-
-namespace spdlog
-{
-namespace details
-{
-struct null_mutex
-{
-    void lock() {}
-    void unlock() {}
-    bool try_lock()
-    {
-        return true;
-    }
-};
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/os.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/os.h b/inc/spdlog/details/os.h
deleted file mode 100644
index 753b6d9..0000000
--- a/inc/spdlog/details/os.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-#include<string>
-#include<cstdio>
-#include<ctime>
-
-#ifdef _WIN32
-# ifndef WIN32_LEAN_AND_MEAN
-#  define WIN32_LEAN_AND_MEAN
-# endif
-# include <Windows.h>
-
-#ifdef __MINGW32__
-#include <share.h>
-#endif
-
-#elif __linux__
-#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
-#include <unistd.h>
-#else
-#include <thread>
-#endif
-
-#include "../common.h"
-
-namespace spdlog
-{
-namespace details
-{
-namespace os
-{
-
-inline spdlog::log_clock::time_point now()
-{
-
-#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
-    timespec ts;
-    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
-    return std::chrono::time_point<log_clock, typename log_clock::duration>(
-               std::chrono::duration_cast<typename log_clock::duration>(
-                   std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
-
-#else
-    return log_clock::now();
-#endif
-
-}
-inline std::tm localtime(const std::time_t &time_tt)
-{
-
-#ifdef _WIN32
-    std::tm tm;
-    localtime_s(&tm, &time_tt);
-#else
-    std::tm tm;
-    localtime_r(&time_tt, &tm);
-#endif
-    return tm;
-}
-
-inline std::tm localtime()
-{
-    std::time_t now_t = time(nullptr);
-    return localtime(now_t);
-}
-
-
-inline std::tm gmtime(const std::time_t &time_tt)
-{
-
-#ifdef _WIN32
-    std::tm tm;
-    gmtime_s(&tm, &time_tt);
-#else
-    std::tm tm;
-    gmtime_r(&time_tt, &tm);
-#endif
-    return tm;
-}
-
-inline std::tm gmtime()
-{
-    std::time_t now_t = time(nullptr);
-    return gmtime(now_t);
-}
-inline bool operator==(const std::tm& tm1, const std::tm& tm2)
-{
-    return (tm1.tm_sec == tm2.tm_sec &&
-            tm1.tm_min == tm2.tm_min &&
-            tm1.tm_hour == tm2.tm_hour &&
-            tm1.tm_mday == tm2.tm_mday &&
-            tm1.tm_mon == tm2.tm_mon &&
-            tm1.tm_year == tm2.tm_year &&
-            tm1.tm_isdst == tm2.tm_isdst);
-}
-
-inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
-{
-    return !(tm1 == tm2);
-}
-
-#ifdef _WIN32
-inline const char* eol()
-{
-    return "\r\n";
-}
-#else
-constexpr inline const char* eol()
-{
-    return "\n";
-}
-#endif
-
-#ifdef _WIN32
-inline unsigned short eol_size()
-{
-    return 2;
-}
-#else
-constexpr inline unsigned short eol_size()
-{
-    return 1;
-}
-#endif
-
-//fopen_s on non windows for writing
-inline int fopen_s(FILE** fp, const std::string& filename, const char* mode)
-{
-#ifdef _WIN32
-    *fp = _fsopen((filename.c_str()), mode, _SH_DENYWR);
-    return *fp == nullptr;
-#else
-    *fp = fopen((filename.c_str()), mode);
-    return *fp == nullptr;
-#endif
-
-
-}
-
-//Return utc offset in minutes or -1 on failure
-inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
-{
-
-#ifdef _WIN32
-    (void)tm; // avoid unused param warning
-    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
-    auto rv = GetDynamicTimeZoneInformation(&tzinfo);
-    if (!rv)
-        return -1;
-    return -1 * (tzinfo.Bias + tzinfo.DaylightBias);
-#else
-    return static_cast<int>(tm.tm_gmtoff / 60);
-#endif
-}
-
-//Return current thread id as size_t
-//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
-inline size_t thread_id()
-{
-#ifdef _WIN32
-    return  static_cast<size_t>(::GetCurrentThreadId());
-#elif __linux__
-    return  static_cast<size_t>(syscall(SYS_gettid));
-#else //Default to standard C++11 (OSX and other Unix)
-    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
-#endif
-
-}
-
-} //os
-} //details
-} //spdlog
-
-
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/pattern_formatter_impl.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/pattern_formatter_impl.h b/inc/spdlog/details/pattern_formatter_impl.h
deleted file mode 100644
index a5b2d21..0000000
--- a/inc/spdlog/details/pattern_formatter_impl.h
+++ /dev/null
@@ -1,628 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <string>
-#include <chrono>
-#include <memory>
-#include <vector>
-#include <thread>
-
-
-#include "../formatter.h"
-#include "./log_msg.h"
-#include "./os.h"
-
-namespace spdlog
-{
-namespace details
-{
-class flag_formatter
-{
-public:
-    virtual ~flag_formatter() {}
-    virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////
-// name & level pattern appenders
-///////////////////////////////////////////////////////////////////////
-namespace
-{
-class name_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << msg.logger_name;
-    }
-};
-}
-
-// log level appender
-class level_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << level::to_str(msg.level);
-    }
-};
-
-// short log level appender
-class short_level_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << level::to_short_str(msg.level);
-    }
-};
-
-///////////////////////////////////////////////////////////////////////
-// Date time pattern appenders
-///////////////////////////////////////////////////////////////////////
-
-static const char* ampm(const tm& t)
-{
-    return t.tm_hour >= 12 ? "PM" : "AM";
-}
-
-static int to12h(const tm& t)
-{
-    return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
-}
-
-//Abbreviated weekday name
-static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
-class a_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << days[tm_time.tm_wday];
-    }
-};
-
-//Full weekday name
-static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
-class A_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << full_days[tm_time.tm_wday];
-    }
-};
-
-//Abbreviated month
-static const std::string  months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
-class b_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted<< months[tm_time.tm_mon];
-    }
-};
-
-//Full month name
-static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
-class B_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << full_months[tm_time.tm_mon];
-    }
-};
-
-
-//write 2 ints seperated by sep with padding of 2
-static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep)
-{
-    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0');
-    return w;
-}
-
-//write 3 ints seperated by sep with padding of 2
-static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep)
-{
-    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0');
-    return w;
-}
-
-
-//Date and time representation (Thu Aug 23 15:35:46 2014)
-class c_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
-        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
-    }
-};
-
-
-// year - 2 digit
-class C_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0');
-    }
-};
-
-
-
-// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
-class D_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/');
-    }
-};
-
-
-// year - 4 digit
-class Y_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << tm_time.tm_year + 1900;
-    }
-};
-
-// month 1-12
-class m_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0');
-    }
-};
-
-// day of month 1-31
-class d_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0');
-    }
-};
-
-// hours in 24 format  0-23
-class H_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0');
-    }
-};
-
-// hours in 12 format  1-12
-class I_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(to12h(tm_time), 2, '0');
-    }
-};
-
-// ninutes 0-59
-class M_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_min, 2, '0');
-    }
-};
-
-// seconds 0-59
-class S_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0');
-    }
-};
-
-// milliseconds
-class e_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        auto duration = msg.time.time_since_epoch();
-        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
-        msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0');
-    }
-};
-
-// microseconds
-class f_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        auto duration = msg.time.time_since_epoch();
-        auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000;
-        msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0');
-    }
-};
-
-// AM/PM
-class p_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        msg.formatted << ampm(tm_time);
-    }
-};
-
-
-// 12 hour clock 02:55:02 pm
-class r_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time);
-    }
-};
-
-// 24-hour HH:MM time, equivalent to %H:%M
-class R_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':');
-    }
-};
-
-// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
-class T_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':');
-    }
-};
-
-
-// ISO 8601 offset from UTC in timezone (+-HH:MM)
-class z_formatter :public flag_formatter
-{
-public:
-    const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
-
-    z_formatter() :_last_update(std::chrono::seconds(0)) {}
-    z_formatter(const z_formatter&) = delete;
-    z_formatter& operator=(const z_formatter&) = delete;
-
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-#ifdef _WIN32
-        int total_minutes = get_cached_offset(msg, tm_time);
-#else
-        // No need to chache under gcc,
-        // it is very fast (already stored in tm.tm_gmtoff)
-        int total_minutes = os::utc_minutes_offset(tm_time);
-#endif
-
-        int h = total_minutes / 60;
-        int m = total_minutes % 60;
-        char sign = h >= 0 ? '+' : '-';
-        msg.formatted << sign;
-        pad_n_join(msg.formatted, h, m, ':');
-    }
-private:
-    log_clock::time_point _last_update;
-    int _offset_minutes;
-    std::mutex _mutex;
-
-    int get_cached_offset(const log_msg& msg, const std::tm& tm_time)
-    {
-        using namespace std::chrono;
-        std::lock_guard<std::mutex> l(_mutex);
-        if (msg.time - _last_update >= cache_refresh)
-        {
-            _offset_minutes = os::utc_minutes_offset(tm_time);
-            _last_update = msg.time;
-        }
-        return _offset_minutes;
-    }
-};
-
-
-
-//Thread id
-class t_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << msg.thread_id;
-    }
-};
-
-
-class v_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
-    }
-};
-
-class ch_formatter :public flag_formatter
-{
-public:
-    explicit ch_formatter(char ch) : _ch(ch)
-    {}
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << _ch;
-    }
-private:
-    char _ch;
-};
-
-
-//aggregate user chars to display as is
-class aggregate_formatter :public flag_formatter
-{
-public:
-    aggregate_formatter()
-    {}
-    void add_ch(char ch)
-    {
-        _str += ch;
-    }
-    void format(details::log_msg& msg, const std::tm&) override
-    {
-        msg.formatted << _str;
-    }
-private:
-    std::string _str;
-};
-
-// Full info formatter
-// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
-class full_formatter :public flag_formatter
-{
-    void format(details::log_msg& msg, const std::tm& tm_time) override
-    {
-#ifndef SPDLOG_NO_DATETIME
-        auto duration = msg.time.time_since_epoch();
-        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
-
-        /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
-        msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
-        tm_time.tm_year + 1900,
-        tm_time.tm_mon + 1,
-        tm_time.tm_mday,
-        tm_time.tm_hour,
-        tm_time.tm_min,
-        tm_time.tm_sec,
-        static_cast<int>(millis),
-        msg.logger_name,
-        level::to_str(msg.level),
-        msg.raw.str());*/
-
-
-        // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
-        msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'
-                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'
-                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' '
-                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':'
-                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':'
-                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'
-                      << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << "] ";
-
-//no datetime needed
-#else
-        (void)tm_time;
-#endif
-
-#ifndef SPDLOG_NO_NAME
-        msg.formatted << '[' << msg.logger_name << "] ";
-#endif
-
-        msg.formatted << '[' << level::to_str(msg.level) << "] ";
-        msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());
-    }
-};
-
-}
-}
-///////////////////////////////////////////////////////////////////////////////
-// pattern_formatter inline impl
-///////////////////////////////////////////////////////////////////////////////
-inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern)
-{
-    compile_pattern(pattern);
-}
-
-inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
-{
-    auto end = pattern.end();
-    std::unique_ptr<details::aggregate_formatter> user_chars;
-    for (auto it = pattern.begin(); it != end; ++it)
-    {
-        if (*it == '%')
-        {
-            if (user_chars) //append user chars found so far
-                _formatters.push_back(std::move(user_chars));
-
-            if (++it != end)
-                handle_flag(*it);
-            else
-                break;
-        }
-        else // chars not following the % sign should be displayed as is
-        {
-            if (!user_chars)
-                user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
-            user_chars->add_ch(*it);
-        }
-    }
-    if (user_chars) //append raw chars found so far
-    {
-        _formatters.push_back(std::move(user_chars));
-    }
-
-}
-inline void spdlog::pattern_formatter::handle_flag(char flag)
-{
-    switch (flag)
-    {
-    // logger name
-    case 'n':
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
-        break;
-
-    case 'l':
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::level_formatter()));
-        break;
-
-    case 'L':
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::short_level_formatter()));
-        break;
-
-    case('t') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::t_formatter()));
-        break;
-
-    case('v') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::v_formatter()));
-        break;
-
-    case('a') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::a_formatter()));
-        break;
-
-    case('A') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::A_formatter()));
-        break;
-
-    case('b') :
-    case('h') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::b_formatter()));
-        break;
-
-    case('B') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::B_formatter()));
-        break;
-    case('c') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::c_formatter()));
-        break;
-
-    case('C') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::C_formatter()));
-        break;
-
-    case('Y') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::Y_formatter()));
-        break;
-
-    case('D') :
-    case('x') :
-
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::D_formatter()));
-        break;
-
-    case('m') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::m_formatter()));
-        break;
-
-    case('d') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::d_formatter()));
-        break;
-
-    case('H') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::H_formatter()));
-        break;
-
-    case('I') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::I_formatter()));
-        break;
-
-    case('M') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::M_formatter()));
-        break;
-
-    case('S') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::S_formatter()));
-        break;
-
-    case('e') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::e_formatter()));
-        break;
-
-    case('f') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::f_formatter()));
-        break;
-
-    case('p') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::p_formatter()));
-        break;
-
-    case('r') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::r_formatter()));
-        break;
-
-    case('R') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::R_formatter()));
-        break;
-
-    case('T') :
-    case('X') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::T_formatter()));
-        break;
-
-    case('z') :
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::z_formatter()));
-        break;
-
-    case ('+'):
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
-        break;
-
-    default: //Unkown flag appears as is
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
-        _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));
-        break;
-    }
-}
-
-
-inline void spdlog::pattern_formatter::format(details::log_msg& msg)
-{
-    try
-    {
-        auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time));
-        for (auto &f : _formatters)
-        {
-            f->format(msg, tm_time);
-        }
-        //write eol
-        msg.formatted << details::os::eol();
-    }
-    catch(const fmt::FormatError& e)
-    {
-        throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/registry.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/registry.h b/inc/spdlog/details/registry.h
deleted file mode 100644
index fd8e4be..0000000
--- a/inc/spdlog/details/registry.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-// Loggers registy of unique name->logger pointer
-// An attempt to create a logger with an alreasy existing name will be ignored
-// If user requests a non existing logger, nullptr will be returned
-// This class is thread safe
-
-#include <string>
-#include <mutex>
-#include <unordered_map>
-#include <functional>
-
-#include "./null_mutex.h"
-#include "../logger.h"
-#include "../async_logger.h"
-#include "../common.h"
-
-namespace spdlog
-{
-namespace details
-{
-template <class Mutex> class registry_t
-{
-public:
-
-    void register_logger(std::shared_ptr<logger> logger)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        register_logger_impl(logger);
-    }
-
-
-    std::shared_ptr<logger> get(const std::string& logger_name)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        auto found = _loggers.find(logger_name);
-        return found == _loggers.end() ? nullptr : found->second;
-    }
-
-    template<class It>
-    std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
-    {
-
-        std::shared_ptr<logger> new_logger;
-
-        std::lock_guard<Mutex> lock(_mutex);
-
-
-        if (_async_mode)
-            new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms);
-        else
-            new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);
-
-        if (_formatter)
-            new_logger->set_formatter(_formatter);
-
-        new_logger->set_level(_level);
-        register_logger_impl(new_logger);
-        return new_logger;
-    }
-
-    void drop(const std::string& logger_name)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _loggers.erase(logger_name);
-    }
-
-    void drop_all()
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _loggers.clear();
-    }
-    std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks)
-    {
-        return create(logger_name, sinks.begin(), sinks.end());
-    }
-
-    std::shared_ptr<logger> create(const std::string& logger_name, sink_ptr sink)
-    {
-        return create(logger_name, { sink });
-    }
-
-
-    void formatter(formatter_ptr f)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _formatter = f;
-        for (auto& l : _loggers)
-            l.second->set_formatter(_formatter);
-    }
-
-    void set_pattern(const std::string& pattern)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _formatter = std::make_shared<pattern_formatter>(pattern);
-        for (auto& l : _loggers)
-            l.second->set_formatter(_formatter);
-    }
-
-    void set_level(level::level_enum log_level)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        for (auto& l : _loggers)
-            l.second->set_level(log_level);
-        _level = log_level;
-    }
-
-    void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _async_mode = true;
-        _async_q_size = q_size;
-        _overflow_policy = overflow_policy;
-        _worker_warmup_cb = worker_warmup_cb;
-        _flush_interval_ms = flush_interval_ms;
-    }
-
-    void set_sync_mode()
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _async_mode = false;
-    }
-
-    static registry_t<Mutex>& instance()
-    {
-        static registry_t<Mutex> s_instance;
-        return s_instance;
-    }
-
-private:
-    void register_logger_impl(std::shared_ptr<logger> logger)
-    {
-        auto logger_name = logger->name();
-        if (_loggers.find(logger_name) != std::end(_loggers))
-            throw spdlog_ex("logger with name " + logger_name + " already exists");
-        _loggers[logger->name()] = logger;
-    }
-    registry_t<Mutex>(){}
-    registry_t<Mutex>(const registry_t<Mutex>&) = delete;
-    registry_t<Mutex>& operator=(const registry_t<Mutex>&) = delete;
-    Mutex _mutex;
-    std::unordered_map <std::string, std::shared_ptr<logger>> _loggers;
-    formatter_ptr _formatter;
-    level::level_enum _level = level::info;
-    bool _async_mode = false;
-    size_t _async_q_size = 0;
-    async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
-    std::function<void()> _worker_warmup_cb = nullptr;
-    std::chrono::milliseconds _flush_interval_ms;
-};
-#ifdef SPDLOG_NO_REGISTRY_MUTEX
-typedef registry_t<spdlog::details::null_mutex> registry;
-#else
-typedef registry_t<std::mutex> registry;
-#endif
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/details/spdlog_impl.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/details/spdlog_impl.h b/inc/spdlog/details/spdlog_impl.h
deleted file mode 100644
index cfd6f82..0000000
--- a/inc/spdlog/details/spdlog_impl.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-//
-// Global registry functions
-//
-#include "registry.h"
-#include "../sinks/file_sinks.h"
-#include "../sinks/stdout_sinks.h"
-#include "../sinks/syslog_sink.h"
-
-inline void spdlog::register_logger(std::shared_ptr<logger> logger)
-{
-    return details::registry::instance().register_logger(logger);
-}
-
-inline std::shared_ptr<spdlog::logger> spdlog::get(const std::string& name)
-{
-    return details::registry::instance().get(name);
-}
-
-inline void spdlog::drop(const std::string &name)
-{
-    details::registry::instance().drop(name);
-}
-
-// Create multi/single threaded rotating file logger
-inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
-{
-    return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
-}
-
-inline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
-{
-    return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, "txt", max_file_size, max_files, force_flush);
-}
-
-// Create file logger which creates new file at midnight):
-inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
-{
-    return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, "txt", hour, minute, force_flush);
-}
-inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush)
-{
-    return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, "txt", hour, minute, force_flush);
-}
-
-
-// Create stdout/stderr loggers
-inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name)
-{
-    return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());
-}
-
-inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name)
-{
-    return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());
-}
-
-inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name)
-{
-    return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());
-}
-
-inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name)
-{
-    return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());
-}
-
-#ifdef __linux__
-// Create syslog logger
-inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
-{
-    return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option);
-}
-#endif
-
-
-//Create logger with multiple sinks
-
-inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
-{
-    return details::registry::instance().create(logger_name, sinks);
-}
-
-
-template <typename Sink, typename... Args>
-inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const Args&... args)
-{
-    sink_ptr sink = std::make_shared<Sink>(args...);
-    return details::registry::instance().create(logger_name, { sink });
-}
-
-
-template<class It>
-inline std::shared_ptr<spdlog::logger> spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
-{
-    return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
-}
-
-inline void spdlog::set_formatter(spdlog::formatter_ptr f)
-{
-    details::registry::instance().formatter(f);
-}
-
-inline void spdlog::set_pattern(const std::string& format_string)
-{
-    return details::registry::instance().set_pattern(format_string);
-}
-
-inline void spdlog::set_level(level::level_enum log_level)
-{
-    return details::registry::instance().set_level(log_level);
-}
-
-
-inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()>& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms)
-{
-    details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms);
-}
-
-inline void spdlog::set_sync_mode()
-{
-    details::registry::instance().set_sync_mode();
-}
-
-inline void spdlog::drop_all()
-{
-    details::registry::instance().drop_all();
-}
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/formatter.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/formatter.h b/inc/spdlog/formatter.h
deleted file mode 100644
index 35ea041..0000000
--- a/inc/spdlog/formatter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-#pragma once
-
-#include "details/log_msg.h"
-namespace spdlog
-{
-namespace details
-{
-class flag_formatter;
-}
-
-class formatter
-{
-public:
-    virtual ~formatter() {}
-    virtual void format(details::log_msg& msg) = 0;
-};
-
-class pattern_formatter : public formatter
-{
-
-public:
-    explicit pattern_formatter(const std::string& pattern);
-    pattern_formatter(const pattern_formatter&) = delete;
-    pattern_formatter& operator=(const pattern_formatter&) = delete;
-    void format(details::log_msg& msg) override;
-private:
-    const std::string _pattern;
-    std::vector<std::unique_ptr<details::flag_formatter>> _formatters;
-    void handle_flag(char flag);
-    void compile_pattern(const std::string& pattern);
-};
-}
-
-#include "details/pattern_formatter_impl.h"
-

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/logger.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/logger.h b/inc/spdlog/logger.h
deleted file mode 100644
index 7a5a31a..0000000
--- a/inc/spdlog/logger.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-// Thread safe logger
-// Has name, log level, vector of std::shared sink pointers and formatter
-// Upon each log write the logger:
-// 1. Checks if its log level is enough to log the message
-// 2. Format the message using the formatter function
-// 3. Pass the formatted message to its sinks to performa the actual logging
-
-#include<vector>
-#include<memory>
-#include "sinks/base_sink.h"
-#include "common.h"
-
-namespace spdlog
-{
-
-namespace details
-{
-class line_logger;
-}
-
-class logger
-{
-public:
-    logger(const std::string& logger_name, sink_ptr single_sink);
-    logger(const std::string& name, sinks_init_list);
-    template<class It>
-    logger(const std::string& name, const It& begin, const It& end);
-
-    virtual ~logger();
-    logger(const logger&) = delete;
-    logger& operator=(const logger&) = delete;
-
-    void set_level(level::level_enum);
-    level::level_enum level() const;
-
-    const std::string& name() const;
-    bool should_log(level::level_enum) const;
-
-    // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
-    template <typename... Args> details::line_logger trace(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger debug(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger info(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger notice(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger warn(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger error(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger critical(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger alert(const char* fmt, const Args&... args);
-    template <typename... Args> details::line_logger emerg(const char* fmt, const Args&... args);
-
-
-    // logger.info(msg) << ".." call style
-    template <typename T> details::line_logger trace(const T&);
-    template <typename T> details::line_logger debug(const T&);
-    template <typename T> details::line_logger info(const T&);
-    template <typename T> details::line_logger notice(const T&);
-    template <typename T> details::line_logger warn(const T&);
-    template <typename T> details::line_logger error(const T&);
-    template <typename T> details::line_logger critical(const T&);
-    template <typename T> details::line_logger alert(const T&);
-    template <typename T> details::line_logger emerg(const T&);
-
-
-    // logger.info() << ".." call  style
-    details::line_logger trace();
-    details::line_logger debug();
-    details::line_logger info();
-    details::line_logger notice();
-    details::line_logger warn();
-    details::line_logger error();
-    details::line_logger critical();
-    details::line_logger alert();
-    details::line_logger emerg();
-
-
-
-    // Create log message with the given level, no matter what is the actual logger's level
-    template <typename... Args>
-    details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
-
-    // Set the format of the log messages from this logger
-    void set_pattern(const std::string&);
-    void set_formatter(formatter_ptr);
-
-    void flush();
-
-protected:
-    virtual void _log_msg(details::log_msg&);
-    virtual void _set_pattern(const std::string&);
-    virtual void _set_formatter(formatter_ptr);
-    details::line_logger _log_if_enabled(level::level_enum lvl);
-    template <typename... Args>
-    details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
-    template<typename T>
-    inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
-
-
-    friend details::line_logger;
-    std::string _name;
-    std::vector<sink_ptr> _sinks;
-    formatter_ptr _formatter;
-    std::atomic_int _level;
-
-};
-}
-
-#include "./details/logger_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/base_sink.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/base_sink.h b/inc/spdlog/sinks/base_sink.h
deleted file mode 100644
index 12d63ea..0000000
--- a/inc/spdlog/sinks/base_sink.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-//
-// base sink templated over a mutex (either dummy or realy)
-// concrete implementation should only overrid the _sink_it method.
-// all locking is taken care of here so no locking needed by the implementors..
-//
-
-#include<string>
-#include<mutex>
-#include<atomic>
-#include "./sink.h"
-#include "../formatter.h"
-#include "../common.h"
-#include "../details/log_msg.h"
-
-
-namespace spdlog
-{
-namespace sinks
-{
-template<class Mutex>
-class base_sink:public sink
-{
-public:
-    base_sink():_mutex() {}
-    virtual ~base_sink() = default;
-
-    base_sink(const base_sink&) = delete;
-    base_sink& operator=(const base_sink&) = delete;
-
-    void log(const details::log_msg& msg) override
-    {
-        std::lock_guard<Mutex> lock(_mutex);
-        _sink_it(msg);
-    }
-
-protected:
-    virtual void _sink_it(const details::log_msg& msg) = 0;
-    Mutex _mutex;
-};
-}
-}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/spdlog/sinks/file_sinks.h
----------------------------------------------------------------------
diff --git a/inc/spdlog/sinks/file_sinks.h b/inc/spdlog/sinks/file_sinks.h
deleted file mode 100644
index 79cbb4e..0000000
--- a/inc/spdlog/sinks/file_sinks.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*************************************************************************/
-/* spdlog - an extremely fast and easy to use c++11 logging library.     */
-/* Copyright (c) 2014 Gabi Melman.                                       */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#pragma once
-
-#include <mutex>
-#include "base_sink.h"
-#include "../details/null_mutex.h"
-#include "../details/file_helper.h"
-#include "../details/format.h"
-
-namespace spdlog
-{
-namespace sinks
-{
-/*
-* Trivial file sink with single file as target
-*/
-template<class Mutex>
-class simple_file_sink : public base_sink < Mutex >
-{
-public:
-    explicit simple_file_sink(const std::string &filename,
-                              bool force_flush = false) :
-        _file_helper(force_flush)
-    {
-        _file_helper.open(filename);
-    }
-    void flush() override
-    {
-        _file_helper.flush();
-    }
-
-protected:
-    void _sink_it(const details::log_msg& msg) override
-    {
-        _file_helper.write(msg);
-    }
-private:
-    details::file_helper _file_helper;
-};
-
-typedef simple_file_sink<std::mutex> simple_file_sink_mt;
-typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
-
-/*
- * Rotating file sink based on size
- */
-template<class Mutex>
-class rotating_file_sink : public base_sink < Mutex >
-{
-public:
-    rotating_file_sink(const std::string &base_filename, const std::string &extension,
-                       std::size_t max_size, std::size_t max_files,
-                       bool force_flush = false) :
-        _base_filename(base_filename),
-        _extension(extension),
-        _max_size(max_size),
-        _max_files(max_files),
-        _current_size(0),
-        _file_helper(force_flush)
-    {
-        _file_helper.open(calc_filename(_base_filename, 0, _extension));
-    }
-
-    void flush() override
-    {
-        _file_helper.flush();
-    }
-
-protected:
-    void _sink_it(const details::log_msg& msg) override
-    {
-        _current_size += msg.formatted.size();
-        if (_current_size > _max_size)
-        {
-            _rotate();
-            _current_size = msg.formatted.size();
-        }
-        _file_helper.write(msg);
-    }
-
-private:
-    static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
-    {
-        fmt::MemoryWriter w;
-        if (index)
-            w.write("{}.{}.{}", filename, index, extension);
-        else
-            w.write("{}.{}", filename, extension);
-        return w.str();
-    }
-
-    // Rotate files:
-    // log.txt -> log.1.txt
-    // log.1.txt -> log2.txt
-    // log.2.txt -> log3.txt
-    // log.3.txt -> delete
-
-    void _rotate()
-    {
-        _file_helper.close();
-        for (auto i = _max_files; i > 0; --i)
-        {
-            std::string src = calc_filename(_base_filename, i - 1, _extension);
-            std::string target = calc_filename(_base_filename, i, _extension);
-
-            if (details::file_helper::file_exists(target))
-            {
-                if (std::remove(target.c_str()) != 0)
-                {
-                    throw spdlog_ex("rotating_file_sink: failed removing " + target);
-                }
-            }
-            if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str()))
-            {
-                throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target);
-            }
-        }
-        _file_helper.reopen(true);
-    }
-    std::string _base_filename;
-    std::string _extension;
-    std::size_t _max_size;
-    std::size_t _max_files;
-    std::size_t _current_size;
-    details::file_helper _file_helper;
-};
-
-typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
-typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
-
-/*
- * Rotating file sink based on date. rotates at midnight
- */
-template<class Mutex>
-class daily_file_sink :public base_sink < Mutex >
-{
-public:
-    //create daily file sink which rotates on given time
-    daily_file_sink(
-        const std::string& base_filename,
-        const std::string& extension,
-        int rotation_hour,
-        int rotation_minute,
-        bool force_flush = false) : _base_filename(base_filename),
-        _extension(extension),
-        _rotation_h(rotation_hour),
-        _rotation_m(rotation_minute),
-        _file_helper(force_flush)
-    {
-        if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
-            throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
-        _rotation_tp = _next_rotation_tp();
-        _file_helper.open(calc_filename(_base_filename, _extension));
-    }
-
-    void flush() override
-    {
-        _file_helper.flush();
-    }
-
-protected:
-    void _sink_it(const details::log_msg& msg) override
-    {
-        if (std::chrono::system_clock::now() >= _rotation_tp)
-        {
-            _file_helper.open(calc_filename(_base_filename, _extension));
-            _rotation_tp = _next_rotation_tp();
-        }
-        _file_helper.write(msg);
-    }
-
-private:
-    std::chrono::system_clock::time_point _next_rotation_tp()
-    {
-        using namespace std::chrono;
-        auto now = system_clock::now();
-        time_t tnow = std::chrono::system_clock::to_time_t(now);
-        tm date = spdlog::details::os::localtime(tnow);
-        date.tm_hour = _rotation_h;
-        date.tm_min = _rotation_m;
-        date.tm_sec = 0;
-        auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
-        if (rotation_time > now)
-            return rotation_time;
-        else
-            return system_clock::time_point(rotation_time + hours(24));
-    }
-
-    //Create filename for the form basename.YYYY-MM-DD.extension
-    static std::string calc_filename(const std::string& basename, const std::string& extension)
-    {
-        std::tm tm = spdlog::details::os::localtime();
-        fmt::MemoryWriter w;
-        w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
-        return w.str();
-    }
-
-    std::string _base_filename;
-    std::string _extension;
-    int _rotation_h;
-    int _rotation_m;
-    std::chrono::system_clock::time_point _rotation_tp;
-    details::file_helper _file_helper;
-};
-
-typedef daily_file_sink<std::mutex> daily_file_sink_mt;
-typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
-}
-}


[18/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Updating .travis.yml to support CMake build system.


Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/commit/b02af540
Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/b02af540
Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/b02af540

Branch: refs/heads/master
Commit: b02af540c4bc664be77174b32c4350dd7971b13d
Parents: 8beb377
Author: Aldrin Piri <al...@apache.org>
Authored: Thu May 5 17:32:57 2016 -0400
Committer: Aldrin Piri <al...@apache.org>
Committed: Thu Oct 13 11:06:55 2016 -0400

----------------------------------------------------------------------
 .gitignore                                      |    7 +
 .travis.yml                                     |    2 +-
 CMakeLists.txt                                  |   74 +
 Makefile                                        |  109 -
 README.md                                       |   90 +-
 inc/Configure.h                                 |  115 -
 inc/Connection.h                                |  201 --
 inc/Exception.h                                 |   95 -
 inc/FlowControlProtocol.h                       |  339 --
 inc/FlowController.h                            |  248 --
 inc/FlowFileRecord.h                            |  220 --
 inc/GenerateFlowFile.h                          |   87 -
 inc/GetFile.h                                   |  117 -
 inc/ListenSyslog.h                              |  209 --
 inc/LogAttribute.h                              |  128 -
 inc/Logger.h                                    |  154 -
 inc/ProcessContext.h                            |   99 -
 inc/ProcessGroup.h                              |  182 -
 inc/ProcessSession.h                            |  116 -
 inc/Processor.h                                 |  346 --
 inc/Property.h                                  |  344 --
 inc/RealTimeDataCollector.h                     |  131 -
 inc/Relationship.h                              |   87 -
 inc/RemoteProcessorGroupPort.h                  |   96 -
 inc/ResourceClaim.h                             |   92 -
 inc/SchedulingAgent.h                           |   98 -
 inc/Site2SiteClientProtocol.h                   |  638 ----
 inc/Site2SitePeer.h                             |  364 --
 inc/TailFile.h                                  |   93 -
 inc/TimeUtil.h                                  |   82 -
 inc/TimerDrivenSchedulingAgent.h                |   66 -
 inc/spdlog/async_logger.h                       |   90 -
 inc/spdlog/common.h                             |  116 -
 inc/spdlog/details/async_log_helper.h           |  326 --
 inc/spdlog/details/async_logger_impl.h          |   82 -
 inc/spdlog/details/file_helper.h                |  144 -
 inc/spdlog/details/format.cc                    | 1353 --------
 inc/spdlog/details/format.h                     | 3155 ------------------
 inc/spdlog/details/line_logger.h                |  221 --
 inc/spdlog/details/log_msg.h                    |   98 -
 inc/spdlog/details/logger_impl.h                |  320 --
 inc/spdlog/details/mpmc_bounded_q.h             |  175 -
 inc/spdlog/details/null_mutex.h                 |   43 -
 inc/spdlog/details/os.h                         |  198 --
 inc/spdlog/details/pattern_formatter_impl.h     |  628 ----
 inc/spdlog/details/registry.h                   |  180 -
 inc/spdlog/details/spdlog_impl.h                |  154 -
 inc/spdlog/formatter.h                          |   58 -
 inc/spdlog/logger.h                             |  132 -
 inc/spdlog/sinks/base_sink.h                    |   66 -
 inc/spdlog/sinks/file_sinks.h                   |  232 --
 inc/spdlog/sinks/null_sink.h                    |   52 -
 inc/spdlog/sinks/ostream_sink.h                 |   67 -
 inc/spdlog/sinks/sink.h                         |   42 -
 inc/spdlog/sinks/stdout_sinks.h                 |   71 -
 inc/spdlog/sinks/syslog_sink.h                  |  102 -
 inc/spdlog/spdlog.h                             |  155 -
 inc/spdlog/tweakme.h                            |   74 -
 include/spdlog/async_logger.h                   |   90 +
 include/spdlog/common.h                         |  116 +
 include/spdlog/details/async_log_helper.h       |  326 ++
 include/spdlog/details/async_logger_impl.h      |   82 +
 include/spdlog/details/file_helper.h            |  144 +
 include/spdlog/details/format.cc                | 1353 ++++++++
 include/spdlog/details/format.h                 | 3155 ++++++++++++++++++
 include/spdlog/details/line_logger.h            |  221 ++
 include/spdlog/details/log_msg.h                |   98 +
 include/spdlog/details/logger_impl.h            |  320 ++
 include/spdlog/details/mpmc_bounded_q.h         |  175 +
 include/spdlog/details/null_mutex.h             |   43 +
 include/spdlog/details/os.h                     |  198 ++
 include/spdlog/details/pattern_formatter_impl.h |  628 ++++
 include/spdlog/details/registry.h               |  180 +
 include/spdlog/details/spdlog_impl.h            |  154 +
 include/spdlog/formatter.h                      |   58 +
 include/spdlog/logger.h                         |  132 +
 include/spdlog/sinks/base_sink.h                |   66 +
 include/spdlog/sinks/file_sinks.h               |  232 ++
 include/spdlog/sinks/null_sink.h                |   52 +
 include/spdlog/sinks/ostream_sink.h             |   67 +
 include/spdlog/sinks/sink.h                     |   42 +
 include/spdlog/sinks/stdout_sinks.h             |   71 +
 include/spdlog/sinks/syslog_sink.h              |  102 +
 include/spdlog/spdlog.h                         |  155 +
 include/spdlog/tweakme.h                        |   74 +
 libminifi/CMakeLists.txt                        |   51 +
 libminifi/include/Configure.h                   |  115 +
 libminifi/include/Connection.h                  |  201 ++
 libminifi/include/Exception.h                   |   95 +
 libminifi/include/FlowControlProtocol.h         |  339 ++
 libminifi/include/FlowController.h              |  248 ++
 libminifi/include/FlowFileRecord.h              |  220 ++
 libminifi/include/GenerateFlowFile.h            |   87 +
 libminifi/include/GetFile.h                     |  117 +
 libminifi/include/ListenSyslog.h                |  209 ++
 libminifi/include/LogAttribute.h                |  128 +
 libminifi/include/Logger.h                      |  154 +
 libminifi/include/ProcessContext.h              |   99 +
 libminifi/include/ProcessGroup.h                |  182 +
 libminifi/include/ProcessSession.h              |  116 +
 libminifi/include/Processor.h                   |  346 ++
 libminifi/include/Property.h                    |  344 ++
 libminifi/include/RealTimeDataCollector.h       |  131 +
 libminifi/include/Relationship.h                |   87 +
 libminifi/include/RemoteProcessorGroupPort.h    |   96 +
 libminifi/include/ResourceClaim.h               |   92 +
 libminifi/include/SchedulingAgent.h             |   98 +
 libminifi/include/Site2SiteClientProtocol.h     |  638 ++++
 libminifi/include/Site2SitePeer.h               |  364 ++
 libminifi/include/TailFile.h                    |   93 +
 libminifi/include/TimeUtil.h                    |   82 +
 libminifi/include/TimerDrivenSchedulingAgent.h  |   66 +
 libminifi/src/Configure.cpp                     |  167 +
 libminifi/src/Connection.cpp                    |  160 +
 libminifi/src/FlowControlProtocol.cpp           |  541 +++
 libminifi/src/FlowController.cpp                | 1190 +++++++
 libminifi/src/FlowFileRecord.cpp                |  231 ++
 libminifi/src/GenerateFlowFile.cpp              |  134 +
 libminifi/src/GetFile.cpp                       |  295 ++
 libminifi/src/ListenSyslog.cpp                  |  342 ++
 libminifi/src/LogAttribute.cpp                  |  158 +
 libminifi/src/Logger.cpp                        |   27 +
 libminifi/src/ProcessGroup.cpp                  |  314 ++
 libminifi/src/ProcessSession.cpp                |  731 ++++
 libminifi/src/Processor.cpp                     |  451 +++
 libminifi/src/RealTimeDataCollector.cpp         |  482 +++
 libminifi/src/RemoteProcessorGroupPort.cpp      |  100 +
 libminifi/src/ResourceClaim.cpp                 |   45 +
 libminifi/src/SchedulingAgent.cpp               |   86 +
 libminifi/src/Site2SiteClientProtocol.cpp       | 1313 ++++++++
 libminifi/src/Site2SitePeer.cpp                 |  435 +++
 libminifi/src/TailFile.cpp                      |  272 ++
 libminifi/src/TimerDrivenSchedulingAgent.cpp    |  134 +
 libminifi/test/FlowFileRecordTest.cpp           |   28 +
 libminifi/test/Server.cpp                       |  607 ++++
 main/CMakeLists.txt                             |   44 +
 src/Configure.cpp                               |  167 -
 src/Connection.cpp                              |  160 -
 src/FlowControlProtocol.cpp                     |  541 ---
 src/FlowController.cpp                          | 1190 -------
 src/FlowFileRecord.cpp                          |  231 --
 src/GenerateFlowFile.cpp                        |  134 -
 src/GetFile.cpp                                 |  295 --
 src/ListenSyslog.cpp                            |  342 --
 src/LogAttribute.cpp                            |  158 -
 src/Logger.cpp                                  |   27 -
 src/ProcessGroup.cpp                            |  314 --
 src/ProcessSession.cpp                          |  731 ----
 src/Processor.cpp                               |  451 ---
 src/RealTimeDataCollector.cpp                   |  482 ---
 src/RemoteProcessorGroupPort.cpp                |  100 -
 src/ResourceClaim.cpp                           |   45 -
 src/SchedulingAgent.cpp                         |   86 -
 src/Site2SiteClientProtocol.cpp                 | 1313 --------
 src/Site2SitePeer.cpp                           |  435 ---
 src/TailFile.cpp                                |  272 --
 src/TimerDrivenSchedulingAgent.cpp              |  134 -
 test/FlowFileRecordTest.cpp                     |   28 -
 test/Server.cpp                                 |  607 ----
 thirdparty/yaml-cpp-yaml-cpp-0.5.3/Makefile     |   40 -
 160 files changed, 21572 insertions(+), 21493 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 9d78a7f..69c2234 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,10 @@
 # Filter out generated files from the included libuuid
 thirdparty/uuid/tst_uuid*
 assemblies
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Makefile
+cmake_install.cmake
+install_manifest.txt
+CTestTestfile.cmake

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index b9c9d20..eb2baa5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,7 +20,7 @@ script:
   # Establish updated toolchain as default
   - sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-4.8 /usr/bin/gcc
   - sudo unlink /usr/bin/g++ && sudo ln -s /usr/bin/g++-4.8 /usr/bin/g++
-  - make
+  - mkdir ./build && cd ./build && cmake .. && make
 
 addons:
   apt:

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..1cc95c2
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+#
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+cmake_minimum_required(VERSION 2.6)
+
+set(PROJECT "nifi-minifi-cpp")
+set(VERSION "0.1.0")
+
+#### Establish Project Configuration ####
+# Enable usage of the VERSION specifier
+# https://cmake.org/cmake/help/v3.0/policy/CMP0048.html#policy:CMP0048
+cmake_policy(SET CMP0048 NEW)
+
+project(${PROJECT}
+        VERSION ${VERSION})
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Provide custom modules for the project
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+#file(GLOB SOURCES "libminifi/src/*.cpp")
+add_subdirectory(thirdparty/yaml-cpp-yaml-cpp-0.5.3)
+add_subdirectory(libminifi)
+add_subdirectory(main)
+
+# Generate source assembly
+set(ASSEMBLY_BASE_NAME "${CMAKE_PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${ASSEMBLY_BASE_NAME}-source")
+set(CPACK_SOURCE_IGNORE_FILES "/build/;/.bzr/;~$;${CPACK_SOURCE_IGNORE_FILES}")
+
+# Generate binary assembly
+install(FILES conf/minifi.properties
+        DESTINATION conf
+        COMPONENT bin)
+
+install(PROGRAMS bin/minifi.sh
+        DESTINATION bin
+        COMPONENT bin)
+
+install(FILES LICENSE README.md NOTICE
+        DESTINATION .
+        COMPONENT bin)
+
+set(CPACK_GENERATOR "TGZ")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache NiFi MiNiFi C++ version ${VERSION}")
+set(CPACK_PACKAGE_VENDOR "Apache NiFi")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+set(CPACK_PACKAGE_FILE_NAME "${ASSEMBLY_BASE_NAME}")
+set(CPACK_BINARY_TGZ, "ON")
+
+set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+set(CPACK_COMPONENTS_ALL bin)
+
+include(CPack)

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 0b03842..0000000
--- a/Makefile
+++ /dev/null
@@ -1,109 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-
-# for ARM make CROSS_COMPILE=arm-linux-gnueabi ARCH=arm
-VERSION=0.1.0
-CC=$(CROSS_COMPILE)-g++
-AR=$(CROSS_COMPILE)-ar
-BUILD_DIR= ./build
-TARGET_DIR=./target
-ASSEMBLIES_DIR = ./assemblies
-TARGET_LIB=libminifi.a
-PROJECT=minifi
-TARGET_EXE=$(PROJECT)
-CFLAGS=-Os -fexceptions -fpermissive -Wno-write-strings -std=c++11 -fPIC -Wall -g -Wno-unused-private-field
-INCLUDES=-I./inc -I./src -I./test -I./thirdparty -I/usr/include/libxml2 -I./thirdparty/yaml-cpp-yaml-cpp-0.5.3/include
-LDDIRECTORY=-L./build -L./thirdparty/uuid -L./thirdparty/yaml-cpp-yaml-cpp-0.5.3/lib/
-LDFLAGS=-lminifi -lxml2 -pthread -luuid -lyaml-cpp
-
-UNAME_S := $(shell uname -s)
-ifeq ($(UNAME_S),Linux)
-  LDFLAGS += -lrt
-endif
-ifeq ($(UNAME_S),Darwin)
-endif
-
-OBJS:=$(shell /bin/ls src/*.cpp | xargs -n1 basename 2>/dev/null |  awk '/\.cpp$$/{a=$$0; gsub("\\.cpp$$",".o", a); print "$(BUILD_DIR)/" a}')
-TESTS:=Server
-
-all: thirdparty/yaml-cpp-yaml-cpp-0.5.3/lib/libyaml-cpp.a directory $(BUILD_DIR)/$(TARGET_LIB) minifi tests assembly-pkgs
-
-thirdparty/yaml-cpp-yaml-cpp-0.5.3/lib/libyaml-cpp.a:
-	make -C thirdparty/yaml-cpp-yaml-cpp-0.5.3
-
-
-.PHONY: directory
-directory:
-	mkdir -p $(BUILD_DIR)
-	mkdir -p $(TARGET_DIR)
-	make -C thirdparty/uuid
-
-$(BUILD_DIR)/%.o: src/%.cpp
-	$(CC) $(CFLAGS) $(INCLUDES) -o $@ -c $<
-
-$(BUILD_DIR)/$(TARGET_LIB): $(OBJS)
-	$(AR) crs $@ $(OBJS)
-
-minifi: $(BUILD_DIR)/$(TARGET_LIB) thirdparty/yaml-cpp-yaml-cpp-0.5.3/lib/libyaml-cpp.a
-	$(CC) $(CFLAGS) $(INCLUDES) -o $(BUILD_DIR)/$(TARGET_EXE) main/MiNiFiMain.cpp $(LDDIRECTORY) $(LDFLAGS)
-	cp $(BUILD_DIR)/$(TARGET_EXE) $(TARGET_DIR)/$(TARGET_EXE)
-	cp $(BUILD_DIR)/$(TARGET_EXE) bin/$(TARGET_EXE)
-
-.PHONY: tests
-tests: $(BUILD_DIR)/$(TARGET_LIB) thirdparty/yaml-cpp-yaml-cpp-0.5.3/lib/libyaml-cpp.a
-	$(foreach TEST_NAME, $(TESTS),\
-	$(CC) $(CFLAGS) $(INCLUDES) -o $(BUILD_DIR)/$(TEST_NAME) test/$(TEST_NAME).cpp $(LDDIRECTORY) $(LDFLAGS))
-
-$(ASSEMBLIES_DIR) :
-	mkdir -p $(ASSEMBLIES_DIR)
-
-.PHONY: assembly-pkgs
-assembly-pkgs: $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin.tar.gz  $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-source.tar.gz
-
-$(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-source.tar.gz : $(ASSEMBLIES_DIR)
-	mkdir -p $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-source
-	cp -r LICENSE \
-    NOTICE \
-    README.md \
-    inc \
-    src \
-    main \
-    bin \
-    conf \
-    thirdparty \
-    Makefile \
-    $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-source
-	tar -czf $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-source.tar.gz  -C $(ASSEMBLIES_DIR) $(PROJECT)-$(VERSION)-source
-
-$(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin.tar.gz : $(ASSEMBLIES_DIR) $(TARGET_EXE)
-	mkdir -p $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin
-	cp -R LICENSE \
-    NOTICE \
-    README.md \
-    conf \
-    bin \
-    $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin
-	cp target/minifi $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin/bin/
-	tar -czf $(ASSEMBLIES_DIR)/$(PROJECT)-$(VERSION)-bin.tar.gz  -C $(ASSEMBLIES_DIR) $(PROJECT)-$(VERSION)-bin
-
-.PHONY: clean
-clean:
-	rm -rf $(BUILD_DIR)
-	rm -rf $(TARGET_DIR)
-	rm -rf $(ASSEMBLIES_DIR)
-	make -C thirdparty/yaml-cpp-yaml-cpp-0.5.3 clean
-	make -C thirdparty/uuid clean

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 0b4ac50..c8abc33 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,8 @@ Perspectives of the role of MiNiFi should be from the perspective of the agent a
 ### To build
 
 #### Utilities
-* Make
+* CMake
+  * 2.8 or greater
 * gcc
   * 4.8.4 or greater
 * g++
@@ -77,33 +78,84 @@ Perspectives of the role of MiNiFi should be from the perspective of the agent a
 ## Getting Started
 
 ### Building
-From your source checkout, perform `make` in the root of the directory where the Makefile is located.  For parallel building, the '-j' or '--jobs' option maybe used.  On an average development machine, a serial build takes approximately 90 seconds.
+- From your source checkout, create a directory to perform the build (e.g. build) and cd into that directory.
+
+
+    # ~/Development/code/apache/nifi-minifi-cpp on git:master
+    $ mkdir build
+    # ~/Development/code/apache/nifi-minifi-cpp on git:master
+    $ cd build
+
+
+- Perform a `cmake ..` to generate the project files
+
+
+    # ~/Development/code/apache/nifi-minifi-cpp on git:master
+    $ cmake ..
+    ...
+    -- Configuring done
+    -- Generating done
+    -- Build files have been written to: /Users/apiri/Development/code/apache/nifi-minifi-cpp/build
+
+
+- Perform a build
+
 
     # ~/Development/code/apache/nifi-minifi-cpp on git:master
     $ make
-    make -C thirdparty/yaml-cpp-yaml-cpp-0.5.3
-    mkdir -p ./build
-    g++ -Os -I./include  -c -o build/parse.o src/parse.cpp
-    mkdir -p ./build
-    g++ -Os -I./include  -c -o build/parser.o src/parser.cpp
-    mkdir -p ./build
-    g++ -Os -I./include  -c -o build/regex_yaml.o src/regex_yaml.cpp
+    Scanning dependencies of target gmock_main
+    Scanning dependencies of target gmock
+    Scanning dependencies of target minifi
+    Scanning dependencies of target gtest
+    Scanning dependencies of target yaml-cpp
+    [  1%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/gmock-1.7.0/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
+    [  3%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/gmock-1.7.0/CMakeFiles/gmock.dir/gtest/src/gtest-all.cc.o
+    [  3%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/gmock-1.7.0/CMakeFiles/gmock.dir/src/gmock-all.cc.o
+    [  6%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/gmock-1.7.0/CMakeFiles/gmock_main.dir/gtest/src/gtest-all.cc.o
+    [  6%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/gmock-1.7.0/CMakeFiles/gmock_main.dir/src/gmock-all.cc.o
+    [  7%] Building CXX object libminifi/CMakeFiles/minifi.dir/src/Configure.cpp.o
+
     ...
 
+    [ 97%] Linking CXX executable minifi
+    [ 97%] Built target minifiexe
+    [ 98%] Building CXX object thirdparty/yaml-cpp-yaml-cpp-0.5.3/test/CMakeFiles/run-tests.dir/node/node_test.cpp.o
+    [100%] Linking CXX executable run-tests
+    [100%] Built target run-tests
+
+
+
+- Create a binary assembly located in your build directory with suffix -bin.tar.gz
+
+
+    ~/Development/code/apache/nifi-minifi-cpp/build
+    $ make package
+    Run CPack packaging tool for source...
+    CPack: Create package using TGZ
+    CPack: Install projects
+    CPack: - Install directory: ~/Development/code/apache/nifi-minifi-cpp
+    CPack: Create package
+    CPack: - package: ~/Development/code/apache/nifi-minifi-cpp/build/nifi-minifi-cpp-0.1.0-bin.tar.gz generated.
+
+
+- Create a source assembly located in your build directory with suffix -source.tar.gz
+
+
+    ~/Development/code/apache/nifi-minifi-cpp/build
+    $ make package_source
+    Run CPack packaging tool for source...
+    CPack: Create package using TGZ
+    CPack: Install projects
+    CPack: - Install directory: ~/Development/code/apache/nifi-minifi-cpp
+    CPack: Create package
+    CPack: - package: ~/Development/code/apache/nifi-minifi-cpp/build/nifi-minifi-cpp-0.1.0-source.tar.gz generated.
+
 
 ### Cleaning
-Generated files and artifacts can be removed by performing a `make clean`.
+Remove the build directory created above.
 
     # ~/Development/code/apache/nifi-minifi-cpp on git:master
-    $ make clean
-    rm -rf ./build
-    rm -rf ./target
-    rm -rf ./assemblies
-    make -C thirdparty/yaml-cpp-yaml-cpp-0.5.3 clean
-    rm -rf ./lib ./build
-    make -C thirdparty/uuid clean
-    rm -f *.o libuuid.a
-    find ./ -iname "*.o" -exec rm -f {} \;
+    $ rm -rf ./build
 
 ### Configuring
 The 'conf' directory in the root contains a template flow.yml document.  

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Configure.h
----------------------------------------------------------------------
diff --git a/inc/Configure.h b/inc/Configure.h
deleted file mode 100644
index d325fa0..0000000
--- a/inc/Configure.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * @file Configure.h
- * Configure class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __CONFIGURE_H__
-#define __CONFIGURE_H__
-
-#include <stdio.h>
-#include <string>
-#include <map>
-#include <stdlib.h>
-#include <errno.h>
-#include <iostream>
-#include <fstream>
-#include "Logger.h"
-
-class Configure {
-public:
-	//! Get the singleton logger instance
-	static Configure * getConfigure()
-	{
-		if (!_configure)
-		{
-			_configure = new Configure();
-		}
-		return _configure;
-	}
-	//! nifi.flow.configuration.file
-	static const char *nifi_flow_configuration_file;
-	static const char *nifi_administrative_yield_duration;
-	static const char *nifi_bored_yield_duration;
-	static const char *nifi_server_name;
-	static const char *nifi_server_port;
-	static const char *nifi_server_report_interval;
-
-	//! Clear the load config
-	void clear()
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		_properties.clear();
-	}
-	//! Set the config value
-	void set(std::string key, std::string value)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		_properties[key] = value;
-	}
-	//! Check whether the config value existed
-	bool has(std::string key)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		return (_properties.find(key) != _properties.end());
-	}
-	//! Get the config value
-	bool get(std::string key, std::string &value);
-	// Trim String utils
-	std::string trim(const std::string& s);
-	std::string trimLeft(const std::string& s);
-	std::string trimRight(const std::string& s);
-	//! Parse one line in configure file like key=value
-	void parseConfigureFileLine(char *buf);
-	//! Load Configure File
-	void loadConfigureFile(const char *fileName);
-    //! Set the determined MINIFI_HOME
-    void setHome(std::string minifiHome)
-    {
-        _minifiHome = minifiHome;
-    }
-
-    //! Get the determined MINIFI_HOME
-    std::string getHome()
-    {
-        return _minifiHome;
-    }
-    //! Parse Command Line
-    void parseCommandLine(int argc, char **argv);
-
-private:
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Logger
-	Logger *_logger;
-	//! Home location for this executable
-	std::string _minifiHome;
-
-	Configure()
-	{
-		_logger = Logger::getLogger();
-	}
-	virtual ~Configure()
-	{
-
-	}
-	static Configure *_configure;
-
-protected:
-	std::map<std::string,std::string> _properties;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Connection.h
----------------------------------------------------------------------
diff --git a/inc/Connection.h b/inc/Connection.h
deleted file mode 100644
index dc6b94b..0000000
--- a/inc/Connection.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * @file Connection.h
- * Connection class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __CONNECTION_H__
-#define __CONNECTION_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-
-#include "FlowFileRecord.h"
-#include "Relationship.h"
-#include "Logger.h"
-
-//! Forwarder declaration
-class Processor;
-
-//! Connection Class
-class Connection
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	Connection(std::string name, uuid_t uuid = NULL, uuid_t srcUUID = NULL, uuid_t destUUID = NULL);
-	//! Destructor
-	virtual ~Connection() {}
-	//! Set Connection Name
-	void setName(std::string name) {
-		_name = name;
-	}
-	//! Get Process Name
-	std::string getName(void) {
-		return (_name);
-	}
-	//! Set UUID
-	void setUUID(uuid_t uuid) {
-		uuid_copy(_uuid, uuid);
-	}
-	//! Set Source Processor UUID
-	void setSourceProcessorUUID(uuid_t uuid) {
-		uuid_copy(_srcUUID, uuid);
-	}
-	//! Set Destination Processor UUID
-	void setDestinationProcessorUUID(uuid_t uuid) {
-		uuid_copy(_destUUID, uuid);
-	}
-	//! Get Source Processor UUID
-	void getSourceProcessorUUID(uuid_t uuid) {
-		uuid_copy(uuid, _srcUUID);
-	}
-	//! Get Destination Processor UUID
-	void getDestinationProcessorUUID(uuid_t uuid) {
-		uuid_copy(uuid, _destUUID);
-	}
-	//! Get UUID
-	bool getUUID(uuid_t uuid) {
-		if (uuid)
-		{
-			uuid_copy(uuid, _uuid);
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Set Connection Source Processor
-	void setSourceProcessor(Processor *source) {
-		_srcProcessor = source;
-	}
-	// ! Get Connection Source Processor
-	Processor *getSourceProcessor() {
-		return _srcProcessor;
-	}
-	//! Set Connection Destination Processor
-	void setDestinationProcessor(Processor *dest) {
-		_destProcessor = dest;
-	}
-	// ! Get Connection Destination Processor
-	Processor *getDestinationProcessor() {
-		return _destProcessor;
-	}
-	//! Set Connection relationship
-	void setRelationship(Relationship relationship) {
-		_relationship = relationship;
-	}
-	// ! Get Connection relationship
-	Relationship getRelationship() {
-		return _relationship;
-	}
-	//! Set Max Queue Size
-	void setMaxQueueSize(uint64_t size)
-	{
-		_maxQueueSize = size;
-	}
-	//! Get Max Queue Size
-	uint64_t getMaxQueueSize()
-	{
-		return _maxQueueSize;
-	}
-	//! Set Max Queue Data Size
-	void setMaxQueueDataSize(uint64_t size)
-	{
-		_maxQueueDataSize = size;
-	}
-	//! Get Max Queue Data Size
-	uint64_t getMaxQueueDataSize()
-	{
-		return _maxQueueDataSize;
-	}
-	//! Set Flow expiration duration in millisecond
-	void setFlowExpirationDuration(uint64_t duration)
-	{
-		_expiredDuration = duration;
-	}
-	//! Get Flow expiration duration in millisecond
-	uint64_t getFlowExpirationDuration()
-	{
-		return _expiredDuration;
-	}
-	//! Check whether the queue is empty
-	bool isEmpty();
-	//! Check whether the queue is full to apply back pressure
-	bool isFull();
-	//! Get queue size
-	uint64_t getQueueSize() {
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _queue.size();
-	}
-	//! Get queue data size
-	uint64_t getQueueDataSize()
-	{
-		return _maxQueueDataSize;
-	}
-	//! Put the flow file into queue
-	void put(FlowFileRecord *flow);
-	//! Poll the flow file from queue, the expired flow file record also being returned
-	FlowFileRecord *poll(std::set<FlowFileRecord *> &expiredFlowRecords);
-	//! Drain the flow records
-	void drain();
-
-protected:
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! Source Processor UUID
-	uuid_t _srcUUID;
-	//! Destination Processor UUID
-	uuid_t _destUUID;
-	//! Connection Name
-	std::string _name;
-	//! Relationship for this connection
-	Relationship _relationship;
-	//! Source Processor (ProcessNode/Port)
-	Processor *_srcProcessor;
-	//! Destination Processor (ProcessNode/Port)
-	Processor *_destProcessor;
-	//! Max queue size to apply back pressure
-	std::atomic<uint64_t> _maxQueueSize;
-	//! Max queue data size to apply back pressure
-	std::atomic<uint64_t> _maxQueueDataSize;
-	//! Flow File Expiration Duration in= MilliSeconds
-	std::atomic<uint64_t> _expiredDuration;
-
-
-private:
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Queued data size
-	std::atomic<uint64_t> _queuedDataSize;
-	//! Queue for the Flow File
-	std::queue<FlowFileRecord *> _queue;
-	//! Logger
-	Logger *_logger;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Connection(const Connection &parent);
-	Connection &operator=(const Connection &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Exception.h
----------------------------------------------------------------------
diff --git a/inc/Exception.h b/inc/Exception.h
deleted file mode 100644
index d321454..0000000
--- a/inc/Exception.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @file Exception.h
- * Exception class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __EXCEPTION_H__
-#define __EXCEPTION_H__
-
-#include <sstream>
-#include <exception>
-#include <stdexcept>
-#include <errno.h>
-#include <string.h>
-
-//! ExceptionType 
-enum ExceptionType 
-{
-	FILE_OPERATION_EXCEPTION = 0,
-	FLOW_EXCEPTION,
-	PROCESSOR_EXCEPTION,
-	PROCESS_SESSION_EXCEPTION,
-	PROCESS_SCHEDULE_EXCEPTION,
-	SITE2SITE_EXCEPTION,
-	GENERAL_EXCEPTION,
-	MAX_EXCEPTION
-};
-
-//! Exception String 
-static const char *ExceptionStr[MAX_EXCEPTION] =
-{
-		"File Operation",
-		"Flow File Operation",
-		"Processor Operation",
-		"Process Session Operation",
-		"Process Schedule Operation",
-		"Site2Site Protocol",
-		"General Operation"
-};
-
-//! Exception Type to String 
-inline const char *ExceptionTypeToString(ExceptionType type)
-{
-	if (type < MAX_EXCEPTION)
-		return ExceptionStr[type];
-	else
-		return NULL;
-}
-
-//! Exception Class
-class Exception : public std::exception
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new flow record
-	 */
-	Exception(ExceptionType type, const char *errorMsg) : _type(type), _errorMsg(errorMsg) {
-	}
-	//! Destructor
-	virtual ~Exception() throw () {}
-	virtual const char * what() const throw () {
-
-		_whatStr = ExceptionTypeToString(_type);
-
-		_whatStr += ":" + _errorMsg;
-		return _whatStr.c_str();
-	}
-
-protected:
-
-private:
-	//! Exception type
-	ExceptionType _type;
-	//! Exception detailed information
-	std::string _errorMsg;
-	//! Hold the what result
-	mutable std::string _whatStr;
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/FlowControlProtocol.h
----------------------------------------------------------------------
diff --git a/inc/FlowControlProtocol.h b/inc/FlowControlProtocol.h
deleted file mode 100644
index 23f2d49..0000000
--- a/inc/FlowControlProtocol.h
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * @file FlowControlProtocol.h
- * FlowControlProtocol class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __FLOW_CONTROL_PROTOCOL_H__
-#define __FLOW_CONTROL_PROTOCOL_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <string>
-#include <errno.h>
-#include <chrono>
-#include <thread>
-#include "Logger.h"
-#include "Configure.h"
-#include "Property.h"
-
-//! Forwarder declaration
-class FlowController;
-
-#define DEFAULT_NIFI_SERVER_PORT 9000
-#define DEFAULT_REPORT_INTERVAL 1000 // 1 sec
-#define MAX_READ_TIMEOUT 30000 // 30 seconds
-
-//! FlowControl Protocol Msg Type
-typedef enum {
-	REGISTER_REQ, // Device Register Request from device to server which contain device serial number, current running flow xml version
-	REGISTER_RESP, // Device Register Respond from server to device, may contain new flow.xml from server ask device to apply and also device report interval
-	REPORT_REQ, // Period Device Report from device to server which contain device serial number, current running flow xml name/version and other period report info
-	REPORT_RESP, // Report Respond from server to device, may ask device to update flow xml or processor property
-	MAX_FLOW_CONTROL_MSG_TYPE
-} FlowControlMsgType;
-
-//! FlowControl Protocol Msg Type String
-static const char *FlowControlMsgTypeStr[MAX_FLOW_CONTROL_MSG_TYPE] =
-{
-		"REGISTER_REQ",
-		"REGISTER_RESP",
-		"REPORT_REQ",
-		"REPORT_RESP"
-};
-
-//! Flow Control Msg Type to String
-inline const char *FlowControlMsgTypeToStr(FlowControlMsgType type)
-{
-	if (type < MAX_FLOW_CONTROL_MSG_TYPE)
-		return FlowControlMsgTypeStr[type];
-	else
-		return NULL;
-}
-
-//! FlowControll Protocol Msg ID (Some Messages are fix length, Some are variable length (TLV)
-typedef enum {
-	//Fix length 8 bytes: client to server in register request, required field
-	FLOW_SERIAL_NUMBER,
-	// Flow XML name TLV: client to server in register request and report request, required field
-	FLOW_XML_NAME,
-	// Flow XML content, TLV: server to client in register respond, option field in case server want to ask client to load xml from server
-	FLOW_XML_CONTENT,
-	// Fix length, 4 bytes Report interval in msec: server to client in register respond, option field
-	REPORT_INTERVAL,
-	// Processor Name TLV:  server to client in report respond, option field in case server want to ask client to update processor property
-	PROCESSOR_NAME,
-	// Processor Property Name TLV: server to client in report respond, option field in case server want to ask client to update processor property
-	PROPERTY_NAME,
-	// Processor Property Value TLV: server to client in report respond, option field in case server want to ask client to update processor property
-	PROPERTY_VALUE,
-	// Report Blob TLV: client to server in report request, option field in case client want to pickyback the report blob in report request to server
-	REPORT_BLOB,
-	MAX_FLOW_MSG_ID
-} FlowControlMsgID;
-
-//! FlowControl Protocol Msg ID String
-static const char *FlowControlMsgIDStr[MAX_FLOW_MSG_ID] =
-{
-		"FLOW_SERIAL_NUMBER",
-		"FLOW_XML_NAME",
-		"FLOW_XML_CONTENT",
-		"REPORT_INTERVAL",
-		"PROCESSOR_NAME"
-		"PROPERTY_NAME",
-		"PROPERTY_VALUE",
-		"REPORT_BLOB"
-};
-
-#define TYPE_HDR_LEN 4 // Fix Hdr Type
-#define TLV_HDR_LEN 8 // Type 4 bytes and Len 4 bytes
-
-//! FlowControl Protocol Msg Len
-inline int FlowControlMsgIDEncodingLen(FlowControlMsgID id, int payLoadLen)
-{
-	if (id == FLOW_SERIAL_NUMBER)
-		return (TYPE_HDR_LEN + 8);
-	else if (id == REPORT_INTERVAL)
-		return (TYPE_HDR_LEN + 4);
-	else if (id < MAX_FLOW_MSG_ID)
-		return (TLV_HDR_LEN + payLoadLen);
-	else
-		return -1;
-}
-
-//! Flow Control Msg Id to String
-inline const char *FlowControlMsgIdToStr(FlowControlMsgID id)
-{
-	if (id < MAX_FLOW_MSG_ID)
-		return FlowControlMsgIDStr[id];
-	else
-		return NULL;
-}
-
-//! Flow Control Respond status code
-typedef enum {
-	RESP_SUCCESS,
-	RESP_TRIGGER_REGISTER, // Server respond to client report to re trigger register
-	RESP_START_FLOW_CONTROLLER, // Server respond to client to start flow controller
-	RESP_STOP_FLOW_CONTROLLER, // Server respond to client to stop flow controller
-	RESP_FAILURE,
-	MAX_RESP_CODE
-} FlowControlRespCode;
-
-//! FlowControl Resp Code str
-static const char *FlowControlRespCodeStr[MAX_RESP_CODE] =
-{
-		"RESP_SUCCESS",
-		"RESP_TRIGGER_REGISTER",
-		"RESP_START_FLOW_CONTROLLER",
-		"RESP_STOP_FLOW_CONTROLLER",
-		"RESP_FAILURE"
-};
-
-//! Flow Control Resp Code to String
-inline const char *FlowControlRespCodeToStr(FlowControlRespCode code)
-{
-	if (code < MAX_RESP_CODE)
-		return FlowControlRespCodeStr[code];
-	else
-		return NULL;
-}
-
-//! Common FlowControlProtocol Header
-typedef struct {
-	uint32_t msgType; //! Msg Type
-	uint32_t seqNumber; //! Seq Number to match Req with Resp
-	uint32_t status; //! Resp Code, see FlowControlRespCode
-	uint32_t payloadLen; //! Msg Payload length
-} FlowControlProtocolHeader;
-
-//! FlowControlProtocol Class
-class FlowControlProtocol
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new control protocol
-	 */
-	FlowControlProtocol(FlowController *controller) {
-		_controller = controller;
-		_logger = Logger::getLogger();
-		_configure = Configure::getConfigure();
-		_socket = 0;
-		_serverName = "localhost";
-		_serverPort = DEFAULT_NIFI_SERVER_PORT;
-		_registered = false;
-		_seqNumber = 0;
-		_reportBlob = NULL;
-		_reportBlobLen = 0;
-		_reportInterval = DEFAULT_REPORT_INTERVAL;
-		_running = false;
-
-		std::string value;
-
-		if (_configure->get(Configure::nifi_server_name, value))
-		{
-			_serverName = value;
-			_logger->log_info("NiFi Server Name %s", _serverName.c_str());
-		}
-		if (_configure->get(Configure::nifi_server_port, value) && Property::StringToInt(value, _serverPort))
-		{
-			_logger->log_info("NiFi Server Port: [%d]", _serverPort);
-		}
-		if (_configure->get(Configure::nifi_server_report_interval, value))
-		{
-			TimeUnit unit;
-			if (Property::StringToTime(value, _reportInterval, unit) &&
-						Property::ConvertTimeUnitToMS(_reportInterval, unit, _reportInterval))
-			{
-				_logger->log_info("NiFi server report interval: [%d] ms", _reportInterval);
-			}
-		}
-	}
-	//! Destructor
-	virtual ~FlowControlProtocol()
-	{
-		stop();
-		if (_socket)
-			close(_socket);
-		if (_reportBlob)
-			delete [] _reportBlob;
-		if (this->_thread)
-			delete this->_thread;
-	}
-
-public:
-
-	//! SendRegisterRequest and Process Register Respond, return 0 for success
-	int sendRegisterReq();
-	//! SendReportReq and Process Report Respond, return 0 for success
-	int sendReportReq();
-	//! Start the flow control protocol
-	void start();
-	//! Stop the flow control protocol
-	void stop();
-	//! Set Report BLOB for periodically report
-	void setReportBlob(char *blob, int len)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		if (_reportBlob && _reportBlobLen >= len)
-		{
-			memcpy(_reportBlob, blob, len);
-			_reportBlobLen = len;
-		}
-		else
-		{
-			if (_reportBlob)
-				delete[] _reportBlob;
-			_reportBlob = new char[len];
-			_reportBlobLen = len;
-		}
-	}
-	//! Run function for the thread
-	static void run(FlowControlProtocol *protocol);
-	//! set 8 bytes SerialNumber
-	void setSerialNumber(uint8_t *number)
-	{
-		memcpy(_serialNumber, number, 8);
-	}
-
-protected:
-
-private:
-	//! Connect to the socket, return sock descriptor if success, 0 for failure
-	int connectServer(const char *host, uint16_t port);
-	//! Send Data via the socket, return -1 for failure
-	int sendData(uint8_t *buf, int buflen);
-	//! Read length into buf, return -1 for failure and 0 for EOF
-	int readData(uint8_t *buf, int buflen);
-	//! Select on the socket
-	int selectClient(int msec);
-	//! Read the header
-	int readHdr(FlowControlProtocolHeader *hdr);
-	//! encode uint32_t
-	uint8_t *encode(uint8_t *buf, uint32_t value)
-	{
-		*buf++ = (value & 0xFF000000) >> 24;
-		*buf++ = (value & 0x00FF0000) >> 16;
-		*buf++ = (value & 0x0000FF00) >> 8;
-		*buf++ = (value & 0x000000FF);
-		return buf;
-	}
-	//! encode uint32_t
-	uint8_t *decode(uint8_t *buf, uint32_t &value)
-	{
-		value = ((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3]));
-		return (buf + 4);
-	}
-	//! encode byte array
-	uint8_t *encode(uint8_t *buf, uint8_t *bufArray, int size)
-	{
-		memcpy(buf, bufArray, size);
-		buf += size;
-		return buf;
-	}
-	//! encode std::string
-	uint8_t *encode(uint8_t *buf, std::string value)
-	{
-		// add the \0 for size
-		buf = encode(buf, value.size()+1);
-		buf = encode(buf, (uint8_t *) value.c_str(), value.size()+1);
-		return buf;
-	}
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Logger
-	Logger *_logger;
-	//! Configure
-	Configure *_configure;
-	//! NiFi server Name
-	std::string _serverName;
-	//! NiFi server port
-	int64_t _serverPort;
-	//! Serial Number
-	uint8_t _serialNumber[8];
-	//! socket to server
-	int _socket;
-	//! report interal in msec
-	int64_t _reportInterval;
-	//! whether it was registered to the NiFi server
-	bool _registered;
-	//! seq number
-	uint32_t _seqNumber;
-	//! FlowController
-	FlowController *_controller;
-	//! report Blob
-	char *_reportBlob;
-	//! report Blob len;
-	int _reportBlobLen;
-	//! thread
-	std::thread *_thread;
-	//! whether it is running
-	bool _running;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	FlowControlProtocol(const FlowControlProtocol &parent);
-	FlowControlProtocol &operator=(const FlowControlProtocol &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/FlowController.h
----------------------------------------------------------------------
diff --git a/inc/FlowController.h b/inc/FlowController.h
deleted file mode 100644
index 0d758df..0000000
--- a/inc/FlowController.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/**
- * @file FlowController.h
- * FlowController class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __FLOW_CONTROLLER_H__
-#define __FLOW_CONTROLLER_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-#include <set>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <yaml-cpp/yaml.h>
-
-#include "Configure.h"
-#include "Property.h"
-#include "Relationship.h"
-#include "FlowFileRecord.h"
-#include "Connection.h"
-#include "Processor.h"
-#include "ProcessContext.h"
-#include "ProcessSession.h"
-#include "ProcessGroup.h"
-#include "GenerateFlowFile.h"
-#include "LogAttribute.h"
-#include "RealTimeDataCollector.h"
-#include "TimerDrivenSchedulingAgent.h"
-#include "FlowControlProtocol.h"
-#include "RemoteProcessorGroupPort.h"
-#include "GetFile.h"
-#include "TailFile.h"
-#include "ListenSyslog.h"
-#include "ExecuteProcess.h"
-
-//! Default NiFi Root Group Name
-#define DEFAULT_ROOT_GROUP_NAME ""
-#define DEFAULT_FLOW_XML_FILE_NAME "conf/flow.xml"
-#define DEFAULT_FLOW_YAML_FILE_NAME "conf/flow.yml"
-#define CONFIG_YAML_PROCESSORS_KEY "Processors"
-
-enum class ConfigFormat { XML, YAML };
-
-struct ProcessorConfig {
-	std::string name;
-	std::string javaClass;
-	std::string maxConcurrentTasks;
-	std::string schedulingStrategy;
-	std::string schedulingPeriod;
-	std::string penalizationPeriod;
-	std::string yieldPeriod;
-	std::string runDurationNanos;
-	std::vector<std::string> autoTerminatedRelationships;
-	std::vector<Property> properties;
-};
-
-//! FlowController Class
-class FlowController
-{
-public:
-    static const int DEFAULT_MAX_TIMER_DRIVEN_THREAD = 10;
-    static const int DEFAULT_MAX_EVENT_DRIVEN_THREAD = 5;
-	//! Constructor
-	/*!
-	 * Create a new Flow Controller
-	 */
-	FlowController(std::string name = DEFAULT_ROOT_GROUP_NAME);
-	//! Destructor
-	virtual ~FlowController();
-	//! Set FlowController Name
-	void setName(std::string name) {
-		_name = name;
-	}
-	//! Get Flow Controller Name
-	std::string getName(void) {
-		return (_name);
-	}
-	//! Set UUID
-	void setUUID(uuid_t uuid) {
-		uuid_copy(_uuid, uuid);
-	}
-	//! Get UUID
-	bool getUUID(uuid_t uuid) {
-		if (uuid)
-		{
-			uuid_copy(uuid, _uuid);
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Set MAX TimerDrivenThreads
-	void setMaxTimerDrivenThreads(int number)
-	{
-		_maxTimerDrivenThreads = number;
-	}
-	//! Get MAX TimerDrivenThreads
-	int getMaxTimerDrivenThreads()
-	{
-		return _maxTimerDrivenThreads;
-	}
-	//! Set MAX EventDrivenThreads
-	void setMaxEventDrivenThreads(int number)
-	{
-		_maxEventDrivenThreads = number;
-	}
-	//! Get MAX EventDrivenThreads
-	int getMaxEventDrivenThreads()
-	{
-		return _maxEventDrivenThreads;
-	}
-	//! Create FlowFile Repository
-	bool createFlowFileRepository();
-	//! Create Content Repository
-	bool createContentRepository();
-
-	//! Life Cycle related function
-	//! Load flow xml from disk, after that, create the root process group and its children, initialize the flows
-	void load(ConfigFormat format);
-	//! Whether the Flow Controller is start running
-	bool isRunning();
-	//! Whether the Flow Controller has already been initialized (loaded flow XML)
-	bool isInitialized();
-	//! Start to run the Flow Controller which internally start the root process group and all its children
-	bool start();
-	//! Stop to run the Flow Controller which internally stop the root process group and all its children
-	void stop(bool force);
-	//! Unload the current flow xml, clean the root process group and all its children
-	void unload();
-	//! Load new xml
-	void reload(std::string xmlFile);
-	//! update property value
-	void updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue)
-	{
-		if (_root)
-			_root->updatePropertyValue(processorName, propertyName, propertyValue);
-	}
-
-	//! Create Processor (Node/Input/Output Port) based on the name
-	Processor *createProcessor(std::string name, uuid_t uuid);
-	//! Create Root Processor Group
-	ProcessGroup *createRootProcessGroup(std::string name, uuid_t uuid);
-	//! Create Remote Processor Group
-	ProcessGroup *createRemoteProcessGroup(std::string name, uuid_t uuid);
-	//! Create Connection
-	Connection *createConnection(std::string name, uuid_t uuid);
-	//! set 8 bytes SerialNumber
-	void setSerialNumber(uint8_t *number)
-	{
-		_protocol->setSerialNumber(number);
-	}
-
-protected:
-
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! FlowController Name
-	std::string _name;
-	//! Configuration File Name
-	std::string _configurationFileName;
-	//! NiFi property File Name
-	std::string _propertiesFileName;
-	//! Root Process Group
-	ProcessGroup *_root;
-	//! MAX Timer Driven Threads
-	int _maxTimerDrivenThreads;
-	//! MAX Event Driven Threads
-	int _maxEventDrivenThreads;
-	//! Config
-	//! FlowFile Repo
-	//! Provenance Repo
-	//! Flow Engines
-	//! Flow Scheduler
-	TimerDrivenSchedulingAgent _timerScheduler;
-	//! Controller Service
-	//! Config
-	//! Site to Site Server Listener
-	//! Heart Beat
-	//! FlowControl Protocol
-	FlowControlProtocol *_protocol;
-
-private:
-
-	//! Mutex for protection
-	std::mutex _mtx;
-	//! Logger
-	Logger *_logger;
-	//! Configure
-	Configure *_configure;
-	//! Whether it is running
-	std::atomic<bool> _running;
-	//! Whether it has already been initialized (load the flow XML already)
-	std::atomic<bool> _initialized;
-	//! Process Processor Node XML
-	void parseProcessorNode(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent);
-	//! Process Port XML
-	void parsePort(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent, TransferDirection direction);
-	//! Process Root Processor Group XML
-	void parseRootProcessGroup(xmlDoc *doc, xmlNode *node);
-	//! Process Property XML
-	void parseProcessorProperty(xmlDoc *doc, xmlNode *node, Processor *processor);
-	//! Process connection XML
-	void parseConnection(xmlDoc *doc, xmlNode *node, ProcessGroup *parent);
-	//! Process Remote Process Group
-	void parseRemoteProcessGroup(xmlDoc *doc, xmlNode *node, ProcessGroup *parent);
-
-	//! Process Processor Node YAML
-	void parseProcessorNodeYaml(YAML::Node processorNode, ProcessGroup *parent);
-	//! Process Port YAML
-	void parsePortYaml(YAML::Node *portNode, ProcessGroup *parent, TransferDirection direction);
-	//! Process Root Processor Group YAML
-	void parseRootProcessGroupYaml(YAML::Node rootNode);
-	//! Process Property YAML
-	void parseProcessorPropertyYaml(YAML::Node *doc, YAML::Node *node, Processor *processor);
-	//! Process connection YAML
-	void parseConnectionYaml(YAML::Node *node, ProcessGroup *parent);
-	//! Process Remote Process Group YAML
-	void parseRemoteProcessGroupYaml(YAML::Node *node, ProcessGroup *parent);
-	//! Parse Properties Node YAML for a processor
-	void parsePropertiesNodeYaml(YAML::Node *propertiesNode, Processor *processor);
-
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	FlowController(const FlowController &parent);
-	FlowController &operator=(const FlowController &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/FlowFileRecord.h
----------------------------------------------------------------------
diff --git a/inc/FlowFileRecord.h b/inc/FlowFileRecord.h
deleted file mode 100644
index 8b7362f..0000000
--- a/inc/FlowFileRecord.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * @file FlowFileRecord.h
- * Flow file record class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __FLOW_FILE_RECORD_H__
-#define __FLOW_FILE_RECORD_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <set>
-
-#include "TimeUtil.h"
-#include "Logger.h"
-#include "ResourceClaim.h"
-
-class ProcessSession;
-class Connection;
-
-#define DEFAULT_FLOWFILE_PATH "."
-
-//! FlowFile Attribute
-enum FlowAttribute
-{
-	//! The flowfile's path indicates the relative directory to which a FlowFile belongs and does not contain the filename
-	PATH = 0,
-	//! The flowfile's absolute path indicates the absolute directory to which a FlowFile belongs and does not contain the filename
-	ABSOLUTE_PATH,
-	//! The filename of the FlowFile. The filename should not contain any directory structure.
-	FILENAME,
-	//! A unique UUID assigned to this FlowFile.
-	UUID,
-	//! A numeric value indicating the FlowFile priority
-	priority,
-	//! The MIME Type of this FlowFile
-	MIME_TYPE,
-	//! Specifies the reason that a FlowFile is being discarded
-	DISCARD_REASON,
-	//! Indicates an identifier other than the FlowFile's UUID that is known to refer to this FlowFile.
-	ALTERNATE_IDENTIFIER,
-	MAX_FLOW_ATTRIBUTES
-};
-
-//! FlowFile Attribute Key
-static const char *FlowAttributeKeyArray[MAX_FLOW_ATTRIBUTES] =
-{
-		"path",
-		"absolute.path",
-		"filename",
-		"uuid",
-		"priority",
-		"mime.type",
-		"discard.reason",
-		"alternate.identifier"
-};
-
-//! FlowFile Attribute Enum to Key
-inline const char *FlowAttributeKey(FlowAttribute attribute)
-{
-	if (attribute < MAX_FLOW_ATTRIBUTES)
-		return FlowAttributeKeyArray[attribute];
-	else
-		return NULL;
-}
-
-//! FlowFile IO Callback functions for input and output
-//! throw exception for error
-class InputStreamCallback
-{
-public:
-	virtual void process(std::ifstream *stream) = 0;
-};
-class OutputStreamCallback
-{
-public:
-	virtual void process(std::ofstream *stream) = 0;
-};
-
-
-//! FlowFile Record Class
-class FlowFileRecord
-{
-	friend class ProcessSession;
-public:
-	//! Constructor
-	/*!
-	 * Create a new flow record
-	 */
-	FlowFileRecord(std::map<std::string, std::string> attributes, ResourceClaim *claim = NULL);
-	//! Destructor
-	virtual ~FlowFileRecord();
-	//! addAttribute key is enum
-	bool addAttribute(FlowAttribute key, std::string value);
-	//! addAttribute key is string
-	bool addAttribute(std::string key, std::string value);
-	//! removeAttribute key is enum
-	bool removeAttribute(FlowAttribute key);
-	//! removeAttribute key is string
-	bool removeAttribute(std::string key);
-	//! updateAttribute key is enum
-	bool updateAttribute(FlowAttribute key, std::string value);
-	//! updateAttribute key is string
-	bool updateAttribute(std::string key, std::string value);
-	//! getAttribute key is enum
-	bool getAttribute(FlowAttribute key, std::string &value);
-	//! getAttribute key is string
-	bool getAttribute(std::string key, std::string &value);
-	//! setAttribute, if attribute already there, update it, else, add it
-	void setAttribute(std::string key, std::string value) {
-		_attributes[key] = value;
-	}
-	//! Get the UUID as string
-	std::string getUUIDStr() {
-		return _uuidStr;
-	}
-	//! Get Attributes
-	std::map<std::string, std::string> getAttributes() {
-		return _attributes;
-	}
-	//! Check whether it is still being penalized
-	bool isPenalized() {
-		return (_penaltyExpirationMs > 0 ? _penaltyExpirationMs > getTimeMillis() : false);
-	}
-	//! Get Size
-	uint64_t getSize() {
-		return _size;
-	}
-	// ! Get Offset
-	uint64_t getOffset() {
-		return _offset;
-	}
-	// ! Get Entry Date
-	uint64_t getEntryDate() {
-		return _entryDate;
-	}
-	// ! Get Lineage Start Date
-	uint64_t getlineageStartDate() {
-		return _lineageStartDate;
-	}
-	// ! Set Original connection
-	void setOriginalConnection (Connection *connection) {
-		_orginalConnection = connection;
-	}
-	//! Get Resource Claim
-	ResourceClaim *getResourceClaim() {
-		return _claim;
-	}
-
-protected:
-
-	//! Date at which the flow file entered the flow
-	uint64_t _entryDate;
-	//! Date at which the origin of this flow file entered the flow
-	uint64_t _lineageStartDate;
-	//! Date at which the flow file was queued
-	uint64_t _lastQueueDate;
-	//! Size in bytes of the data corresponding to this flow file
-	uint64_t _size;
-	//! A global unique identifier
-	uuid_t _uuid;
-	//! A local unique identifier
-	uint64_t _id;
-	//! Offset to the content
-	uint64_t _offset;
-	//! Penalty expiration
-	uint64_t _penaltyExpirationMs;
-	//! Attributes key/values pairs for the flow record
-	std::map<std::string, std::string> _attributes;
-	//! Pointer to the associated content resource claim
-	ResourceClaim *_claim;
-	//! UUID string
-	std::string _uuidStr;
-	//! UUID string for all parents
-	std::set<std::string> _lineageIdentifiers;
-	//! duplicate the original flow file
-	void duplicate(FlowFileRecord *original);
-
-private:
-
-	//! Local flow sequence ID
-	static std::atomic<uint64_t> _localFlowSeqNumber;
-	//! Mark for deletion
-	bool _markedDelete;
-	//! Connection queue that this flow file will be transfer or current in
-	Connection *_connection;
-	//! Orginal connection queue that this flow file was dequeued from
-	Connection *_orginalConnection;
-	//! Logger
-	Logger *_logger;
-	//! Snapshot flow record for session rollback
-	bool _snapshot;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	FlowFileRecord(const FlowFileRecord &parent);
-	FlowFileRecord &operator=(const FlowFileRecord &parent);
-
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/GenerateFlowFile.h
----------------------------------------------------------------------
diff --git a/inc/GenerateFlowFile.h b/inc/GenerateFlowFile.h
deleted file mode 100644
index 27aa43b..0000000
--- a/inc/GenerateFlowFile.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file GenerateFlowFile.h
- * GenerateFlowFile class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __GENERATE_FLOW_FILE_H__
-#define __GENERATE_FLOW_FILE_H__
-
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! GenerateFlowFile Class
-class GenerateFlowFile : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	GenerateFlowFile(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_data = NULL;
-		_dataSize = 0;
-	}
-	//! Destructor
-	virtual ~GenerateFlowFile()
-	{
-		if (_data)
-			delete[] _data;
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property FileSize;
-	static Property BatchSize;
-	static Property DataFormat;
-	static Property UniqueFlowFiles;
-	static const char *DATA_FORMAT_BINARY;
-	static const char *DATA_FORMAT_TEXT;
-	//! Supported Relationships
-	static Relationship Success;
-	//! Nest Callback Class for write stream
-	class WriteCallback : public OutputStreamCallback
-	{
-		public:
-		WriteCallback(char *data, uint64_t size)
-		: _data(data), _dataSize(size) {}
-		char *_data;
-		uint64_t _dataSize;
-		void process(std::ofstream *stream) {
-			if (_data && _dataSize > 0)
-				stream->write(_data, _dataSize);
-		}
-	};
-
-public:
-	//! OnTrigger method, implemented by NiFi GenerateFlowFile
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi GenerateFlowFile
-	virtual void initialize(void);
-
-protected:
-
-private:
-	//! Generated data
-	char * _data;
-	//! Size of the generate data
-	uint64_t _dataSize;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/GetFile.h
----------------------------------------------------------------------
diff --git a/inc/GetFile.h b/inc/GetFile.h
deleted file mode 100644
index eb975fd..0000000
--- a/inc/GetFile.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * @file GetFile.h
- * GetFile class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __GET_FILE_H__
-#define __GET_FILE_H__
-
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! GetFile Class
-class GetFile : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	GetFile(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-		_directory = ".";
-		_recursive = true;
-		_keepSourceFile = false;
-		_minAge = 0;
-		_maxAge = 0;
-		_minSize = 0;
-		_maxSize = 0;
-		_ignoreHiddenFile = true;
-		_pollInterval = 0;
-		_batchSize = 10;
-		_lastDirectoryListingTime = getTimeMillis();
-		_fileFilter = "[^\\.].*";
-	}
-	//! Destructor
-	virtual ~GetFile()
-	{
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property Directory;
-	static Property Recurse;
-	static Property KeepSourceFile;
-	static Property MinAge;
-	static Property MaxAge;
-	static Property MinSize;
-	static Property MaxSize;
-	static Property IgnoreHiddenFile;
-	static Property PollInterval;
-	static Property BatchSize;
-	static Property FileFilter;
-	//! Supported Relationships
-	static Relationship Success;
-
-public:
-	//! OnTrigger method, implemented by NiFi GetFile
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi GetFile
-	virtual void initialize(void);
-	//! perform directory listing
-	void performListing(std::string dir);
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-	//! Queue for store directory list
-	std::queue<std::string> _dirList;
-	//! Get Listing size
-	uint64_t getListingSize() {
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _dirList.size();
-	}
-	//! Whether the directory listing is empty
-	bool isListingEmpty();
-	//! Put full path file name into directory listing
-	void putListing(std::string fileName);
-	//! Poll directory listing for files
-	void pollListing(std::queue<std::string> &list, int maxSize);
-	//! Check whether file can be added to the directory listing
-	bool acceptFile(std::string fileName);
-	//! Mutex for protection of the directory listing
-	std::mutex _mtx;
-	std::string _directory;
-	bool _recursive;
-	bool _keepSourceFile;
-	int64_t _minAge;
-	int64_t _maxAge;
-	int64_t _minSize;
-	int64_t _maxSize;
-	bool _ignoreHiddenFile;
-	int64_t _pollInterval;
-	int64_t _batchSize;
-	uint64_t _lastDirectoryListingTime;
-	std::string _fileFilter;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/ListenSyslog.h
----------------------------------------------------------------------
diff --git a/inc/ListenSyslog.h b/inc/ListenSyslog.h
deleted file mode 100644
index 81bc92c..0000000
--- a/inc/ListenSyslog.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * @file ListenSyslog.h
- * ListenSyslog class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __LISTEN_SYSLOG_H__
-#define __LISTEN_SYSLOG_H__
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <chrono>
-#include <thread>
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! SyslogEvent
-typedef struct {
-	uint8_t *payload;
-	uint64_t len;
-} SysLogEvent;
-
-//! ListenSyslog Class
-class ListenSyslog : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	ListenSyslog(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-		_eventQueueByteSize = 0;
-		_serverSocket = 0;
-		_recvBufSize = 65507;
-		_maxSocketBufSize = 1024*1024;
-		_maxConnections = 2;
-		_maxBatchSize = 1;
-		_messageDelimiter = "\n";
-		_protocol = "UDP";
-		_port = 514;
-		_parseMessages = false;
-		_serverSocket = 0;
-		_maxFds = 0;
-		FD_ZERO(&_readfds);
-		_thread = NULL;
-		_resetServerSocket = false;
-		_serverTheadRunning = false;
-	}
-	//! Destructor
-	virtual ~ListenSyslog()
-	{
-		_serverTheadRunning = false;
-		if (this->_thread)
-			delete this->_thread;
-		// need to reset the socket
-		std::vector<int>::iterator it;
-		for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
-		{
-			int clientSocket = *it;
-			close(clientSocket);
-		}
-		_clientSockets.clear();
-		if (_serverSocket > 0)
-		{
-			_logger->log_info("ListenSysLog Server socket %d close", _serverSocket);
-			close(_serverSocket);
-			_serverSocket = 0;
-		}
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property RecvBufSize;
-	static Property MaxSocketBufSize;
-	static Property MaxConnections;
-	static Property MaxBatchSize;
-	static Property MessageDelimiter;
-	static Property ParseMessages;
-	static Property Protocol;
-	static Property Port;
-	//! Supported Relationships
-	static Relationship Success;
-	static Relationship Invalid;
-	//! Nest Callback Class for write stream
-	class WriteCallback : public OutputStreamCallback
-	{
-		public:
-		WriteCallback(char *data, uint64_t size)
-		: _data(data), _dataSize(size) {}
-		char *_data;
-		uint64_t _dataSize;
-		void process(std::ofstream *stream) {
-			if (_data && _dataSize > 0)
-				stream->write(_data, _dataSize);
-		}
-	};
-
-public:
-	//! OnTrigger method, implemented by NiFi ListenSyslog
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi ListenSyslog
-	virtual void initialize(void);
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-	//! Run function for the thread
-	static void run(ListenSyslog *process);
-	//! Run Thread
-	void runThread();
-	//! Queue for store syslog event
-	std::queue<SysLogEvent> _eventQueue;
-	//! Size of Event queue in bytes
-	uint64_t _eventQueueByteSize;
-	//! Get event queue size
-	uint64_t getEventQueueSize() {
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _eventQueue.size();
-	}
-	//! Get event queue byte size
-	uint64_t getEventQueueByteSize() {
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _eventQueueByteSize;
-	}
-	//! Whether the event queue  is empty
-	bool isEventQueueEmpty()
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		return _eventQueue.empty();
-	}
-	//! Put event into directory listing
-	void putEvent(uint8_t *payload, uint64_t len)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-		SysLogEvent event;
-		event.payload = payload;
-		event.len = len;
-		_eventQueue.push(event);
-		_eventQueueByteSize += len;
-	}
-	//! Read \n terminated line from TCP socket
-	int readline( int fd, char *bufptr, size_t len );
-	//! start server socket and handling client socket
-	void startSocketThread();
-	//! Poll event
-	void pollEvent(std::queue<SysLogEvent> &list, int maxSize)
-	{
-		std::lock_guard<std::mutex> lock(_mtx);
-
-		while (!_eventQueue.empty() && (maxSize == 0 || list.size() < maxSize))
-		{
-			SysLogEvent event = _eventQueue.front();
-			_eventQueue.pop();
-			_eventQueueByteSize -= event.len;
-			list.push(event);
-		}
-		return;
-	}
-	//! Mutex for protection of the directory listing
-	std::mutex _mtx;
-	int64_t _recvBufSize;
-	int64_t _maxSocketBufSize;
-	int64_t _maxConnections;
-	int64_t _maxBatchSize;
-	std::string _messageDelimiter;
-	std::string _protocol;
-	int64_t _port;
-	bool _parseMessages;
-	int _serverSocket;
-	std::vector<int> _clientSockets;
-	int _maxFds;
-	fd_set _readfds;
-	//! thread
-	std::thread *_thread;
-	//! whether to reset the server socket
-	bool _resetServerSocket;
-	bool _serverTheadRunning;
-	//! buffer for read socket
-	uint8_t _buffer[2048];
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/LogAttribute.h
----------------------------------------------------------------------
diff --git a/inc/LogAttribute.h b/inc/LogAttribute.h
deleted file mode 100644
index 125ebf3..0000000
--- a/inc/LogAttribute.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * @file LogAttribute.h
- * LogAttribute class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __LOG_ATTRIBUTE_H__
-#define __LOG_ATTRIBUTE_H__
-
-#include "FlowFileRecord.h"
-#include "Processor.h"
-#include "ProcessSession.h"
-
-//! LogAttribute Class
-class LogAttribute : public Processor
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new processor
-	 */
-	LogAttribute(std::string name, uuid_t uuid = NULL)
-	: Processor(name, uuid)
-	{
-		_logger = Logger::getLogger();
-	}
-	//! Destructor
-	virtual ~LogAttribute()
-	{
-	}
-	//! Processor Name
-	static const std::string ProcessorName;
-	//! Supported Properties
-	static Property LogLevel;
-	static Property AttributesToLog;
-	static Property AttributesToIgnore;
-	static Property LogPayload;
-	static Property LogPrefix;
-	//! Supported Relationships
-	static Relationship Success;
-	enum LogAttrLevel {
-        LogAttrLevelTrace, LogAttrLevelDebug, LogAttrLevelInfo, LogAttrLevelWarn, LogAttrLevelError
-    };
-	//! Convert log level from string to enum
-	bool logLevelStringToEnum(std::string logStr, LogAttrLevel &level)
-	{
-		if (logStr == "trace")
-		{
-			level = LogAttrLevelTrace;
-			return true;
-		}
-		else if (logStr == "debug")
-		{
-			level = LogAttrLevelDebug;
-			return true;
-		}
-		else if (logStr == "info")
-		{
-			level = LogAttrLevelInfo;
-			return true;
-		}
-		else if (logStr == "warn")
-		{
-			level = LogAttrLevelWarn;
-			return true;
-		}
-		else if (logStr == "error")
-		{
-			level = LogAttrLevelError;
-			return true;
-		}
-		else
-			return false;
-	}
-	//! Nest Callback Class for read stream
-	class ReadCallback : public InputStreamCallback
-	{
-		public:
-		ReadCallback(uint64_t size)
-		{
-			_bufferSize = size;
-			_buffer = new char[_bufferSize];
-		}
-		~ReadCallback()
-		{
-			if (_buffer)
-				delete[] _buffer;
-		}
-		void process(std::ifstream *stream) {
-
-			stream->read(_buffer, _bufferSize);
-			if (!stream)
-				_readSize = stream->gcount();
-			else
-				_readSize = _bufferSize;
-		}
-		char  *_buffer;
-		uint64_t _bufferSize;
-		uint64_t _readSize;
-	};
-
-public:
-	//! OnTrigger method, implemented by NiFi LogAttribute
-	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
-	//! Initialize, over write by NiFi LogAttribute
-	virtual void initialize(void);
-
-protected:
-
-private:
-	//! Logger
-	Logger *_logger;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/Logger.h
----------------------------------------------------------------------
diff --git a/inc/Logger.h b/inc/Logger.h
deleted file mode 100644
index 3edad9d..0000000
--- a/inc/Logger.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * @file Logger.h
- * Logger class declaration
- * This is a C++ wrapper for spdlog, a lightweight C++ logging library
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __LOGGER_H__
-#define __LOGGER_H__
-
-#include "spdlog/spdlog.h"
-
-using spdlog::stdout_logger_mt;
-using spdlog::rotating_logger_mt;
-using spdlog::logger;
-
-#define LOG_BUFFER_SIZE 1024
-#define FILL_BUFFER  char buffer[LOG_BUFFER_SIZE]; \
-    va_list args; \
-    va_start(args, format); \
-    vsnprintf(buffer, LOG_BUFFER_SIZE,format, args); \
-    va_end(args);
-
-//! 5M default log file size
-#define DEFAULT_LOG_FILE_SIZE (5*1024*1024)
-//! 3 log files rotation
-#define DEFAULT_LOG_FILE_NUMBER 3
-#define LOG_NAME "minifi log"
-#define LOG_FILE_NAME "minifi-app.log"
-
-typedef enum
-{
-    trace    = 0,
-    debug    = 1,
-    info     = 2,
-    notice   = 3,
-    warn     = 4,
-    err      = 5,
-    critical = 6,
-    alert    = 7,
-    emerg    = 8,
-    off      = 9
-} LOG_LEVEL_E;
-
-//! Logger Class
-class Logger {
-
-public:
-
-	//! Get the singleton logger instance
-	static Logger * getLogger() {
-		if (!_logger)
-			_logger = new Logger();
-		return _logger;
-	}
-	void setLogLevel(LOG_LEVEL_E level) {
-		if (_spdlog == NULL)
-			return;
-		_spdlog->set_level((spdlog::level::level_enum) level);
-	}
-	//! Destructor
-	~Logger() {}
-	/**
-	 * @brief Log error message
-	 * @param format format string ('man printf' for syntax)
-	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
-	 */
-	void log_error(const char *const format, ...) {
-		if(_spdlog == NULL)
-			return;
-		FILL_BUFFER
-	    _spdlog->error(buffer);
-	}
-	/**
-	 * @brief Log warn message
-	 * @param format format string ('man printf' for syntax)
-	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
-	 */
-	void log_warn(const char *const format, ...) {
-		if(_spdlog == NULL)
-			return;
-		FILL_BUFFER
-	    _spdlog->warn(buffer);
-	}
-	/**
-	 * @brief Log info message
-	 * @param format format string ('man printf' for syntax)
-	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
-	 */
-	void log_info(const char *const format, ...) {
-		if(_spdlog == NULL)
-			return;
-		FILL_BUFFER
-	    _spdlog->info(buffer);
-	}
-	/**
-	 * @brief Log debug message
-	 * @param format format string ('man printf' for syntax)
-	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
-	 */
-	void log_debug(const char *const format, ...) {
-		if(_spdlog == NULL)
-			return;
-		FILL_BUFFER
-	    _spdlog->debug(buffer);
-	}
-	/**
-	 * @brief Log trace message
-	 * @param format format string ('man printf' for syntax)
-	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
-	 */
-	void log_trace(const char *const format, ...) {
-		if(_spdlog == NULL)
-			return;
-		FILL_BUFFER
-	    _spdlog->trace(buffer);
-	}
-
-protected:
-
-private:
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	Logger(const Logger &parent);
-	Logger &operator=(const Logger &parent);
-	//! Constructor
-	/*!
-	 * Create a logger
-	 * */
-	Logger(const std::string logger_name = LOG_NAME, const std::string filename = LOG_FILE_NAME, size_t max_file_size = DEFAULT_LOG_FILE_SIZE, size_t max_files = DEFAULT_LOG_FILE_NUMBER, bool force_flush = true) {
-        _spdlog = rotating_logger_mt(logger_name, filename, max_file_size, max_files, force_flush);
-		_spdlog->set_level((spdlog::level::level_enum) debug);
-	}
-	//! spdlog
-	std::shared_ptr<logger> _spdlog;
-
-	//! Singleton logger instance
-	static Logger *_logger;
-};
-
-#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/inc/ProcessContext.h
----------------------------------------------------------------------
diff --git a/inc/ProcessContext.h b/inc/ProcessContext.h
deleted file mode 100644
index 2a88b93..0000000
--- a/inc/ProcessContext.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * @file ProcessContext.h
- * ProcessContext class declaration
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __PROCESS_CONTEXT_H__
-#define __PROCESS_CONTEXT_H__
-
-#include <uuid/uuid.h>
-#include <vector>
-#include <queue>
-#include <map>
-#include <mutex>
-#include <atomic>
-#include <algorithm>
-
-#include "Logger.h"
-#include "Processor.h"
-
-//! ProcessContext Class
-class ProcessContext
-{
-public:
-	//! Constructor
-	/*!
-	 * Create a new process context associated with the processor/controller service/state manager
-	 */
-	ProcessContext(Processor *processor = NULL) : _processor(processor) {
-		_logger = Logger::getLogger();
-	}
-	//! Destructor
-	virtual ~ProcessContext() {}
-	//! Get Processor associated with the Process Context
-	Processor *getProcessor() {
-		return _processor;
-	}
-	bool getProperty(std::string name, std::string &value) {
-		if (_processor)
-			return _processor->getProperty(name, value);
-		else
-			return false;
-	}
-	//! Whether the relationship is supported
-	bool isSupportedRelationship(Relationship relationship) {
-		if (_processor)
-			return _processor->isSupportedRelationship(relationship);
-		else
-			return false;
-	}
-	//! Check whether the relationship is auto terminated
-	bool isAutoTerminated(Relationship relationship) {
-		if (_processor)
-			return _processor->isAutoTerminated(relationship);
-		else
-			return false;
-	}
-	//! Get ProcessContext Maximum Concurrent Tasks
-	uint8_t getMaxConcurrentTasks(void) {
-		if (_processor)
-			return _processor->getMaxConcurrentTasks();
-		else
-			return 0;
-	}
-	//! Yield based on the yield period
-	void yield() {
-		if (_processor)
-			_processor->yield();
-	}
-
-protected:
-
-private:
-
-	//! Processor
-	Processor *_processor;
-	// Prevent default copy constructor and assignment operation
-	// Only support pass by reference or pointer
-	ProcessContext(const ProcessContext &parent);
-	ProcessContext &operator=(const ProcessContext &parent);
-	//! Logger
-	Logger *_logger;
-
-};
-
-#endif


[09/18] nifi-minifi-cpp git commit: MINIFI-34 Establishing CMake build system to provide build functionality equivalent to pre-existing Makefile.

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/null_sink.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/null_sink.h b/include/spdlog/sinks/null_sink.h
new file mode 100644
index 0000000..992b3b7
--- /dev/null
+++ b/include/spdlog/sinks/null_sink.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+#include <mutex>
+#include "./base_sink.h"
+#include "../details/null_mutex.h"
+
+
+namespace spdlog
+{
+namespace sinks
+{
+
+template <class Mutex>
+class null_sink : public base_sink < Mutex >
+{
+protected:
+    void _sink_it(const details::log_msg&) override
+    {}
+
+    void flush() override
+    {}
+
+};
+typedef null_sink<details::null_mutex> null_sink_st;
+typedef null_sink<std::mutex> null_sink_mt;
+
+}
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/ostream_sink.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/ostream_sink.h b/include/spdlog/sinks/ostream_sink.h
new file mode 100644
index 0000000..f2fe3b2
--- /dev/null
+++ b/include/spdlog/sinks/ostream_sink.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <ostream>
+#include <mutex>
+#include <memory>
+
+#include "../details/null_mutex.h"
+#include "./base_sink.h"
+
+namespace spdlog
+{
+namespace sinks
+{
+template<class Mutex>
+class ostream_sink: public base_sink<Mutex>
+{
+public:
+    explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
+    ostream_sink(const ostream_sink&) = delete;
+    ostream_sink& operator=(const ostream_sink&) = delete;
+    virtual ~ostream_sink() = default;
+
+protected:
+    void _sink_it(const details::log_msg& msg) override
+    {
+        _ostream.write(msg.formatted.data(), msg.formatted.size());
+        if (_force_flush)
+            _ostream.flush();
+    }
+
+    void flush() override
+    {
+        _ostream.flush();
+    }
+
+    std::ostream& _ostream;
+    bool _force_flush;
+};
+
+typedef ostream_sink<std::mutex> ostream_sink_mt;
+typedef ostream_sink<details::null_mutex> ostream_sink_st;
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/sink.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/sink.h b/include/spdlog/sinks/sink.h
new file mode 100644
index 0000000..88c423a
--- /dev/null
+++ b/include/spdlog/sinks/sink.h
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include "../details/log_msg.h"
+
+namespace spdlog
+{
+namespace sinks
+{
+class sink
+{
+public:
+    virtual ~sink() {}
+    virtual void log(const details::log_msg& msg) = 0;
+    virtual void flush() = 0;
+};
+}
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/stdout_sinks.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/stdout_sinks.h b/include/spdlog/sinks/stdout_sinks.h
new file mode 100644
index 0000000..4ca16ac
--- /dev/null
+++ b/include/spdlog/sinks/stdout_sinks.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#include <iostream>
+#include <mutex>
+#include "./ostream_sink.h"
+#include "spdlog/details/null_mutex.h"
+
+namespace spdlog
+{
+namespace sinks
+{
+
+template <class Mutex>
+class stdout_sink : public ostream_sink<Mutex>
+{
+    using MyType = stdout_sink<Mutex>;
+public:
+    stdout_sink() : ostream_sink<Mutex>(std::cout, true) {}
+    static std::shared_ptr<MyType> instance()
+    {
+        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
+        return instance;
+    }
+};
+
+typedef stdout_sink<details::null_mutex> stdout_sink_st;
+typedef stdout_sink<std::mutex> stdout_sink_mt;
+
+
+template <class Mutex>
+class stderr_sink : public ostream_sink<Mutex>
+{
+    using MyType = stderr_sink<Mutex>;
+public:
+    stderr_sink() : ostream_sink<Mutex>(std::cerr, true) {}
+    static std::shared_ptr<MyType> instance()
+    {
+        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
+        return instance;
+    }
+
+};
+
+typedef stderr_sink<std::mutex> stderr_sink_mt;
+typedef stderr_sink<details::null_mutex> stderr_sink_st;
+}
+}

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/sinks/syslog_sink.h
----------------------------------------------------------------------
diff --git a/include/spdlog/sinks/syslog_sink.h b/include/spdlog/sinks/syslog_sink.h
new file mode 100644
index 0000000..37b6513
--- /dev/null
+++ b/include/spdlog/sinks/syslog_sink.h
@@ -0,0 +1,102 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#pragma once
+
+#ifdef __linux__
+
+#include <array>
+#include <string>
+#include <syslog.h>
+
+#include "./sink.h"
+#include "../common.h"
+#include "../details/log_msg.h"
+
+
+namespace spdlog
+{
+namespace sinks
+{
+/**
+ * Sink that write to syslog using the `syscall()` library call.
+ *
+ * Locking is not needed, as `syslog()` itself is thread-safe.
+ */
+class syslog_sink : public sink
+{
+public:
+    //
+    syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER):
+        _ident(ident)
+    {
+        _priorities[static_cast<int>(level::trace)] = LOG_DEBUG;
+        _priorities[static_cast<int>(level::debug)] = LOG_DEBUG;
+        _priorities[static_cast<int>(level::info)] = LOG_INFO;
+        _priorities[static_cast<int>(level::notice)] = LOG_NOTICE;
+        _priorities[static_cast<int>(level::warn)] = LOG_WARNING;
+        _priorities[static_cast<int>(level::err)] = LOG_ERR;
+        _priorities[static_cast<int>(level::critical)] = LOG_CRIT;
+        _priorities[static_cast<int>(level::alert)] = LOG_ALERT;
+        _priorities[static_cast<int>(level::emerg)] = LOG_EMERG;
+        _priorities[static_cast<int>(level::off)] = LOG_INFO;
+
+        //set ident to be program name if empty
+        ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility);
+    }
+    ~syslog_sink()
+    {
+        ::closelog();
+    }
+
+    syslog_sink(const syslog_sink&) = delete;
+    syslog_sink& operator=(const syslog_sink&) = delete;
+
+    void log(const details::log_msg &msg) override
+    {
+        ::syslog(syslog_prio_from_level(msg), "%s", msg.formatted.str().c_str());
+    }
+
+    void flush() override
+    {
+    }
+
+
+private:
+    std::array<int, 10> _priorities;
+    //must store the ident because the man says openlog might use the pointer as is and not a string copy
+    const std::string _ident;
+
+    //
+    // Simply maps spdlog's log level to syslog priority level.
+    //
+    int syslog_prio_from_level(const details::log_msg &msg) const
+    {
+        return _priorities[static_cast<int>(msg.level)];
+    }
+};
+}
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/spdlog.h
----------------------------------------------------------------------
diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h
new file mode 100644
index 0000000..5cec562
--- /dev/null
+++ b/include/spdlog/spdlog.h
@@ -0,0 +1,155 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+
+// spdlog main header file.
+//see example.cpp for usage example
+
+#pragma once
+
+#include "tweakme.h"
+#include "common.h"
+#include "logger.h"
+
+namespace spdlog
+{
+// Return an existing logger or nullptr if a logger with such name doesn't exist.
+// Examples:
+//
+// spdlog::get("mylog")->info("Hello");
+// auto logger = spdlog::get("mylog");
+// logger.info("This is another message" , x, y, z);
+// logger.info() << "This is another message" << x << y << z;
+std::shared_ptr<logger> get(const std::string& name);
+
+//
+// Set global formatting
+// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
+//
+void set_pattern(const std::string& format_string);
+void set_formatter(formatter_ptr f);
+
+//
+// Set global logging level for
+//
+void set_level(level::level_enum log_level);
+
+//
+// Turn on async mode (off by default) and set the queue size for each async_logger.
+// effective only for loggers created after this call.
+// queue_size: size of queue (must be power of 2):
+//    Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
+//
+// async_overflow_policy (optional, block_retry by default):
+//    async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
+//    async_overflow_policy::discard_log_msg - never block and discard any new messages when queue  overflows.
+//
+// worker_warmup_cb (optional):
+//     callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
+//
+void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function<void()>& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero());
+
+// Turn off async mode
+void set_sync_mode();
+
+//
+// Create and register multi/single threaded rotating file logger
+//
+std::shared_ptr<logger> rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
+std::shared_ptr<logger> rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false);
+
+//
+// Create file logger which creates new file on the given time (default in  midnight):
+//
+std::shared_ptr<logger> daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
+std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const std::string& filename, int hour=0, int minute=0, bool force_flush = false);
+
+
+//
+// Create and register stdout/stderr loggers
+//
+std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name);
+std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name);
+std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name);
+std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name);
+
+
+//
+// Create and register a syslog logger
+//
+#ifdef __linux__
+std::shared_ptr<logger> syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0);
+#endif
+
+
+// Create and register a logger with multiple sinks
+std::shared_ptr<logger> create(const std::string& logger_name, sinks_init_list sinks);
+template<class It>
+std::shared_ptr<logger> create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end);
+
+
+// Create and register a logger with templated sink type
+// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
+template <typename Sink, typename... Args>
+std::shared_ptr<spdlog::logger> create(const std::string& logger_name, const Args&...);
+
+
+// Register the given logger with the given name
+void register_logger(std::shared_ptr<logger> logger);
+
+// Drop the reference to the given logger
+void drop(const std::string &name);
+
+// Drop all references
+void drop_all();
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Macros to be display source file & line
+// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
+// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
+//
+// Example:
+// spdlog::set_level(spdlog::level::debug);
+// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SPDLOG_TRACE_ON
+#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
+#else
+#define SPDLOG_TRACE(logger, ...)
+#endif
+
+#ifdef SPDLOG_DEBUG_ON
+#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__)  << " (" << __FILE__ << " #" << __LINE__ <<")";
+#else
+#define SPDLOG_DEBUG(logger, ...)
+#endif
+
+
+}
+
+
+#include "details/spdlog_impl.h"

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/include/spdlog/tweakme.h
----------------------------------------------------------------------
diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h
new file mode 100644
index 0000000..b651658
--- /dev/null
+++ b/include/spdlog/tweakme.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* spdlog - an extremely fast and easy to use c++11 logging library.     */
+/* Copyright (c) 2014 Gabi Melman.                                       */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+
+#pragma once
+
+///////////////////////////////////////////////////////////////////////////////
+// Edit this file to squeeze every last drop of performance out of spdlog.
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.
+// This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ.
+// Uncomment to use it instead of the regular (but slower) clock.
+// #define SPDLOG_CLOCK_COARSE
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Uncomment if date/time logging is not needed.
+// This will prevent spdlog from quering the clock on each log call.
+// #define SPDLOG_NO_DATETIME
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
+// This will prevent spdlog from quering the thread id on each log call.
+// #define SPDLOG_NO_THREAD_ID
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Uncomment if logger name logging is not needed.
+// This will prevent spdlog from copying the logger name  on each log call.
+// #define SPDLOG_NO_NAME
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros.
+// #define SPDLOG_DEBUG_ON
+// #define SPDLOG_TRACE_ON
+///////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()).
+// Use only if your code never modifes concurrently the registry.
+// Note that upon creating a logger the registry is modified by spdlog..
+// #define SPDLOG_NO_REGISTRY_MUTEX
+///////////////////////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt
new file mode 100644
index 0000000..571b73d
--- /dev/null
+++ b/libminifi/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+#
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless qrequired by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+cmake_minimum_required (VERSION 2.6)
+
+set(PROJECT "apache-nifi-minifi-cpp")
+set(VERSION "0.1.0")
+
+#### Establish Project Configuration ####
+# Enable usage of the VERSION specifier
+# https://cmake.org/cmake/help/v3.0/policy/CMP0048.html#policy:CMP0048
+cmake_policy(SET CMP0048 NEW)
+
+project(${PROJECT}
+        VERSION ${VERSION})
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include_directories(../include)
+include_directories(include)
+
+file(GLOB SOURCES "src/*.cpp")
+
+add_library(spdlog INTERFACE)
+add_library(minifi STATIC ${SOURCES})
+
+# Include libxml2
+find_package (LibXml2)
+if (LIBXML2_FOUND)
+    include_directories(${LIBXML2_INCLUDE_DIR})
+    target_link_libraries (minifi ${LIBXML2_LIBRARIES})
+else ()
+    # Build from our local version
+endif (LIBXML2_FOUND)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Configure.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Configure.h b/libminifi/include/Configure.h
new file mode 100644
index 0000000..d325fa0
--- /dev/null
+++ b/libminifi/include/Configure.h
@@ -0,0 +1,115 @@
+/**
+ * @file Configure.h
+ * Configure class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __CONFIGURE_H__
+#define __CONFIGURE_H__
+
+#include <stdio.h>
+#include <string>
+#include <map>
+#include <stdlib.h>
+#include <errno.h>
+#include <iostream>
+#include <fstream>
+#include "Logger.h"
+
+class Configure {
+public:
+	//! Get the singleton logger instance
+	static Configure * getConfigure()
+	{
+		if (!_configure)
+		{
+			_configure = new Configure();
+		}
+		return _configure;
+	}
+	//! nifi.flow.configuration.file
+	static const char *nifi_flow_configuration_file;
+	static const char *nifi_administrative_yield_duration;
+	static const char *nifi_bored_yield_duration;
+	static const char *nifi_server_name;
+	static const char *nifi_server_port;
+	static const char *nifi_server_report_interval;
+
+	//! Clear the load config
+	void clear()
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		_properties.clear();
+	}
+	//! Set the config value
+	void set(std::string key, std::string value)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		_properties[key] = value;
+	}
+	//! Check whether the config value existed
+	bool has(std::string key)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		return (_properties.find(key) != _properties.end());
+	}
+	//! Get the config value
+	bool get(std::string key, std::string &value);
+	// Trim String utils
+	std::string trim(const std::string& s);
+	std::string trimLeft(const std::string& s);
+	std::string trimRight(const std::string& s);
+	//! Parse one line in configure file like key=value
+	void parseConfigureFileLine(char *buf);
+	//! Load Configure File
+	void loadConfigureFile(const char *fileName);
+    //! Set the determined MINIFI_HOME
+    void setHome(std::string minifiHome)
+    {
+        _minifiHome = minifiHome;
+    }
+
+    //! Get the determined MINIFI_HOME
+    std::string getHome()
+    {
+        return _minifiHome;
+    }
+    //! Parse Command Line
+    void parseCommandLine(int argc, char **argv);
+
+private:
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Logger
+	Logger *_logger;
+	//! Home location for this executable
+	std::string _minifiHome;
+
+	Configure()
+	{
+		_logger = Logger::getLogger();
+	}
+	virtual ~Configure()
+	{
+
+	}
+	static Configure *_configure;
+
+protected:
+	std::map<std::string,std::string> _properties;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Connection.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Connection.h b/libminifi/include/Connection.h
new file mode 100644
index 0000000..dc6b94b
--- /dev/null
+++ b/libminifi/include/Connection.h
@@ -0,0 +1,201 @@
+/**
+ * @file Connection.h
+ * Connection class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+
+#include "FlowFileRecord.h"
+#include "Relationship.h"
+#include "Logger.h"
+
+//! Forwarder declaration
+class Processor;
+
+//! Connection Class
+class Connection
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	Connection(std::string name, uuid_t uuid = NULL, uuid_t srcUUID = NULL, uuid_t destUUID = NULL);
+	//! Destructor
+	virtual ~Connection() {}
+	//! Set Connection Name
+	void setName(std::string name) {
+		_name = name;
+	}
+	//! Get Process Name
+	std::string getName(void) {
+		return (_name);
+	}
+	//! Set UUID
+	void setUUID(uuid_t uuid) {
+		uuid_copy(_uuid, uuid);
+	}
+	//! Set Source Processor UUID
+	void setSourceProcessorUUID(uuid_t uuid) {
+		uuid_copy(_srcUUID, uuid);
+	}
+	//! Set Destination Processor UUID
+	void setDestinationProcessorUUID(uuid_t uuid) {
+		uuid_copy(_destUUID, uuid);
+	}
+	//! Get Source Processor UUID
+	void getSourceProcessorUUID(uuid_t uuid) {
+		uuid_copy(uuid, _srcUUID);
+	}
+	//! Get Destination Processor UUID
+	void getDestinationProcessorUUID(uuid_t uuid) {
+		uuid_copy(uuid, _destUUID);
+	}
+	//! Get UUID
+	bool getUUID(uuid_t uuid) {
+		if (uuid)
+		{
+			uuid_copy(uuid, _uuid);
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Set Connection Source Processor
+	void setSourceProcessor(Processor *source) {
+		_srcProcessor = source;
+	}
+	// ! Get Connection Source Processor
+	Processor *getSourceProcessor() {
+		return _srcProcessor;
+	}
+	//! Set Connection Destination Processor
+	void setDestinationProcessor(Processor *dest) {
+		_destProcessor = dest;
+	}
+	// ! Get Connection Destination Processor
+	Processor *getDestinationProcessor() {
+		return _destProcessor;
+	}
+	//! Set Connection relationship
+	void setRelationship(Relationship relationship) {
+		_relationship = relationship;
+	}
+	// ! Get Connection relationship
+	Relationship getRelationship() {
+		return _relationship;
+	}
+	//! Set Max Queue Size
+	void setMaxQueueSize(uint64_t size)
+	{
+		_maxQueueSize = size;
+	}
+	//! Get Max Queue Size
+	uint64_t getMaxQueueSize()
+	{
+		return _maxQueueSize;
+	}
+	//! Set Max Queue Data Size
+	void setMaxQueueDataSize(uint64_t size)
+	{
+		_maxQueueDataSize = size;
+	}
+	//! Get Max Queue Data Size
+	uint64_t getMaxQueueDataSize()
+	{
+		return _maxQueueDataSize;
+	}
+	//! Set Flow expiration duration in millisecond
+	void setFlowExpirationDuration(uint64_t duration)
+	{
+		_expiredDuration = duration;
+	}
+	//! Get Flow expiration duration in millisecond
+	uint64_t getFlowExpirationDuration()
+	{
+		return _expiredDuration;
+	}
+	//! Check whether the queue is empty
+	bool isEmpty();
+	//! Check whether the queue is full to apply back pressure
+	bool isFull();
+	//! Get queue size
+	uint64_t getQueueSize() {
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _queue.size();
+	}
+	//! Get queue data size
+	uint64_t getQueueDataSize()
+	{
+		return _maxQueueDataSize;
+	}
+	//! Put the flow file into queue
+	void put(FlowFileRecord *flow);
+	//! Poll the flow file from queue, the expired flow file record also being returned
+	FlowFileRecord *poll(std::set<FlowFileRecord *> &expiredFlowRecords);
+	//! Drain the flow records
+	void drain();
+
+protected:
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! Source Processor UUID
+	uuid_t _srcUUID;
+	//! Destination Processor UUID
+	uuid_t _destUUID;
+	//! Connection Name
+	std::string _name;
+	//! Relationship for this connection
+	Relationship _relationship;
+	//! Source Processor (ProcessNode/Port)
+	Processor *_srcProcessor;
+	//! Destination Processor (ProcessNode/Port)
+	Processor *_destProcessor;
+	//! Max queue size to apply back pressure
+	std::atomic<uint64_t> _maxQueueSize;
+	//! Max queue data size to apply back pressure
+	std::atomic<uint64_t> _maxQueueDataSize;
+	//! Flow File Expiration Duration in= MilliSeconds
+	std::atomic<uint64_t> _expiredDuration;
+
+
+private:
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Queued data size
+	std::atomic<uint64_t> _queuedDataSize;
+	//! Queue for the Flow File
+	std::queue<FlowFileRecord *> _queue;
+	//! Logger
+	Logger *_logger;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Connection(const Connection &parent);
+	Connection &operator=(const Connection &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Exception.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Exception.h b/libminifi/include/Exception.h
new file mode 100644
index 0000000..d321454
--- /dev/null
+++ b/libminifi/include/Exception.h
@@ -0,0 +1,95 @@
+/**
+ * @file Exception.h
+ * Exception class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __EXCEPTION_H__
+#define __EXCEPTION_H__
+
+#include <sstream>
+#include <exception>
+#include <stdexcept>
+#include <errno.h>
+#include <string.h>
+
+//! ExceptionType 
+enum ExceptionType 
+{
+	FILE_OPERATION_EXCEPTION = 0,
+	FLOW_EXCEPTION,
+	PROCESSOR_EXCEPTION,
+	PROCESS_SESSION_EXCEPTION,
+	PROCESS_SCHEDULE_EXCEPTION,
+	SITE2SITE_EXCEPTION,
+	GENERAL_EXCEPTION,
+	MAX_EXCEPTION
+};
+
+//! Exception String 
+static const char *ExceptionStr[MAX_EXCEPTION] =
+{
+		"File Operation",
+		"Flow File Operation",
+		"Processor Operation",
+		"Process Session Operation",
+		"Process Schedule Operation",
+		"Site2Site Protocol",
+		"General Operation"
+};
+
+//! Exception Type to String 
+inline const char *ExceptionTypeToString(ExceptionType type)
+{
+	if (type < MAX_EXCEPTION)
+		return ExceptionStr[type];
+	else
+		return NULL;
+}
+
+//! Exception Class
+class Exception : public std::exception
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new flow record
+	 */
+	Exception(ExceptionType type, const char *errorMsg) : _type(type), _errorMsg(errorMsg) {
+	}
+	//! Destructor
+	virtual ~Exception() throw () {}
+	virtual const char * what() const throw () {
+
+		_whatStr = ExceptionTypeToString(_type);
+
+		_whatStr += ":" + _errorMsg;
+		return _whatStr.c_str();
+	}
+
+protected:
+
+private:
+	//! Exception type
+	ExceptionType _type;
+	//! Exception detailed information
+	std::string _errorMsg;
+	//! Hold the what result
+	mutable std::string _whatStr;
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/FlowControlProtocol.h
----------------------------------------------------------------------
diff --git a/libminifi/include/FlowControlProtocol.h b/libminifi/include/FlowControlProtocol.h
new file mode 100644
index 0000000..23f2d49
--- /dev/null
+++ b/libminifi/include/FlowControlProtocol.h
@@ -0,0 +1,339 @@
+/**
+ * @file FlowControlProtocol.h
+ * FlowControlProtocol class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __FLOW_CONTROL_PROTOCOL_H__
+#define __FLOW_CONTROL_PROTOCOL_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <string>
+#include <errno.h>
+#include <chrono>
+#include <thread>
+#include "Logger.h"
+#include "Configure.h"
+#include "Property.h"
+
+//! Forwarder declaration
+class FlowController;
+
+#define DEFAULT_NIFI_SERVER_PORT 9000
+#define DEFAULT_REPORT_INTERVAL 1000 // 1 sec
+#define MAX_READ_TIMEOUT 30000 // 30 seconds
+
+//! FlowControl Protocol Msg Type
+typedef enum {
+	REGISTER_REQ, // Device Register Request from device to server which contain device serial number, current running flow xml version
+	REGISTER_RESP, // Device Register Respond from server to device, may contain new flow.xml from server ask device to apply and also device report interval
+	REPORT_REQ, // Period Device Report from device to server which contain device serial number, current running flow xml name/version and other period report info
+	REPORT_RESP, // Report Respond from server to device, may ask device to update flow xml or processor property
+	MAX_FLOW_CONTROL_MSG_TYPE
+} FlowControlMsgType;
+
+//! FlowControl Protocol Msg Type String
+static const char *FlowControlMsgTypeStr[MAX_FLOW_CONTROL_MSG_TYPE] =
+{
+		"REGISTER_REQ",
+		"REGISTER_RESP",
+		"REPORT_REQ",
+		"REPORT_RESP"
+};
+
+//! Flow Control Msg Type to String
+inline const char *FlowControlMsgTypeToStr(FlowControlMsgType type)
+{
+	if (type < MAX_FLOW_CONTROL_MSG_TYPE)
+		return FlowControlMsgTypeStr[type];
+	else
+		return NULL;
+}
+
+//! FlowControll Protocol Msg ID (Some Messages are fix length, Some are variable length (TLV)
+typedef enum {
+	//Fix length 8 bytes: client to server in register request, required field
+	FLOW_SERIAL_NUMBER,
+	// Flow XML name TLV: client to server in register request and report request, required field
+	FLOW_XML_NAME,
+	// Flow XML content, TLV: server to client in register respond, option field in case server want to ask client to load xml from server
+	FLOW_XML_CONTENT,
+	// Fix length, 4 bytes Report interval in msec: server to client in register respond, option field
+	REPORT_INTERVAL,
+	// Processor Name TLV:  server to client in report respond, option field in case server want to ask client to update processor property
+	PROCESSOR_NAME,
+	// Processor Property Name TLV: server to client in report respond, option field in case server want to ask client to update processor property
+	PROPERTY_NAME,
+	// Processor Property Value TLV: server to client in report respond, option field in case server want to ask client to update processor property
+	PROPERTY_VALUE,
+	// Report Blob TLV: client to server in report request, option field in case client want to pickyback the report blob in report request to server
+	REPORT_BLOB,
+	MAX_FLOW_MSG_ID
+} FlowControlMsgID;
+
+//! FlowControl Protocol Msg ID String
+static const char *FlowControlMsgIDStr[MAX_FLOW_MSG_ID] =
+{
+		"FLOW_SERIAL_NUMBER",
+		"FLOW_XML_NAME",
+		"FLOW_XML_CONTENT",
+		"REPORT_INTERVAL",
+		"PROCESSOR_NAME"
+		"PROPERTY_NAME",
+		"PROPERTY_VALUE",
+		"REPORT_BLOB"
+};
+
+#define TYPE_HDR_LEN 4 // Fix Hdr Type
+#define TLV_HDR_LEN 8 // Type 4 bytes and Len 4 bytes
+
+//! FlowControl Protocol Msg Len
+inline int FlowControlMsgIDEncodingLen(FlowControlMsgID id, int payLoadLen)
+{
+	if (id == FLOW_SERIAL_NUMBER)
+		return (TYPE_HDR_LEN + 8);
+	else if (id == REPORT_INTERVAL)
+		return (TYPE_HDR_LEN + 4);
+	else if (id < MAX_FLOW_MSG_ID)
+		return (TLV_HDR_LEN + payLoadLen);
+	else
+		return -1;
+}
+
+//! Flow Control Msg Id to String
+inline const char *FlowControlMsgIdToStr(FlowControlMsgID id)
+{
+	if (id < MAX_FLOW_MSG_ID)
+		return FlowControlMsgIDStr[id];
+	else
+		return NULL;
+}
+
+//! Flow Control Respond status code
+typedef enum {
+	RESP_SUCCESS,
+	RESP_TRIGGER_REGISTER, // Server respond to client report to re trigger register
+	RESP_START_FLOW_CONTROLLER, // Server respond to client to start flow controller
+	RESP_STOP_FLOW_CONTROLLER, // Server respond to client to stop flow controller
+	RESP_FAILURE,
+	MAX_RESP_CODE
+} FlowControlRespCode;
+
+//! FlowControl Resp Code str
+static const char *FlowControlRespCodeStr[MAX_RESP_CODE] =
+{
+		"RESP_SUCCESS",
+		"RESP_TRIGGER_REGISTER",
+		"RESP_START_FLOW_CONTROLLER",
+		"RESP_STOP_FLOW_CONTROLLER",
+		"RESP_FAILURE"
+};
+
+//! Flow Control Resp Code to String
+inline const char *FlowControlRespCodeToStr(FlowControlRespCode code)
+{
+	if (code < MAX_RESP_CODE)
+		return FlowControlRespCodeStr[code];
+	else
+		return NULL;
+}
+
+//! Common FlowControlProtocol Header
+typedef struct {
+	uint32_t msgType; //! Msg Type
+	uint32_t seqNumber; //! Seq Number to match Req with Resp
+	uint32_t status; //! Resp Code, see FlowControlRespCode
+	uint32_t payloadLen; //! Msg Payload length
+} FlowControlProtocolHeader;
+
+//! FlowControlProtocol Class
+class FlowControlProtocol
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new control protocol
+	 */
+	FlowControlProtocol(FlowController *controller) {
+		_controller = controller;
+		_logger = Logger::getLogger();
+		_configure = Configure::getConfigure();
+		_socket = 0;
+		_serverName = "localhost";
+		_serverPort = DEFAULT_NIFI_SERVER_PORT;
+		_registered = false;
+		_seqNumber = 0;
+		_reportBlob = NULL;
+		_reportBlobLen = 0;
+		_reportInterval = DEFAULT_REPORT_INTERVAL;
+		_running = false;
+
+		std::string value;
+
+		if (_configure->get(Configure::nifi_server_name, value))
+		{
+			_serverName = value;
+			_logger->log_info("NiFi Server Name %s", _serverName.c_str());
+		}
+		if (_configure->get(Configure::nifi_server_port, value) && Property::StringToInt(value, _serverPort))
+		{
+			_logger->log_info("NiFi Server Port: [%d]", _serverPort);
+		}
+		if (_configure->get(Configure::nifi_server_report_interval, value))
+		{
+			TimeUnit unit;
+			if (Property::StringToTime(value, _reportInterval, unit) &&
+						Property::ConvertTimeUnitToMS(_reportInterval, unit, _reportInterval))
+			{
+				_logger->log_info("NiFi server report interval: [%d] ms", _reportInterval);
+			}
+		}
+	}
+	//! Destructor
+	virtual ~FlowControlProtocol()
+	{
+		stop();
+		if (_socket)
+			close(_socket);
+		if (_reportBlob)
+			delete [] _reportBlob;
+		if (this->_thread)
+			delete this->_thread;
+	}
+
+public:
+
+	//! SendRegisterRequest and Process Register Respond, return 0 for success
+	int sendRegisterReq();
+	//! SendReportReq and Process Report Respond, return 0 for success
+	int sendReportReq();
+	//! Start the flow control protocol
+	void start();
+	//! Stop the flow control protocol
+	void stop();
+	//! Set Report BLOB for periodically report
+	void setReportBlob(char *blob, int len)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		if (_reportBlob && _reportBlobLen >= len)
+		{
+			memcpy(_reportBlob, blob, len);
+			_reportBlobLen = len;
+		}
+		else
+		{
+			if (_reportBlob)
+				delete[] _reportBlob;
+			_reportBlob = new char[len];
+			_reportBlobLen = len;
+		}
+	}
+	//! Run function for the thread
+	static void run(FlowControlProtocol *protocol);
+	//! set 8 bytes SerialNumber
+	void setSerialNumber(uint8_t *number)
+	{
+		memcpy(_serialNumber, number, 8);
+	}
+
+protected:
+
+private:
+	//! Connect to the socket, return sock descriptor if success, 0 for failure
+	int connectServer(const char *host, uint16_t port);
+	//! Send Data via the socket, return -1 for failure
+	int sendData(uint8_t *buf, int buflen);
+	//! Read length into buf, return -1 for failure and 0 for EOF
+	int readData(uint8_t *buf, int buflen);
+	//! Select on the socket
+	int selectClient(int msec);
+	//! Read the header
+	int readHdr(FlowControlProtocolHeader *hdr);
+	//! encode uint32_t
+	uint8_t *encode(uint8_t *buf, uint32_t value)
+	{
+		*buf++ = (value & 0xFF000000) >> 24;
+		*buf++ = (value & 0x00FF0000) >> 16;
+		*buf++ = (value & 0x0000FF00) >> 8;
+		*buf++ = (value & 0x000000FF);
+		return buf;
+	}
+	//! encode uint32_t
+	uint8_t *decode(uint8_t *buf, uint32_t &value)
+	{
+		value = ((buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|(buf[3]));
+		return (buf + 4);
+	}
+	//! encode byte array
+	uint8_t *encode(uint8_t *buf, uint8_t *bufArray, int size)
+	{
+		memcpy(buf, bufArray, size);
+		buf += size;
+		return buf;
+	}
+	//! encode std::string
+	uint8_t *encode(uint8_t *buf, std::string value)
+	{
+		// add the \0 for size
+		buf = encode(buf, value.size()+1);
+		buf = encode(buf, (uint8_t *) value.c_str(), value.size()+1);
+		return buf;
+	}
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Logger
+	Logger *_logger;
+	//! Configure
+	Configure *_configure;
+	//! NiFi server Name
+	std::string _serverName;
+	//! NiFi server port
+	int64_t _serverPort;
+	//! Serial Number
+	uint8_t _serialNumber[8];
+	//! socket to server
+	int _socket;
+	//! report interal in msec
+	int64_t _reportInterval;
+	//! whether it was registered to the NiFi server
+	bool _registered;
+	//! seq number
+	uint32_t _seqNumber;
+	//! FlowController
+	FlowController *_controller;
+	//! report Blob
+	char *_reportBlob;
+	//! report Blob len;
+	int _reportBlobLen;
+	//! thread
+	std::thread *_thread;
+	//! whether it is running
+	bool _running;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	FlowControlProtocol(const FlowControlProtocol &parent);
+	FlowControlProtocol &operator=(const FlowControlProtocol &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/FlowController.h
----------------------------------------------------------------------
diff --git a/libminifi/include/FlowController.h b/libminifi/include/FlowController.h
new file mode 100644
index 0000000..0d758df
--- /dev/null
+++ b/libminifi/include/FlowController.h
@@ -0,0 +1,248 @@
+/**
+ * @file FlowController.h
+ * FlowController class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __FLOW_CONTROLLER_H__
+#define __FLOW_CONTROLLER_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <algorithm>
+#include <set>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <yaml-cpp/yaml.h>
+
+#include "Configure.h"
+#include "Property.h"
+#include "Relationship.h"
+#include "FlowFileRecord.h"
+#include "Connection.h"
+#include "Processor.h"
+#include "ProcessContext.h"
+#include "ProcessSession.h"
+#include "ProcessGroup.h"
+#include "GenerateFlowFile.h"
+#include "LogAttribute.h"
+#include "RealTimeDataCollector.h"
+#include "TimerDrivenSchedulingAgent.h"
+#include "FlowControlProtocol.h"
+#include "RemoteProcessorGroupPort.h"
+#include "GetFile.h"
+#include "TailFile.h"
+#include "ListenSyslog.h"
+#include "ExecuteProcess.h"
+
+//! Default NiFi Root Group Name
+#define DEFAULT_ROOT_GROUP_NAME ""
+#define DEFAULT_FLOW_XML_FILE_NAME "conf/flow.xml"
+#define DEFAULT_FLOW_YAML_FILE_NAME "conf/flow.yml"
+#define CONFIG_YAML_PROCESSORS_KEY "Processors"
+
+enum class ConfigFormat { XML, YAML };
+
+struct ProcessorConfig {
+	std::string name;
+	std::string javaClass;
+	std::string maxConcurrentTasks;
+	std::string schedulingStrategy;
+	std::string schedulingPeriod;
+	std::string penalizationPeriod;
+	std::string yieldPeriod;
+	std::string runDurationNanos;
+	std::vector<std::string> autoTerminatedRelationships;
+	std::vector<Property> properties;
+};
+
+//! FlowController Class
+class FlowController
+{
+public:
+    static const int DEFAULT_MAX_TIMER_DRIVEN_THREAD = 10;
+    static const int DEFAULT_MAX_EVENT_DRIVEN_THREAD = 5;
+	//! Constructor
+	/*!
+	 * Create a new Flow Controller
+	 */
+	FlowController(std::string name = DEFAULT_ROOT_GROUP_NAME);
+	//! Destructor
+	virtual ~FlowController();
+	//! Set FlowController Name
+	void setName(std::string name) {
+		_name = name;
+	}
+	//! Get Flow Controller Name
+	std::string getName(void) {
+		return (_name);
+	}
+	//! Set UUID
+	void setUUID(uuid_t uuid) {
+		uuid_copy(_uuid, uuid);
+	}
+	//! Get UUID
+	bool getUUID(uuid_t uuid) {
+		if (uuid)
+		{
+			uuid_copy(uuid, _uuid);
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Set MAX TimerDrivenThreads
+	void setMaxTimerDrivenThreads(int number)
+	{
+		_maxTimerDrivenThreads = number;
+	}
+	//! Get MAX TimerDrivenThreads
+	int getMaxTimerDrivenThreads()
+	{
+		return _maxTimerDrivenThreads;
+	}
+	//! Set MAX EventDrivenThreads
+	void setMaxEventDrivenThreads(int number)
+	{
+		_maxEventDrivenThreads = number;
+	}
+	//! Get MAX EventDrivenThreads
+	int getMaxEventDrivenThreads()
+	{
+		return _maxEventDrivenThreads;
+	}
+	//! Create FlowFile Repository
+	bool createFlowFileRepository();
+	//! Create Content Repository
+	bool createContentRepository();
+
+	//! Life Cycle related function
+	//! Load flow xml from disk, after that, create the root process group and its children, initialize the flows
+	void load(ConfigFormat format);
+	//! Whether the Flow Controller is start running
+	bool isRunning();
+	//! Whether the Flow Controller has already been initialized (loaded flow XML)
+	bool isInitialized();
+	//! Start to run the Flow Controller which internally start the root process group and all its children
+	bool start();
+	//! Stop to run the Flow Controller which internally stop the root process group and all its children
+	void stop(bool force);
+	//! Unload the current flow xml, clean the root process group and all its children
+	void unload();
+	//! Load new xml
+	void reload(std::string xmlFile);
+	//! update property value
+	void updatePropertyValue(std::string processorName, std::string propertyName, std::string propertyValue)
+	{
+		if (_root)
+			_root->updatePropertyValue(processorName, propertyName, propertyValue);
+	}
+
+	//! Create Processor (Node/Input/Output Port) based on the name
+	Processor *createProcessor(std::string name, uuid_t uuid);
+	//! Create Root Processor Group
+	ProcessGroup *createRootProcessGroup(std::string name, uuid_t uuid);
+	//! Create Remote Processor Group
+	ProcessGroup *createRemoteProcessGroup(std::string name, uuid_t uuid);
+	//! Create Connection
+	Connection *createConnection(std::string name, uuid_t uuid);
+	//! set 8 bytes SerialNumber
+	void setSerialNumber(uint8_t *number)
+	{
+		_protocol->setSerialNumber(number);
+	}
+
+protected:
+
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! FlowController Name
+	std::string _name;
+	//! Configuration File Name
+	std::string _configurationFileName;
+	//! NiFi property File Name
+	std::string _propertiesFileName;
+	//! Root Process Group
+	ProcessGroup *_root;
+	//! MAX Timer Driven Threads
+	int _maxTimerDrivenThreads;
+	//! MAX Event Driven Threads
+	int _maxEventDrivenThreads;
+	//! Config
+	//! FlowFile Repo
+	//! Provenance Repo
+	//! Flow Engines
+	//! Flow Scheduler
+	TimerDrivenSchedulingAgent _timerScheduler;
+	//! Controller Service
+	//! Config
+	//! Site to Site Server Listener
+	//! Heart Beat
+	//! FlowControl Protocol
+	FlowControlProtocol *_protocol;
+
+private:
+
+	//! Mutex for protection
+	std::mutex _mtx;
+	//! Logger
+	Logger *_logger;
+	//! Configure
+	Configure *_configure;
+	//! Whether it is running
+	std::atomic<bool> _running;
+	//! Whether it has already been initialized (load the flow XML already)
+	std::atomic<bool> _initialized;
+	//! Process Processor Node XML
+	void parseProcessorNode(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent);
+	//! Process Port XML
+	void parsePort(xmlDoc *doc, xmlNode *processorNode, ProcessGroup *parent, TransferDirection direction);
+	//! Process Root Processor Group XML
+	void parseRootProcessGroup(xmlDoc *doc, xmlNode *node);
+	//! Process Property XML
+	void parseProcessorProperty(xmlDoc *doc, xmlNode *node, Processor *processor);
+	//! Process connection XML
+	void parseConnection(xmlDoc *doc, xmlNode *node, ProcessGroup *parent);
+	//! Process Remote Process Group
+	void parseRemoteProcessGroup(xmlDoc *doc, xmlNode *node, ProcessGroup *parent);
+
+	//! Process Processor Node YAML
+	void parseProcessorNodeYaml(YAML::Node processorNode, ProcessGroup *parent);
+	//! Process Port YAML
+	void parsePortYaml(YAML::Node *portNode, ProcessGroup *parent, TransferDirection direction);
+	//! Process Root Processor Group YAML
+	void parseRootProcessGroupYaml(YAML::Node rootNode);
+	//! Process Property YAML
+	void parseProcessorPropertyYaml(YAML::Node *doc, YAML::Node *node, Processor *processor);
+	//! Process connection YAML
+	void parseConnectionYaml(YAML::Node *node, ProcessGroup *parent);
+	//! Process Remote Process Group YAML
+	void parseRemoteProcessGroupYaml(YAML::Node *node, ProcessGroup *parent);
+	//! Parse Properties Node YAML for a processor
+	void parsePropertiesNodeYaml(YAML::Node *propertiesNode, Processor *processor);
+
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	FlowController(const FlowController &parent);
+	FlowController &operator=(const FlowController &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/FlowFileRecord.h
----------------------------------------------------------------------
diff --git a/libminifi/include/FlowFileRecord.h b/libminifi/include/FlowFileRecord.h
new file mode 100644
index 0000000..8b7362f
--- /dev/null
+++ b/libminifi/include/FlowFileRecord.h
@@ -0,0 +1,220 @@
+/**
+ * @file FlowFileRecord.h
+ * Flow file record class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __FLOW_FILE_RECORD_H__
+#define __FLOW_FILE_RECORD_H__
+
+#include <uuid/uuid.h>
+#include <vector>
+#include <queue>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <set>
+
+#include "TimeUtil.h"
+#include "Logger.h"
+#include "ResourceClaim.h"
+
+class ProcessSession;
+class Connection;
+
+#define DEFAULT_FLOWFILE_PATH "."
+
+//! FlowFile Attribute
+enum FlowAttribute
+{
+	//! The flowfile's path indicates the relative directory to which a FlowFile belongs and does not contain the filename
+	PATH = 0,
+	//! The flowfile's absolute path indicates the absolute directory to which a FlowFile belongs and does not contain the filename
+	ABSOLUTE_PATH,
+	//! The filename of the FlowFile. The filename should not contain any directory structure.
+	FILENAME,
+	//! A unique UUID assigned to this FlowFile.
+	UUID,
+	//! A numeric value indicating the FlowFile priority
+	priority,
+	//! The MIME Type of this FlowFile
+	MIME_TYPE,
+	//! Specifies the reason that a FlowFile is being discarded
+	DISCARD_REASON,
+	//! Indicates an identifier other than the FlowFile's UUID that is known to refer to this FlowFile.
+	ALTERNATE_IDENTIFIER,
+	MAX_FLOW_ATTRIBUTES
+};
+
+//! FlowFile Attribute Key
+static const char *FlowAttributeKeyArray[MAX_FLOW_ATTRIBUTES] =
+{
+		"path",
+		"absolute.path",
+		"filename",
+		"uuid",
+		"priority",
+		"mime.type",
+		"discard.reason",
+		"alternate.identifier"
+};
+
+//! FlowFile Attribute Enum to Key
+inline const char *FlowAttributeKey(FlowAttribute attribute)
+{
+	if (attribute < MAX_FLOW_ATTRIBUTES)
+		return FlowAttributeKeyArray[attribute];
+	else
+		return NULL;
+}
+
+//! FlowFile IO Callback functions for input and output
+//! throw exception for error
+class InputStreamCallback
+{
+public:
+	virtual void process(std::ifstream *stream) = 0;
+};
+class OutputStreamCallback
+{
+public:
+	virtual void process(std::ofstream *stream) = 0;
+};
+
+
+//! FlowFile Record Class
+class FlowFileRecord
+{
+	friend class ProcessSession;
+public:
+	//! Constructor
+	/*!
+	 * Create a new flow record
+	 */
+	FlowFileRecord(std::map<std::string, std::string> attributes, ResourceClaim *claim = NULL);
+	//! Destructor
+	virtual ~FlowFileRecord();
+	//! addAttribute key is enum
+	bool addAttribute(FlowAttribute key, std::string value);
+	//! addAttribute key is string
+	bool addAttribute(std::string key, std::string value);
+	//! removeAttribute key is enum
+	bool removeAttribute(FlowAttribute key);
+	//! removeAttribute key is string
+	bool removeAttribute(std::string key);
+	//! updateAttribute key is enum
+	bool updateAttribute(FlowAttribute key, std::string value);
+	//! updateAttribute key is string
+	bool updateAttribute(std::string key, std::string value);
+	//! getAttribute key is enum
+	bool getAttribute(FlowAttribute key, std::string &value);
+	//! getAttribute key is string
+	bool getAttribute(std::string key, std::string &value);
+	//! setAttribute, if attribute already there, update it, else, add it
+	void setAttribute(std::string key, std::string value) {
+		_attributes[key] = value;
+	}
+	//! Get the UUID as string
+	std::string getUUIDStr() {
+		return _uuidStr;
+	}
+	//! Get Attributes
+	std::map<std::string, std::string> getAttributes() {
+		return _attributes;
+	}
+	//! Check whether it is still being penalized
+	bool isPenalized() {
+		return (_penaltyExpirationMs > 0 ? _penaltyExpirationMs > getTimeMillis() : false);
+	}
+	//! Get Size
+	uint64_t getSize() {
+		return _size;
+	}
+	// ! Get Offset
+	uint64_t getOffset() {
+		return _offset;
+	}
+	// ! Get Entry Date
+	uint64_t getEntryDate() {
+		return _entryDate;
+	}
+	// ! Get Lineage Start Date
+	uint64_t getlineageStartDate() {
+		return _lineageStartDate;
+	}
+	// ! Set Original connection
+	void setOriginalConnection (Connection *connection) {
+		_orginalConnection = connection;
+	}
+	//! Get Resource Claim
+	ResourceClaim *getResourceClaim() {
+		return _claim;
+	}
+
+protected:
+
+	//! Date at which the flow file entered the flow
+	uint64_t _entryDate;
+	//! Date at which the origin of this flow file entered the flow
+	uint64_t _lineageStartDate;
+	//! Date at which the flow file was queued
+	uint64_t _lastQueueDate;
+	//! Size in bytes of the data corresponding to this flow file
+	uint64_t _size;
+	//! A global unique identifier
+	uuid_t _uuid;
+	//! A local unique identifier
+	uint64_t _id;
+	//! Offset to the content
+	uint64_t _offset;
+	//! Penalty expiration
+	uint64_t _penaltyExpirationMs;
+	//! Attributes key/values pairs for the flow record
+	std::map<std::string, std::string> _attributes;
+	//! Pointer to the associated content resource claim
+	ResourceClaim *_claim;
+	//! UUID string
+	std::string _uuidStr;
+	//! UUID string for all parents
+	std::set<std::string> _lineageIdentifiers;
+	//! duplicate the original flow file
+	void duplicate(FlowFileRecord *original);
+
+private:
+
+	//! Local flow sequence ID
+	static std::atomic<uint64_t> _localFlowSeqNumber;
+	//! Mark for deletion
+	bool _markedDelete;
+	//! Connection queue that this flow file will be transfer or current in
+	Connection *_connection;
+	//! Orginal connection queue that this flow file was dequeued from
+	Connection *_orginalConnection;
+	//! Logger
+	Logger *_logger;
+	//! Snapshot flow record for session rollback
+	bool _snapshot;
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	FlowFileRecord(const FlowFileRecord &parent);
+	FlowFileRecord &operator=(const FlowFileRecord &parent);
+
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/GenerateFlowFile.h
----------------------------------------------------------------------
diff --git a/libminifi/include/GenerateFlowFile.h b/libminifi/include/GenerateFlowFile.h
new file mode 100644
index 0000000..27aa43b
--- /dev/null
+++ b/libminifi/include/GenerateFlowFile.h
@@ -0,0 +1,87 @@
+/**
+ * @file GenerateFlowFile.h
+ * GenerateFlowFile class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __GENERATE_FLOW_FILE_H__
+#define __GENERATE_FLOW_FILE_H__
+
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! GenerateFlowFile Class
+class GenerateFlowFile : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	GenerateFlowFile(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_data = NULL;
+		_dataSize = 0;
+	}
+	//! Destructor
+	virtual ~GenerateFlowFile()
+	{
+		if (_data)
+			delete[] _data;
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property FileSize;
+	static Property BatchSize;
+	static Property DataFormat;
+	static Property UniqueFlowFiles;
+	static const char *DATA_FORMAT_BINARY;
+	static const char *DATA_FORMAT_TEXT;
+	//! Supported Relationships
+	static Relationship Success;
+	//! Nest Callback Class for write stream
+	class WriteCallback : public OutputStreamCallback
+	{
+		public:
+		WriteCallback(char *data, uint64_t size)
+		: _data(data), _dataSize(size) {}
+		char *_data;
+		uint64_t _dataSize;
+		void process(std::ofstream *stream) {
+			if (_data && _dataSize > 0)
+				stream->write(_data, _dataSize);
+		}
+	};
+
+public:
+	//! OnTrigger method, implemented by NiFi GenerateFlowFile
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi GenerateFlowFile
+	virtual void initialize(void);
+
+protected:
+
+private:
+	//! Generated data
+	char * _data;
+	//! Size of the generate data
+	uint64_t _dataSize;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/GetFile.h
----------------------------------------------------------------------
diff --git a/libminifi/include/GetFile.h b/libminifi/include/GetFile.h
new file mode 100644
index 0000000..eb975fd
--- /dev/null
+++ b/libminifi/include/GetFile.h
@@ -0,0 +1,117 @@
+/**
+ * @file GetFile.h
+ * GetFile class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __GET_FILE_H__
+#define __GET_FILE_H__
+
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! GetFile Class
+class GetFile : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	GetFile(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+		_directory = ".";
+		_recursive = true;
+		_keepSourceFile = false;
+		_minAge = 0;
+		_maxAge = 0;
+		_minSize = 0;
+		_maxSize = 0;
+		_ignoreHiddenFile = true;
+		_pollInterval = 0;
+		_batchSize = 10;
+		_lastDirectoryListingTime = getTimeMillis();
+		_fileFilter = "[^\\.].*";
+	}
+	//! Destructor
+	virtual ~GetFile()
+	{
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property Directory;
+	static Property Recurse;
+	static Property KeepSourceFile;
+	static Property MinAge;
+	static Property MaxAge;
+	static Property MinSize;
+	static Property MaxSize;
+	static Property IgnoreHiddenFile;
+	static Property PollInterval;
+	static Property BatchSize;
+	static Property FileFilter;
+	//! Supported Relationships
+	static Relationship Success;
+
+public:
+	//! OnTrigger method, implemented by NiFi GetFile
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi GetFile
+	virtual void initialize(void);
+	//! perform directory listing
+	void performListing(std::string dir);
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+	//! Queue for store directory list
+	std::queue<std::string> _dirList;
+	//! Get Listing size
+	uint64_t getListingSize() {
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _dirList.size();
+	}
+	//! Whether the directory listing is empty
+	bool isListingEmpty();
+	//! Put full path file name into directory listing
+	void putListing(std::string fileName);
+	//! Poll directory listing for files
+	void pollListing(std::queue<std::string> &list, int maxSize);
+	//! Check whether file can be added to the directory listing
+	bool acceptFile(std::string fileName);
+	//! Mutex for protection of the directory listing
+	std::mutex _mtx;
+	std::string _directory;
+	bool _recursive;
+	bool _keepSourceFile;
+	int64_t _minAge;
+	int64_t _maxAge;
+	int64_t _minSize;
+	int64_t _maxSize;
+	bool _ignoreHiddenFile;
+	int64_t _pollInterval;
+	int64_t _batchSize;
+	uint64_t _lastDirectoryListingTime;
+	std::string _fileFilter;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/ListenSyslog.h
----------------------------------------------------------------------
diff --git a/libminifi/include/ListenSyslog.h b/libminifi/include/ListenSyslog.h
new file mode 100644
index 0000000..81bc92c
--- /dev/null
+++ b/libminifi/include/ListenSyslog.h
@@ -0,0 +1,209 @@
+/**
+ * @file ListenSyslog.h
+ * ListenSyslog class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LISTEN_SYSLOG_H__
+#define __LISTEN_SYSLOG_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <chrono>
+#include <thread>
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! SyslogEvent
+typedef struct {
+	uint8_t *payload;
+	uint64_t len;
+} SysLogEvent;
+
+//! ListenSyslog Class
+class ListenSyslog : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	ListenSyslog(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+		_eventQueueByteSize = 0;
+		_serverSocket = 0;
+		_recvBufSize = 65507;
+		_maxSocketBufSize = 1024*1024;
+		_maxConnections = 2;
+		_maxBatchSize = 1;
+		_messageDelimiter = "\n";
+		_protocol = "UDP";
+		_port = 514;
+		_parseMessages = false;
+		_serverSocket = 0;
+		_maxFds = 0;
+		FD_ZERO(&_readfds);
+		_thread = NULL;
+		_resetServerSocket = false;
+		_serverTheadRunning = false;
+	}
+	//! Destructor
+	virtual ~ListenSyslog()
+	{
+		_serverTheadRunning = false;
+		if (this->_thread)
+			delete this->_thread;
+		// need to reset the socket
+		std::vector<int>::iterator it;
+		for (it = _clientSockets.begin(); it != _clientSockets.end(); ++it)
+		{
+			int clientSocket = *it;
+			close(clientSocket);
+		}
+		_clientSockets.clear();
+		if (_serverSocket > 0)
+		{
+			_logger->log_info("ListenSysLog Server socket %d close", _serverSocket);
+			close(_serverSocket);
+			_serverSocket = 0;
+		}
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property RecvBufSize;
+	static Property MaxSocketBufSize;
+	static Property MaxConnections;
+	static Property MaxBatchSize;
+	static Property MessageDelimiter;
+	static Property ParseMessages;
+	static Property Protocol;
+	static Property Port;
+	//! Supported Relationships
+	static Relationship Success;
+	static Relationship Invalid;
+	//! Nest Callback Class for write stream
+	class WriteCallback : public OutputStreamCallback
+	{
+		public:
+		WriteCallback(char *data, uint64_t size)
+		: _data(data), _dataSize(size) {}
+		char *_data;
+		uint64_t _dataSize;
+		void process(std::ofstream *stream) {
+			if (_data && _dataSize > 0)
+				stream->write(_data, _dataSize);
+		}
+	};
+
+public:
+	//! OnTrigger method, implemented by NiFi ListenSyslog
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi ListenSyslog
+	virtual void initialize(void);
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+	//! Run function for the thread
+	static void run(ListenSyslog *process);
+	//! Run Thread
+	void runThread();
+	//! Queue for store syslog event
+	std::queue<SysLogEvent> _eventQueue;
+	//! Size of Event queue in bytes
+	uint64_t _eventQueueByteSize;
+	//! Get event queue size
+	uint64_t getEventQueueSize() {
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _eventQueue.size();
+	}
+	//! Get event queue byte size
+	uint64_t getEventQueueByteSize() {
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _eventQueueByteSize;
+	}
+	//! Whether the event queue  is empty
+	bool isEventQueueEmpty()
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		return _eventQueue.empty();
+	}
+	//! Put event into directory listing
+	void putEvent(uint8_t *payload, uint64_t len)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+		SysLogEvent event;
+		event.payload = payload;
+		event.len = len;
+		_eventQueue.push(event);
+		_eventQueueByteSize += len;
+	}
+	//! Read \n terminated line from TCP socket
+	int readline( int fd, char *bufptr, size_t len );
+	//! start server socket and handling client socket
+	void startSocketThread();
+	//! Poll event
+	void pollEvent(std::queue<SysLogEvent> &list, int maxSize)
+	{
+		std::lock_guard<std::mutex> lock(_mtx);
+
+		while (!_eventQueue.empty() && (maxSize == 0 || list.size() < maxSize))
+		{
+			SysLogEvent event = _eventQueue.front();
+			_eventQueue.pop();
+			_eventQueueByteSize -= event.len;
+			list.push(event);
+		}
+		return;
+	}
+	//! Mutex for protection of the directory listing
+	std::mutex _mtx;
+	int64_t _recvBufSize;
+	int64_t _maxSocketBufSize;
+	int64_t _maxConnections;
+	int64_t _maxBatchSize;
+	std::string _messageDelimiter;
+	std::string _protocol;
+	int64_t _port;
+	bool _parseMessages;
+	int _serverSocket;
+	std::vector<int> _clientSockets;
+	int _maxFds;
+	fd_set _readfds;
+	//! thread
+	std::thread *_thread;
+	//! whether to reset the server socket
+	bool _resetServerSocket;
+	bool _serverTheadRunning;
+	//! buffer for read socket
+	uint8_t _buffer[2048];
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/LogAttribute.h
----------------------------------------------------------------------
diff --git a/libminifi/include/LogAttribute.h b/libminifi/include/LogAttribute.h
new file mode 100644
index 0000000..125ebf3
--- /dev/null
+++ b/libminifi/include/LogAttribute.h
@@ -0,0 +1,128 @@
+/**
+ * @file LogAttribute.h
+ * LogAttribute class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LOG_ATTRIBUTE_H__
+#define __LOG_ATTRIBUTE_H__
+
+#include "FlowFileRecord.h"
+#include "Processor.h"
+#include "ProcessSession.h"
+
+//! LogAttribute Class
+class LogAttribute : public Processor
+{
+public:
+	//! Constructor
+	/*!
+	 * Create a new processor
+	 */
+	LogAttribute(std::string name, uuid_t uuid = NULL)
+	: Processor(name, uuid)
+	{
+		_logger = Logger::getLogger();
+	}
+	//! Destructor
+	virtual ~LogAttribute()
+	{
+	}
+	//! Processor Name
+	static const std::string ProcessorName;
+	//! Supported Properties
+	static Property LogLevel;
+	static Property AttributesToLog;
+	static Property AttributesToIgnore;
+	static Property LogPayload;
+	static Property LogPrefix;
+	//! Supported Relationships
+	static Relationship Success;
+	enum LogAttrLevel {
+        LogAttrLevelTrace, LogAttrLevelDebug, LogAttrLevelInfo, LogAttrLevelWarn, LogAttrLevelError
+    };
+	//! Convert log level from string to enum
+	bool logLevelStringToEnum(std::string logStr, LogAttrLevel &level)
+	{
+		if (logStr == "trace")
+		{
+			level = LogAttrLevelTrace;
+			return true;
+		}
+		else if (logStr == "debug")
+		{
+			level = LogAttrLevelDebug;
+			return true;
+		}
+		else if (logStr == "info")
+		{
+			level = LogAttrLevelInfo;
+			return true;
+		}
+		else if (logStr == "warn")
+		{
+			level = LogAttrLevelWarn;
+			return true;
+		}
+		else if (logStr == "error")
+		{
+			level = LogAttrLevelError;
+			return true;
+		}
+		else
+			return false;
+	}
+	//! Nest Callback Class for read stream
+	class ReadCallback : public InputStreamCallback
+	{
+		public:
+		ReadCallback(uint64_t size)
+		{
+			_bufferSize = size;
+			_buffer = new char[_bufferSize];
+		}
+		~ReadCallback()
+		{
+			if (_buffer)
+				delete[] _buffer;
+		}
+		void process(std::ifstream *stream) {
+
+			stream->read(_buffer, _bufferSize);
+			if (!stream)
+				_readSize = stream->gcount();
+			else
+				_readSize = _bufferSize;
+		}
+		char  *_buffer;
+		uint64_t _bufferSize;
+		uint64_t _readSize;
+	};
+
+public:
+	//! OnTrigger method, implemented by NiFi LogAttribute
+	virtual void onTrigger(ProcessContext *context, ProcessSession *session);
+	//! Initialize, over write by NiFi LogAttribute
+	virtual void initialize(void);
+
+protected:
+
+private:
+	//! Logger
+	Logger *_logger;
+};
+
+#endif

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b02af540/libminifi/include/Logger.h
----------------------------------------------------------------------
diff --git a/libminifi/include/Logger.h b/libminifi/include/Logger.h
new file mode 100644
index 0000000..3edad9d
--- /dev/null
+++ b/libminifi/include/Logger.h
@@ -0,0 +1,154 @@
+/**
+ * @file Logger.h
+ * Logger class declaration
+ * This is a C++ wrapper for spdlog, a lightweight C++ logging library
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LOGGER_H__
+#define __LOGGER_H__
+
+#include "spdlog/spdlog.h"
+
+using spdlog::stdout_logger_mt;
+using spdlog::rotating_logger_mt;
+using spdlog::logger;
+
+#define LOG_BUFFER_SIZE 1024
+#define FILL_BUFFER  char buffer[LOG_BUFFER_SIZE]; \
+    va_list args; \
+    va_start(args, format); \
+    vsnprintf(buffer, LOG_BUFFER_SIZE,format, args); \
+    va_end(args);
+
+//! 5M default log file size
+#define DEFAULT_LOG_FILE_SIZE (5*1024*1024)
+//! 3 log files rotation
+#define DEFAULT_LOG_FILE_NUMBER 3
+#define LOG_NAME "minifi log"
+#define LOG_FILE_NAME "minifi-app.log"
+
+typedef enum
+{
+    trace    = 0,
+    debug    = 1,
+    info     = 2,
+    notice   = 3,
+    warn     = 4,
+    err      = 5,
+    critical = 6,
+    alert    = 7,
+    emerg    = 8,
+    off      = 9
+} LOG_LEVEL_E;
+
+//! Logger Class
+class Logger {
+
+public:
+
+	//! Get the singleton logger instance
+	static Logger * getLogger() {
+		if (!_logger)
+			_logger = new Logger();
+		return _logger;
+	}
+	void setLogLevel(LOG_LEVEL_E level) {
+		if (_spdlog == NULL)
+			return;
+		_spdlog->set_level((spdlog::level::level_enum) level);
+	}
+	//! Destructor
+	~Logger() {}
+	/**
+	 * @brief Log error message
+	 * @param format format string ('man printf' for syntax)
+	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
+	 */
+	void log_error(const char *const format, ...) {
+		if(_spdlog == NULL)
+			return;
+		FILL_BUFFER
+	    _spdlog->error(buffer);
+	}
+	/**
+	 * @brief Log warn message
+	 * @param format format string ('man printf' for syntax)
+	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
+	 */
+	void log_warn(const char *const format, ...) {
+		if(_spdlog == NULL)
+			return;
+		FILL_BUFFER
+	    _spdlog->warn(buffer);
+	}
+	/**
+	 * @brief Log info message
+	 * @param format format string ('man printf' for syntax)
+	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
+	 */
+	void log_info(const char *const format, ...) {
+		if(_spdlog == NULL)
+			return;
+		FILL_BUFFER
+	    _spdlog->info(buffer);
+	}
+	/**
+	 * @brief Log debug message
+	 * @param format format string ('man printf' for syntax)
+	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
+	 */
+	void log_debug(const char *const format, ...) {
+		if(_spdlog == NULL)
+			return;
+		FILL_BUFFER
+	    _spdlog->debug(buffer);
+	}
+	/**
+	 * @brief Log trace message
+	 * @param format format string ('man printf' for syntax)
+	 * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
+	 */
+	void log_trace(const char *const format, ...) {
+		if(_spdlog == NULL)
+			return;
+		FILL_BUFFER
+	    _spdlog->trace(buffer);
+	}
+
+protected:
+
+private:
+	// Prevent default copy constructor and assignment operation
+	// Only support pass by reference or pointer
+	Logger(const Logger &parent);
+	Logger &operator=(const Logger &parent);
+	//! Constructor
+	/*!
+	 * Create a logger
+	 * */
+	Logger(const std::string logger_name = LOG_NAME, const std::string filename = LOG_FILE_NAME, size_t max_file_size = DEFAULT_LOG_FILE_SIZE, size_t max_files = DEFAULT_LOG_FILE_NUMBER, bool force_flush = true) {
+        _spdlog = rotating_logger_mt(logger_name, filename, max_file_size, max_files, force_flush);
+		_spdlog->set_level((spdlog::level::level_enum) debug);
+	}
+	//! spdlog
+	std::shared_ptr<logger> _spdlog;
+
+	//! Singleton logger instance
+	static Logger *_logger;
+};
+
+#endif