You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/14 06:15:24 UTC

[17/50] [abbrv] webworks commit: Fix JPPS and Utils plugins directory structure

Fix JPPS and Utils plugins directory structure

Tested by Tracy Li <tl...@blackberry.com>


Project: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/commit/b3960ef0
Tree: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/tree/b3960ef0
Diff: http://git-wip-us.apache.org/repos/asf/cordova-blackberry/diff/b3960ef0

Branch: refs/heads/master
Commit: b3960ef0c39ee88a953c2be9ff4f11ec8637d5ec
Parents: 63452db
Author: Bryan Higgins <bh...@blackberry.com>
Authored: Wed Apr 10 16:40:49 2013 -0400
Committer: Bryan Higgins <bh...@blackberry.com>
Committed: Fri May 3 10:13:30 2013 -0400

----------------------------------------------------------------------
 .../bin/templates/project/plugins/JPPS/Makefile    |    8 -
 .../templates/project/plugins/JPPS/native/Makefile |    8 +
 .../project/plugins/JPPS/native/common.mk          |   34 +
 .../project/plugins/JPPS/native/device/libjpps.so  |  Bin 0 -> 138046 bytes
 .../plugins/JPPS/native/simulator/libjpps.so       |  Bin 0 -> 224392 bytes
 .../plugins/JPPS/native/src/core/PPSEvent.h        |  108 +++
 .../plugins/JPPS/native/src/core/PPSInterface.cpp  |  632 +++++++++++++++
 .../plugins/JPPS/native/src/core/PPSInterface.h    |  238 ++++++
 .../plugins/JPPS/native/src/core/PPSNotifier.cpp   |  126 +++
 .../plugins/JPPS/native/src/core/PPSNotifier.h     |  159 ++++
 .../JPPS/native/src/core/PPSNotifyGroupManager.cpp |  107 +++
 .../JPPS/native/src/core/PPSNotifyGroupManager.h   |  133 +++
 .../plugins/JPPS/native/src/core/PPSTypes.h        |   96 +++
 .../plugins/JPPS/native/src/plugin/JPPSPlugin.cpp  |  149 ++++
 .../plugins/JPPS/native/src/plugin/JPPSPlugin.h    |  122 +++
 .../JPPS/native/src/plugin/JPPSServerPlugin.cpp    |  168 ++++
 .../JPPS/native/src/plugin/JPPSServerPlugin.h      |  115 +++
 .../JPPS/native/src/plugin/PPSInterfaceGlue.cpp    |  355 ++++++++
 .../JPPS/native/src/plugin/PPSInterfaceGlue.h      |  177 ++++
 .../JPPS/native/src/plugin/PPSServerGlue.cpp       |  300 +++++++
 .../plugins/JPPS/native/src/plugin/PPSServerGlue.h |  165 ++++
 .../plugins/JPPS/native/src/plugin/PluginTypes.h   |   35 +
 .../JPPS/native/src/plugin/pluginManifest.cpp      |   76 ++
 .../project/plugins/JPPS/native/src/utils/Logger.h |   94 +++
 .../plugins/JPPS/native/src/utils/Thread.cpp       |   71 ++
 .../project/plugins/JPPS/native/src/utils/Thread.h |   73 ++
 .../templates/project/plugins/JPPS/src/Makefile    |    8 -
 .../project/plugins/JPPS/src/blackberry10/Makefile |    8 -
 .../plugins/JPPS/src/blackberry10/native/Makefile  |    8 -
 .../plugins/JPPS/src/blackberry10/native/common.mk |   34 -
 .../JPPS/src/blackberry10/native/device/libjpps.so |  Bin 138046 -> 0 bytes
 .../src/blackberry10/native/simulator/libjpps.so   |  Bin 224392 -> 0 bytes
 .../src/blackberry10/native/src/core/PPSEvent.h    |  108 ---
 .../blackberry10/native/src/core/PPSInterface.cpp  |  632 ---------------
 .../blackberry10/native/src/core/PPSInterface.h    |  238 ------
 .../blackberry10/native/src/core/PPSNotifier.cpp   |  126 ---
 .../src/blackberry10/native/src/core/PPSNotifier.h |  159 ----
 .../native/src/core/PPSNotifyGroupManager.cpp      |  107 ---
 .../native/src/core/PPSNotifyGroupManager.h        |  133 ---
 .../src/blackberry10/native/src/core/PPSTypes.h    |   96 ---
 .../blackberry10/native/src/plugin/JPPSPlugin.cpp  |  149 ----
 .../blackberry10/native/src/plugin/JPPSPlugin.h    |  122 ---
 .../native/src/plugin/JPPSServerPlugin.cpp         |  168 ----
 .../native/src/plugin/JPPSServerPlugin.h           |  115 ---
 .../native/src/plugin/PPSInterfaceGlue.cpp         |  355 --------
 .../native/src/plugin/PPSInterfaceGlue.h           |  177 ----
 .../native/src/plugin/PPSServerGlue.cpp            |  300 -------
 .../blackberry10/native/src/plugin/PPSServerGlue.h |  165 ----
 .../blackberry10/native/src/plugin/PluginTypes.h   |   35 -
 .../native/src/plugin/pluginManifest.cpp           |   76 --
 .../src/blackberry10/native/src/utils/Logger.h     |   94 ---
 .../src/blackberry10/native/src/utils/Thread.cpp   |   71 --
 .../src/blackberry10/native/src/utils/Thread.h     |   73 --
 .../bin/templates/project/plugins/Utils/Makefile   |    8 -
 .../project/plugins/Utils/native/Makefile          |    8 +
 .../project/plugins/Utils/native/common.mk         |   18 +
 .../plugins/Utils/native/device/libutils.so        |  Bin 0 -> 130206 bytes
 .../plugins/Utils/native/simulator/libutils.so     |  Bin 0 -> 183184 bytes
 .../plugins/Utils/native/webworks_utils.cpp        |   55 ++
 .../plugins/Utils/native/webworks_utils.hpp        |   34 +
 .../templates/project/plugins/Utils/src/Makefile   |    8 -
 .../plugins/Utils/src/blackberry10/Makefile        |    8 -
 .../plugins/Utils/src/blackberry10/native/Makefile |    8 -
 .../Utils/src/blackberry10/native/common.mk        |   18 -
 .../src/blackberry10/native/device/libutils.so     |  Bin 130206 -> 0 bytes
 .../src/blackberry10/native/simulator/libutils.so  |  Bin 183184 -> 0 bytes
 .../src/blackberry10/native/webworks_utils.cpp     |   55 --
 .../src/blackberry10/native/webworks_utils.hpp     |   34 -
 68 files changed, 3656 insertions(+), 3704 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/Makefile b/blackberry10/bin/templates/project/plugins/JPPS/Makefile
