summaryrefslogtreecommitdiff
path: root/examples/OICMiddle
diff options
context:
space:
mode:
Diffstat (limited to 'examples/OICMiddle')
-rw-r--r--examples/OICMiddle/Client.cpp83
-rw-r--r--examples/OICMiddle/Client.h58
-rw-r--r--examples/OICMiddle/LineInput.cpp458
-rw-r--r--examples/OICMiddle/LineInput.h72
-rw-r--r--examples/OICMiddle/OICMiddle.cpp152
-rw-r--r--examples/OICMiddle/OICMiddle.h94
-rw-r--r--examples/OICMiddle/README37
-rw-r--r--examples/OICMiddle/RestInput.cpp166
-rw-r--r--examples/OICMiddle/RestInput.h50
-rw-r--r--examples/OICMiddle/SConstruct81
-rw-r--r--examples/OICMiddle/Server.cpp155
-rw-r--r--examples/OICMiddle/Server.h56
-rw-r--r--examples/OICMiddle/WrapResource.cpp289
-rw-r--r--examples/OICMiddle/WrapResource.h121
-rw-r--r--examples/OICMiddle/makefile87
15 files changed, 1959 insertions, 0 deletions
diff --git a/examples/OICMiddle/Client.cpp b/examples/OICMiddle/Client.cpp
new file mode 100644
index 000000000..8d6e7d16e
--- /dev/null
+++ b/examples/OICMiddle/Client.cpp
@@ -0,0 +1,83 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <map>
+
+#include "WrapResource.h"
+#include "Client.h"
+
+MiddleClient::MiddleClient()
+{
+ m_findCB = bind(&MiddleClient::foundOCResource, this, placeholders::_1);
+}
+
+bool MiddleClient::init()
+{
+ findResources();
+ return true;
+}
+
+void MiddleClient::findResources()
+{
+ m_resourceMap.clear();
+
+ OC::OCPlatform::findResource("", OC_WELL_KNOWN_QUERY, m_findCB);
+}
+
+void MiddleClient::foundOCResource(shared_ptr<OCResource> resource)
+{
+ WrapResource *wres;
+ string resourceID = formatResourceID(resource);
+
+ m_mutexFoundCB.lock();
+
+ try {
+ wres = m_resourceMap.at(resourceID);
+ } catch (const std::out_of_range) {
+ wres = new WrapResource(resourceID, resource);
+ m_resourceMap[resourceID] = wres;
+ }
+
+ m_mutexFoundCB.unlock();
+
+ wres->findTypes();
+}
+
+/*
+ * I need a unique ID, so I concatenate the host string and resource uri
+ * It's arbitrary and sufficient.
+ */
+string MiddleClient::formatResourceID(std::shared_ptr<OCResource> resource)
+{
+ string host = resource->host();
+ if (host.compare(0, 7, "coap://") == 0)
+ host = host.erase(0, 7);
+ return host + resource->uri();
+}
+
+void MiddleClient::addResource(WrapResource *wres)
+{
+ string resourceID = wres->getResourceID();
+ try {
+ m_resourceMap[resourceID];
+ } catch (const std::out_of_range) {
+ m_resourceMap[resourceID] = wres;
+ }
+}
diff --git a/examples/OICMiddle/Client.h b/examples/OICMiddle/Client.h
new file mode 100644
index 000000000..ef32e8635
--- /dev/null
+++ b/examples/OICMiddle/Client.h
@@ -0,0 +1,58 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <mutex>
+
+#include "OICMiddle.h"
+
+typedef map<string, WrapResource *> resourcemap_t;
+typedef pair<string, WrapResource *> resourcemappair_t;
+
+class MiddleClient
+{
+public:
+ MiddleClient();
+
+ bool init();
+ void findResources();
+
+ friend class LineInput;
+ friend class HueResource;
+ friend class HueResources;
+ friend class RestInput;
+
+protected:
+ mutex m_mutexFoundCB;
+ map<string, WrapResource *> m_resourceMap;
+ HueResources *m_hueResources;
+ std::function<void(std::shared_ptr<OCResource> resource)> m_findCB;
+
+ void foundOCResource(shared_ptr<OCResource> resource);
+ string formatResourceID(std::shared_ptr<OCResource> resource);
+ void findHueResources();
+ void addResource(WrapResource *wres);
+};
+
+
+#endif // CLIENT_H
+
diff --git a/examples/OICMiddle/LineInput.cpp b/examples/OICMiddle/LineInput.cpp
new file mode 100644
index 000000000..52a8528d8
--- /dev/null
+++ b/examples/OICMiddle/LineInput.cpp
@@ -0,0 +1,458 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <map>
+#include <iostream>
+
+#include <stdio.h>
+
+#include "WrapResource.h"
+#include "LineInput.h"
+
+#define NEED_CLIENT { if (!m_client) return LR_NoClient; }
+
+LineInput::LineInput(MiddleClient *client)
+ : m_client(client), m_server(nullptr),
+ m_obsCB(nullptr), m_observer(nullptr)
+{
+ m_obsCB = std::bind(&LineInput::obsCB, this,
+ placeholders::_1,
+ placeholders::_2,
+ placeholders::_3,
+ placeholders::_4,
+ placeholders::_5);
+}
+
+void LineInput::setServer(MiddleServer *server) {
+ m_server = server;
+}
+
+int LineInput::run()
+{
+ size_t len;
+ char *line = nullptr;
+
+ while (true) {
+ fputs(">", stdout);
+ len = 0;
+ getline(&line, &len, stdin);
+ int n = strlen(line);
+ if (!n)
+ continue;
+ if (m_observer) {
+ m_observer->cancelObserve();
+ m_observer = nullptr;
+ }
+ if (line[n - 1] == '\n') {
+ if (n == 1)
+ continue;
+ line[n - 1] = '\0';
+ }
+ stringstream result;
+ LineResult lr = processLine(line, result, m_obsCB);
+ if (lr == LR_Quit)
+ break;
+ cout << result.str();
+ }
+ free(line);
+ return true;
+}
+
+LineResult LineInput::processLine(string command, stringstream& result, observecb_t cb)
+{
+ elements_t elems;
+
+ if (parseLine(command, elems) != LR_OK) {
+ cerr << "syntax error" << endl;
+ return LR_Syntax;
+ }
+ if (!elems.size())
+ return LR_NoCommand;
+
+ if (elems[0] == "quit" || elems[0] == "exit")
+ return LR_Quit;
+
+ if (elems.size() == 1) {
+ if (elems[0] == "help") {
+ return processHelp(elems, result);
+ } else if (elems[0] == "find") {
+ NEED_CLIENT return processFind(elems, result);
+ } else if (elems[0] == "show") {
+ NEED_CLIENT return processShow(elems, result);
+ }
+ } else if (elems.size() == 2) {
+ if (elems[0] == "details") {
+ NEED_CLIENT return processDetails(elems, result);
+ } else if (elems[0] == "get") {
+ NEED_CLIENT return processGet(elems, result);
+ } else if (elems[0] == "observe") {
+ NEED_CLIENT return processObserve(elems, result, cb);
+ } else if (elems[0] == "cancel") {
+ NEED_CLIENT return processCancel(elems, result);
+ }
+ } else {
+ if (elems[0] == "put") {
+ NEED_CLIENT return processPut(elems, result);
+ }
+ }
+
+ return processUnrecognized(elems, result);
+}
+
+LineResult LineInput::processHelp(elements_t& elems, stringstream& ss)
+{
+ ss << "\nUsage:\n"
+ "\tfind\t\tFind resources\n"
+ "\tshow\t\tShow resources\n"
+ "\tdetails n\tShow details of resource n\n"
+ "\tget n\t\tGet value(s) of resource n\n"
+ "\tput n v\t\tPut value(s) to resource n\n"
+ "\tobserve n\tObserve value(s) of resource n\n"
+ "\thelp\t\tThis usage message\n"
+ "\nResource can be identified by Resource ID or Show index\n"
+ "\nValue in 'put' can be key=value or key:value\n\n"
+ ;
+ return LR_OK;
+}
+
+LineResult LineInput::processUnrecognized(elements_t& elems, stringstream& ss)
+{
+ ss << "Command not recognized\n";
+ processHelp(elems, ss);
+ return LR_Unrecognized;
+}
+
+LineResult LineInput::processFind(elements_t& elems, stringstream& ss)
+{
+ m_client->findResources();
+ return LR_OK;
+}
+
+void LineInput::registerResourceWithServer(std::string & url) {
+ string type;
+ std::size_t index = url.rfind("/");
+ if (index != std::string::npos) {
+ type = url.substr(index+1);
+ }
+ const std::string resType = type;
+ const std::string iface = "MB_INTERFACE";
+ m_server->registerResource(url, resType, iface);
+}
+
+LineResult LineInput::processShow(elements_t& elems, stringstream& ss)
+{
+ int index = 0;
+ m_resourceList.clear();
+ resourcemap_t& pmap = m_client->m_resourceMap;
+
+ for (resourcemap_t::iterator it = pmap.begin(); it != pmap.end(); it++) {
+ string resID = it->first;
+ ss << index++ << '\t' << resID << '\n';
+ m_resourceList.push_back(resID);
+ if (m_server) {
+ registerResourceWithServer(resID);
+ }
+ }
+
+ return LR_OK;
+}
+
+LineResult LineInput::processDetails(elements_t& elems, stringstream& ss)
+{
+ WrapResource *wres = resolveResource(elems[1], ss);
+ if (!wres)
+ return LR_NoResource;
+
+ ss << wres->getResourceID() + " [ ";
+ for (auto &types : wres->getResourceTypes()) {
+ ss << types + ' ';
+ }
+ ss << "] ";
+ for (auto &ifs : wres->getResourceInterfaces()) {
+ ss << ifs << " ";
+ }
+ ss << '\n';
+ return LR_OK;
+}
+
+void printJSONAsTable(std::string &jsonString) {
+ std::string str = jsonString;
+ std::string key, value;
+ size_t found = str.find("rep");
+ if (found == std::string::npos) { // not found
+ return;
+ }
+ str = str.substr(found+5);
+ while (true) {
+ found = str.find(":");
+ if (found == std::string::npos) {
+ return;
+ }
+ key = str.substr(1, found-1);
+ str = str.substr(found);
+ found = str.find(",");
+ if (found != std::string::npos) {
+ value = str.substr(1, found-1);
+ str = str.substr(found);
+ } else {
+ found = str.find("}");
+ if (found != std::string::npos) {
+ value = str.substr(1, found-1);
+ str = str.substr(found);
+ }
+ }
+ cout << key << "\t:" << value << endl;
+ }
+}
+
+LineResult LineInput::processGet(elements_t& elems, stringstream& ss)
+{
+ WrapResource *wres = resolveResource(elems[1], ss);
+ if (!wres)
+ return LR_NoResource;
+
+ token_t token = wres->getResource();
+
+ WrapRequest *wreq = wres->waitResource(token);
+ if (!wreq) {
+ ss << "Get timed out\n";
+ return LR_Timeout;
+ }
+
+ std::string jsonRep = wreq->m_rep.getJSONRepresentation();
+ //ss << jsonRep << endl;
+ printJSONAsTable(jsonRep);
+ return LR_OK;
+}
+
+LineResult LineInput::processPut(elements_t& elems, stringstream& ss)
+{
+ WrapResource *wres = resolveResource(elems[1], ss);
+ if (!wres)
+ return LR_NoResource;
+
+ string format;
+ OCRepresentation rep;
+
+ bool error = false;
+ for (size_t i = 2; i < elems.size(); i++) {
+ string elem = elems[i];
+ char *s = (char *)elem.c_str(); // elem string is intentionally damaged
+ char *key = strtok(s, "=:");
+ char *value = strtok(nullptr, "");
+ if (!value) {
+ ss << "missing separator in element starting with " << key << '\n';
+ error = true;
+ continue;
+ }
+ char delim = value[0];
+ size_t len = strlen(value);
+ if (delim == '\'' || delim == '"') {
+ if (len > 1 && delim == value[len - 1]) {
+ value[len - 1] = '\0';
+ value++;
+ }
+ }
+ string v(value, len);
+ stringmap_t formats = wres->getFormats();
+ try {
+ format = formats.at(key);
+ } catch (...) {
+ cerr << "element in arg " << i << " has no format\n";
+ continue;
+ }
+ if (format == "bool") {
+ bool b = v != "0" && v != "false";
+ rep.setValue(key, b);
+ } else if (format == "number") {
+ char *end;
+ int n = (int)strtol(value, &end, 10);
+ if (size_t(end - value) != len) {
+ double d = atof(value);
+ rep.setValue(key, d);
+ } else {
+ rep.setValue(key, n);
+ }
+ } else { // assume string
+ rep.setValue(key, v);
+ }
+ }
+ if (error)
+ return LR_Param;
+
+ token_t token = wres->putResource(rep);
+
+ WrapRequest *wreq = wres->waitResource(token);
+ if (!wreq) {
+ ss << "Get timed out\n";
+ return LR_Timeout;
+ }
+
+ return LR_OK;
+}
+
+LineResult LineInput::processObserve(elements_t& elems, stringstream& ss, observecb_t cb)
+{
+ WrapResource *wres = resolveResource(elems[1], ss);
+ if (!wres)
+ return LR_NoResource;
+ m_observer = wres;
+ wres->observeResource(cb);
+ return LR_OK;
+}
+
+LineResult LineInput::processCancel(elements_t& elems, stringstream& ss)
+{
+ WrapResource *wres = resolveResource(elems[1], ss);
+ if (!wres)
+ return LR_NoResource;
+
+ wres->cancelObserve();
+ m_observer = nullptr;
+ return LR_OK;
+}
+
+WrapResource *LineInput::resolveResource(string resID, stringstream& ss)
+{
+ size_t len;
+ string useID = resID;
+ int index = std::stoi(useID, &len);
+
+ if (len == resID.size()) { // it's an index, not a uri
+ if (size_t(index) >= m_resourceList.size()) {
+ cout << "Resource index out of range (use 'show')\n";
+ return nullptr;
+ }
+ useID = m_resourceList[index]; // now it's a uri
+ }
+
+ resourcemap_t::iterator it = m_client->m_resourceMap.find(useID);
+ if (it == m_client->m_resourceMap.end()) {
+ cout << resID << " is currently not available\n";
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+void LineInput::obsCB(token_t token, const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode, const int sequenceNumber)
+{
+ if (!m_observer)
+ return;
+ cout << "cb " << eCode << " " << sequenceNumber << '\n';
+ cout << rep.getJSONRepresentation() << "\n";
+}
+
+ParseState LineInput::finishElem(char*& e, elements_t& elems)
+{
+ *e = '\0';
+ elems.push_back(m_elem);
+ e = m_elem;
+ return PS_Between;
+}
+
+ParseState LineInput::putCharInElem(char c, char *& e, ParseState newState)
+{
+ *e++ = c;
+ if (size_t(e - m_elem) >= sizeof (m_elem))
+ throw 20; // hightly unlikely exception
+ return newState;
+}
+
+/*
+ * See processHelp() above for line format
+ */
+LineResult LineInput::parseLine(string lineIn, elements_t& elems)
+{
+ const char *d;
+ char c, *e, delim;
+ bool isSep1, isSep2;
+ size_t len = lineIn.size();
+ ParseState state = PS_Between;
+ const char *line = lineIn.c_str();
+
+ d = line;
+ e = m_elem;
+ while (true) {
+ if (size_t(d - line) >= len) {
+ if (e != m_elem) {
+ if (state == PS_Infirst || state == PS_Endsecond || (state == PS_Insecond && !delim)) {
+ state = finishElem(e, elems);
+ return LR_OK;
+ }
+ }
+ return LR_Syntax;
+ }
+ c = *d++;
+ if (c == '\n')
+ continue;
+ isSep1 = c == ' ' || c == '\t';
+ isSep2 = c == '=' || c == ':';
+
+ switch (state) {
+ case PS_Between:
+ if (isSep1)
+ continue;
+ if (isSep2)
+ return LR_Syntax;
+ state = putCharInElem(c, e, PS_Infirst);
+ break;
+ case PS_Infirst:
+ if (isSep1) {
+ state = finishElem(e, elems);
+ continue;
+ }
+ if (isSep2) {
+ delim = 0;
+ state = PS_Startsecond;
+ }
+ putCharInElem(c, e, state);
+ break;
+ case PS_Startsecond:
+ if (isSep1 || isSep2)
+ return LR_Syntax;
+ if (c == '\'' || c == '"' || c == '|')
+ delim = c;
+ state = putCharInElem(c, e, PS_Insecond);
+ break;
+ case PS_Insecond:
+ if (isSep1 && delim == 0) {
+ state = finishElem(e, elems);
+ continue;
+ }
+ if (c == delim) {
+ state = PS_Endsecond;
+ }
+ *e++ = c;
+ break;
+ case PS_Endsecond:
+ if (isSep1) {
+ state = finishElem(e, elems);
+ continue;
+ }
+ return LR_Syntax;
+ case PS_None:
+ return LR_Syntax;
+ }
+ }
+ return LR_OK;
+}
+
+
diff --git a/examples/OICMiddle/LineInput.h b/examples/OICMiddle/LineInput.h
new file mode 100644
index 000000000..bc7d4afa2
--- /dev/null
+++ b/examples/OICMiddle/LineInput.h
@@ -0,0 +1,72 @@
+#ifndef LINEINPUT_H
+#define LINEINPUT_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 "OICMiddle.h"
+#include "Client.h"
+#include "Server.h"
+
+typedef vector<string> elements_t;
+
+enum ParseState {
+ PS_None,
+ PS_Between,
+ PS_Infirst,
+ PS_Startsecond,
+ PS_Insecond,
+ PS_Endsecond,
+};
+
+class LineInput
+{
+public:
+ LineInput(MiddleClient *client);
+ void setServer(MiddleServer *server);
+ int run();
+ LineResult processLine(string command, stringstream& result, observecb_t cb);
+
+protected:
+ MiddleClient *m_client;
+ MiddleServer *m_server;
+ vector<string> m_resourceList;
+ observecb_t m_obsCB;
+ WrapResource *m_observer;
+ char m_elem[1000];
+
+ LineResult processHelp(elements_t& elems, stringstream& ss);
+ LineResult processUnrecognized(elements_t& elems, stringstream& ss);
+ LineResult processFind(elements_t& elems, stringstream& ss);
+ LineResult processShow(elements_t& elems, stringstream& ss);
+ LineResult processDetails(elements_t& elems, stringstream& ss);
+ LineResult processGet(elements_t& elems, stringstream& ss);
+ LineResult processPut(elements_t& elems, stringstream& ss);
+ LineResult processObserve(elements_t& elems, stringstream& ss, observecb_t cb);
+ LineResult processCancel(elements_t& elems, stringstream& ss);
+ WrapResource *resolveResource(string resID, stringstream& ss);
+ LineResult parseLine(string lineIn, elements_t& elems);
+ ParseState finishElem(char*& e, elements_t& elems);
+ ParseState putCharInElem(char c, char *& e, ParseState newState);
+ void obsCB(const token_t token, const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode, const int sequenceNumber);
+ void registerResourceWithServer(std::string &url);
+};
+
+#endif // LINEINPUT_H
diff --git a/examples/OICMiddle/OICMiddle.cpp b/examples/OICMiddle/OICMiddle.cpp
new file mode 100644
index 000000000..0da414599
--- /dev/null
+++ b/examples/OICMiddle/OICMiddle.cpp
@@ -0,0 +1,152 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+//
+// OICMiddle.cpp : OIC demo application for Minnowboard
+//
+
+#include <unistd.h>
+
+#include "OICMiddle.h"
+#include "WrapResource.h"
+#include "Client.h"
+#include "Server.h"
+#include "LineInput.h"
+#include "RestInput.h"
+
+class Middle middle; // one and only
+
+Middle::Middle() :
+ m_appType(AT_None),
+ m_useLineInput(false),
+ m_useRestInput(false),
+ m_client(nullptr),
+ m_server(nullptr),
+ m_lineInput(nullptr),
+ m_restInput(nullptr)
+{
+}
+
+void Middle::init()
+{
+
+}
+
+void Middle::run(int argc, char* argv[])
+{
+ parseCommandLineOptions(argc, argv);
+
+ startPlatform();
+
+ if (m_appType & AT_Client) {
+ m_client = new MiddleClient();
+ m_client->init();
+ }
+
+ m_lineInput = new LineInput(m_client);
+
+ if (m_appType & AT_Server) {
+ m_server = new MiddleServer();
+ m_server->init();
+ }
+ if (m_useRestInput) {
+ if (!m_server) {
+ m_server = new MiddleServer();
+ m_server->init();
+ }
+ m_restInput = new RestInput(m_lineInput);
+ m_restInput->init();
+ }
+ if (m_useLineInput) {
+ if (m_server) {
+ m_lineInput->setServer(m_server);
+ }
+ m_lineInput->run();
+ } else {
+ while (true)
+ sleep(1);
+ }
+}
+
+void Middle::startPlatform()
+{
+ uint16_t port = 0;
+ //std::string ipaddr = INADDR_ANY;
+ std::string ipaddr = "0.0.0.0";
+
+ PlatformConfig cfg { ServiceType::InProc, ModeType::Both,
+ ipaddr, port, QualityOfService::LowQos};
+
+ OC::OCPlatform::Configure(cfg);
+}
+
+void Middle::provideHelp()
+{
+ static const char usage[] = "\nUsage: IOCMiddle args\n"
+ " where args may include any of these:\n"
+ "\t-client Run OIC client\n"
+ "\t-server Run OIC server\n"
+ "\t-both Run OIC client and server\n"
+ "\t-console Run console line interpreter\n"
+ "\t-rest Run ReST server\n"
+ "\t-hue addr Enable Hue resources on bridge at addr\n"
+ "\t-help Show Usage again\n"
+ "Any combination of the above is okay.\n\n";
+ cout << usage;
+}
+
+bool Middle::parseCommandLineOptions(int argc, char *argv[])
+{
+ bool any = false;
+
+ for (int i = 1; i < argc; i++) {
+ if (argv[i] == string("-server")) {
+ middle.m_appType = AT_Server; any = true;
+ } else if (argv[i] == string("-client")) {
+ middle.m_appType = AT_Client; any = true;
+ } else if (argv[i] == string("-both")) {
+ middle.m_appType = AT_Both; any = true;
+ } else if (argv[i] == string("-console")) {
+ middle.m_useLineInput = true; any = true;
+ } else if (argv[i] == string("-rest")) {
+ middle.m_useRestInput = true; any = true;
+ } else if (argv[i] == string("-hue")) {
+ if (i + 1 < argc && argv[i + 1][0] != '-') {
+ m_hueAddr = argv[++i];
+ any = true;
+ }
+ } else if (argv[i] == string("-help")) {
+ any = false;
+ break;
+ } else {
+ std::cerr << "Not enough or invalid arguments, please try again.\n";
+ exit(1);
+ }
+ }
+ if (!any)
+ provideHelp();
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+ middle.run(argc, argv);
+ return 0;
+}
diff --git a/examples/OICMiddle/OICMiddle.h b/examples/OICMiddle/OICMiddle.h
new file mode 100644
index 000000000..457b7a8fd
--- /dev/null
+++ b/examples/OICMiddle/OICMiddle.h
@@ -0,0 +1,94 @@
+#ifndef OICMIDDLE_H
+#define OICMIDDLE_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <string>
+#include <cstdlib>
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+class MiddleClient;
+class MiddleServer;
+class LineInput;
+class RestInput;
+class WrapResource;
+class HueResources;
+
+using namespace OC;
+using namespace std;
+
+enum AppType {
+ AT_None = 0,
+ AT_Server = 1,
+ AT_Client = 2,
+ AT_Both = 3
+};
+
+enum LineResult {
+ LR_OK,
+ LR_NoCommand,
+ LR_NoClient,
+ LR_NoResource,
+ LR_Timeout,
+ LR_Param,
+ LR_Unrecognized,
+ LR_Quit,
+ LR_Syntax,
+ LR_Error
+};
+
+class HueResource;
+
+typedef int token_t;
+typedef map<string, string> stringmap_t;
+
+class Middle
+{
+public:
+ Middle();
+ void init();
+ void run(int argc, char* argv[]);
+
+protected:
+ friend class MiddleClient;
+ friend class MiddleServer;
+ friend class RestInput;
+ friend class HueResources;
+
+ AppType m_appType;
+ bool m_useLineInput;
+ bool m_useRestInput;
+ string m_hueAddr;
+ MiddleClient *m_client;
+ MiddleServer *m_server;
+ LineInput *m_lineInput;
+ RestInput *m_restInput;
+
+protected:
+ void startPlatform();
+ bool parseCommandLineOptions(int argc, char *argv[]);
+ void provideHelp();
+};
+
+extern Middle middle;
+
+#endif // OICMIDDLE_H
diff --git a/examples/OICMiddle/README b/examples/OICMiddle/README
new file mode 100644
index 000000000..518fb2a3a
--- /dev/null
+++ b/examples/OICMiddle/README
@@ -0,0 +1,37 @@
+OICMiddle was written to
+* be part of a demonstration of OIC Yocto capability,
+* act as an example of resource callbacks using class methods,
+* provide a simple promiscuous resource editor for examining OIC systems, and
+* act as a starting code base for further exploration of OIC capabilities.
+
+As a demonstration, it runs on an Minnowboard running a Yocto-built OS, acting
+as a gateway between an Android device (acting as an OIC client) and an
+Edison board (acting as an OIC server) with sensors and actuators.
+
+As an example of resource callbacks, it shows a method of using class methods
+as callbacks, a critical capability not shown in any of the examples in
+iotivity/resource/examples.
+
+As a promiscuous resource editor, it can find, get, put and observe any
+resource using a simple command-line interface using the system console.
+
+As a code base, the command-line editor can be the basis for adding additional
+editing capabilities, like the additions of various filters.
+
+Running OICMiddle with no arguments on a console shows the various capabilities
+it offers. The most important are:
+ -client. Act as an OIC client.
+ -console. Accept command lines from console input to drive the OIC client.
+ -server. Advertise resources found by the OIC client as OIC resources.
+
+The -server capabilites might be the basis for a gateway.
+
+Typing 'help' (or invalid commands) to the console gives a console usage
+message. The important ones are:
+ find Find all resources. Also performed automatically at startup.
+ show Show the found resources and an assigned index.
+ get Get the value(s) of the resource with the given index.
+ put Put one or more resource values for the given index.
+
+
+12/24/2014
diff --git a/examples/OICMiddle/RestInput.cpp b/examples/OICMiddle/RestInput.cpp
new file mode 100644
index 000000000..b6e240f35
--- /dev/null
+++ b/examples/OICMiddle/RestInput.cpp
@@ -0,0 +1,166 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 "WrapResource.h"
+#include "RestInput.h"
+#include "LineInput.h"
+#include "OICMiddle.h"
+
+using namespace std;
+
+#define BUFLEN 10000
+#define MAX_CONNS 5
+
+static bool enableDebug = false; // set to true to print debug messages
+
+void printDebugMessage(std::string message)
+{
+ if (enableDebug) {
+ cout << "RestInput: " << message << endl;
+ }
+}
+
+RestInput::RestInput(LineInput *lineInput) : m_lineInput(lineInput)
+{
+ m_data = (char*)malloc(BUFLEN);
+ m_thread = new std::thread[MAX_CONNS];
+ m_threadCount = 0;
+}
+
+bool RestInput::init()
+{
+ m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (m_sockfd < 0) {
+ cerr << "Failed to open socket. Exiting" << endl;
+ return false;
+ }
+ m_port = 1441; //listening on port 1441
+
+ m_serverAddr.sin_family = AF_INET;
+ m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ m_serverAddr.sin_port = htons(m_port);
+
+ if (::bind(m_sockfd, (struct sockaddr*)&m_serverAddr, sizeof m_serverAddr) < 0) {
+ cerr << "Failed to bind. Exiting " << endl;
+ return false;
+ }
+
+ listen(m_sockfd, MAX_CONNS);
+ startAccept(m_sockfd);
+ return true;
+}
+
+// accept incoming connection(s)
+void RestInput::startAccept(int &sockfd)
+{
+ if (m_threadCount >= MAX_CONNS) {
+ cerr << " Max # of connections reached. Skipping " << endl;
+ return;
+ } else {
+ while (true) {
+ int connfd = accept(sockfd, (struct sockaddr *)NULL, NULL);
+ if (connfd < 0) {
+ cerr << " Failed to accept incoming connection " << endl;
+ return;
+ }
+ int n = read(connfd, m_data, BUFLEN);
+ if (n < 0) {
+ cerr << "Failed to read from socket" << endl;
+ return;
+ }
+ startThread();
+ }
+ }
+}
+
+// start client thread
+void RestInput::startThread()
+{
+ std::thread t(&RestInput::processClient, this);
+ m_thread[m_threadCount] = std::move(t);
+ m_thread[m_threadCount++].join();
+}
+
+// process read commands for the client
+void RestInput::processClient(void)
+{
+ std::string restCmd = m_data;
+ std::size_t found = restCmd.find('\n');
+ if (found != std::string::npos) {
+ restCmd = restCmd.substr(0, found-1);
+ }
+ handleRead(restCmd);
+}
+
+void RestInput::handleRead(std::string& restCmd)
+{
+ parseString(restCmd);
+ if (restCmd.find("exit") == 0) {
+ std::thread::id id = std::this_thread::get_id();
+ for(int i = 0; i < m_threadCount; ++i) {
+ if (id == m_thread[i].get_id()) {
+ m_thread[i].detach();
+ --m_threadCount;
+ cout << "Exiting thread " << id << endl;
+ }
+ }
+ return;
+ }
+ stringstream ss;
+ observecb_t cb;
+ std::string msg = "command sent to LineInput is: " + restCmd;
+ printDebugMessage(msg);
+ m_lineInput->processLine(restCmd, ss, cb);
+ if (restCmd.find("show") != string::npos) {
+ // if command is show, we want to list out the details of each resource
+ handleShow(ss, cb);
+ }
+}
+
+void RestInput::handleShow(stringstream &ss, observecb_t &cb) {
+ std::string temp = ss.str();
+ size_t n = std::count(temp.begin(), temp.end(), '\n'); // number of resources found
+ std::stringstream sstm;
+ std::string lineInputData;
+
+ for (size_t i = 0; i < n; ++i) {
+ sstm.str("");
+ sstm << "details " << i;
+ lineInputData = sstm.str();
+ std::string msg = "Details: " + lineInputData;
+ printDebugMessage(msg);
+ m_lineInput->processLine(lineInputData, ss, cb);
+ sstm.str("");
+ sstm << "get " << i;
+ lineInputData = sstm.str();
+ msg = "Get: " + lineInputData;
+ printDebugMessage(msg);
+ m_lineInput->processLine(lineInputData, ss, cb);
+ }
+}
+
+void RestInput::parseString(std::string &toParse)
+{
+ std::size_t pos = toParse.find("HTTP"); // split on HTTP
+ toParse = toParse.substr(0, pos);
+ pos = toParse.find("/"); // find 1st occurance of /
+ toParse = toParse.substr(pos + 1, toParse.size() - 1);
+ std::replace(toParse.begin(), toParse.end(), '/', ' '); // replace all '/' with ' '
+}
diff --git a/examples/OICMiddle/RestInput.h b/examples/OICMiddle/RestInput.h
new file mode 100644
index 000000000..2e1cad6fd
--- /dev/null
+++ b/examples/OICMiddle/RestInput.h
@@ -0,0 +1,50 @@
+#ifndef RESTINPUT_H
+#define RESTINPUT_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <netinet/in.h>
+
+class LineInput;
+class Connection;
+
+class RestInput
+{
+public:
+ RestInput(LineInput *lineInput);
+ bool init();
+ void startAccept(int &sockfd);
+ void startThread();
+ void processClient(void);
+ void handleRead(std::string & restCmd);
+ void handleShow(stringstream &ss, observecb_t &cb);
+ void parseString(std::string &toParse);
+
+protected:
+ LineInput *m_lineInput;
+ int m_sockfd, m_port, m_threadCount;
+ struct sockaddr_in m_serverAddr;
+ char *m_data;
+ std::thread *m_thread;
+};
+
+#endif // RESTINPUT_H
+
diff --git a/examples/OICMiddle/SConstruct b/examples/OICMiddle/SConstruct
new file mode 100644
index 000000000..02a2d8e9b
--- /dev/null
+++ b/examples/OICMiddle/SConstruct
@@ -0,0 +1,81 @@
+#For Yocto builds, set OS=yocto as a command-line argument to scons once
+#the Yocto toolchain is installed and configured.
+
+#For Linux builds, set the following two variables:
+#Set OIC_RESOURCE_PATH to the root of oic-resource on Ubuntu.
+
+OIC_RESOURCE_PATH = '../..'
+
+#Set OIC_LIBS_PATH to path on Ubuntu that contains liboc.so, liboctbstack.so,
+#liboc_logger.so and libcoap.so.
+
+OIC_LIBS_PATH = '../../out/linux/x86_64/release'
+
+env = DefaultEnvironment()
+target_os = ARGUMENTS.get("OS", "linux").lower()
+output_dir = env.GetLaunchDir() + "/out/" + target_os
+env.VariantDir(output_dir, env.GetLaunchDir(), duplicate=0)
+env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall'])
+env.AppendUnique(LINKFLAGS = ['-pthread'])
+env.AppendUnique(LIBS = ['oc', 'octbstack', 'oc_logger', 'coap'])
+env.Program(output_dir + '/OICMiddle', [output_dir + '/OICMiddle.cpp',
+ output_dir + '/Client.cpp',
+ output_dir + '/Server.cpp',
+ output_dir + '/WrapResource.cpp',
+ output_dir + '/LineInput.cpp',
+ output_dir + '/RestInput.cpp'])
+
+if target_os == "yocto":
+ '''
+ This code injects Yocto cross-compilation flags into scons' default environment
+ in order to invoke the relevant tools while performing a build.
+ '''
+ import os.path, re
+ sdk_root = ''
+ try:
+ CC = os.environ['CC']
+ sdk_root = re.search(r'--sysroot=\S+', CC).group().split('=')[1]
+ target_prefix = CC.split()[0]
+ target_prefix = target_prefix[:len(target_prefix)-3]
+ tools = {"CC" : target_prefix+"gcc",
+ "CXX" : target_prefix+"g++",
+ "AS" : target_prefix+"as",
+ "LD" : target_prefix+"ld",
+ "GDB" : target_prefix+"gdb",
+ "STRIP" : target_prefix+"strip",
+ "RANLIB" : target_prefix+"ranlib",
+ "OBJCOPY" : target_prefix+"objcopy",
+ "OBJDUMP" : target_prefix+"objdump",
+ "AR" : target_prefix+"ar",
+ "NM" : target_prefix+"nm",
+ "M4" : "m4",
+ "STRINGS": target_prefix+"strings"}
+ PATH = os.environ['PATH'].split(os.pathsep)
+ for tool in tools:
+ if tool in os.environ:
+ for path in PATH:
+ if os.path.isfile(os.path.join(path, tools[tool])):
+ env[tool] = os.path.join(path, os.environ[tool])
+ env.AppendUnique(CPPPATH = [
+ sdk_root + '/usr/include/oic/',
+ sdk_root + '/usr/include/oic/stack/',
+ sdk_root + '/usr/include/oic/ocsocket/',
+ sdk_root + '/usr/include/oic/oc_logger/',
+ ])
+ except:
+ print "ERROR configuring Yocto cross-toolchain environment."
+ Exit(1)
+elif target_os == "linux":
+ if OIC_RESOURCE_PATH == '' or OIC_LIBS_PATH == '':
+ print "ERROR Please set both OIC_RESOURCE_PATH and OIC_LIBS_PATH in SConstruct"
+ Exit(1)
+ env.AppendUnique(CPPPATH = [
+ OIC_RESOURCE_PATH + '/resource/include',
+ OIC_RESOURCE_PATH + '/resource/csdk/stack/include',
+ OIC_RESOURCE_PATH + '/resource/csdk/ocsocket/include',
+ OIC_RESOURCE_PATH + '/resource/oc_logger/include',
+ ])
+ env.AppendUnique(LIBPATH = [OIC_LIBS_PATH])
+else:
+ print "ERROR ", target_os, " is an unsupported target"
+ Exit(1)
diff --git a/examples/OICMiddle/Server.cpp b/examples/OICMiddle/Server.cpp
new file mode 100644
index 000000000..b55e71556
--- /dev/null
+++ b/examples/OICMiddle/Server.cpp
@@ -0,0 +1,155 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 "Server.h"
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+namespace PH = std::placeholders;
+
+MiddleServer *serverObject = nullptr; // to be filled in by object
+
+MiddleServer::MiddleServer()
+{
+ cb = std::bind(&MiddleServer::entityHandler, this, std::placeholders::_1);
+ serverObject = this;
+}
+
+bool MiddleServer::init() {
+ return true;
+}
+
+OCEntityHandlerResult MiddleServer::entityHandler(const std::shared_ptr<OCResourceRequest> request) {
+ if (!request) {
+ return OC_EH_OK;
+ }
+
+ std::string requestType = request->getRequestType();
+ int requestFlag = request->getRequestHandlerFlag();
+ bool responseNeeded = false;
+
+ if (requestFlag && RequestHandlerFlag::InitFlag) {
+ return OC_EH_OK;
+ }
+
+ if (requestFlag && RequestHandlerFlag::RequestFlag) {
+ if (requestType == "PUT") {
+ responseNeeded = true;
+ } else if (requestType == "GET") {
+ responseNeeded = true;
+ } else if (requestType == "POST") { // handle post requests here
+ } else if (requestType == "DELETE") { // handle delete requests here
+ }
+ }
+
+ if (requestFlag && RequestHandlerFlag::ObserverFlag) {
+ }
+
+ if (responseNeeded) {
+ auto response = std::make_shared<OC::OCResourceResponse>();
+ response->setRequestHandle(request->getRequestHandle());
+ response->setResourceHandle(request->getResourceHandle());
+ response->setErrorCode(200);
+ response->setResponseResult(OC_EH_OK);
+ if (OC_STACK_OK != OCPlatform::sendResponse(response)) {
+ return OC_EH_ERROR;
+ }
+ }
+ return OC_EH_OK;
+}
+
+// for debug purposes - to see if the result of registerResource is valid or not
+void MiddleServer::printRegisterResourceResult(OCStackResult &result) {
+ switch (result) {
+ case OC_STACK_OK:
+ cout << "OC_STACK_OK\n";
+ break;
+ case OC_STACK_INVALID_URI:
+ cout << "OC_STACK_INVALID_URI\n";
+ break;
+ case OC_STACK_INVALID_QUERY:
+ cout << "OC_STACK_INVALID_QUERY\n";
+ break;
+ case OC_STACK_INVALID_IP:
+ cout << "OC_STACK_INVALID_IP\n";
+ break;
+ case OC_STACK_INVALID_PORT:
+ cout << "OC_STACK_INVALID_PORT\n";
+ break;
+ case OC_STACK_INVALID_CALLBACK:
+ cout << "OC_STACK_INVALID_CALLBACK\n";
+ break;
+ case OC_STACK_INVALID_METHOD:
+ cout << "OC_STACK_INVALID_METHOD\n";
+ break;
+ case OC_STACK_NO_MEMORY:
+ cout << "OC_STACK_NO_MEMORY\n";
+ break;
+ case OC_STACK_COMM_ERROR:
+ cout << "OC_STACK_COMM_ERROR\n";
+ break;
+ case OC_STACK_INVALID_PARAM:
+ cout << "OC_STACK_INVALID_PARAM\n";
+ break;
+ case OC_STACK_NOTIMPL:
+ cout << "OC_STACK_NOTIMPL\n";
+ break;
+ case OC_STACK_NO_RESOURCE:
+ cout << "OC_STACK_NO_RESOURCE\n";
+ break;
+ case OC_STACK_RESOURCE_ERROR:
+ cout << "OC_STACK_RESOURCE_ERROR\n";
+ break;
+ case OC_STACK_SLOW_RESOURCE:
+ cout << "OC_STACK_SLOW_RESOURCE\n";
+ break;
+ case OC_STACK_NO_OBSERVERS:
+ cout << "OC_STACK_NO_OBSERVERS\n";
+ break;
+ case OC_STACK_ERROR:
+ cout << "OC_STACK_ERROR\n";
+ break;
+ default:
+ cout << "UNKNOWN\n";
+ break;
+ }
+}
+
+bool MiddleServer::registerResource(std::string & resourceUrl, const std::string& resourceTypeName, const std::string& resourceInterface)
+{
+ OCResourceHandle resourceHandle;
+ // OCResourceProperty is defined ocstack.h
+ uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
+
+ //uncomment to enable debugging
+
+ // This will internally create and register the resource.
+ OCStackResult result = OC::OCPlatform::registerResource(
+ resourceHandle, resourceUrl, resourceTypeName,
+ resourceInterface,
+ cb,
+ resourceProperty);
+ // enable this to see the result of registerResource
+ //printRegisterResourceResult_(result);
+ if (result != OC_STACK_OK) {
+ return false;
+ }
+ return true;
+}
diff --git a/examples/OICMiddle/Server.h b/examples/OICMiddle/Server.h
new file mode 100644
index 000000000..049c708f3
--- /dev/null
+++ b/examples/OICMiddle/Server.h
@@ -0,0 +1,56 @@
+#ifndef SERVER_H
+#define SERVER_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 "OICMiddle.h"
+
+class MiddleServer
+{
+private:
+ std::string m_name;
+ bool m_state;
+ int m_power;
+ std::string m_url;
+ OCResourceHandle m_resourceHandle;
+ OCRepresentation *m_rep;
+ std::function<OCEntityHandlerResult(const std::shared_ptr<OCResourceRequest>)> cb;
+
+public:
+ MiddleServer();
+
+ bool init();
+ bool createAndRegisterResources(std::vector<std::string> &resourceUrlList,
+ std::vector<std::string> &resourceTypeList,
+ std::vector<std::string> &resourceInterfaceList,
+ std::vector<std::string> &nameList,
+ std::vector<std::string> &powerList,
+ std::vector<std::string> &stateList);
+ OCEntityHandlerResult entityHandler(const std::shared_ptr<OCResourceRequest>);
+
+ bool registerResource(std::string & resourceUrl,
+ const std::string &resourceTypeName,
+ const std::string & resourceInterface);
+private:
+ void printRegisterResourceResult(OCStackResult &result);
+};
+
+#endif // SERVER_H
diff --git a/examples/OICMiddle/WrapResource.cpp b/examples/OICMiddle/WrapResource.cpp
new file mode 100644
index 000000000..3cadb7ddf
--- /dev/null
+++ b/examples/OICMiddle/WrapResource.cpp
@@ -0,0 +1,289 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <sys/time.h>
+
+#include "WrapResource.h"
+
+unsigned long GetTickCount()
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) != 0)
+ return 0;
+ return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+WrapResource::WrapResource(string resourceID, ocresource_t resource)
+ : m_resourceID(resourceID), m_ocResource(resource),
+ m_listIndex(-1), m_x(0), m_repGetReady(false), m_gettingRep(false),
+ m_observeCB(nullptr), m_callbackRunning(false),
+ m_requestToken(0), m_observeRequest(nullptr),
+ m_typeRequest(nullptr)
+{
+}
+
+string WrapResource::getResourceID() {
+ return m_resourceID;
+}
+
+token_t WrapResource::getResource()
+{
+ WrapRequest *wreq;
+ QueryParamsMap m;
+
+ wreq = newRequest(RT_Get);
+ m_ocResource->get(m, wreq->m_getCB, QualityOfService::HighQos);
+ return wreq->m_token;
+}
+
+token_t WrapResource::putResource(OCRepresentation& rep)
+{
+ WrapRequest *wreq;
+ QueryParamsMap m;
+
+ wreq = newRequest(RT_Put);
+ rep.setUri(m_ocResource->uri());
+ m_ocResource->put(rep, m, wreq->m_putCB, QualityOfService::HighQos);
+ return wreq->m_token;
+}
+
+token_t WrapResource::observeResource(observecb_t& cb)
+{
+ WrapRequest *wreq;
+ QueryParamsMap m;
+ ObserveType type;
+
+ wreq = newRequest(RT_Observe);
+ m_observeRequest = wreq;
+ m_observeCB = cb;
+ m_callbackRunning = true;
+ type = ObserveType::Observe;
+ m_ocResource->observe(type, m, wreq->m_obsCB);
+ return wreq->m_token;
+}
+
+bool WrapResource::cancelObserve()
+{
+ m_callbackRunning = false;
+ m_observeCB = nullptr;
+
+ if (!m_observeRequest)
+ return false;
+
+ OCStackResult result = m_ocResource->cancelObserve();
+ if (result != OC_STACK_OK)
+ return false;
+
+ m_observeRequest->m_touchTime = GetTickCount();
+ return true;
+}
+
+WrapRequest *WrapResource::waitResource(token_t token)
+{
+ WrapRequest *wreq;
+ cv_status st;
+
+ try {
+ m_mutexMap.lock();
+ wreq = m_requestMap.at(token);
+ m_mutexMap.unlock();
+ } catch (const out_of_range& oor) {
+ m_mutexMap.unlock();
+ return nullptr;
+ }
+
+ std::unique_lock<std::mutex> lk(m_mutexGet);
+ st = wreq->m_cvGet.wait_for(lk, chrono::seconds(5));
+ return (st == cv_status::no_timeout) ? wreq : nullptr;
+}
+
+std::vector<std::string> WrapResource::getResourceTypes()
+{
+ return m_ocResource->getResourceTypes();
+}
+
+std::vector<std::string> WrapResource::getResourceInterfaces()
+{
+ return m_ocResource->getResourceInterfaces();
+}
+
+WrapRequest *WrapResource::newRequest(RequestType type)
+{
+ WrapRequest *wreq = new WrapRequest(this, type, ++m_requestToken);
+ m_requestMap[m_requestToken] = wreq;
+ return wreq;
+}
+
+void WrapResource::resourceCallback(WrapRequest *wreq)
+{
+ parseJSON(wreq);
+
+ if (wreq->m_forTypeOnly) {
+ wreq->m_typeReady = true;
+ return;
+ }
+
+ if (wreq->m_type == RT_Observe) {
+ if (!m_observeCB) {
+ if (m_callbackRunning)
+ cout << "callback missing " << m_resourceID << '\n';
+ return;
+ }
+ m_observeCB(wreq->m_token, wreq->m_headerOptions, wreq->m_rep, wreq->m_eCode,
+ wreq->m_sequenceNumber);
+ } else {
+ wreq->m_cvGet.notify_one();
+ }
+
+ wreq->m_touchTime = GetTickCount();
+}
+
+/*
+ * this parser infers types from json string since no other introspection
+ * is available. It also parses the key-value pairs.
+ */
+void WrapResource::parseJSON(WrapRequest *wreq)
+{
+ string sep = "\":";
+ string anchor = "\"rep\":{";
+ string json = wreq->m_rep.getJSONRepresentation();
+ string name, type, value, next;
+ size_t r, e, e1, s, c;
+
+ r = json.find(anchor);
+ if (r == string::npos) {
+ return;
+ }
+ c = r + anchor.length() - 1;
+ do {
+ c++;
+ if (json[c] != '"') {
+ if (json[c] == '}')
+ break;
+ return;
+ }
+ c++;
+ e = json.find(sep, c);
+ if (e == string::npos) {
+ return;
+ }
+ name = json.substr(c, e - c);
+ s = e + sep.length();
+ char q = json[s];
+ switch (q) {
+ case 't':
+ case 'f':
+ type = "bool";
+ e1 = json.find_first_of(",}", s + 1);
+ if (e1 == string::npos) {
+ return;
+ }
+ value = json.substr(s, e1 - s);
+ break;
+ case '"':
+ type = "string";
+ s++;
+ e1 = json.find_first_of("\"", s);
+ if (e1 == string::npos) {
+ return;
+ }
+ value = json.substr(s, e1 - s);
+ e1++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ type = "number";
+ e1 = json.find_first_of(",}", s + 1);
+ if (e1 == string::npos) {
+ return;
+ }
+ value = json.substr(s, e1 - s);
+ break;
+ default:
+ return;
+ }
+ wreq->m_valueMap[name] = value; // key-value map
+ m_typeMap[name] = type; // key-type map
+ c = e1;
+ } while (json[c] == ',');
+}
+
+void WrapResource::findTypes()
+{
+ delete m_typeRequest;
+ m_typeRequest = new WrapRequest(this, RT_Get, ++m_requestToken);
+ m_typeRequest->m_forTypeOnly = true;
+ getResource();
+}
+
+const stringmap_t& WrapResource::getFormats()
+{
+ return m_typeMap;
+}
+
+/********** WrapRequest ***********/
+
+WrapRequest::WrapRequest(WrapResource *wres, RequestType type, token_t token)
+ : m_eCode(0), m_sequenceNumber(0), m_parent(wres), m_type(type),
+ m_token(token), m_forTypeOnly(false), m_typeReady(false)
+{
+ m_getCB = std::bind(&WrapRequest::getCB, this,
+ placeholders::_1, placeholders::_2, placeholders::_3);
+ m_putCB = std::bind(&WrapRequest::putCB, this,
+ placeholders::_1, placeholders::_2, placeholders::_3);
+ m_obsCB = std::bind(&WrapRequest::observeCB, this,
+ placeholders::_1, placeholders::_2, placeholders::_3, placeholders::_4);
+ m_touchTime = GetTickCount();
+}
+
+void WrapRequest::getCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode)
+{
+ m_headerOptions = headerOptions;
+ m_rep = rep;
+ m_eCode = eCode;
+ m_parent->resourceCallback(this);
+}
+
+void WrapRequest::putCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode)
+{
+ m_headerOptions = headerOptions;
+ m_rep = rep;
+ m_eCode = eCode;
+ m_parent->resourceCallback(this);
+}
+
+void WrapRequest::observeCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode, int sequenceNumber)
+{
+ m_headerOptions = headerOptions;
+ m_rep = rep;
+ m_eCode = eCode;
+ m_sequenceNumber = sequenceNumber;
+ m_parent->resourceCallback(this);
+}
diff --git a/examples/OICMiddle/WrapResource.h b/examples/OICMiddle/WrapResource.h
new file mode 100644
index 000000000..472ce12de
--- /dev/null
+++ b/examples/OICMiddle/WrapResource.h
@@ -0,0 +1,121 @@
+#ifndef WRAPRESOURCE_H
+#define WRAPRESOURCE_H
+
+//******************************************************************
+//
+// Copyright 2014 Intel Corporation.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 <map>
+#include <mutex>
+#include <condition_variable>
+
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+#include "OICMiddle.h"
+
+using namespace OC;
+using namespace std;
+
+class WrapRequest;
+class MiddleClient;
+
+enum RequestType {
+ RT_Get,
+ RT_Put,
+ RT_Observe,
+};
+
+typedef std::shared_ptr<OCResource> ocresource_t;
+typedef std::map<token_t, WrapRequest *> requestmap_t;
+typedef std::function<void(const token_t token, const HeaderOptions&, const OCRepresentation&, const int, const int)> observecb_t;
+
+class WrapResource
+{
+public:
+ WrapResource(string resourceID, ocresource_t resource);
+
+ token_t getResource();
+ token_t putResource(OCRepresentation& rep);
+ token_t observeResource(observecb_t& callback);
+ string getResourceID();
+ bool cancelObserve();
+ std::vector<std::string> getResourceTypes();
+ std::vector<std::string> getResourceInterfaces();
+ WrapRequest *waitResource(token_t token);
+ const stringmap_t& getFormats();
+
+ friend class WrapRequest;
+ friend class MiddleClient;
+
+protected:
+ WrapRequest *newRequest(RequestType type);
+ void resourceCallback(WrapRequest *wreq);
+ void parseJSON(WrapRequest *wreq);
+ void findTypes();
+
+ string m_resourceID;
+ ocresource_t m_ocResource;
+ int m_listIndex;
+ int m_x;
+ bool m_repGetReady;
+ bool m_gettingRep;
+ mutex m_mutexMap;
+ mutex m_mutexGet;
+ observecb_t m_observeCB;
+ bool m_callbackRunning;
+ int m_requestToken;
+ requestmap_t m_requestMap;
+ WrapRequest *m_observeRequest; // can only be one
+ stringmap_t m_typeMap;
+ vector<WrapRequest *> m_typeResults;
+ WrapRequest *m_typeRequest;
+};
+
+struct WrapRequest
+{
+ WrapRequest(WrapResource *wres, RequestType type, token_t token);
+
+ friend class WrapResource;
+
+ HeaderOptions m_headerOptions;
+ OCRepresentation m_rep;
+ int m_eCode;
+ int m_sequenceNumber;
+ stringmap_t m_valueMap;
+ unsigned long m_touchTime;
+
+protected:
+ WrapResource *m_parent;
+ RequestType m_type;
+ token_t m_token;
+ condition_variable m_cvGet;
+ bool m_forTypeOnly;
+ bool m_typeReady;
+
+ void getCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode);
+ void putCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode);
+ void observeCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode, const int sequenceNumber);
+
+ GetCallback m_getCB;
+ PutCallback m_putCB;
+ ObserveCallback m_obsCB;
+};
+
+#endif // WRAPRESOURCE_H
diff --git a/examples/OICMiddle/makefile b/examples/OICMiddle/makefile
new file mode 100644
index 000000000..527921835
--- /dev/null
+++ b/examples/OICMiddle/makefile
@@ -0,0 +1,87 @@
+#//******************************************************************
+#//
+#// Copyright 2014 Intel Corporation.
+#//
+#//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#//
+#// Licensed 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.
+#//
+#//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+# override with `make BUILD=release`
+# default to release build
+BUILD := debug
+PLATFORM := linux
+CXX := g++
+#CXX := clang
+OUT_DIR := $(BUILD)
+OIC := ../..
+OIC_RES := $(OIC)/resource
+OIC_LIB := $(OIC)/out/linux/x86_64/release
+OBJS := OICMiddle.o \
+ Client.o \
+ Server.o \
+ WrapResource.o \
+ LineInput.o \
+ RestInput.o
+
+CXX_FLAGS.debug := -O0 -g3 -std=c++0x -Wall -pthread
+
+CXX_FLAGS.release := -O3 -std=c++0x -Wall -pthread
+
+CXX_INC := -I$(OIC_RES)/include/
+CXX_INC += -I$(OIC_RES)/oc_logger/include
+CXX_INC += -I$(OIC_RES)/csdk/stack/include
+CXX_INC += -I$(OIC_RES)/csdk/ocsocket/include
+CXX_INC += -I$(OIC_RES)/csdk/ocrandom/include
+CXX_INC += -I$(OIC_RES)/csdk/logger/include
+CXX_INC += -I$(OIC_RES)/csdk/libcoap
+CXX_INC += -I$(OIC_RES)/../extlibs/cereal/include
+
+CXX_LIBS := $(OIC_LIB)/liboc.so
+CXX_LIBS += $(OIC_LIB)/liboctbstack.so
+CXX_LIBS += $(OIC_LIB)/liboc_logger.so
+CXX_LIBS += $(OIC_LIB)/liboc_logger_core.so
+CXX_LIBS += $(OIC_LIB)/libcoap.so
+
+all: prep_dirs OICMiddle
+
+prep_dirs:
+ -mkdir -p $(OUT_DIR)
+
+OICMiddle: $(OBJS)
+ $(CXX) $(CXX_FLAGS.$(BUILD)) -o $(OUT_DIR)/$@ $(OBJS) $(CXX_LIBS)
+
+OICMiddle.o: OICMiddle.cpp OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) OICMiddle.cpp $(CXX_INC)
+
+Client.o: Client.cpp Client.h OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) Client.cpp $(CXX_INC)
+
+Server.o: Server.cpp Server.h OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) Server.cpp $(CXX_INC)
+
+WrapResource.o: WrapResource.cpp WrapResource.h OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) WrapResource.cpp $(CXX_INC)
+
+LineInput.o: LineInput.cpp LineInput.h OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) LineInput.cpp $(CXX_INC)
+
+RestInput.o: RestInput.cpp RestInput.h OICMiddle.h
+ $(CXX) -c $(CXX_FLAGS.$(BUILD)) RestInput.cpp $(CXX_INC)
+
+clean:
+ rm $(OBJS)
+ rm -rf debug
+ rm -rf release
+