deleted file mode 100644
index 0e22650..0000000
--- a/blackberry10/bin/templates/project/plugins/JPPS/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-LIST=VARIANT
-ifndef QRECURSE
-QRECURSE=recurse.mk
-ifdef QCONFIG
-QRDIR=$(dir $(QCONFIG))
-endif
-endif
-include $(QRDIR)$(QRECURSE)

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile b/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
new file mode 100644
index 0000000..0cc5eae
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/Makefile
@@ -0,0 +1,8 @@
+LIST=CPU
+ifndef QRECURSE
+QRECURSE=recurse.mk
+ifdef QCONFIG
+QRDIR=$(dir $(QCONFIG))
+endif
+endif
+include $(QRDIR)$(QRECURSE)

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk b/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
new file mode 100644
index 0000000..6cecca9
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/common.mk
@@ -0,0 +1,34 @@
+ifndef QCONFIG
+QCONFIG=qconfig.mk
+endif
+include $(QCONFIG)
+
+NAME=jpps
+PLUGIN=yes
+UTILS=yes
+
+include ../../../../../../meta.mk
+
+override CCFLAGS := $(filter-out -Werror , $(CCFLAGS))
+
+EXTRA_SRCVPATH+=$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/utils \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/core \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/plugin
+
+EXTRA_INCVPATH+=$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/utils \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/core \
+				$(WEBWORKS_DIR)/plugin/com.blackberry.jpps/src/blackberry10/native/src/plugin
+
+SRCS+=src/utils/Thread.cpp \
+      src/core/PPSInterface.cpp \
+      src/core/PPSNotifier.cpp \
+      src/core/PPSNotifyGroupManager.cpp \
+      src/plugin/JPPSPlugin.cpp \
+      src/plugin/PPSInterfaceGlue.cpp \
+      src/plugin/JPPSServerPlugin.cpp \
+      src/plugin/PPSServerGlue.cpp \
+      src/plugin/pluginManifest.cpp
+
+include $(MKFILES_ROOT)/qtargets.mk
+
+LIBS+=pps

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so b/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so
new file mode 100644
index 0000000..f0eb90d
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/JPPS/native/device/libjpps.so differ

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so b/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so
new file mode 100644
index 0000000..f2c12ff
Binary files /dev/null and b/blackberry10/bin/templates/project/plugins/JPPS/native/simulator/libjpps.so differ

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
new file mode 100644
index 0000000..808e699
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSEvent.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPSEVENT_H_
+#define PPSEVENT_H_
+
+#include <string>
+#include "PPSTypes.h"
+
+namespace jpps {
+
+/**
+ * A class representing a PPS event. Used to notify interested parties when something
+ * happens to a PPS object.
+ */
+class PPSEvent {
+
+public:
+
+	/**
+	 * The possible types of this event.
+	 */
+	enum PPSEventType {
+		/** The PPS object's first data read is complete. */
+		PPS_EVENT_FIRST_READ_COMPLETE,
+		/** The PPS object has new data. */
+		PPS_EVENT_NEW_DATA,
+		/** The PPS object was successfully opened. */
+		PPS_EVENT_OPENED,
+		/** A PPS object was closed. */
+		PPS_EVENT_CLOSED,
+		/** An attempt to open a PPS object failed. */
+		PPS_EVENT_OPEN_FAILED,
+		/** An attempt to read from a PPS object failed. */
+		PPS_EVENT_READ_FAILED,
+		/** An attempt to write to a PPS object failed. */
+		PPS_EVENT_WRITE_FAILED,
+	};
+
+	/**
+	 * Constructor.
+	 *
+	 * @param eventType The type of event this is.
+	 * @param data If eventType == PPS_EVENT_NEW_DATA, the new data.
+	 */
+	PPSEvent(PPSEventType eventType, const std::string& msg = "", const ppsObject& newData = ppsObject())
+	: m_eventType(eventType)
+	, m_message(msg)
+	, m_newData(newData)
+	{}
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~PPSEvent() {}
+
+	/**
+	 * Get the event type.
+	 */
+	inline PPSEventType getEventType() const { return m_eventType; }
+
+	/**
+	 * Get the message associated with this event.
+	 */
+	inline std::string getMessage() const { return m_message; }
+
+	/**
+	 * Get the new data. This value is only populated if the eventType is PPS_EVENT_NEW_DATA. This data
+	 * is what was parsed out of the PPS object.
+	 */
+	inline ppsObject getNewData() const { return m_newData; }
+
+private:
+
+	// Disable the default constructor.
+	PPSEvent();
+
+	/** The type of this event. */
+	PPSEventType m_eventType;
+
+	/** A message associated to the event. */
+	std::string m_message;
+
+	/** If m_eventType == PPS_EVENT_NEW_DATA, this contains the new data. Else m_newData is empty.
+	 * This data is the data that was read from the PPS object, un-massaged. */
+	ppsObject m_newData;
+};
+
+} /* namespace jpps */
+#endif /* PPSEVENT_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
new file mode 100644
index 0000000..dfb575b
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.cpp
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "PPSInterface.h"
+
+#include <sstream>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <ppsparse.h>
+#include <string.h>
+
+#include "PPSNotifyGroupManager.h"
+#include "PPSEvent.h"
+
+namespace jpps {
+
+// Const statics
+const char* PPSInterface::PPS_ROOT = "/pps/";
+const int PPSInterface::MaxPPSReadSize = (32 * 1024);
+
+// Static data members
+pthread_mutex_t PPSInterface::sm_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t PPSInterface::sm_cond;
+volatile bool PPSInterface::sm_firstInitDone = false;
+std::map<unsigned int, PPSInterface*> PPSInterface::sm_interfaceLookupTable;
+
+PPSInterface::PPSInterface()
+: m_pEventFunc(NULL)
+, m_pEventArg(NULL)
+, m_interfaceId(0)
+, m_fd(-1)
+, m_oflags(0)
+, m_firstRead(true)
+, m_cachedRead()
+, m_logger()
+{
+	// This is used to assign a unique ID to each PPSInterface object
+	static unsigned int interfaceIDs = 0;
+
+	::pthread_mutex_lock(&sm_mutex);
+
+	m_interfaceId = interfaceIDs;
+	interfaceIDs++; // Increment this so that the next object has a unique id.
+
+	// Add myself to the lookup table
+	sm_interfaceLookupTable.insert(std::pair<unsigned int, PPSInterface*>(m_interfaceId, this));
+
+	if (!sm_firstInitDone) {
+
+		// Initialize the condvar
+		pthread_condattr_t condAttr;
+		::pthread_condattr_init(&condAttr);
+		::pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
+		::pthread_cond_init(&sm_cond, &condAttr);
+		::pthread_condattr_destroy(&condAttr);
+
+		sm_firstInitDone = true;
+	}
+
+	::pthread_mutex_unlock(&sm_mutex);
+}
+
+PPSInterface::~PPSInterface()
+{
+	std::ostringstream ostream;
+	ostream << "PPSInterface::~PPSInterface() - Destruct fd:" << m_fd << ".";
+	m_logger.slog(Logger::debug, ostream.str());
+
+	// Close my open PPS object, if I have one
+	close();
+
+	// Remove myself from the lookup table
+	sm_interfaceLookupTable.erase(m_interfaceId);
+}
+
+void PPSInterface::setVerbose(unsigned short v)
+{
+	m_logger.setVerbosity(v);
+}
+
+void PPSInterface::setEventFunc(const PPSEventFunc* pEventFunc, void* pArg)
+{
+	m_pEventFunc = pEventFunc;
+	m_pEventArg = pArg;
+}
+
+bool PPSInterface::open(const std::string& path, int oflag, int mode, bool server)
+{
+	// If we've already got an open file, fail
+	if (m_fd != -1) {
+
+		m_logger.slog(Logger::warning, "PPSInterface::open() Failed - Attempted to open an object that is already open.");
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_OPEN_FAILED, "Attempted to open an object that is already open."));
+		return false;
+	}
+
+	std::string errorMsg;
+	bool ok = false;
+
+	// Prepend PPS_ROOT to the path if it doesn't start with a '/'
+	std::string fullpath = (path[0] != '/' ? PPSInterface::PPS_ROOT : "") + path;
+
+	// This flag is used to prevent the notify thread from performing reads while the
+	// open() function is running and doing its first read.
+	::pthread_mutex_lock(&sm_mutex);
+	m_firstRead = true;
+	::pthread_mutex_unlock(&sm_mutex);
+
+	// Remove any options from the path otherwise lstat will fail
+	std::string pathNoOptions(fullpath);
+	std::size_t nPosOpts = fullpath.rfind('?');
+
+	if (nPosOpts != std::string::npos)
+		pathNoOptions = fullpath.substr(0, nPosOpts);
+
+	// There are a few complexities associated with symbolic links.  If
+	// the last component of the path is a symlink we have to resolve it
+	// since we won't be able to resolve the name when the options are
+	// added.  Also we need to get the path relative to the pps filesystem
+	// so we can locate the .notify file.  So, if the object already
+	// exists, resolve the path.  If it doesn't and O_CREAT is specified
+	// resolve the directory it's in, otherwise it's a failure.
+	std::string resolvedName;
+	char szResolvedName[PATH_MAX+128]; // buffer for use with the C functions
+
+	if (::realpath(pathNoOptions.c_str(), szResolvedName) != NULL) {
+
+		resolvedName = szResolvedName;
+		ok = true;
+	}
+	else if (oflag & O_CREAT) {
+
+		// Chop off the file name, so we can try to resolve the directory
+		size_t nPos = pathNoOptions.rfind('/');
+
+		// We found a '/'
+		if (nPos != std::string::npos) {
+
+			// Get the directory path
+			std::string dirPath = pathNoOptions.substr(0, nPos); // Don't include the '/'
+
+			if (::realpath(dirPath.c_str(), szResolvedName) != NULL) {
+
+				// Concatenate the file name to the resolved directory path
+				resolvedName = szResolvedName + pathNoOptions.substr(nPos); // include the '/' at the start
+				ok = true;
+			}
+		}
+	}
+
+	if (ok) {
+
+		struct stat info;
+		int result = ::lstat(resolvedName.c_str(), &info);
+
+		if (result != 0) {
+
+			// If we failed and we're not creating a non-existent file, it's an error.
+			if ((errno != ENOENT) && !(oflag & O_CREAT))
+				ok = false;
+		}
+		else if (S_ISDIR(info.st_mode))
+			ok = false;
+	}
+
+	if (ok) {
+
+		std::string options;
+
+		// Now lets work with the options to ensure we have a complete version
+		std::string pathOptions;
+		
+		// Get just the stuff after '?'
+		size_t nPos = fullpath.rfind('?');
+
+		if (nPos != std::string::npos) {
+			pathOptions = fullpath.substr(nPos);
+		}
+
+		if ((oflag & O_ACCMODE) != O_WRONLY) {
+
+			// This is used as the return object for the joinNotifyGroup() call
+			// It's only valid if joinNotifyGroup() returned true
+			std::string groupId;
+
+			PPSNotifyGroupManager::mutexLock();
+			PPSNotifyGroupManager& notifyManager = PPSNotifyGroupManager::getInstance();
+			bool groupJoined = notifyManager.joinNotifyGroup(resolvedName, groupId);
+			PPSNotifyGroupManager::mutexUnlock();
+
+			if (groupJoined) {
+
+				// If we're acting as a server, we use server as an option
+				// otherwise we have to specify delta mode.  PPS has a fit
+				// if we specify both delta and deltadir so check for this.
+				std::string modeExtra;
+
+				// Add in the options we need.  If both server and delta are specified, use only
+				// server (it kind of implies delta and at one point pps would not like both being
+				// present)
+				if (server) {
+					modeExtra = ",server";
+				}
+				// If we have no options or there's no 'deltadir' specified, use delta mode
+				else if (pathOptions.empty() || pathOptions.find("deltadir") == std::string::npos) {
+					modeExtra = ",delta";
+				}
+
+				// We embed the m_interfaceID as a unique identifier that will be passed on to the
+				// PPSNotifier. PPSNotifier will use this id in conjunction with getPPSInterface()
+				// in order to send this object notifications that content is ready for reading later.
+				std::ostringstream ostream;
+				ostream << "?" << (pathOptions.empty() ? "" : pathOptions.substr(1) + ",") << "notify="
+						<< groupId << ":" << m_interfaceId << modeExtra;
+				options = ostream.str();
+			}
+		}
+
+		if (!options.empty()) {
+
+			resolvedName += options;
+		}
+
+		// The big moment... Let's try to actually open the PPS object...
+		if (ok) {
+			m_fd = ::open(resolvedName.c_str(), oflag, mode);
+		}
+
+		// Error opening the PPS object
+		if (m_fd < 0) {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::open() Failed - ::open("
+					<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+					   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+					   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+					<< ((oflag & O_CREAT) ? ":create" : "")
+					<< ") " << resolvedName << " (" << errno << ": " << strerror(errno) << ")";
+			m_logger.slog(Logger::warning, ostream.str());
+			errorMsg = ostream.str();
+		}
+		else {
+			// Depending on our umask, the permissions might not have
+			// been as specified. So if O_CREAT was specified, re-set the
+			// permissions.  The object might already exist, but perhaps
+			// that's OK too.
+			if (oflag & O_CREAT) {
+				::fchmod(m_fd, mode);
+			}
+
+			m_oflags = oflag;
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::open() - ::open("
+					<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+					   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+					   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+					<< ((oflag & O_CREAT) ? ":create" : "")
+					<< ") " << resolvedName;
+			m_logger.slog(Logger::debug, ostream.str());
+		}
+	}
+	// For whatever reason, the path to the PPS object was not valid
+	else {
+		std::ostringstream ostream;
+		ostream << "PPSInterface::open() Failed - ::open("
+				<< (((oflag & O_ACCMODE) == O_WRONLY) ? "write" :
+				   ((oflag & O_ACCMODE) == O_RDONLY) ? "read" :
+				   ((oflag & O_ACCMODE) == O_RDWR) ? "r/w" : "???")
+				<< ((oflag & O_CREAT) ? ":create" : "")
+				<< ") " << path << " The PPS object could not be resolved properly.";
+		m_logger.slog(Logger::warning, ostream.str());
+		errorMsg = ostream.str();
+	}
+
+	sendEvent(PPSEvent(m_fd >= 0 ? PPSEvent::PPS_EVENT_OPENED : PPSEvent::PPS_EVENT_OPEN_FAILED, errorMsg));
+
+	if (m_fd >= 0 && (oflag & O_ACCMODE) != O_WRONLY) {
+
+		// Perform the initial read
+		readFromObject();
+	}
+
+	// Tell the other thread we are done with the first read
+	::pthread_mutex_lock(&sm_mutex);
+	m_firstRead = false;
+	::pthread_cond_broadcast(&sm_cond);
+	::pthread_mutex_unlock(&sm_mutex);
+
+	return m_fd >= 0;
+}
+
+void PPSInterface::write(const std::string& data)
+{
+	// We're trying to write to an unopened PPS object
+	if (m_fd == -1) {
+
+		std::string msg("PPSInterface::write() Failed - Attempting to write to a file that isn't open.");
+		m_logger.slog(Logger::warning, msg);
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_WRITE_FAILED, msg));
+	}
+
+	ssize_t ret = ::write(m_fd, data.c_str(), data.length());
+
+	// Debug slog the write call if it was successful
+	if (ret >= 0) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::write() - fd:" << m_fd << " : \n" << data;
+		m_logger.slog(Logger::debug, ostream.str());
+	}
+
+	// There was an error writing
+	if (ret == -1) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::write() Failed - Error writing to fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+		m_logger.slog(Logger::warning, ostream.str());
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_WRITE_FAILED, ostream.str()));
+	}
+
+	// If we wrote successfully and the file is open in read/write mode, then we need to manually update the
+	// read cache. When in O_RDWR mode, we do NOT receive notifications of our own write() operations.
+	// This means that the cache of read data becomes stale - it is missing the data that we have written
+	// to the object ourselves. In this case, we will manually update the cache.
+	// NOTE: this seems fraught with peril, but unfortunately there don't seem to be any good solutions to
+	// fixing the problem of read/write mode and read() integrity.
+	if (ret >= 0 && (m_oflags & O_RDWR)) {
+
+		// We're going to try to fool the ppsparse() method into parsing the data we write.
+		char* pWriteData = new char[data.length() + 1];
+
+		// The later call to ppsparse() moves the pWriteData pointer forward, and we need the original pointer
+		// in order to properly delete the object later, so let's cache it here
+		char* pWriteDataCopy = pWriteData;
+
+		std::strcpy(pWriteData, data.c_str()); // strcpy null terminates for us
+
+		// Parse the write buffer - this should give us a ppsObject with only attributes
+		ppsObject parsedData = parsePPSData(pWriteData);
+
+		// The data being written does not include the object name other object properties (duh)
+		// So parsedData contains only attribute info. We want to preserve the object name
+		// and properties, so lets just copy the ones in the cache into our parsedData struct
+		// so that the call to updateCachedReadData() will preserve them (i.e. copy them back)
+		parsedData.name = m_cachedRead.name;
+		parsedData.flags = m_cachedRead.flags;
+		parsedData.options = m_cachedRead.options;
+		parsedData.optionMask = m_cachedRead.optionMask;
+
+		// Update the cache
+		updateCachedReadData(parsedData);
+
+		// Cleanup our allocated memory
+		if (pWriteDataCopy) {
+
+			delete[] pWriteDataCopy;
+		}
+	}
+}
+
+void PPSInterface::sync()
+{
+	if (m_fd >= 0)
+		::fsync(m_fd);
+}
+
+void PPSInterface::close()
+{
+	if (m_fd >= 0) {
+
+		::close(m_fd);
+		m_fd = -1;
+		m_cachedRead = ppsObject();
+		m_oflags = 0;
+
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_CLOSED));
+	}
+}
+
+void PPSInterface::onNotify(NotifyType event)
+{
+	// We only handle read notifications
+	if (event != PPS_READ) {
+		return;
+	}
+
+	if (m_firstRead) {
+		::pthread_mutex_lock(&sm_mutex);
+		while (m_firstRead) {
+			::pthread_cond_wait(&sm_cond, &sm_mutex);
+		}
+		::pthread_mutex_unlock(&sm_mutex);
+	}
+
+	readFromObject();
+}
+
+void PPSInterface::readFromObject()
+{
+	bool sendFirstReadEvent = m_firstRead;
+
+	// This was a uint8_t - was there a reason?
+	char szBuffer[MaxPPSReadSize + 1];
+	int bufferLen;
+
+	// Read from the actual PPS file - this call is not blocking
+	while ((bufferLen = ::read(m_fd, szBuffer, MaxPPSReadSize)) > 0) {
+
+		if (bufferLen <= MaxPPSReadSize) {
+
+			// Make sure the buffer is null terminated.
+			szBuffer[bufferLen] = '\0';
+
+			std::string buf(szBuffer, bufferLen);
+			std::ostringstream ostream;
+			ostream << "PPSInterface::readFromObject() - fd:" << m_fd << " len:" << bufferLen << "\n" << buf;
+			m_logger.slog(Logger::debug, ostream.str());
+
+			// Parse the PPS data
+			ppsObject parsedPPS = parsePPSData(szBuffer);
+
+			// Update the cache with the data we just read
+			updateCachedReadData(parsedPPS);
+
+			// If this is the first read, then send the first read event.
+			if (sendFirstReadEvent) {
+
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_FIRST_READ_COMPLETE, "", parsedPPS));
+				sendFirstReadEvent = false;
+			}
+			else {
+
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_NEW_DATA, "", parsedPPS));
+			}
+		}
+		else {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::readFromObject() Failed - fd:" << m_fd << " oversized message len:" << bufferLen << ".";
+			m_logger.slog(Logger::warning, ostream.str());
+		}
+	}
+
+	if (bufferLen == -1) {
+
+		std::ostringstream ostream;
+		ostream << "PPSInterface::readFromObject() Failed - Error reading from fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+		m_logger.slog(Logger::warning, ostream.str());
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, ostream.str()));
+	}
+
+	// It's possible that we won't go into the while() loop above (sometimes the first read is legitimately empty)
+	// in which case, we still need to send a first read complete event
+	if (sendFirstReadEvent) {
+
+		// Send an empty first read object
+		sendEvent(PPSEvent(PPSEvent::PPS_EVENT_FIRST_READ_COMPLETE, "", ppsObject()));
+		sendFirstReadEvent = false;
+	}
+}
+
+void PPSInterface::sendEvent(const PPSEvent& event) const
+{
+	if (m_pEventFunc) {
+		m_pEventFunc(m_pEventArg, event);
+	}
+}
+
+PPSInterface* const PPSInterface::getPPSInterface(const unsigned int id)
+{
+	::pthread_mutex_lock(&sm_mutex);
+
+	std::map<unsigned int, PPSInterface*>::iterator it = sm_interfaceLookupTable.find(id);
+
+	if (it != sm_interfaceLookupTable.end()) {
+
+		::pthread_mutex_unlock(&sm_mutex);
+		return (*it).second;
+	}
+
+	::pthread_mutex_unlock(&sm_mutex);
+	return NULL;
+}
+
+ppsObject PPSInterface::parsePPSData(char* data) const
+{
+	// This is the structure that will contain parsed data for each line of the PPS object
+	// It needs to be initialized to NULL
+	pps_attrib_t info;
+	std::memset(&info, 0, sizeof(info));
+
+	// The return code for each PPS line that gets parsed
+	pps_status_t rc;
+	ppsObject ppsObj;
+
+	while ((rc = ::ppsparse(&data, NULL, NULL, &info, 0)) != PPS_END) {
+
+		if (rc == -1) {
+
+			std::ostringstream ostream;
+			ostream << "PPSInterface::parsePPSData() Failed - Error calling ppsparse() fd:" << m_fd << " (" << errno << ": " << strerror(errno) << ")";
+			m_logger.slog(Logger::warning, ostream.str());
+			sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, ostream.str()));
+		}
+
+		if (info.flags & PPS_INCOMPLETE) {
+			m_logger.slog(Logger::debug, "PPSInterface::parsePPSData - PPS data incomplete.");
+		}
+
+		switch (rc) {
+
+			// When the object has been modified, update the object settings
+			case PPS_OBJECT:
+			case PPS_OBJECT_CREATED:
+			case PPS_OBJECT_DELETED:
+			case PPS_OBJECT_TRUNCATED:
+			{
+				ppsObj.name = info.obj_name;
+				ppsObj.flags = info.flags;
+				ppsObj.options = info.options;
+				ppsObj.optionMask = info.option_mask;
+				break;
+			}
+
+			// An attribute has been updated
+			case PPS_ATTRIBUTE:
+			case PPS_ATTRIBUTE_DELETED:
+			{
+				ppsAttribute ppsAttrib;
+				ppsAttrib.name = info.attr_name;
+
+				// Value and encoding aren't valid if rc == PPS_ATTRIBUTE_DELETED
+				if (rc == PPS_ATTRIBUTE) {
+
+					ppsAttrib.value = info.value;
+					ppsAttrib.encoding = info.encoding;
+				}
+
+				ppsAttrib.flags = info.flags;
+				ppsAttrib.options = info.options;
+				ppsAttrib.optionMask = info.option_mask;
+
+				ppsObj.attributes.insert(ppsAttrPair(ppsAttrib.name, ppsAttrib));
+				break;
+			}
+
+			case PPS_ERROR:
+			{
+				std::string msg("PPSInterface::parsePPSData() Failed - Error parsing PPS data.");
+				m_logger.slog(Logger::warning, msg);
+				sendEvent(PPSEvent(PPSEvent::PPS_EVENT_READ_FAILED, msg));
+				break;
+			}
+
+			case PPS_END:
+			default:
+				break;
+		}
+
+	}
+
+	return ppsObj;
+}
+
+void PPSInterface::updateCachedReadData(const ppsObject& newData)
+{
+	::pthread_mutex_lock(&sm_mutex);
+
+	// Update the object
+	m_cachedRead.name = newData.name;
+	m_cachedRead.flags = newData.flags;
+	m_cachedRead.options = newData.options;
+	m_cachedRead.optionMask = newData.optionMask;
+
+	::pthread_mutex_unlock(&sm_mutex);
+
+	// Update the attributes
+	for (const_ppsAttrIter it = newData.attributes.begin(); it != newData.attributes.end(); it++) {
+
+		ppsAttribute attr = (*it).second;
+
+		// An attribute is being deleted
+		if (attr.flags & PPS_DELETED) {
+
+			::pthread_mutex_lock(&sm_mutex);
+
+			// Look for this attribute in the cache and remove it
+			ppsAttrIter findIt = m_cachedRead.attributes.find(attr.name);
+
+			if (findIt != m_cachedRead.attributes.end()) {
+				m_cachedRead.attributes.erase(findIt);
+			}
+
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+		// We're adding a new attribute - don't search for it
+		else if (attr.flags & PPS_CREATED){
+
+			::pthread_mutex_lock(&sm_mutex);
+			m_cachedRead.attributes.insert(ppsAttrPair(attr.name, attr));
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+		else {
+
+			::pthread_mutex_lock(&sm_mutex);
+
+			// Look for this attribute in the cache
+			ppsAttrIter findIt = m_cachedRead.attributes.find(attr.name);
+
+			// If we find it, update the attribute values
+			if (findIt != m_cachedRead.attributes.end()) {
+
+				(*findIt).second.name = attr.name;
+				(*findIt).second.encoding = attr.encoding;
+				(*findIt).second.value = attr.value;
+				(*findIt).second.flags = attr.flags;
+				(*findIt).second.options = attr.options;
+				(*findIt).second.optionMask = attr.optionMask;
+			}
+			// If we don't find it, insert it
+			else {
+				m_cachedRead.attributes.insert(ppsAttrPair(attr.name, attr));
+			}
+			::pthread_mutex_unlock(&sm_mutex);
+		}
+	}
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
new file mode 100644
index 0000000..0fde80c
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSInterface.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPS_H_
+#define PPS_H_
+
+#include <string>
+#include <map>
+
+#include <sys/types.h>
+
+#include "PPSTypes.h"
+#include "PPSEvent.h"
+#include "../utils/Logger.h"
+
+namespace jpps {
+
+/**
+ * This class augments standard PPS functionality by providing events for when PPS objects are opened,
+ * closed, have new data, etc.
+ *
+ * When a PPS object is opened using PPSInterface::open(), the object is opened as part of a notification group
+ * managed by PPSNotifyGroupManager. The notification group monitors the PPS object and notifies PPSInterface
+ * whenever there is new data available in the PPS object.
+ *
+ * PPSInterface should be used in order to simplify PPS object monitoring (i.e. watching for new data in a PPS
+ * object.) PPSInterface takes over management of watching for new data and uses a notification callback mechanism
+ * with a defined set of possible events to inform the client of changes to the PPS object.
+ */
+class PPSInterface {
+
+public:
+
+	/**
+	 * Used with onNotify to allow the PPSNotifier to tell us what type of notification
+	 * message it is sending.
+	 */
+	enum NotifyType {
+		/** The .notify object received a notification that data is ready to be read. */
+		PPS_READ = 0,
+		/** The .notify object received a notification that a file being watched is closing. */
+		PPS_CLOSE = 1 };
+
+	/**
+	 * Constructor.
+	 */
+	PPSInterface();
+
+	/**
+	 * Destructor.
+	 */
+	~PPSInterface();
+
+	/**
+	 * Set up a function to call to be notified about PPS events.
+	 *
+	 * @param pEventFunc The function to call whenever an event happens in PPSInterface.
+	 * @param pArg An optional parameter that will be passed back to pEventFunc every time it
+	 * is called. PPSInterface will not modify pArg.
+	 */
+	void setEventFunc(const PPSEventFunc* pEventFunc, void* pArg = NULL);
+
+	/**
+	 * Enable verbose mode. Increase the number of �v�s to increase verbosity.
+	 *
+	 * @param v The level of verbosity. A value of 0 is off, 1 shows info messages, 2 shows
+	 * debug messages.
+	 */
+	void setVerbose(unsigned short v);
+
+	/**
+	 * Open a PPS object. If the open() call is successful, a PPS_EVENT_OPENED event will be sent.
+	 * The PPS object will be read as part of the open operation and the PPS_EVENT_FIRST_READ_COMPLETE
+	 * will be sent when the first read is complete. Note that there may be a PPS_EVENT_NEW_DATA
+	 * event *before* the PPS_EVENT_FIRST_READ_COMPLETE event, or there may not be.
+	 * PPS_EVENT_FIRST_READ_COMPLETE only guarantees that at least one read has been performed, not
+	 * that it will be the first read event to fire.
+	 *
+	 * If the open operation fails, the function returns false and a PPS_EVENT_OPEN_FAILED will be sent.
+	 *
+	 * @param path The PPS file/directory path.
+	 * @param oflags Flags passed to ::open.
+	 * @param mode Mode passed to ::open.
+	 * @param serverMode If true, open the object in server mode as the server.
+	 * @return True if the open was successful, false otherwise.
+	 */
+	bool open(const std::string& path, int oflags, int mode, bool serverMode);
+
+	/**
+	 * Check if this PPS object is open.
+	 * @return True if the file is open, false otherwise.
+	 */
+	inline bool isOpen() const { return m_fd >= 0; }
+
+	/**
+	 * Write data to a PPS object.
+	 * @param data The data to write to the PPS object.
+	 */
+	void write(const std::string& data);
+
+	/**
+	 * Read PPS data. Note that this reads cached data from the last read performed when a
+	 * new data available notification was received.
+	 *
+	 * @return A structured representation of the PPS object, culled from a call to ppsparse()
+	 * a function found in ppsparse.h.
+	 */
+
+	inline ppsObject read() const { return m_cachedRead; }
+
+	/**
+	 * Close this PPS object.
+	 */
+	void close();
+
+	/**
+	 * Forces all queued I/O operations for this object to finish, synchronizing the file's state.
+	 * The function blocks until this is finished.
+	 */
+	void sync();
+
+	/**
+	 * Called to notify us that there is data ready to be read.
+	 *
+	 * @param event The type of event we're being notified about.
+	 */
+	void onNotify(NotifyType event);
+
+	/**
+	 * Given a unique id, return the PPSInterface* matching that id.
+	 *
+	 * Every PPSInterface object is assigned a unique identifier at construction. This
+	 * unique identifier can be used to get a pointer to a PPSInterface at runtime.
+	 *
+	 * In particular, the PPSNotifier gets notifications with this number embedded in them.
+	 * Using this id, the PPSNotifier can callback into the correct PPSInterface instance.
+	 *
+	 * @param id An id that uniquely identifies a PPSInterface object.
+	 * @return a PPSInterface* or NULL if no object matches the given id.
+	 */
+	static PPSInterface* const getPPSInterface(const unsigned int id);
+
+private:
+
+	/**
+	 * Read from the PPS object. Generally this function is called by onNotify() when
+	 * the notifier thread is notified that there is data to be read. This function
+	 * performs a read() of the PPS object that is non-blocking.
+	 */
+	void readFromObject();
+
+	/**
+	 * Given data from a PPS read, parse the PPS data.
+	 */
+	ppsObject parsePPSData(char* data) const;
+
+	/**
+	 * Given new PPS data, update the cached read value.
+	 */
+	void updateCachedReadData(const ppsObject& newData);
+
+	/**
+	 * Call the function set in setEventFunc() with the given event.
+	 *
+	 * @param event The event to send.
+	 */
+	void sendEvent(const PPSEvent& event) const;
+
+	/** The default PPS location. */
+	static const char* PPS_ROOT;
+
+	/** The maximum amount of data that can be read from a PPS object. */
+	static const int MaxPPSReadSize;
+
+	/** The function to call to notify about PPS events. */
+	PPSEventFunc* m_pEventFunc;
+
+	/** An argument that goes with m_pEventFunc. PPSInterface does not modify or use
+	 * this parameter - we simply send it back with every m_pEventFunc call. */
+	void* m_pEventArg;
+
+	/** An identifier that uniquely identifies this PPSInterface object. This is used to look up
+	 * this object in a global table. */
+	unsigned int m_interfaceId;
+
+	/** The file descriptor of the PPS object being opened. */
+	int m_fd;
+
+	/** The open mode flags used when this object was opened. */
+	int m_oflags;
+
+	/** If true, main thread is performing initial open/read of PPS object. This is shared
+	 * across threads and needs to be mutexed when accessed.*/
+	volatile bool m_firstRead;
+
+	/** The data from the last read performed. */
+	ppsObject m_cachedRead;
+
+	/** The logger used to log error messages */
+	Logger m_logger;
+
+	/** Mutex used to prevent threads from clobbering each other. */
+	static pthread_mutex_t sm_mutex;
+
+	/** Condvar used for multi-thread signaling. */
+	static pthread_cond_t sm_cond;
+
+	/** Used to ensure that initialization of statics happens only once. This is shared
+	 * across threads and needs to be mutexed when accessed.*/
+	static volatile bool sm_firstInitDone;
+
+	/** The PPSNotifier needs a way to transform an id that uniquely identifies a PPSInterface object
+	 * into an actual PPSInterface*. When we construct a new PPSInterface, we will assign it a unique id
+	 * and we will put the id and the pointer to the object into this table. The table can then be used
+	 * to lookup this object from its unique id. */
+	static std::map<unsigned int, PPSInterface*> sm_interfaceLookupTable;
+};
+
+} /* namespace jpps */
+#endif /* PPS_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
new file mode 100644
index 0000000..7869a56
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "PPSNotifier.h"
+
+#include <sstream>
+
+#include <fcntl.h>
+
+#include "PPSInterface.h"
+#include "../utils/Logger.h"
+
+namespace jpps {
+
+PPSNotifier::PPSNotifier()
+: m_notifyObjPath("")
+, m_notifyObjFd(-1)
+, m_notifyGroupId("")
+, m_thread()
+{
+
+}
+
+PPSNotifier::~PPSNotifier()
+{
+	// Stop the thread
+	m_thread.stop();
+
+	// Close the .notify file
+	if (m_notifyObjFd >= 0) {
+		::close(m_notifyObjFd);
+	}
+}
+
+void PPSNotifier::startNotifyLoop()
+{
+	m_thread.start(_notifyLoop, this, "plugin_jPPS_PPSNotifier(" + m_notifyObjPath + "/.notify)");
+}
+
+
+void* PPSNotifier::_notifyLoop(void* pArg)
+{
+	// Something is messed up
+	if (pArg == NULL)
+		return NULL;
+
+	PPSNotifier* pNotifier = static_cast<PPSNotifier*> (pArg);
+
+	// pArg is supposed to be a PPSNotifier object...
+	if (pNotifier == NULL)
+		return NULL;
+
+	pNotifier->notifyLoop();
+
+	return NULL;
+}
+
+void PPSNotifier::notifyLoop()
+{
+	// Buffer for read() operation
+	char szData[256];
+	int dataLen;
+
+	// This is a blocking read call: this will wait in this loop forever
+	while ((dataLen = ::read(m_notifyObjFd, szData, sizeof(szData)-1)) > 0) {
+
+                szData[dataLen] = '\0';
+		std::string data(szData);
+
+		if ((unsigned int)dataLen > sizeof(szData)-1) {
+
+			std::ostringstream ostream;
+			ostream << "PPSNotifier::notifyLoop() - Notify read overflow " << dataLen << ".";
+			Logger logger;
+			logger.slog(Logger::error, ostream.str());
+		}
+
+		std::size_t nPos = data.find('\n');
+
+		// While we find linefeeds
+		while(nPos != std::string::npos) {
+
+			// Read the first char
+			PPSInterface::NotifyType event = data[0] == '-' ? PPSInterface::PPS_CLOSE : PPSInterface::PPS_READ;
+			std::size_t nAddrPos = data.find(':');
+
+			if (nAddrPos != std::string::npos) {
+
+				std::string sAddress = data.substr(nAddrPos+1);
+				std::size_t nAddrEnd = sAddress.find('\n');
+
+				if (nAddrEnd != std::string::npos) {
+
+					sAddress = sAddress.substr(0, nAddrEnd);
+
+					unsigned int interfaceId = 0;
+
+					std::stringstream ss;
+					ss << sAddress;
+					ss >> interfaceId;
+
+					PPSInterface* const pPPS = PPSInterface::getPPSInterface(interfaceId);
+
+					if (pPPS) {
+						pPPS->onNotify(event);
+					}
+				}
+			}
+
+			// Don't go off the end of the string
+			if (++nPos < data.length()) {
+
+				// Remove the stuff up to the first '\n' and look for the next '\n'
+				data = data.substr(nPos);
+				nPos = data.find('\n');
+			}
+			else {
+
+				nPos = std::string::npos;
+			}
+		}
+	}
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.h
new file mode 100644
index 0000000..143f052
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifier.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPSNOTIFIER_H_
+#define PPSNOTIFIER_H_
+
+#include <string>
+
+#include "../utils/Thread.h"
+
+namespace jpps {
+
+/**
+ * PPSNotifier is an encapsulation of an open PPS .notify object. PPSNotifier has a
+ * blocking thread dedicated to reading from its .notify object. The thread constantly
+ * waits for new notifications in the .notify object.
+ *
+ * The way the PPS notify mechanism works is that on the first open/read of a .notify object,
+ * PPS provides a notify group id. This group id can be used when opening any PPS object to make
+ * the PPS object join the notify group.
+ *
+ * For example, you open a .notify file and the group id returned is "2a3".
+ * You subsequently open a PPS object and make it join that notify group:
+ *
+ * ::open("/pps/myppsobj?notify=2a3:someUniqueValueIDecide");
+ *
+ * Now, every time myppsobj changes, the .notify file will be updated in the following manner:
+ *
+ * <code>Notify 2a3:someUniqueValueIDecide</code>
+ *
+ * For a change to the file. And
+ *
+ * <code>-2a3:someUniqueValueIDecide</code>
+ *
+ * if myppsobj is closed.
+ *
+ * When PPSNotifier reads a notification, the unique value is actually a unique identifier for a
+ * PPSInterface object that can be looked up in a global PPSInterface lookup table. Getting the
+ * PPSInterface object designated by the unique identifier, PPSNotifier calls PPSInterface::onNotify()
+ * to inform the PPSInterface object that there is new data pending or that the file has closed.
+ * It is then up to the PPSInterface to decide how to proceed to get that data from myppsobj.
+ */
+class PPSNotifier {
+
+public:
+
+	/**
+	 * Constructor.
+	 */
+	PPSNotifier();
+
+	/**
+	 * Destructor. Note that this destructor will attempt to close the .notify
+	 * object's file.
+	 */
+	virtual ~PPSNotifier();
+
+	/**
+	 * Start the notify thread.
+	 */
+	void startNotifyLoop();
+
+	/**
+	 * Get the .notify object's path.
+	 *
+	 * @return The path to the .notify object.
+	 */
+	inline std::string getNotifyObjPath() const { return m_notifyObjPath; }
+
+	/**
+	 * Set the .notify object's path.
+	 *
+	 * @param path The path of the .notify object (note that this should not include the
+	 * .notify object name).
+	 */
+	inline void setNotifyOjbPath(const std::string& path) { m_notifyObjPath = path; }
+
+	/**
+	 * Get the .notify object's file descriptor.
+	 *
+	 * @return The file descriptor for the open .notify object.
+	 */
+	inline int getObjFd() const { return m_notifyObjFd; }
+
+	/**
+	 * Set the .notify object's file descriptor.
+	 *
+	 * @param The file descriptor for the open .notify object.
+	 */
+	inline void setObjFd(const int fd) { m_notifyObjFd = fd; }
+
+	/**
+	 * Set this notifier's .notify group ID (assigned by PPS).
+	 *
+	 * @param The .notify object's group ID, which is returned by PPS on the first read
+	 * of the .notify object.
+	 */
+	inline std::string getNotifyGroupId() const { return m_notifyGroupId; }
+
+	/**
+	 * Get this notifier's .notify group ID (assigned by PPS).
+	 *
+	 * @return The .notify object's group ID.
+	 */
+	inline void setNotifyGroupId(const std::string& id) { m_notifyGroupId = id; }
+
+private:
+
+	// Disable the copy constructor
+	PPSNotifier(const PPSNotifier& manager);
+
+	// Disable the assignment operator
+	PPSNotifier& operator=(const PPSNotifier& rhs);
+
+	/**
+	 * Function used to start the thread. Pass this into the Thread::start() function.
+	 *
+	 * @param pArg A pointer to a PPSNotifier.
+	 */
+	static void* _notifyLoop(void* pArg);
+
+	/**
+	 * The main thread loop. Blocks on reading the .notify file.
+	 */
+	void notifyLoop();
+
+	/** The path of the .notify file we're monitoring to know when to get data. */
+	std::string m_notifyObjPath;
+
+	/** The file descriptor of the .notify file we're monitoring to know when to get data. */
+	int m_notifyObjFd;
+
+	/** The .notify group ID assigned by PPS when the group was created. */
+	std::string m_notifyGroupId;
+
+	/** The thread I'm running on. */
+	Thread m_thread;
+};
+
+} /* namespace jpps */
+#endif /* PPSNOTIFIER_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.cpp b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.cpp
new file mode 100644
index 0000000..5392ca8
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "PPSNotifyGroupManager.h"
+
+#include <fcntl.h>
+
+#include "PPSNotifier.h"
+
+namespace jpps {
+
+typedef std::map<std::string, PPSNotifier*>::iterator groupIter;
+typedef std::map<std::string, PPSNotifier*>::const_iterator const_groupIter;
+typedef std::pair<std::string, PPSNotifier*> groupValue;
+
+pthread_mutex_t PPSNotifyGroupManager::sm_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+PPSNotifyGroupManager::PPSNotifyGroupManager()
+{
+
+}
+
+PPSNotifyGroupManager::~PPSNotifyGroupManager()
+{
+	// Delete the allocated memory for all the PPSNotifiers
+	for (groupIter it = m_notifyGroups.begin(); it != m_notifyGroups.end(); it++) {
+
+		if ((*it).second != NULL) {
+
+			delete (*it).second;
+			(*it).second = NULL;
+		}
+	}
+}
+
+PPSNotifyGroupManager& PPSNotifyGroupManager::getInstance()
+{
+	// The one and only PPSNotifyGroupManager
+	static PPSNotifyGroupManager manager;
+	return manager;
+}
+
+bool PPSNotifyGroupManager::joinNotifyGroup(const std::string& path, std::string& groupId)
+{
+	std::string notifyFile;
+	std::string notifyPath(path);
+	std::size_t nPos = notifyPath.rfind('/');
+
+	// Search through the directories in the string until we find a valid .notify object
+	while (nPos != std::string::npos) {
+
+		// Chop off everything after the last '/' to get the path without the PPS object name
+		notifyPath = notifyPath.substr(0, nPos);
+
+		// Do we already have a notify group for this path?
+		const_groupIter it = m_notifyGroups.find(notifyPath);
+
+		// We found a match!
+		if (it != m_notifyGroups.end() && (*it).second != NULL) {
+
+			groupId = (*it).second->getNotifyGroupId();
+			return true;
+		}
+
+		// Add ".notify?wait" to the notify path, to make it a real file
+		notifyFile = notifyPath + "/.notify?wait";
+
+		// Try to open this .notify object
+		int fd = ::open(notifyFile.c_str(), O_RDONLY);
+
+		// This is the .notify object to use
+		if (fd >= 0) {
+
+			char data[20];
+			int len = ::read(fd, data, sizeof(data) - 1);
+			// Terminate string to remove the newline char
+			data[len > 0 ? len - 1 : 0] = '\0';
+
+			PPSNotifier* pNotifier = new PPSNotifier();
+			pNotifier->setNotifyGroupId(std::string(data));
+			pNotifier->setNotifyOjbPath(notifyPath);
+			pNotifier->setObjFd(::dup(fd));
+                        ::close(fd);
+
+			// Add this badboy to our cache of notify groups
+			m_notifyGroups.insert(groupValue(notifyPath, pNotifier));
+
+			// Start the notify reading thread
+			pNotifier->startNotifyLoop();
+
+			groupId = pNotifier->getNotifyGroupId();
+			return true;
+		}
+		// Keep looking
+		else {
+
+			nPos = notifyPath.rfind('/');
+		}
+	}
+
+	// We didn't find a notify group
+	groupId = "";
+	return false;
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.h
new file mode 100644
index 0000000..03b0e3e
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSNotifyGroupManager.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPSNOTIFYGROUPMANAGER_H_
+#define PPSNOTIFYGROUPMANAGER_H_
+
+#include <map>
+#include <string>
+#include <pthread.h>
+
+namespace jpps {
+
+// Forward declaration
+class PPSNotifier;
+
+
+/**
+ * The PPSNotifyGroupManager is used to manage a global pool of .notify objects. PPS has a mechanism
+ * where every folder can contain a special PPS object ".notify". Opening the .notify object will return
+ * a group id on the first read of the .notify object. The group id is used to open the real PPS object
+ * for which we desire to receive notifications. Once this is done, the .notify object is the one that will
+ * receive change notifications for the real PPS object. In this model, the real PPS object DOES NOT
+ * open in blocking read or ionotify/select mode. The .notify object is the one responsible for blocking
+ * on read and tracking data publishing.
+ *
+ * This object is a global singleton - any access to it needs to be wrapped in a mutex to prevent
+ * concurrency problems. Two functions mutex_lock() and mutex_unlock() are provided for this purpose.
+ */
+class PPSNotifyGroupManager
+{
+public:
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~PPSNotifyGroupManager();
+
+	/**
+	 * Get the one and only instance of the PPSNotifier.Always wrap calls to getInstance() in a call to
+	 * PPSNotifyGroupManager::mutexLock()/mutexUnlock().
+	 */
+	static PPSNotifyGroupManager& getInstance();
+
+	/**
+	 * Use this function to get the notify group id of the "closest" .notify object in the /pps hierarchy
+	 * that contains path.
+	 *
+	 * The function will go backwards through the directories in path looking for a .notify object. It will return
+	 * the group id of the first .notify object it finds on this path. It is the responsibility of the caller
+	 * to have the PPS object in path join the notify group by opening the object with the "notify=groupId:val"
+	 * option set.
+	 *
+	 * PPSNotifyGroupManager maintains a pool of opened .notify objects. It is possible for a single .notify object
+	 * to have a very disparate (and numerous) set of PPS objects that it monitors. In order to tweak performance
+	 * it is advisable that .notify object be created in strategic directories in the /pps directory hierarchy, in
+	 * order to spread the load of notification monitoring. Each .notify object opened will spawn a thread that blocks
+	 * on reading from the .notify object. Having several .notify objects means having several threads that read
+	 * notifications.
+	 *
+	 * Note that joinNotifyGroup() will NOT create any .notify PPS objects. The /pps/.notify object always exists,
+	 * and if the /pps directory hierarchy contains no other .notify objects, /pps/.notify will end up being the
+	 * notification group that all objects join.
+	 *
+	 * Always wrap calls to joinNotifyGroup() in a call to PPSNotifyGroupManager::mutexLock()/mutexUnlock().
+	 *
+	 * @param The PPS object that wants to join the notify group.
+	 * @param groupId The id of the notify group joined. This is an output parameter.
+	 * @return True if a notify group was successfully joined, false otherwise. If true, then the groupId
+	 * variable will be set.
+	 */
+	bool joinNotifyGroup(const std::string& path, std::string& groupId);
+
+	/**
+	 * Returns how many notification groups the manager is managing.
+	 *
+	 * @return The number of notification groups (i.e. open .notify objects) in use.
+	 */
+	inline std::size_t getNumGroups() const { return m_notifyGroups.size(); }
+
+	/**
+	 * Should be used to wrap all calls to PPSNotifyGroupManager APIs. Because this is a singleton global
+	 * object, multiple threads may try to access this object at one time. It is therefore important to
+	 * mutex lock all access to this object.
+	 */
+	static inline void mutexLock() { pthread_mutex_lock(&sm_mutex); }
+
+	/**
+	 * Should be used to wrap all calls to PPSNotifyGroupManager APIs. Because this is a singleton global
+	 * object, multiple threads may try to access this object at one time. It is therefore important to
+	 * mutex lock all access to this object.
+	 */
+	static inline void mutexUnlock() { pthread_mutex_unlock(&sm_mutex); }
+
+private:
+
+	/**
+	 * Constructor. Private as part of the singleton pattern of this object.
+	 */
+	PPSNotifyGroupManager();
+
+	// Disable the copy constructor.
+	PPSNotifyGroupManager(const PPSNotifyGroupManager& manager);
+
+	// Disable the assignment operator.
+	PPSNotifyGroupManager& operator=(const PPSNotifyGroupManager& rhs);
+
+	/** This is a cache of all the .notify objects. */
+	std::map<std::string, PPSNotifier*> m_notifyGroups;
+
+	/** Mutex used to prevent threads from clobbering each other. */
+	static pthread_mutex_t sm_mutex;
+};
+
+} /* namespace jpps */
+#endif /* PPSNOTIFYGROUPMANAGER_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSTypes.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSTypes.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSTypes.h
new file mode 100644
index 0000000..362d236
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/core/PPSTypes.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef PPSTYPES_H_
+#define PPSTYPES_H_
+
+#include <map>
+
+namespace jpps {
+
+class PPSEvent;
+
+/**
+ * A struct representing an attribute of a PPS object.
+ */
+struct ppsAttribute {
+
+	/** The attribute name. */
+	std::string name;
+	/** The attribute value. */
+	std::string value;
+	/** The attribute encoding. */
+	std::string encoding;
+	/** Flags associated to the attribute. */
+	int flags;
+	/** Attribute options. */
+	int options;
+	/** The attribute options mask. */
+	int optionMask;
+};
+
+/**
+ * A struct representing a PPS object.
+ */
+struct ppsObject {
+
+	/** The PPS object name. */
+	std::string name;
+	/** The PPS object flags. */
+	int flags;
+	/** The PPS object options. */
+	int options;
+	/** The PPS object option mask. */
+	int optionMask;
+	/** The attributes of this PPS object. */
+	std::map<std::string, ppsAttribute> attributes;
+};
+
+/**
+ * Typedef for ppsAttribute iterator.
+ */
+typedef std::map<std::string, ppsAttribute>::iterator ppsAttrIter;
+
+/**
+ * Typedef for ppsAttribute const iterator.
+ */
+typedef std::map<std::string, ppsAttribute>::const_iterator const_ppsAttrIter;
+
+/**
+ * A pair used to insert attributes into the map.
+ */
+typedef std::pair<std::string, ppsAttribute> ppsAttrPair;
+
+/**
+ * This is the definition of the notify function clients of PPSInterface use in order
+ * to be informed of events the PPSInterface generates.
+ *
+ * @param pArg A user defined parameter. This value can be passed in to PPSInterface::setEventFunc()
+ * and will be passed back with the event handler every time it is called. PPSInterface will not
+ * modify this value.
+ *
+ * @aparam event The PPS event being broadcast.
+ */
+typedef void (PPSEventFunc)(void* pArg, const PPSEvent& event);
+
+};
+
+#endif /* PPSTYPES_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.cpp b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.cpp
new file mode 100644
index 0000000..9b5d711
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "JPPSPlugin.h"
+
+#include <string>
+#include <sstream>
+
+namespace jpps {
+
+const char* JPPSPlugin::CLASS_NAME = "PPS";
+const std::string JPPSPlugin::METHOD_OPEN = "Open";
+const std::string JPPSPlugin::METHOD_CLOSE = "Close";
+const std::string JPPSPlugin::METHOD_WRITE = "Write";
+const std::string JPPSPlugin::METHOD_READ = "Read";
+const std::string JPPSPlugin::METHOD_SET_VERBOSE = "SetVerbose";
+
+JPPSPlugin::JPPSPlugin(const std::string& jnextObjectId)
+: m_jnextObjId(jnextObjectId)
+, m_ppsInterface()
+{
+	// We only have one event handler, we'll use it for all events
+	m_ppsInterface.callbackInit(this,
+								onEvent,
+								onEvent,
+								onEvent,
+								onEvent,
+								onEvent,
+								onEvent,
+								onEvent);
+}
+
+JPPSPlugin::~JPPSPlugin()
+{
+
+}
+
+std::string JPPSPlugin::InvokeMethod(const std::string& strCommand)
+{
+	// Parameter sanity check
+	if (strCommand == "")
+		return std::string(szERROR) + " JPPSPlugin::InvokeMethod() called with no method to invoke.";
+
+	// Tokenize the stream of input information
+	std::stringstream args(strCommand);
+	std::string method;
+	args >> method;
+
+	// Invoke the method requested
+	if (method == JPPSPlugin::METHOD_WRITE) {
+		return write(args);
+	}
+	else if (method == JPPSPlugin::METHOD_READ) {
+		return read();
+	}
+	else if (method == JPPSPlugin::METHOD_OPEN) {
+		return open(args);
+	}
+	else if (method == JPPSPlugin::METHOD_CLOSE) {
+		return close();
+	}
+	else if (method == JPPSPlugin::METHOD_SET_VERBOSE) {
+		return setVerbose(args);
+	}
+
+	return std::string(szERROR) + m_jnextObjId + " JPPSPlugin::InvokeMethod() - unknown method \"" + method + "\"";
+}
+
+std::string JPPSPlugin::open(std::stringstream& args)
+{
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSPlugin::open() - invalid number of arguments.";
+
+	// Get the arguments
+	// 1st arg, the path
+	std::string path;
+	args >> path;
+
+	// Missing argument
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSPlugin::open() - invalid number of arguments.";
+
+	// 2nd arg, the open flags (i.e. O_RDONLY O_CREAT, etc.)
+	int oflags = 0;
+	args >> oflags;
+
+	bool bRet = m_ppsInterface.open(path, oflags);
+
+	return bRet ? std::string(szOK) + m_jnextObjId : std::string(szERROR) + m_jnextObjId + " JPPSPlugin::open() - failed to open \"" + path + "\".";
+}
+
+std::string JPPSPlugin::close()
+{
+	m_ppsInterface.close();
+	return szOK + m_jnextObjId;
+}
+
+std::string JPPSPlugin::write(std::stringstream& args)
+{
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSPlugin::write() - invalid number of arguments.";
+
+	// This truncates the buffer from the current position onwards (if you don't do this, you keep
+	// the method name that's at the beginning of the args stream)
+	args.seekg(1, std::ios_base::cur); 	// Skip the initial whitespace that was between the method name and the parameter
+	std::stringstream tmp;
+	tmp << args.rdbuf();
+
+	m_ppsInterface.write(tmp.str());
+	return szOK + m_jnextObjId;
+}
+
+std::string JPPSPlugin::read() const
+{
+	return std::string(szOK) + m_ppsInterface.read();
+}
+
+std::string JPPSPlugin::setVerbose(std::stringstream& args)
+{
+	unsigned short verbosity = 0;
+
+	// If no param was passed, default to 0, else read the value
+	if (!args.eof())
+		args >> verbosity;
+
+	m_ppsInterface.setVerbose(verbosity);
+	return szOK;
+}
+
+void JPPSPlugin::onEvent(const std::string& sEvent) const
+{
+	// We have to add our object Id to the event
+	std::string pluginEvent = m_jnextObjId + " " + sEvent;
+	SendPluginEvent(pluginEvent.c_str(), m_pContext);
+}
+
+void JPPSPlugin::onEvent(void* pArg, const std::string& sEvent)
+{
+	// Cast pArg back to JPPSPlugin and invoke onEvent()
+	JPPSPlugin* pPlugin = static_cast<JPPSPlugin*>(pArg);
+
+	if (pPlugin != NULL)
+		pPlugin->onEvent(sEvent);
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.h
new file mode 100644
index 0000000..1a56ab2
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSPlugin.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef JPPSPLUGIN_H_
+#define JPPSPLUGIN_H_
+
+#include "../common/plugin.h"
+#include "PPSInterfaceGlue.h"
+
+namespace jpps {
+
+/**
+ * JPPSPlugin is a JNext extension which provides PPS support to JavaScript.
+ * This class is merely a wrapper for PPSInterfaceGlue, providing the necessary
+ * JNext interface and performing string-parameter encoding and decoding.
+ *
+ * The intention is that this class will be replaced with a different plug-in framework.
+ */
+class JPPSPlugin : public JSExt {
+
+public:
+
+	// Constants
+
+	/** The only class supported by this plugin. */
+	static const char* CLASS_NAME;
+
+	// List of object methods supported by this extension
+
+	/** Open a PPS object/directory. */
+	static const std::string METHOD_OPEN;
+	/** Close a PPS object/directory. */
+	static const std::string METHOD_CLOSE;
+	/** Write a PPS object. */
+	static const std::string METHOD_WRITE;
+	/** Read a PPS object. */
+	static const std::string METHOD_READ;
+	/** Adjust output verbosity. */
+	static const std::string METHOD_SET_VERBOSE;
+
+	/**
+	 * Constructor.
+	 */
+	JPPSPlugin(const std::string& jnextObjectId);
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~JPPSPlugin();
+
+	// Inherited from JSExt
+	virtual std::string InvokeMethod(const std::string& strCommand);
+	virtual inline bool CanDelete(void) { return true; }
+
+	/**
+	 *  Static callback method, changes pArg back into a JPPSPlugin and invokes
+	 *  the non-static version of onEvent().
+	 */
+	static void onEvent(void* pArg, const std::string& sEvent);
+
+private:
+
+	// Disable the default constructor
+	JPPSPlugin();
+
+	/**
+	 * The non-static version of onEvent. Handler for the PPSInterfaceGlue class' events.
+	 */
+	void onEvent(const std::string& sEvent) const;
+
+	/**
+	 * Open a PPS object.
+	 */
+	std::string open(std::stringstream& args);
+
+	/**
+	 * Close the PPS object.
+	 */
+	std::string close();
+
+	/**
+	 * Write data to the PPS object.
+	 */
+	std::string write(std::stringstream& args);
+
+	/**
+	 * Read the cached PPS data from the last read.
+	 */
+	std::string read() const;
+
+	/**
+	 * Set the verbosity level for logging to slog.
+	 */
+	std::string setVerbose(std::stringstream& args);
+
+	/** A unique JNext id for this object */
+	std::string m_jnextObjId;
+
+	/** The PPS object. */
+	PPSInterfaceGlue m_ppsInterface;
+};
+
+} /* namespace jpps */
+#endif /* JPPSPLUGIN_H_ */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.cpp
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.cpp b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.cpp
new file mode 100644
index 0000000..6c3bc2d
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+#include "JPPSServerPlugin.h"
+
+#include <sstream>
+
+namespace jpps {
+
+const char* JPPSServerPlugin::CLASS_NAME = "PPSServer";
+
+const std::string JPPSServerPlugin::METHOD_OPEN = "Open";
+const std::string JPPSServerPlugin::METHOD_CLOSE = "Close";
+const std::string JPPSServerPlugin::METHOD_SET_VERBOSE = "SetVerbose";
+const std::string JPPSServerPlugin::METHOD_SEND_MESSAGE = "SendMessage";
+const std::string JPPSServerPlugin::METHOD_BROADCAST_MESSAGE = "BroadcastMessage";
+
+JPPSServerPlugin::JPPSServerPlugin(const std::string& jnextObjectId)
+: m_jnextObjId(jnextObjectId)
+, m_ppsServer()
+{
+	m_ppsServer.callbackInit(this,
+							 onEvent,
+							 onEvent,
+							 onEvent,
+							 onEvent,
+							 onEvent,
+							 onEvent,
+							 onEvent,
+							 onEvent);
+}
+
+JPPSServerPlugin::~JPPSServerPlugin()
+{
+}
+
+std::string JPPSServerPlugin::InvokeMethod(const std::string& strCommand)
+{
+	// Parameter sanity check
+	if (strCommand == "")
+		return std::string(szERROR) + " JPPSServerPlugin::InvokeMethod() called with no method to invoke.";
+
+	// Tokenize the stream of input information
+	std::stringstream args(strCommand);
+	std::string method;
+	args >> method;
+
+	// Invoke the method requested
+	if (method == JPPSServerPlugin::METHOD_OPEN) {
+		return open(args);
+	}
+	else if (method == JPPSServerPlugin::METHOD_CLOSE) {
+		return close();
+	}
+	else if (method == JPPSServerPlugin::METHOD_SET_VERBOSE) {
+		return setVerbose(args);
+	}
+	else if (method == JPPSServerPlugin::METHOD_SEND_MESSAGE) {
+		return sendMessage(args);
+	}
+	else if (method == JPPSServerPlugin::METHOD_BROADCAST_MESSAGE) {
+		return broadcastMessage(args);
+	}
+
+	return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::InvokeMethod() - unknown method \"" + method + "\"";
+}
+
+std::string JPPSServerPlugin::open(std::stringstream& args)
+{
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::open() - invalid number of arguments.";
+
+	// Get the arguments
+	// 1st arg, the path
+	std::string path;
+	args >> path;
+
+	// Missing argument
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::open() - invalid number of arguments.";
+
+	// 2nd arg, the open flags (i.e. O_RDONLY O_CREAT, etc.)
+	int oflags = 0;
+	args >> oflags;
+
+	bool bRet = m_ppsServer.open(path, oflags);
+
+	return bRet ? std::string(szOK) + m_jnextObjId : std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::open() - failed to open \"" + path + "\".";
+}
+
+std::string JPPSServerPlugin::close()
+{
+	m_ppsServer.close();
+	return szOK + m_jnextObjId;
+}
+
+std::string JPPSServerPlugin::setVerbose(std::stringstream& args)
+{
+	unsigned short verbosity = 0;
+
+	// If no param was passed, default to 0, else read the value
+	if (!args.eof())
+		args >> verbosity;
+
+	m_ppsServer.setVerbose(verbosity);
+	return szOK + m_jnextObjId;
+}
+
+std::string JPPSServerPlugin::sendMessage(std::stringstream& args)
+{
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::sendMessage() - invalid number of arguments.";
+
+	// Get the arguments
+	// 1st arg, the clientId
+	std::string clientId;
+	args >> clientId;
+
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::sendMessage() - invalid number of arguments.";
+
+	// This truncates the buffer from the current position onwards (if you don't do this, you keep
+	// the method name that's at the beginning of the args stream)
+	args.seekg(1, std::ios_base::cur); 	// Skip the whitespace that was between the clientID and the message
+	std::stringstream tmp;
+	tmp << args.rdbuf();
+
+	m_ppsServer.sendMessage(clientId, tmp.str());
+	return szOK + m_jnextObjId;
+}
+
+std::string JPPSServerPlugin::broadcastMessage(std::stringstream& args)
+{
+	// We don't have enough args
+	if (args.eof())
+		return std::string(szERROR) + m_jnextObjId + " JPPSServerPlugin::broadcastMessage() - invalid number of arguments.";
+
+	// This truncates the buffer from the current position onwards (if you don't do this, you keep
+	// the method name that's at the beginning of the args stream)
+	args.seekg(1, std::ios_base::cur); 	// Skip the whitespace that was between the method name and the message
+	std::stringstream tmp;
+	tmp << args.rdbuf();
+
+	m_ppsServer.broadcastMessage(tmp.str());
+	return szOK + m_jnextObjId;
+}
+
+void JPPSServerPlugin::onEvent(const std::string& sEvent) const
+{
+	// We have to add our object Id to the event
+	std::string pluginEvent = m_jnextObjId + " " + sEvent;
+	SendPluginEvent(pluginEvent.c_str(), m_pContext);
+}
+
+void JPPSServerPlugin::onEvent(void* pArg, const std::string& sEvent)
+{
+	// Cast pArg back to JPPSPlugin and invoke onEvent()
+	JPPSServerPlugin* pPlugin = static_cast<JPPSServerPlugin*>(pArg);
+
+	if (pPlugin != NULL)
+		pPlugin->onEvent(sEvent);
+}
+
+} /* namespace jpps */

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/b3960ef0/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.h
----------------------------------------------------------------------
diff --git a/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.h b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.h
new file mode 100644
index 0000000..ea5b18f
--- /dev/null
+++ b/blackberry10/bin/templates/project/plugins/JPPS/native/src/plugin/JPPSServerPlugin.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ */
+
+/*
+ * $QNXLicenseC:
+ * Copyright 2009, QNX Software Systems. All Rights Reserved.
+ *
+ * You must obtain a written license from and pay applicable license fees to QNX
+ * Software Systems before you may reproduce, modify or distribute this software,
+ * or any work that includes all or part of this software.   Free development
+ * licenses are available for evaluation and non-commercial purposes.  For more
+ * information visit http://licensing.qnx.com or email licensing@qnx.com.
+ *
+ * This file may contain contributions from others.  Please review this entire
+ * file for other proprietary rights or license notices, as well as the QNX
+ * Development Suite License Guide at http://licensing.qnx.com/license-guide/
+ * for other information.
+ * $
+ */
+
+#ifndef JPPSSERVERPLUGIN_H_
+#define JPPSSERVERPLUGIN_H_
+
+#include "../common/plugin.h"
+#include "PPSServerGlue.h"
+
+namespace jpps {
+
+class JPPSServerPlugin: public JSExt {
+
+public:
+
+	// Constants
+
+	/** The only class supported by this plugin. */
+	static const char* CLASS_NAME;
+
+	// List of object methods supported by this extension
+
+	/** Open a PPS object/directory. */
+	static const std::string METHOD_OPEN;
+	/** Close a PPS object/directory. */
+	static const std::string METHOD_CLOSE;
+	/** Adjust output verbosity. */
+	static const std::string METHOD_SET_VERBOSE;
+	/** Send a message to a particular client. */
+	static const std::string METHOD_SEND_MESSAGE;
+	/** Send a message to all clients. */
+	static const std::string METHOD_BROADCAST_MESSAGE;
+
+	/**
+	 * Constructor.
+	 */
+	JPPSServerPlugin(const std::string& jnextObjectId);
+
+	/**
+	 * Destructor.
+	 */
+	virtual ~JPPSServerPlugin();
+
+	// Inherited from JSExt
+	virtual std::string InvokeMethod(const std::string& strCommand);
+	virtual inline bool CanDelete(void) { return true; }
+
+	/**
+	 *  Static callback method, changes pArg back into a JPPSServerPlugin and invokes
+	 *  the non-static version of onEvent().
+	 */
+	static void onEvent(void* pArg, const std::string& sEvent);
+
+private:
+
+	// Disable default constructor.
+	JPPSServerPlugin();
+
+	/**
+	 * The non-static version of onEvent. Handler for the PPSServerGlue class' events.
+	 */
+	void onEvent(const std::string& sEvent) const;
+
+	/**
+	 * Open a PPS object.
+	 */
+	std::string open(std::stringstream& args);
+
+	/**
+	 * Close the PPS object.
+	 */
+	std::string close();
+
+	/**
+	 * Set the verbosity level for logging to slog.
+	 */
+	std::string setVerbose(std::stringstream& args);
+
+	/**
+	 * Send a message to a particular client.
+	 */
+	std::string sendMessage(std::stringstream& args);
+
+	/**
+	 * Send a message to all clients.
+	 */
+	std::string broadcastMessage(std::stringstream& args);
+
+	/** A unique JNext id for this object */
+	std::string m_jnextObjId;
+
+	/** The PPS object. */
+	PPSServerGlue m_ppsServer;
+};
+
+} /* namespace jpps */
+#endif /* JPPSSERVERPLUGIN_H_ */