--- /dev/null
+Mu-Woong Lee <muwoong.lee@samsung.com>
+Jihoon Park <jhp27.park@samsung.com>
+Somin Kim <somin926.kim@samsung.com>
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(context-service)
+INCLUDE(GNUInstallDirs)
+
+# Targets
+SET(target "contextd")
+
+# Source Lists
+FILE(GLOB_RECURSE SRCS src/*.cpp)
+MESSAGE("Sources: ${SRCS}")
+
+# Dependencies
+SET(DEPS
+ vconf
+ libxml-2.0
+ sqlite3
+ capi-system-info
+ capi-appfw-app-manager
+ appsvc
+ pkgmgr-info
+ capi-security-privilege-manager
+ vasum
+ alarm-service
+ notification
+ clips
+ context-common
+ device-context-provider
+ statistics-context-provider
+ place-context-provider
+)
+
+# Dependencies regarding profiles
+IF("${PROFILE}" STREQUAL "mobile")
+ ADD_DEFINITIONS("-D_MOBILE")
+ENDIF("${PROFILE}" STREQUAL "mobile")
+
+IF("${PROFILE}" STREQUAL "wearable")
+ ADD_DEFINITIONS("-D_WEARABLE")
+ENDIF("${PROFILE}" STREQUAL "wearable")
+
+# Target vs Emulator
+IF("${ARCH}" STREQUAL "arm")
+ ADD_DEFINITIONS("-D_TARGET")
+ELSE("${ARCH}" STREQUAL "arm")
+ ADD_DEFINITIONS("-D_EMULATOR")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+# Common Options
+INCLUDE(FindPkgConfig)
+INCLUDE_DIRECTORIES(
+ /usr/include
+ /usr/include/glib-2.0
+)
+ADD_DEFINITIONS(-g -O2 -Wall -fPIC -fvisibility=hidden -Wl,--as-needed)
+
+# Building Daemon
+pkg_check_modules(daemon_pkg REQUIRED ${DEPS})
+
+SET(DAEMON_EXTRA_CFLAGS -fPIE)
+FOREACH(flag ${daemon_pkg_CFLAGS})
+ SET(DAEMON_EXTRA_CFLAGS "${DAEMON_EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+ADD_EXECUTABLE(${target} ${SRCS})
+TARGET_LINK_LIBRARIES(${target} ${daemon_pkg_LDFLAGS} -pie)
+SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS ${DAEMON_EXTRA_CFLAGS})
+SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_DEFINITIONS "LOG_TAG=\"CONTEXT\"")
+
+# Installing Daemon
+INSTALL(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+
+ 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.
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+\r
+<ContextAccessConfig>\r
+\r
+ <Privilege name="alarm.set">\r
+ <Allow subject="timer/event/on_time"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="network.get">\r
+ <Allow subject="system/state/wifi"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="telephony">\r
+ <Allow subject="social/state/call"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="message.read">\r
+ <Allow subject="social/event/message"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="location">\r
+ <Allow subject="place/event/geofence"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="apphistory.read">\r
+ <Allow subject="app/history/recently_used"/>\r
+ <Allow subject="app/history/frequently_used"/>\r
+ <Allow subject="app/history/rarely_used"/>\r
+ <Allow subject="app/history/peak_time"/>\r
+ <Allow subject="app/history/common_setting"/>\r
+ <Allow subject="app/history/use_freq"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="mediahistory.read">\r
+ <Allow subject="music/history/peak_time"/>\r
+ <Allow subject="video/history/peak_time"/>\r
+ <Allow subject="music/history/common_setting"/>\r
+ <Allow subject="video/history/common_setting"/>\r
+ <Allow subject="music/history/play_freq"/>\r
+ <Allow subject="video/history/play_freq"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="mediahistory.admin">\r
+ <Allow subject="music/event/start"/>\r
+ <Allow subject="music/event/stop"/>\r
+ <Allow subject="video/event/start"/>\r
+ <Allow subject="video/event/stop"/>\r
+ </Privilege>\r
+\r
+ <Privilege name="callhistory.read">\r
+ <Allow subject="contact/history/comm_freq"/>\r
+ </Privilege>\r
+\r
+</ContextAccessConfig>\r
--- /dev/null
+#!/bin/bash
+
+function print_sql {
+ echo "UPDATE context_trigger_template SET j_template='{$2 }' WHERE name='$1';"
+ echo "INSERT OR IGNORE INTO context_trigger_template (name, j_template) VALUES ('$1', '{$2 }');"
+}
+
+echo "CREATE TABLE IF NOT EXISTS context_trigger_template ("
+echo " name TEXT DEFAULT '' NOT NULL PRIMARY KEY,"
+echo " j_template TEXT DEFAULT '' NOT NULL);"
+
+template_json_file="$1"
+
+while read -r line
+do
+ keyword=`echo $line | awk '{print $1}' | tr -cd '[:alpha:]'`
+
+ if [[ $keyword = "name" ]]; then
+
+ if [ -n "$template" ]; then
+ print_sql "$name" "$template"
+ template=""
+ fi
+
+ name=`echo $line | tr -d '":,' | awk '{print $2}'`
+ fi
+
+ if [[ $keyword = "name" ]] || [[ $keyword = "attributes" ]] || [[ $keyword = "option" ]]; then
+ template="$template $line"
+ fi
+
+done < "$template_json_file"
+
+print_sql "$name" "$template"
--- /dev/null
+{
+ "templates": [
+ {
+ "name": "timer/event",
+ "attributes": ["TimeOfDay", "DayOfWeek"]
+ },
+ {
+ "name": "timer/state",
+ "attributes": ["TimeOfDay", "DayOfWeek", "DayOfMonth"]
+ },
+ {
+ "name": "system/state/battery",
+ "attributes": ["Level", "IsCharging"]
+ },
+ {
+ "name": "system/state/charger",
+ "attributes": ["IsConnected"]
+ },
+ {
+ "name": "system/state/flight_mode",
+ "attributes": ["IsEnabled"]
+ },
+ {
+ "name": "system/state/gps",
+ "attributes": ["State"]
+ },
+ {
+ "name": "system/state/headphone",
+ "attributes": ["IsConnected", "Type"]
+ },
+ {
+ "name": "system/state/ps_mode",
+ "attributes": ["IsEnabled"]
+ },
+ {
+ "name": "system/state/silent_mode",
+ "attributes": ["IsEnabled"]
+ },
+ {
+ "name": "system/state/vibration_mode",
+ "attributes": ["IsEnabled"]
+ },
+ {
+ "name": "system/state/usb",
+ "attributes": ["IsConnected"]
+ },
+ {
+ "name": "system/state/wifi",
+ "attributes": ["State", "BSSID"]
+ },
+ {
+ "name": "social/state/call",
+ "attributes": ["Medium", "State", "Address"]
+ },
+ {
+ "name": "social/event/email",
+ "attributes": ["Event"]
+ },
+ {
+ "name": "social/event/message",
+ "attributes": ["Event", "Type", "Address"]
+ },
+ {
+ "name": "activity/event/stationary",
+ "attributes": ["Event", "Accuracy"]
+ },
+ {
+ "name": "activity/event/walking",
+ "attributes": ["Event", "Accuracy"]
+ },
+ {
+ "name": "activity/event/running",
+ "attributes": ["Event", "Accuracy"]
+ },
+ {
+ "name": "activity/event/in_vehicle",
+ "attributes": ["Event", "Accuracy"]
+ },
+ {
+ "name": "place/event/geofence",
+ "attributes": ["Event"],
+ "option": ["PlaceId"]
+ },
+ {
+ "name": "app/history/use_freq",
+ "attributes": ["Rank", "TotalCount"],
+ "option": ["AppId", "TimeOfDay", "DayOfWeek"]
+ },
+ {
+ "name": "contact/history/comm_freq",
+ "attributes": ["Rank", "TotalCount"],
+ "option": ["Address", "TimeOfDay", "DayOfWeek"]
+ },
+ {
+ "name": "music/history/play_freq",
+ "attributes": ["TotalCount"],
+ "option": ["TimeOfDay", "DayOfWeek"]
+ },
+ {
+ "name": "video/history/play_freq",
+ "attributes": ["TotalCount"],
+ "option": ["TimeOfDay", "DayOfWeek"]
+ }
+ ]
+}
--- /dev/null
+<manifest>
+ <define>
+ <domain name="context-service"/>
+ <permit>
+ <smack permit="dbus" type="rwx"/>
+ </permit>
+ <request>
+ <smack request="xorg" type="rw"/>
+ <smack request="security-server::api-cookie-check" type="w"/>
+ <smack request="security-server::api-privilege-by-pid" type="w"/>
+ <smack request="vasum::manage" type="rw"/>
+ <smack request="sys-assert::core" type="rwxat"/>
+ <smack request="system::vconf" type="rwxl"/>
+ <smack request="system::vconf_system" type="rl"/>
+ <smack request="system::vconf_inhouse" type="rl"/>
+ <smack request="system::vconf_multimedia" type="rl"/>
+ <smack request="device::app_logging" type="rw"/>
+ <smack request="device::sys_logging" type="rw"/>
+ <smack request="deviced::display" type="rw"/>
+ <smack request="ail::db" type="rlx"/>
+ <smack request="pkgmgr" type="r"/>
+ <smack request="pkgmgr::db" type="rwx"/>
+ <smack request="pkgmgr::info" type="r"/>
+ <smack request="alarm-server::alarm" type="rw"/>
+ <smack request="libaccounts-svc" type="r"/>
+ <smack request="libaccounts-svc::db" type="rl"/>
+ <smack request="libaccounts-svc::check_read" type="r"/>
+ <smack request="telephony_framework::api_sim" type="r"/>
+ <smack request="telephony_framework::api_phonebook" type="rx"/>
+ <smack request="telephony_framework::properties" type="rw"/>
+ <smack request="connman::get" type="rw"/>
+ <smack request="connman::set" type="rw"/>
+ <smack request="connman::profile" type="rw"/>
+ <smack request="telephony_framework::api_ps_public" type="rw"/>
+ <smack request="telephony_framework::api_ps_profile" type="rw"/>
+ <smack request="telephony_framework::api_sms" type="rwx"/>
+ <smack request="telephony_framework::api_network" type="rwx"/>
+ <smack request="telephony_framework::api_call" type="rwx"/>
+ <smack request="privilege::tizen::telephony.admin" type="rw"/>
+ <smack request="privilege::tizen::telephony" type="rw"/>
+ <smack request="data-provider-master::notification" type="rwl"/>
+ <smack request="data-provider-master::notification.client" type="rw"/>
+ <smack request="aul::launch" type="x"/>
+ <smack request="privilege::tizen::call" type="rw"/>
+ <smack request="privilege::tizen::bluetooth" type="rw"/>
+ <smack request="privilege::tizen::network.get" type="rw"/>
+ <smack request="privilege::tizen::network.profile" type="rw"/>
+ <smack request="privilege::tizen::message.read" type="rw"/>
+ <smack request="msg-service" type="rwx"/>
+ <smack request="msg-service::db" type="r"/>
+ <smack request="msg-service::read" type="rw"/>
+ <smack request="msg-service::vconf" type="r"/>
+ <smack request="tizen::vconf::message" type="r"/>
+ <smack request="privilege::tizen::message.write" type="rw"/>
+ <smack request="privilege::tizen::message.read" type="rw"/>
+ <smack request="msg-service::write" type="rw"/>
+ <smack request="msg-service::read" type="rw"/>
+ <smack request="app-svc::jump" type="x"/>
+ <smack request="tizen::vconf::public::r::platform::rw" type="rlw"/>
+ </request>
+ </define>
+ <request>
+ <domain name="context-service"/>
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/contextd" exec_label="context-service" label="context-service"/>
+ </assign>
+</manifest>
--- /dev/null
+[Unit]
+Description=Contextual Service Framework Daemon
+
+[Service]
+Type=dbus
+User=system
+Group=system
+SmackProcessLabel=context-service
+BusName=org.tizen.context
+ExecStart=/usr/bin/contextd
+Restart=always
+RestartSec=1
+
+[Install]
+WantedBy=graphical.target
--- /dev/null
+Name: context-service
+Summary: Context-Service
+Version: 0.4.4
+Release: 1
+Group: Framework/system
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1: context-service.service
+Source2: org.tizen.context.service
+
+BuildRequires: cmake
+BuildRequires: sed
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(sqlite3)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(capi-appfw-app-manager)
+BuildRequires: pkgconfig(appsvc)
+BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: pkgconfig(capi-security-privilege-manager)
+BuildRequires: pkgconfig(vasum)
+BuildRequires: pkgconfig(alarm-service)
+BuildRequires: pkgconfig(notification)
+
+BuildRequires: pkgconfig(clips)
+BuildRequires: pkgconfig(context-common)
+BuildRequires: pkgconfig(context)
+BuildRequires: context-internal
+
+BuildRequires: pkgconfig(device-context-provider)
+BuildRequires: pkgconfig(statistics-context-provider)
+BuildRequires: pkgconfig(place-context-provider)
+
+Requires(preun): /usr/bin/systemctl
+Requires(post): sys-assert
+Requires(post): /usr/bin/systemctl
+Requires(post): /usr/bin/sqlite3
+Requires(postun): /usr/bin/systemctl
+
+%ifarch %{arm}
+%define ARCH arm
+%else
+%define ARCH i586
+%endif
+
+%description
+Context-Service
+
+%prep
+%setup -q
+
+%build
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+
+export CFLAGS+=" -Wextra -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wswitch-default"
+export CXXFLAGS+=" -Wextra -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wswitch-default -Wnon-virtual-dtor -Wno-c++0x-compat"
+
+export CFLAGS+=" -Wno-unused-parameter -Wno-empty-body"
+export CXXFLAGS+=" -Wno-unused-parameter -Wno-empty-body"
+
+export CFLAGS+=" -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-strict-aliasing -fno-unroll-loops -fsigned-char -fstrict-overflow -fno-common"
+export CXXFLAGS+=" -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-strict-aliasing -fno-unroll-loops -fsigned-char -fstrict-overflow"
+#export CXXFLAGS+=" -std=c++0x"
+
+export CFLAGS+=" -DTIZEN_ENGINEER_MODE"
+export CXXFLAGS+=" -DTIZEN_ENGINEER_MODE"
+export FFLAGS+=" -DTIZEN_ENGINEER_MODE"
+
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DARCH=%{ARCH} -DMAJORVER=${MAJORVER} -DFULLVER=%{version} -DPROFILE=%{?tizen_profile_name}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}%{_unitdir}
+#mkdir -p %{buildroot}%{_datadir}/dbus-1/services
+mkdir -p %{buildroot}%{_datadir}/license
+mkdir -p %{buildroot}%{_datadir}/packages
+mkdir -p %{buildroot}/opt/dbspace
+mkdir -p %{buildroot}/opt/data/context-service
+sqlite3 %{buildroot}/opt/dbspace/.context-service.db "PRAGMA journal_mode = PERSIST;"
+sqlite3 %{buildroot}/opt/dbspace/.context-service.db "CREATE TABLE VERSION (VERSION TEXT);"
+sqlite3 %{buildroot}/opt/dbspace/.context-service.db "INSERT INTO VERSION VALUES ('%{version}');"
+install -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}
+#install -m 0644 %{SOURCE2} %{buildroot}%{_datadir}/dbus-1/services/
+cp LICENSE %{buildroot}%{_datadir}/license/%{name}
+sed -i "s/^\tversion=\".*\"/\tversion=\"%{version}\"/g" packaging/context-service.xml
+cp packaging/context-service.xml %{buildroot}%{_datadir}/packages/
+cp data/access-config.xml %{buildroot}/opt/data/context-service/
+cp data/trigger-template.json %{buildroot}/opt/data/context-service/
+sh data/template-json-to-sql.sh data/trigger-template.json > %{buildroot}/opt/data/context-service/trigger-template.sql
+
+%post
+sqlite3 -echo /opt/dbspace/.context-service.db < /opt/data/context-service/trigger-template.sql
+mkdir -p %{_unitdir}/graphical.target.wants
+ln -s ../context-service.service %{_unitdir}/graphical.target.wants/
+/sbin/ldconfig
+systemctl daemon-reload
+#if [ $1 == 1 ]; then
+# systemctl restart context-service
+#fi
+
+%preun
+if [ $1 == 0 ]; then
+ systemctl stop context-service
+fi
+
+%postun
+rm -f %{_unitdir}/graphical.target.wants/context-service.service
+systemctl daemon-reload
+/sbin/ldconfig
+
+%files
+%manifest packaging/%{name}.manifest
+%defattr(-,root,root,-)
+%{_bindir}/*
+%{_unitdir}/context-service.service
+#%{_datadir}/dbus-1/services/org.tizen.context.service
+%{_datadir}/license/%{name}
+%{_datadir}/packages/*.xml
+%defattr(0600,system,system,-)
+/opt/data/context-service/*
+%config(noreplace) /opt/dbspace/.context-service.db*
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest xmlns="http://tizen.org/ns/packages"
+ package="context-service"
+ version="0.0.0"
+ install-location="internal-only"
+ type="rpm">
+ <label>Context Service</label>
+ <description>Context Service</description>
+ <service-application appid="context-service"
+ exec="/usr/bin/contextd"
+ type="capp"
+ multiple="false"
+ taskmanage="false"
+ nodisplay="true"
+ mainapp="true">
+ <label>Context Service</label>
+ </service-application>
+ <privileges>
+ <privilege>http://tizen.org/privilege/location</privilege>
+ </privileges>
+</manifest>
--- /dev/null
+[D-BUS Service]
+Name=org.tizen.context
+Exec=/bin/false
+SystemdService=context-service.service
+User=system
+Group=system
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+
+#include <types_internal.h>
+
+#include "privilege.h"
+#include "config_loader.h"
+
+#define CONFIG_PATH "/opt/data/context-service/access-config.xml"
+#define ELM_ROOT "ContextAccessConfig"
+#define ELM_PRIV "Privilege"
+#define ELM_LINK "Link"
+#define ELM_ALLOW "Allow"
+#define ATTR_NAME "name"
+#define ATTR_SUBJ "subject"
+#define IS_NODE_OF(node, element) (xmlStrcmp((node)->name, (const xmlChar *)(element)) == 0)
+
+static void parse_priv_node(xmlNodePtr cursor)
+{
+ char *prop = (char*)(xmlGetProp(cursor, (const xmlChar*)ATTR_NAME));
+ IF_FAIL_VOID_TAG(prop, _E, "Failed to get '%s'", ATTR_NAME);
+
+ std::string name = prop;
+ free(prop);
+
+ cursor = cursor->xmlChildrenNode;
+ IF_FAIL_VOID_TAG(cursor, _E, "No child node exists");
+
+ while (cursor) {
+ if (!IS_NODE_OF(cursor, ELM_ALLOW)) {
+ _D("Skipping a node '%s'", (const char*)cursor->name);
+ cursor = cursor->next;
+ continue;
+ }
+
+ prop = (char*)(xmlGetProp(cursor, (const xmlChar*)ATTR_SUBJ));
+ if (prop == NULL) {
+ _E("Failed to get '%s'", ATTR_SUBJ);
+ cursor = cursor->next;
+ continue;
+ }
+
+ _SI("Set Privilege: %s <- %s", prop, name.c_str());
+ ctx::privilege_manager::set(prop, name.c_str());
+
+ free(prop);
+ cursor = cursor->next;
+ }
+}
+
+static void parse_link_node(xmlNodePtr cursor)
+{
+ //TODO: Not supported yet
+ _D("Skipping a link node\n");
+}
+
+bool ctx::access_config_loader::load()
+{
+ xmlDocPtr doc = xmlParseFile(CONFIG_PATH);
+ IF_FAIL_RETURN_TAG(doc, false, _E, "XML parsing failed");
+
+ xmlNodePtr cursor = xmlDocGetRootElement(doc);
+ IF_FAIL_CATCH_TAG(cursor, _E, "No root node");
+ IF_FAIL_CATCH_TAG(IS_NODE_OF(cursor, ELM_ROOT), _E, "Invalid root node");
+
+ cursor = cursor->xmlChildrenNode;
+
+ while (cursor) {
+ if (IS_NODE_OF(cursor, ELM_PRIV)) {
+ parse_priv_node(cursor);
+ } else if (IS_NODE_OF(cursor, ELM_LINK)) {
+ parse_link_node(cursor);
+ }
+
+ cursor = cursor->next;
+ }
+
+ xmlFreeDoc(doc);
+ return true;
+
+CATCH:
+ xmlFreeDoc(doc);
+ return false;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_ACCESS_CONFIG_LOADER_H__
+#define __CONTEXT_ACCESS_CONFIG_LOADER_H__
+
+namespace ctx {
+ namespace access_config_loader {
+
+ bool load();
+
+ }
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_ACCESS_CONFIG_LOADER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <map>
+
+#include <pkgmgr-info.h>
+#include <privilege_checker.h>
+
+#include <types_internal.h>
+
+#include "config_loader.h"
+#include "privilege.h"
+
+typedef std::map<std::string, std::string> string_map_t;
+
+static string_map_t *privilege_map = NULL;
+
+bool ctx::privilege_manager::init()
+{
+ IF_FAIL_RETURN(privilege_map == NULL, true);
+
+ privilege_map = new(std::nothrow) string_map_t;
+
+ if (!ctx::access_config_loader::load()) {
+ _E("Loading failed");
+ delete privilege_map;
+ return false;
+ }
+
+ return true;
+}
+
+void ctx::privilege_manager::release()
+{
+ delete privilege_map;
+ privilege_map = NULL;
+}
+
+void ctx::privilege_manager::set(const char* subject, const char* priv)
+{
+ (*privilege_map)[subject] = priv;
+}
+
+bool ctx::privilege_manager::is_allowed(const char* pkg_id, const char* subject)
+{
+ IF_FAIL_RETURN_TAG(pkg_id && subject, true, _E, "Invalid parameter");
+ IF_FAIL_RETURN_TAG(pkg_id[0]!='\0' && subject[0]!='\0', true, _E, "Invalid parameter");
+
+ string_map_t::iterator it = privilege_map->find(subject);
+ if (it == privilege_map->end()) {
+ // Non-Privileged Subject
+ return true;
+ }
+
+ _D("PkgId: %s, Priv: %s", pkg_id, (it->second).c_str());
+ std::string priv = "http://tizen.org/privilege/";
+ priv += (it->second).c_str();
+ int ret = privilege_checker_check_package_privilege(pkg_id, priv.c_str());
+ _D("Privilege Check Result: %#x", ret);
+ return (ret == PRIV_CHECKER_ERR_NONE);
+}
+
+std::string ctx::privilege_manager::get_pkg_id(const char* app_id)
+{
+ std::string pkg_id;
+ IF_FAIL_RETURN_TAG(app_id, pkg_id, _E, "Null AppId");
+
+ int ret;
+ pkgmgrinfo_appinfo_h app_info;
+
+ ret = pkgmgrinfo_appinfo_get_appinfo(app_id, &app_info);
+ IF_FAIL_RETURN_TAG(ret == PMINFO_R_OK, pkg_id, _E, "Failed to get app_info");
+
+ char *pkg_name = NULL;
+ ret = pkgmgrinfo_appinfo_get_pkgname(app_info, &pkg_name);
+ if (ret != PMINFO_R_OK || pkg_name == NULL) {
+ pkgmgrinfo_appinfo_destroy_appinfo(app_info);
+ _E("Failed to get package name");
+ return pkg_id;
+ }
+
+ pkg_id = pkg_name;
+ pkgmgrinfo_appinfo_destroy_appinfo(app_info);
+ return pkg_id;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_PRIVILEGE_MANAGER_H__
+#define __CONTEXT_PRIVILEGE_MANAGER_H__
+
+#include <string>
+
+namespace ctx {
+ namespace privilege_manager {
+
+ bool init();
+ void release();
+
+ void set(const char* subject, const char* priv);
+ bool is_allowed(const char* pkg_id, const char* subject);
+ std::string get_pkg_id(const char* app_id);
+
+ } /* namespace ctx::privilege_manager */
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_PRIVILEGE_MANAGER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <unistd.h>
+#include <glib.h>
+#include <security-server.h>
+#include <app_manager.h>
+#include <types_internal.h>
+#include <dbus_server.h>
+#include "zone_util_impl.h"
+#include "dbus_server_impl.h"
+#include "access_control/privilege.h"
+#include "client_request.h"
+
+ctx::client_request::client_request(int type, const char* client, int req_id, const char* subj, const char* desc, const char* cookie, GDBusMethodInvocation *inv)
+ : request_info(type, client, req_id, subj, desc)
+ , invocation(inv)
+{
+ gsize size;
+ int client_pid;
+ char *decoded = NULL;
+ const char *zone_name = NULL;
+ char *pkg_id = NULL;
+
+ decoded = reinterpret_cast<char*>(g_base64_decode(cookie, &size));
+ IF_FAIL_CATCH_TAG(decoded, _E, "Cookie decoding failed");
+
+ raw_cookie = decoded;
+ client_pid = security_server_get_cookie_pid(decoded);
+ pkg_id = security_server_get_smacklabel_cookie(decoded);
+ g_free(decoded);
+ IF_FAIL_CATCH_TAG(client_pid > 0, _E, "Invalid PID (%d)", client_pid);
+
+ if (pkg_id == NULL) {
+ _W(RED("security_server_get_smacklabel_cookie() failed"));
+ char* app_id = NULL;
+ app_manager_get_app_id(client_pid, &app_id);
+ client_app_id = ctx::privilege_manager::get_pkg_id(app_id);
+ g_free(app_id);
+ } else {
+ //FIXME: Yes.. this is actually the package id
+ client_app_id = pkg_id;
+ g_free(pkg_id);
+ }
+
+ zone_name = ctx::zone_util::get_name_by_pid(client_pid);
+ IF_FAIL_CATCH_TAG(zone_name, _E, RED("Zone name retrieval failed"));
+ _zone_name = zone_name;
+
+ _SD(CYAN("Package: '%s' / Zone: '%s'"), client_app_id.c_str(), zone_name);
+ return;
+
+CATCH:
+ invocation = NULL;
+ throw ERR_OPERATION_FAILED;
+}
+
+ctx::client_request::~client_request()
+{
+ if (invocation)
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+}
+
+const char* ctx::client_request::get_cookie()
+{
+ return raw_cookie.c_str();
+}
+
+const char* ctx::client_request::get_app_id()
+{
+ if (!client_app_id.empty())
+ return client_app_id.c_str();
+
+ return NULL;
+}
+
+bool ctx::client_request::reply(int error)
+{
+ IF_FAIL_RETURN(invocation, true);
+
+ _I("Reply %#x", error);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", error, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ invocation = NULL;
+ return true;
+}
+
+bool ctx::client_request::reply(int error, ctx::json& request_result)
+{
+ IF_FAIL_RETURN(invocation, true);
+ IF_FAIL_RETURN(_type != REQ_READ_SYNC, true);
+
+ char *result = request_result.dup_cstr();
+ IF_FAIL_RETURN_TAG(result, false, _E, "Memory allocation failed");
+
+ _I("Reply %#x", error);
+ _SD("Result: %s", result);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", error, result, EMPTY_JSON_OBJECT));
+ invocation = NULL;
+
+ g_free(result);
+ return true;
+}
+
+bool ctx::client_request::reply(int error, ctx::json& request_result, ctx::json& data_read)
+{
+ if (invocation == NULL) {
+ return publish(error, data_read);
+ }
+
+ char *result = NULL;
+ char *data = NULL;
+
+ result = request_result.dup_cstr();
+ IF_FAIL_CATCH_TAG(result, _E, "Memory allocation failed");
+
+ data = data_read.dup_cstr();
+ IF_FAIL_CATCH_TAG(data, _E, "Memory allocation failed");
+
+ _I("Reply %#x", error);
+ _SD("Result: %s", result);
+ _SD("Data: %s", data);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", error, result, data));
+ invocation = NULL;
+
+ g_free(result);
+ g_free(data);
+ return true;
+
+CATCH:
+ g_free(result);
+ g_free(data);
+ return false;
+}
+
+bool ctx::client_request::publish(int error, ctx::json& data)
+{
+ char *data_str = data.dup_cstr();
+ IF_FAIL_RETURN_TAG(data_str, false, _E, "Memory allocation failed");
+
+ dbus_server::publish(_client.c_str(), _req_id, _subject.c_str(), error, data_str);
+ g_free(data_str);
+
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_CLIENT_REQUEST_H__
+#define __CONTEXT_CLIENT_REQUEST_H__
+
+#include <gio/gio.h>
+#include "request.h"
+
+namespace ctx {
+
+ class client_request : public request_info {
+ public:
+ client_request(int type, const char* client, int req_id, const char* subj, const char* desc, const char* cookie, GDBusMethodInvocation *inv);
+ ~client_request();
+
+ const char* get_cookie();
+ const char* get_app_id();
+
+ bool reply(int error);
+ bool reply(int error, ctx::json& request_result);
+ bool reply(int error, ctx::json& request_result, ctx::json& data_read);
+ bool publish(int error, ctx::json& data);
+
+ private:
+ GDBusMethodInvocation *invocation;
+ std::string raw_cookie;
+ std::string client_app_id;
+ std::string exec_path;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_CLIENT_REQUEST_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <glib.h>
+#include <string>
+
+#include <types_internal.h>
+#include <json.h>
+#include <provider_iface.h>
+#include "server.h"
+#include "context_mgr_impl.h"
+#include "zone_util_impl.h"
+#include "access_control/privilege.h"
+
+/* Analyzer Headers */
+#include <internal/device_context_provider.h>
+#include <internal/app_statistics_provider.h>
+#include <internal/social_statistics_provider.h>
+#include <internal/media_statistics_provider.h>
+#include <internal/place_context_provider.h>
+
+ctx::context_manager_impl::context_manager_impl()
+{
+}
+
+ctx::context_manager_impl::~context_manager_impl()
+{
+ release();
+}
+
+bool ctx::context_manager_impl::init()
+{
+ IF_FAIL_RETURN_TAG(provider_list.size()==0, false, _W, "Re-initialization");
+
+ try {
+ /* List of all providers */
+ load_provider(new ctx::device_context_provider());
+ load_provider(new ctx::app_statistics_provider());
+ load_provider(new ctx::social_statistics_provider());
+ load_provider(new ctx::media_statistics_provider());
+ load_provider(new ctx::place_context_provider());
+
+ } catch (std::bad_alloc& ba) {
+ _E("Analyzer loading failed (bad alloc)");
+ return false;
+ } catch (int e) {
+ _E("Analyzer loading failed (%#x)", e);
+ return false;
+ }
+
+ return true;
+}
+
+void ctx::context_manager_impl::release()
+{
+ subject_provider_map.clear();
+
+ for (provider_list_t::iterator it = provider_list.begin(); it != provider_list.end(); ++it) {
+ delete *it;
+ }
+ provider_list.clear();
+
+ for (request_list_t::iterator it = subscribe_request_list.begin(); it != subscribe_request_list.end(); ++it) {
+ delete *it;
+ }
+ subscribe_request_list.clear();
+
+ for (request_list_t::iterator it = read_request_list.begin(); it != read_request_list.end(); ++it) {
+ delete *it;
+ }
+ read_request_list.clear();
+}
+
+void ctx::context_manager_impl::load_provider(context_provider_iface* provider)
+{
+ if (!provider) {
+ _E("Analyzer NULL");
+ throw static_cast<int>(ERR_INVALID_PARAMETER);
+ }
+
+ provider_list.push_back(provider);
+
+ if (!provider->init()) {
+ _E("Analyzer initialization failed");
+ throw ERR_OPERATION_FAILED;
+ }
+}
+
+bool ctx::context_manager_impl::register_provider(const char* subject, ctx::context_provider_iface* cp)
+{
+ IF_FAIL_RETURN_TAG(subject && cp, false, _E, "Invalid parameter");
+
+ if (subject_provider_map.find(subject) != subject_provider_map.end()) {
+ _E("The provider for the subject '%s' is already registered.", subject);
+ return false;
+ }
+
+ _I("Registering provider for '%s'", subject);
+ subject_provider_map[subject] = cp;
+
+ return true;
+}
+
+void ctx::context_manager_impl::assign_request(ctx::request_info* request)
+{
+ int req_type = request->get_type();
+ context_provider_iface *provider = NULL;
+
+ if (req_type != REQ_UNSUBSCRIBE) {
+ subject_provider_map_t::iterator it = subject_provider_map.find(request->get_subject());
+ if (it == subject_provider_map.end()) {
+ _E("Unknown subject '%s'", request->get_subject());
+ request->reply(ERR_NOT_SUPPORTED);
+ delete request;
+ return;
+ }
+ provider = it->second;
+ }
+
+ std::string app_id;
+ // If the ClientAppId attribute exists but is empty.
+ if (request->get_description().get(NULL, COMMON_ATTR_CLIENT_APP_ID, &app_id)) {
+ if (app_id.empty() && request->get_app_id()) {
+ request->get_description().set(NULL, COMMON_ATTR_CLIENT_APP_ID, request->get_app_id());
+ }
+ }
+
+ switch (req_type) {
+ case REQ_SUBSCRIBE:
+ if (!check_permission(request)) {
+ request->reply(ERR_PERMISSION_DENIED);
+ delete request;
+ break;
+ }
+ subscribe(request, provider);
+ break;
+ case REQ_UNSUBSCRIBE:
+ unsubscribe(request);
+ break;
+ case REQ_READ:
+ case REQ_READ_SYNC:
+ if (!check_permission(request)) {
+ request->reply(ERR_PERMISSION_DENIED);
+ delete request;
+ break;
+ }
+ read(request, provider);
+ break;
+ case REQ_WRITE:
+ if (!check_permission(request)) {
+ request->reply(ERR_PERMISSION_DENIED);
+ delete request;
+ break;
+ }
+ write(request, provider);
+ break;
+ case REQ_SUPPORT:
+ if (provider->is_supported(request->get_subject(), request->get_zone_name())) {
+ request->reply(ERR_NONE);
+ } else {
+ request->reply(ERR_NOT_SUPPORTED);
+ }
+ delete request;
+ break;
+ default:
+ _E("Invalid type of request");
+ delete request;
+ }
+}
+
+bool ctx::context_manager_impl::is_supported(const char* subject, const char* zone)
+{
+ subject_provider_map_t::iterator it = subject_provider_map.find(subject);
+ IF_FAIL_RETURN(it != subject_provider_map.end(), false);
+
+ return it->second->is_supported(subject, zone);
+}
+
+ctx::context_manager_impl::request_list_t::iterator
+ctx::context_manager_impl::find_request(request_list_t& r_list, std::string subject, json& option, const char* zone)
+{
+ return find_request(r_list.begin(), r_list.end(), subject, option, zone);
+}
+
+ctx::context_manager_impl::request_list_t::iterator
+ctx::context_manager_impl::find_request(request_list_t& r_list, std::string client, int req_id)
+{
+ request_list_t::iterator it;
+ for (it = r_list.begin(); it != r_list.end(); ++it) {
+ if (client == (*it)->get_client() && req_id == (*it)->get_id()) {
+ break;
+ }
+ }
+ return it;
+}
+
+ctx::context_manager_impl::request_list_t::iterator
+ctx::context_manager_impl::find_request(request_list_t::iterator begin, request_list_t::iterator end, std::string subject, json& option, const char* zone)
+{
+ //TODO: Do we need to consider the case that the inparam option is a subset of the request description?
+ request_list_t::iterator it;
+ for (it = begin; it != end; ++it) {
+ if (subject == (*it)->get_subject() && option == (*it)->get_description() && STR_EQ(zone, (*it)->get_zone_name())) {
+ break;
+ }
+ }
+ return it;
+}
+
+bool ctx::context_manager_impl::check_permission(ctx::request_info* request)
+{
+ const char* app_id = request->get_app_id();
+ _D("Peer AppID: %s", app_id);
+ IF_FAIL_RETURN_TAG(app_id, false, _E, "AppID NULL");
+ IF_FAIL_RETURN_TAG(!STR_EQ(app_id, TRIGGER_CLIENT_NAME), true, _D, "Skipping permission check for Trigger");
+
+ scope_zone_joiner sz(request->get_zone_name());
+
+ bool allowed = ctx::privilege_manager::is_allowed(app_id, request->get_subject());
+ IF_FAIL_RETURN_TAG(allowed, false, _W, "Permission denied");
+
+ return true;
+}
+
+void ctx::context_manager_impl::subscribe(ctx::request_info* request, ctx::context_provider_iface* provider)
+{
+ _I(CYAN("[%s] '%s' subscribes '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
+
+ ctx::json request_result;
+ int error = provider->subscribe(request->get_subject(), request->get_description().str(), &request_result, request->get_zone_name());
+
+ _D("Analyzer returned %d", error);
+
+ if (!request->reply(error, request_result) || error != ERR_NONE) {
+ delete request;
+ return;
+ }
+
+ subscribe_request_list.push_back(request);
+}
+
+void ctx::context_manager_impl::unsubscribe(ctx::request_info* request)
+{
+ _I(CYAN("[%s] '%s' unsubscribes RID-%d"), request->get_zone_name(), request->get_client(), request->get_id());
+
+ // Search the subscribe request to be removed
+ request_list_t::iterator target = find_request(subscribe_request_list, request->get_client(), request->get_id());
+ if (target == subscribe_request_list.end()) {
+ _W("Unknown request");
+ delete request;
+ return;
+ }
+
+ // Keep the pointer to the request found
+ request_info *req_found = *target;
+
+ // Remove the request from the list
+ subscribe_request_list.erase(target);
+
+ // Check if there exist the same requests
+ if (find_request(subscribe_request_list, req_found->get_subject(), req_found->get_description(), req_found->get_zone_name()) != subscribe_request_list.end()) {
+ // Do not stop detecting the subject
+ _D("A same request from '%s' exists", req_found->get_client());
+ request->reply(ERR_NONE);
+ delete request;
+ delete req_found;
+ return;
+ }
+
+ // Find the proper provider
+ subject_provider_map_t::iterator ca = subject_provider_map.find(req_found->get_subject());
+ if (ca == subject_provider_map.end()) {
+ _E("Invalid subject '%s'", req_found->get_subject());
+ delete request;
+ delete req_found;
+ return;
+ }
+
+ // Stop detecting the subject
+ int error = ca->second->unsubscribe(req_found->get_subject(), req_found->get_description(), req_found->get_zone_name());
+ request->reply(error);
+ delete request;
+ delete req_found;
+}
+
+void ctx::context_manager_impl::read(ctx::request_info* request, ctx::context_provider_iface* provider)
+{
+ _I(CYAN("[%s] '%s' reads '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
+
+ ctx::json request_result;
+ int error = provider->read(request->get_subject(), request->get_description().str(), &request_result, request->get_zone_name());
+
+ _D("Analyzer returned %d", error);
+
+ if (!request->reply(error, request_result) || error != ERR_NONE) {
+ delete request;
+ return;
+ }
+
+ read_request_list.push_back(request);
+}
+
+void ctx::context_manager_impl::write(ctx::request_info* request, ctx::context_provider_iface* provider)
+{
+ _I(CYAN("[%s] '%s' writes '%s' (RID-%d)"), request->get_zone_name(), request->get_client(), request->get_subject(), request->get_id());
+
+ ctx::json request_result;
+ int error = provider->write(request->get_subject(), request->get_description(), &request_result, request->get_zone_name());
+
+ _D("Analyzer returned %d", error);
+
+ request->reply(error, request_result);
+ delete request;
+}
+
+bool ctx::context_manager_impl::_publish(const char* subject, ctx::json option, int error, ctx::json data_updated, const char* zone)
+{
+ IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
+
+ _I("Publishing '%s'", subject);
+ _J("Option", option);
+
+ request_list_t::iterator end = subscribe_request_list.end();
+ request_list_t::iterator target = find_request(subscribe_request_list.begin(), end, subject, option, zone);
+
+ while (target != end) {
+ if (!(*target)->publish(error, data_updated)) {
+ return false;
+ }
+ target = find_request(++target, end, subject, option, zone);
+ }
+
+ return true;
+}
+
+bool ctx::context_manager_impl::_reply_to_read(const char* subject, ctx::json option, int error, ctx::json data_read, const char* zone)
+{
+ IF_FAIL_RETURN_TAG(subject, false, _E, "Invalid parameter");
+
+ _I("Sending data of '%s'", subject);
+ _J("Option", option);
+ _J("Data", data_read);
+ _SI("Zone: '%s'", zone);
+
+ request_list_t::iterator end = read_request_list.end();
+ request_list_t::iterator target = find_request(read_request_list.begin(), end, subject, option, zone);
+ request_list_t::iterator prev;
+
+ ctx::json dummy;
+
+ while (target != end) {
+ (*target)->reply(error, dummy, data_read);
+ prev = target;
+ target = find_request(++target, end, subject, option, zone);
+
+ delete *prev;
+ read_request_list.erase(prev);
+ }
+
+ return true;
+}
+
+struct published_data_s {
+ int type;
+ ctx::context_manager_impl *mgr;
+ std::string subject;
+ std::string zone;
+ int error;
+ ctx::json option;
+ ctx::json data;
+ published_data_s(int t, ctx::context_manager_impl *m, const char* s, ctx::json& o, int e, ctx::json& d, const char* z)
+ : type(t), mgr(m), subject(s), error(e)
+ {
+ option = o.str();
+ data = d.str();
+ zone = z;
+ }
+};
+
+gboolean ctx::context_manager_impl::thread_switcher(gpointer data)
+{
+ published_data_s *tuple = static_cast<published_data_s*>(data);
+
+ switch (tuple->type) {
+ case REQ_SUBSCRIBE:
+ tuple->mgr->_publish(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data, tuple->zone.c_str());
+ break;
+ case REQ_READ:
+ tuple->mgr->_reply_to_read(tuple->subject.c_str(), tuple->option, tuple->error, tuple->data, tuple->zone.c_str());
+ break;
+ default:
+ _W("Invalid type");
+ }
+
+ delete tuple;
+ return FALSE;
+}
+
+bool ctx::context_manager_impl::publish(const char* subject, ctx::json& option, int error, ctx::json& data_updated, const char* zone)
+{
+ IF_FAIL_RETURN_TAG(subject && zone, false, _E, "Invalid parameter");
+
+ published_data_s *tuple = new(std::nothrow) published_data_s(REQ_SUBSCRIBE, this, subject, option, error, data_updated, zone);
+ IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
+
+ g_idle_add(thread_switcher, tuple);
+
+ return true;
+}
+
+bool ctx::context_manager_impl::reply_to_read(const char* subject, ctx::json& option, int error, ctx::json& data_read, const char* zone)
+{
+ IF_FAIL_RETURN_TAG(subject && zone, false, _E, "Invalid parameter");
+
+ published_data_s *tuple = new(std::nothrow) published_data_s(REQ_READ, this, subject, option, error, data_read, zone);
+ IF_FAIL_RETURN_TAG(tuple, false, _E, "Memory allocation failed");
+
+ g_idle_add(thread_switcher, tuple);
+
+ return true;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_MANAGER_IMPL_H__
+#define __CONTEXT_MANAGER_IMPL_H__
+
+#include <vector>
+#include <list>
+#include <map>
+#include <context_mgr_iface.h>
+#include "request.h"
+
+#define TRIGGER_CLIENT_NAME "TRIGGER"
+
+namespace ctx {
+
+ class context_manager_impl : public context_manager_iface {
+ public:
+ typedef std::list<request_info*> request_list_t;
+
+ context_manager_impl();
+ ~context_manager_impl();
+
+ bool init();
+ void release();
+
+ void assign_request(ctx::request_info* request);
+ bool is_supported(const char* subject, const char* zone);
+
+ // From the interface class
+ bool register_provider(const char* subject, ctx::context_provider_iface* cp);
+ bool publish(const char* subject, ctx::json& option, int error, ctx::json& data_updated, const char* zone);
+ bool reply_to_read(const char* subject, ctx::json& option, int error, ctx::json& data_read, const char* zone);
+ // ---
+
+ private:
+ typedef std::vector<context_provider_iface*> provider_list_t;
+ typedef std::map<std::string, context_provider_iface*> subject_provider_map_t;
+
+ provider_list_t provider_list;
+ request_list_t subscribe_request_list;
+ request_list_t read_request_list;
+ subject_provider_map_t subject_provider_map;
+
+ void load_provider(ctx::context_provider_iface* provider);
+
+ void subscribe(request_info* request, context_provider_iface* provider);
+ void unsubscribe(request_info* request);
+ void read(request_info* request, context_provider_iface* provider);
+ void write(request_info* request, context_provider_iface* provider);
+
+ bool check_permission(request_info* request);
+
+ static gboolean thread_switcher(gpointer data);
+ bool _publish(const char* subject, ctx::json option, int error, ctx::json data_updated, const char* zone);
+ bool _reply_to_read(const char* subject, ctx::json option, int error, ctx::json data_read, const char* zone);
+
+ request_list_t::iterator find_request(request_list_t& r_list, std::string subject, json& option, const char* zone);
+ request_list_t::iterator find_request(request_list_t& r_list, std::string client, int req_id);
+ request_list_t::iterator find_request(request_list_t::iterator begin, request_list_t::iterator end, std::string subject, json& option, const char* zone);
+
+ }; /* class context_manager_impl */
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_MANAGER_IMPL_H__ */
--- /dev/null
+/*
+ * context-service
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <types_internal.h>
+#include <json.h>
+#include <string>
+#include <sstream>
+#include <cstdlib>
+#include "clips_handler.h"
+#include "rule_manager.h"
+
+extern "C"
+{
+#include <clips/clips.h>
+}
+
+static void* env = NULL;
+static ctx::rule_manager* rule_mgr = NULL;
+static int string_to_int(std::string str);
+
+ctx::clips_handler::clips_handler()
+{
+}
+
+ctx::clips_handler::~clips_handler()
+{
+ if (env) {
+ DestroyEnvironment(env);
+ }
+}
+
+bool ctx::clips_handler::init(ctx::rule_manager* rm)
+{
+ rule_mgr = rm;
+
+ int error = init_environment(env);
+ IF_FAIL_RETURN(error == ERR_NONE, false);
+
+ bool ret = define_global_variable_string("zone", "");
+ IF_FAIL_RETURN(ret, false);
+
+ return true;
+}
+
+int ctx::clips_handler::init_environment(void* &environment)
+{
+ environment = CreateEnvironment();
+ if (!environment) {
+ _E("Create environment failed");
+ return ERR_OPERATION_FAILED;
+ }
+
+ char* func_name = strdup("execute_action");
+ char* restrictions = strdup("1s");
+
+ if (func_name == NULL || restrictions == NULL) {
+ _E("Memory allocation failed");
+ free(func_name);
+ free(restrictions);
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ EnvDefineFunction2(environment, func_name, 'i', PTIEF execute_action, func_name, restrictions);
+
+ free(func_name);
+ free(restrictions);
+
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::define_template(std::string& script)
+{
+ IF_FAIL_RETURN_TAG(env_build(script) == ERR_NONE, ERR_OPERATION_FAILED, _E, "Deftemplate failed");
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::define_class(std::string& script)
+{
+ IF_FAIL_RETURN_TAG(env_build(script) == ERR_NONE, ERR_OPERATION_FAILED, _E, "Defclass failed");
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::define_rule(std::string& script)
+{
+ IF_FAIL_RETURN_TAG(env_build(script) == ERR_NONE, ERR_OPERATION_FAILED, _E, "Defrule failed");
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::env_build(std::string& script)
+{
+ ASSERT_NOT_NULL(env);
+ if (script.length() == 0)
+ return ERR_INVALID_PARAMETER;
+
+ _I("EnvBuild script (%s)", script.c_str());
+ int ret = EnvBuild(env, script.c_str());
+
+ return (ret == 1)? ERR_NONE : ERR_OPERATION_FAILED;
+}
+
+int ctx::clips_handler::run_environment()
+{
+ ASSERT_NOT_NULL(env);
+
+ int fired_rule_num = EnvRun(env, -1);
+ IF_FAIL_RETURN(fired_rule_num >= 0, ERR_OPERATION_FAILED);
+
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::add_fact(std::string& fact)
+{
+ ASSERT_NOT_NULL(env);
+ if (fact.length() == 0)
+ return ERR_INVALID_PARAMETER;
+
+ void* assert_fact = EnvAssertString(env, fact.c_str());
+ IF_FAIL_RETURN_TAG(assert_fact, ERR_OPERATION_FAILED, _E, "Fact assertion failed");
+
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::route_string_command(std::string& script)
+{
+ ASSERT_NOT_NULL(env);
+ if (script.length() == 0)
+ return ERR_INVALID_PARAMETER;
+
+ int error;
+ if (RouteCommand(env, script.c_str(), TRUE)){
+ _D("Route command succeeded(%s).", script.c_str());
+ error = ERR_NONE;
+ } else {
+ _E("Route command failed");
+ error = ERR_OPERATION_FAILED;
+ }
+
+ return error;
+}
+
+int ctx::clips_handler::make_instance(std::string& script)
+{
+ ASSERT_NOT_NULL(env);
+ if (script.length() == 0)
+ return ERR_INVALID_PARAMETER;
+
+ int error;
+ if (EnvMakeInstance(env, script.c_str())){
+ _D("Make instance succeeded - %s", script.c_str());
+ error = ERR_NONE;
+ } else {
+ _E("Make instance failed");
+ error = ERR_OPERATION_FAILED;
+ }
+
+ return error;
+}
+
+int ctx::clips_handler::unmake_instance(std::string& instance_name)
+{
+ ASSERT_NOT_NULL(env);
+ if (instance_name.length() == 0)
+ return ERR_INVALID_PARAMETER;
+
+ void* instance = find_instance_internal(instance_name);
+ if (!instance) {
+ _E("Cannot find instance(%s).", instance_name.c_str());
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (!EnvUnmakeInstance(env, instance)){
+ _E("Unmake instance failed");
+ return ERR_OPERATION_FAILED;
+ }
+
+ _D("Unmake instance succeeded(%s).", instance_name.c_str());
+ return ERR_NONE;
+}
+
+int ctx::clips_handler::execute_action()
+{
+ if (!env) {
+ _E("Environment not created");
+ return ERR_OPERATION_FAILED;
+ }
+
+ const char* result = EnvRtnLexeme(env, 1);
+ if (!result) {
+ _E("Failed to get returned rule id");
+ return ERR_OPERATION_FAILED;
+ }
+ std::string rule_id = result;
+ std::string id_str = rule_id.substr(4);
+
+ int id = string_to_int(id_str);
+ rule_mgr->on_rule_triggered(id);
+
+ return ERR_NONE;
+}
+
+bool ctx::clips_handler::find_instance(std::string& instance_name)
+{
+ ASSERT_NOT_NULL(env);
+ if (find_instance_internal(instance_name)) {
+ _D("[%s] already exists", instance_name.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+void* ctx::clips_handler::find_instance_internal(std::string& instance_name)
+{
+ void* instance = EnvFindInstance(env, NULL, instance_name.c_str(), TRUE);
+ return instance;
+}
+
+int string_to_int(std::string str)
+{
+ int i;
+ std::istringstream convert(str);
+
+ if (!(convert >> i))
+ i = 0;
+
+ return i;
+}
+
+bool ctx::clips_handler::define_global_variable_string(std::string variable_name, std::string value)
+{
+ std::string script = "(defglobal ?*";
+ script += variable_name;
+ script += "* = \"";
+ script += value;
+ script += "\")";
+
+ IF_FAIL_RETURN_TAG(env_build(script) == ERR_NONE, false, _E, "Defglobal failed");
+ return true;
+}
+
+bool ctx::clips_handler::set_global_variable_string(std::string variable_name, std::string value)
+{
+ ASSERT_NOT_NULL(env);
+ if (variable_name.length() == 0)
+ return false;
+
+ DATA_OBJECT data;
+ SetType(data, STRING);
+ SetValue(data, EnvAddSymbol(env, value.c_str())) ;
+
+ int ret = EnvSetDefglobalValue(env, variable_name.c_str(), &data);
+
+ IF_FAIL_RETURN_TAG(ret == 1, false, _E, "Set global variable(%s) failed", variable_name.c_str());
+ return true;
+}
--- /dev/null
+/*
+* context-service
+*
+* Copyright (c) 2014 Samsung Electronics Co., Ltd.
+*
+* 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.
+*
+*/
+
+#ifndef __CLIPS_HANDLER_H__
+#define __CLIPS_HANDLER_H__
+
+namespace ctx {
+
+ class json;
+ class rule_manager;
+
+ class clips_handler {
+ public:
+ clips_handler();
+ ~clips_handler();
+ bool init(ctx::rule_manager* rm);
+
+ int define_template(std::string& script);
+ int define_class(std::string& script);
+ int define_rule(std::string& script);
+ int run_environment();
+ int add_fact(std::string& fact);
+ int route_string_command(std::string& fact);
+ int make_instance(std::string& script);
+ int unmake_instance(std::string& instance_name);
+ static int execute_action();
+ bool find_instance(std::string& instance_name);
+ bool define_global_variable_string(std::string variable_name, std::string value);
+ bool set_global_variable_string(std::string variable_name, std::string value);
+
+ private:
+ int init_environment(void* &environment);
+ int env_build(std::string& script);
+ void* find_instance_internal(std::string& instance_name);
+
+ }; /* class clips_handler */
+
+} /* namespace ctx */
+
+#endif /* End of __CLIPS_HANDLER_H__ */
--- /dev/null
+/*
+ * context-service
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <types_internal.h>
+#include <json.h>
+#include <context_trigger_types_internal.h>
+#include "context_monitor.h"
+#include "fact_reader.h"
+#include "timer_types.h"
+
+static ctx::fact_reader *reader = NULL;
+typedef std::map<std::string, ctx::trigger_timer> timer_map_t;
+static timer_map_t timer_map; // <zone_name, timer>
+
+ctx::context_monitor::context_monitor()
+{
+}
+
+ctx::context_monitor::~context_monitor()
+{
+}
+
+bool ctx::context_monitor::init(ctx::fact_reader* fr, ctx::context_trigger* tr)
+{
+ reader = fr;
+ trigger = tr;
+
+ return true;
+}
+
+int ctx::context_monitor::subscribe(int rule_id, std::string subject, ctx::json event, const char* zone)
+{
+ if (subject.compare(TIMER_EVENT_SUBJECT) == 0) {
+ // option is event json in case of ON_TIME
+ return subscribe_timer(event, zone);
+ }
+
+ ctx::json eoption = NULL;
+ event.get(NULL, CT_RULE_EVENT_OPTION, &eoption);
+
+ int req_id = reader->subscribe(subject.c_str(), &eoption, zone, true);
+ IF_FAIL_RETURN_TAG(req_id > 0, ERR_OPERATION_FAILED, _E, "Subscribe event failed");
+ _D(YELLOW("Subscribe event(rule%d). req%d"), rule_id, req_id);
+ request_map[rule_id] = req_id;
+ read_req_cnt_map[req_id]++;
+
+ return ERR_NONE;
+}
+
+int ctx::context_monitor::unsubscribe(int rule_id, std::string subject, ctx::json option, const char* zone)
+{
+ if (subject.compare(TIMER_EVENT_SUBJECT) == 0) {
+ return unsubscribe_timer(option, zone);
+ }
+
+ _D(YELLOW("Unsubscribe event(rule%d). req%d"), rule_id, request_map[rule_id]);
+ int req_id = request_map[rule_id];
+ request_map.erase(rule_id);
+
+ read_req_cnt_map[req_id]--;
+ if (read_req_cnt_map[req_id] == 0) {
+ reader->unsubscribe(req_id);
+ read_req_cnt_map.erase(req_id);
+ }
+
+ return ERR_NONE;
+}
+
+int ctx::context_monitor::read_time(ctx::json* result, const char* zone)
+{
+ int dom = ctx::trigger_timer::get_day_of_month();
+ (*result).set(NULL, TIMER_RESPONSE_KEY_DAY_OF_MONTH, dom);
+
+ std::string dow = ctx::trigger_timer::get_day_of_week();
+ (*result).set(NULL, TIMER_RESPONSE_KEY_DAY_OF_WEEK, dow);
+
+ int time = ctx::trigger_timer::get_minute_of_day();
+ (*result).set(NULL, TIMER_RESPONSE_KEY_TIME_OF_DAY, time);
+
+ return ERR_NONE;
+}
+
+int ctx::context_monitor::read(std::string subject, json option, const char* zone, ctx::json* result)
+{
+ bool ret;
+ if (subject.compare(TIMER_CONDITION_SUBJECT) == 0) {
+ return read_time(result, zone);
+ }
+
+ context_fact fact;
+ ret = reader->read(subject.c_str(), &option, zone, fact);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Read fact failed");
+
+ *result = fact.get_data();
+
+ return ERR_NONE;
+}
+
+static int arrange_day_of_week(ctx::json day_info)
+{
+ int result = 0;
+
+ std::string key_op;
+ if (!day_info.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &key_op)) {
+ result = ctx::trigger_timer::convert_string_to_day_of_week("\"" TIMER_EVERYDAY "\"");
+ return result;
+ }
+
+ if (key_op.compare("and") == 0) {
+ result = ctx::trigger_timer::convert_string_to_day_of_week("\"" TIMER_EVERYDAY "\"");
+ }
+
+ std::string tmp_d;
+ for (int i = 0; day_info.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &tmp_d); i++) {
+ int dow = ctx::trigger_timer::convert_string_to_day_of_week(tmp_d);
+ std::string op;
+ day_info.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, i, &op);
+
+ if (op.compare("neq") == 0) {
+ dow = ctx::trigger_timer::convert_string_to_day_of_week("\"" TIMER_EVERYDAY "\"") & ~dow;
+ }
+
+ if (key_op.compare("and") == 0) {
+ result &= dow;
+ } else {
+ result |= dow;
+ }
+ }
+ _D("Requested day of week (%#x)", result);
+
+ return result;
+}
+
+timer_map_t::iterator ctx::context_monitor::get_zone_timer(std::string zone)
+{
+ timer_map_t::iterator it = timer_map.find(zone);
+
+ if (it == timer_map.end()) {
+ timer_map.insert(std::pair<std::string, ctx::trigger_timer>(zone, ctx::trigger_timer(trigger, zone)));
+ }
+
+ return timer_map.find(zone);
+}
+
+int ctx::context_monitor::subscribe_timer(ctx::json option, const char* zone)
+{
+ ctx::json day_info;
+ ctx::json time_info;
+
+ ctx::json it;
+ for (int i = 0; option.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &it); i++){
+ std::string key;
+ it.get(NULL, CT_RULE_DATA_KEY, &key);
+
+ if (key.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
+ day_info = it;
+ } else if (key.compare(TIMER_RESPONSE_KEY_TIME_OF_DAY) == 0) {
+ time_info = it;
+ }
+ }
+
+ // Day option processing
+ int dow = arrange_day_of_week(day_info);
+
+ // Time option processing
+ int time; // minute
+ timer_map_t::iterator timer = get_zone_timer(zone);
+ for (int i = 0; time_info.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &time); i++) {
+ (timer->second).add(time, dow);
+ }
+
+ return ERR_NONE;
+}
+
+int ctx::context_monitor::unsubscribe_timer(ctx::json option, const char* zone)
+{
+ ctx::json day_info;
+ ctx::json time_info;
+
+ ctx::json it;
+ for (int i = 0; option.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &it); i++){
+ std::string key;
+ it.get(NULL, CT_RULE_DATA_KEY, &key);
+
+ if (key.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
+ day_info = it;
+ } else if (key.compare(TIMER_RESPONSE_KEY_TIME_OF_DAY) == 0) {
+ time_info = it;
+ }
+ }
+
+ // Day option processing
+ int dow = arrange_day_of_week(day_info);
+
+ // Time option processing
+ int time; // minute
+ timer_map_t::iterator timer = get_zone_timer(zone);
+ for (int i = 0; time_info.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &time); i++) {
+ (timer->second).remove(time, dow);
+ }
+
+ if ((timer->second).empty()) {
+ timer_map.erase(timer);
+ }
+
+ return ERR_NONE;
+}
+
+bool ctx::context_monitor::is_supported(std::string subject, const char* zone)
+{
+ if (subject.compare(TIMER_EVENT_SUBJECT) == 0
+ || subject.compare(TIMER_CONDITION_SUBJECT) == 0) {
+ return true;
+ }
+
+ return reader->is_supported(subject.c_str(), zone);
+}
--- /dev/null
+/*
+* context-service
+*
+* Copyright (c) 2014 Samsung Electronics Co., Ltd.
+*
+* 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.
+*
+*/
+
+#ifndef __CONTEXT_MONITOR_H__
+#define __CONTEXT_MONITOR_H__
+
+#include <map>
+#include "timer.h"
+
+namespace ctx {
+
+ class json;
+ class fact_reader;
+ class context_fact;
+
+ class context_monitor {
+ public:
+ context_monitor();
+ ~context_monitor();
+ bool init(ctx::fact_reader* fr, ctx::context_trigger* tr);
+
+ int subscribe(int rule_id, std::string subject, ctx::json event, const char* zone);
+ int unsubscribe(int rule_id, std::string subject, ctx::json option, const char* zone);
+ int read(std::string subject, json option, const char* zone, ctx::json* result);
+ bool is_supported(std::string subject, const char* zone);
+
+ private:
+ std::map<std::string, ctx::trigger_timer>::iterator get_zone_timer(std::string zone);
+ int subscribe_timer(ctx::json option, const char* zone);
+ int unsubscribe_timer(ctx::json option, const char* zone);
+ int read_day_of_month(ctx::json* result, const char* zone);
+ int read_day_of_week(ctx::json* result, const char* zone);
+ int read_time(ctx::json* result, const char* zone);
+ std::map<int, int> request_map; // <rule_id, fact_read_req_id>
+ std::map<int, int> read_req_cnt_map; // <fact_read_req_id, count>
+ ctx::context_trigger* trigger;
+
+ }; /* class context_monitor */
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_MONITOR_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <types_internal.h>
+#include "fact.h"
+
+ctx::context_fact::context_fact()
+ : req_id(-1)
+ , error(ERR_NONE)
+{
+}
+
+ctx::context_fact::context_fact(int id, int err, const char* s, ctx::json& o, ctx::json& d, const char* z)
+ : req_id(id)
+ , error(err)
+ , subject(s)
+ , option(o)
+ , data(d)
+{
+ if (z) {
+ zone_name = z;
+ }
+}
+
+ctx::context_fact::~context_fact()
+{
+}
+
+void ctx::context_fact::set_req_id(int id)
+{
+ req_id = id;
+}
+
+void ctx::context_fact::set_error(int err)
+{
+ error = err;
+}
+
+void ctx::context_fact::set_subject(const char* s)
+{
+ subject = s;
+}
+
+void ctx::context_fact::set_option(ctx::json& o)
+{
+ option = o;
+}
+
+void ctx::context_fact::set_data(ctx::json& d)
+{
+ data = d;
+}
+
+void ctx::context_fact::set_zone_name(const char* z)
+{
+ zone_name = z;
+}
+
+int ctx::context_fact::get_req_id()
+{
+ return req_id;
+}
+
+int ctx::context_fact::get_error()
+{
+ return error;
+}
+
+const char* ctx::context_fact::get_subject()
+{
+ return subject.c_str();
+}
+
+const char* ctx::context_fact::get_zone_name()
+{
+ return zone_name.c_str();
+}
+
+ctx::json& ctx::context_fact::get_option()
+{
+ return option;
+}
+
+ctx::json& ctx::context_fact::get_data()
+{
+ return data;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_CONTEXT_TRIGGER_FACT_H__
+#define __CONTEXT_CONTEXT_TRIGGER_FACT_H__
+
+#include <string>
+#include <json.h>
+
+namespace ctx {
+
+ class context_fact {
+ private:
+ int req_id;
+ int error;
+ std::string subject;
+ ctx::json option;
+ ctx::json data;
+ std::string zone_name;
+
+ public:
+ context_fact();
+ context_fact(int id, int err, const char* s, ctx::json& o, ctx::json& d, const char* z);
+ ~context_fact();
+
+ void set_req_id(int id);
+ void set_error(int err);
+ void set_subject(const char* s);
+ void set_option(ctx::json& o);
+ void set_zone_name(const char* z);
+ void set_data(ctx::json& d);
+
+ int get_req_id();
+ int get_error();
+ const char* get_subject();
+ const char* get_zone_name();
+ ctx::json& get_option();
+ ctx::json& get_data();
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_CONTEXT_TRIGGER_FACT_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <scope_mutex.h>
+#include "trigger.h"
+#include "fact_request.h"
+#include "fact_reader.h"
+
+#define CLIENT_NAME TRIGGER_CLIENT_NAME
+#define COND_END_TIME(T) (g_get_monotonic_time() + (T) * G_TIME_SPAN_SECOND)
+#define SUBSCRIBE_TIMEOUT 3
+#define READ_TIMEOUT 10
+
+static GMutex request_mutex;
+static GCond request_cond;
+static int last_rid;
+static int last_err;
+static ctx::json last_data_read;
+
+ctx::context_manager_impl *ctx::fact_reader::_context_mgr = NULL;
+ctx::context_trigger *ctx::fact_reader::_trigger = NULL;
+
+static int generate_req_id()
+{
+ static int req_id = 0;
+
+ if (++req_id < 0) {
+ // Overflow handling
+ req_id = 1;
+ }
+
+ return req_id;
+}
+
+ctx::fact_reader::fact_reader(context_manager_impl* mgr, context_trigger* trigger)
+{
+ _context_mgr = mgr;
+ _trigger = trigger;
+}
+
+ctx::fact_reader::~fact_reader()
+{
+ for (subscr_list_t::iterator it = subscr_list.begin(); it != subscr_list.end(); ++it) {
+ delete *it;
+ }
+ subscr_list.clear();
+}
+
+int ctx::fact_reader::find_sub(const char* subject, json* option, const char* zone)
+{
+ json opt_j;
+ if (option) {
+ opt_j = *option;
+ }
+
+ for (subscr_list_t::iterator it = subscr_list.begin(); it != subscr_list.end(); ++it) {
+ if ((*it)->subject == subject && (*it)->option == opt_j && (*it)->zone_name == zone) {
+ return (*it)->sid;
+ }
+ }
+
+ return -1;
+}
+
+bool ctx::fact_reader::add_sub(int sid, const char* subject, json* option, const char* zone)
+{
+ subscr_info_s *info = new(std::nothrow) subscr_info_s(sid, subject, option, zone);
+ IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+
+ subscr_list.push_back(info);
+ return true;
+}
+
+void ctx::fact_reader::remove_sub(const char* subject, json* option, const char* zone)
+{
+ json opt_j;
+ if (option) {
+ opt_j = *option;
+ }
+
+ for (subscr_list_t::iterator it = subscr_list.begin(); it != subscr_list.end(); ++it) {
+ if ((*it)->subject == subject && (*it)->option == opt_j && (*it)->zone_name == zone) {
+ delete *it;
+ subscr_list.erase(it);
+ return;
+ }
+ }
+}
+
+void ctx::fact_reader::remove_sub(int sid)
+{
+ for (subscr_list_t::iterator it = subscr_list.begin(); it != subscr_list.end(); ++it) {
+ if ((*it)->sid == sid) {
+ delete *it;
+ subscr_list.erase(it);
+ return;
+ }
+ }
+}
+
+gboolean ctx::fact_reader::send_request(gpointer data)
+{
+ fact_request *req = static_cast<fact_request*>(data);
+ _context_mgr->assign_request(req);
+ return FALSE;
+}
+
+bool ctx::fact_reader::is_supported(const char* subject, const char* zone)
+{
+ IF_FAIL_RETURN_TAG(zone, false, _E, "'zone' cannot be NULL");
+ return _context_mgr->is_supported(subject, zone);
+}
+
+int ctx::fact_reader::subscribe(const char* subject, json* option, const char* zone, bool wait_response)
+{
+ IF_FAIL_RETURN_TAG(zone, ERR_INVALID_PARAMETER, _E, "'zone' cannot be NULL");
+ IF_FAIL_RETURN(subject, ERR_INVALID_PARAMETER);
+
+ ctx::scope_mutex sm(&request_mutex);
+
+ int rid = find_sub(subject, option, zone);
+ if (rid > 0) {
+ _D("Duplicated request for %s", subject);
+ return rid;
+ }
+
+ rid = generate_req_id();
+
+ fact_request *req = new(std::nothrow) fact_request(REQ_SUBSCRIBE, CLIENT_NAME,
+ rid, subject, option ? option->str().c_str() : NULL, zone, wait_response ? this : NULL);
+ IF_FAIL_RETURN_TAG(req, -1, _E, "Memory allocation failed");
+
+ g_idle_add(send_request, req);
+ add_sub(rid, subject, option, zone);
+
+ IF_FAIL_RETURN_TAG(wait_response, rid, _D, "Ignoring response for %s", subject);
+
+ while (last_rid != rid) {
+ if (!g_cond_wait_until(&request_cond, &request_mutex, COND_END_TIME(SUBSCRIBE_TIMEOUT))) {
+ _E("Timeout: subject %s", subject);
+ //TODO: what happens if the request actually takes more time than the timeout
+ remove_sub(rid);
+ return -1;
+ }
+ }
+
+ if (last_err != ERR_NONE) {
+ remove_sub(rid);
+ _E("Subscription request failed: %#x", last_err);
+ return -1;
+ }
+
+ return rid;
+}
+
+void ctx::fact_reader::unsubscribe(const char* subject, json* option, const char* zone)
+{
+ IF_FAIL_VOID_TAG(zone, _E, "'zone' cannot be NULL");
+ IF_FAIL_VOID(subject);
+
+ ctx::scope_mutex sm(&request_mutex);
+
+ int rid = find_sub(subject, option, zone);
+ IF_FAIL_VOID_TAG(rid > 0, _W, "Unknown subscription for %s", subject);
+
+ unsubscribe(rid);
+}
+
+void ctx::fact_reader::unsubscribe(int subscription_id)
+{
+ fact_request *req = new(std::nothrow) fact_request(REQ_UNSUBSCRIBE, CLIENT_NAME, subscription_id, "", NULL, NULL, NULL);
+ IF_FAIL_VOID_TAG(req, _E, "Memory allocation failed");
+
+ g_idle_add(send_request, req);
+ remove_sub(subscription_id);
+}
+
+bool ctx::fact_reader::read(const char* subject, json* option, const char* zone, context_fact& fact)
+{
+ IF_FAIL_RETURN_TAG(zone, false, _E, "'zone' cannot be NULL");
+ IF_FAIL_RETURN(subject, false);
+
+ ctx::scope_mutex sm(&request_mutex);
+
+ int rid = generate_req_id();
+
+ fact_request *req = new(std::nothrow) fact_request(REQ_READ_SYNC, CLIENT_NAME,
+ rid, subject, option ? option->str().c_str() : NULL, zone, this);
+ IF_FAIL_RETURN_TAG(req, false, _E, "Memory allocation failed");
+
+ g_idle_add(send_request, req);
+
+ while (last_rid != rid) {
+ if (!g_cond_wait_until(&request_cond, &request_mutex, COND_END_TIME(READ_TIMEOUT))) {
+ _E("Timeout: subject %s", subject);
+ //TODO: what happens if the request actually takes more time than the timeout
+ return false;
+ }
+ }
+
+ if (last_err != ERR_NONE) {
+ _E("Read request failed: %#x", last_err);
+ return false;
+ }
+
+ fact.set_req_id(rid);
+ fact.set_subject(subject);
+ fact.set_data(last_data_read);
+ if (zone) {
+ fact.set_zone_name(zone);
+ }
+
+ last_data_read = EMPTY_JSON_OBJECT;
+
+ return true;
+}
+
+void ctx::fact_reader::reply_result(int req_id, int error, const char* zone, json* request_result, json* fact)
+{
+ ctx::scope_mutex sm(&request_mutex);
+
+ last_rid = req_id;
+ last_err = error;
+ last_data_read = (fact ? *fact : EMPTY_JSON_OBJECT);
+
+ g_cond_signal(&request_cond);
+}
+
+void ctx::fact_reader::publish_fact(int req_id, int error, const char* zone, const char* subject, json* option, json* fact)
+{
+ _trigger->push_fact(req_id, error, subject, *option, *fact, zone);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_FACT_READER_H__
+#define __CONTEXT_FACT_READER_H__
+
+#include <list>
+#include <json.h>
+#include "../context_mgr_impl.h"
+#include "fact.h"
+
+namespace ctx {
+
+ class context_trigger;
+
+ class fact_reader {
+ public:
+ fact_reader(context_manager_impl* mgr, context_trigger* trigger);
+ ~fact_reader();
+
+ bool is_supported(const char* subject, const char* zone);
+
+ int subscribe(const char* subject, json* option, const char* zone, bool wait_response = false);
+ void unsubscribe(const char* subject, json* option, const char* zone);
+ void unsubscribe(int subscription_id);
+ bool read(const char* subject, json* option, const char* zone, context_fact& fact);
+
+ void reply_result(int req_id, int error, const char* zone, json* request_result = NULL, json* fact = NULL);
+ void publish_fact(int req_id, int error, const char* zone, const char* subject, json* option, json* fact);
+
+ private:
+ static context_manager_impl* _context_mgr;
+ static context_trigger* _trigger;
+
+ struct subscr_info_s {
+ int sid;
+ std::string subject;
+ ctx::json option;
+ std::string zone_name;
+ subscr_info_s(int id, const char* subj, ctx::json* opt, const char* zone)
+ : sid(id), subject(subj)
+ {
+ if (opt)
+ option = *opt;
+
+ if (zone)
+ zone_name = zone;
+ }
+ };
+
+ typedef std::list<subscr_info_s*> subscr_list_t;
+ subscr_list_t subscr_list;
+
+ int find_sub(const char* subject, json* option, const char* zone);
+ bool add_sub(int sid, const char* subject, json* option, const char* zone);
+ void remove_sub(const char* subject, json* option, const char* zone);
+ void remove_sub(int sid);
+
+ static gboolean send_request(gpointer data);
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_FACT_READER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <types_internal.h>
+#include "fact_request.h"
+
+ctx::fact_request::fact_request(int type, const char* client, int req_id, const char* subj, const char* desc, const char* zone, fact_reader* reader)
+ : request_info(type, client, req_id, subj, desc)
+ , _reader(reader)
+ , replied(false)
+{
+ if (zone)
+ _zone_name = zone;
+}
+
+ctx::fact_request::~fact_request()
+{
+ reply(ERR_OPERATION_FAILED);
+}
+
+bool ctx::fact_request::reply(int error)
+{
+ IF_FAIL_RETURN(!replied && _reader, true);
+ _reader->reply_result(_req_id, error, _zone_name.c_str());
+ return (replied = true);
+}
+
+bool ctx::fact_request::reply(int error, ctx::json& request_result)
+{
+ IF_FAIL_RETURN(!replied && _reader, true);
+ IF_FAIL_RETURN(_type != REQ_READ_SYNC, true);
+ _reader->reply_result(_req_id, error, _zone_name.c_str(), &request_result);
+ return (replied = true);
+}
+
+bool ctx::fact_request::reply(int error, ctx::json& request_result, ctx::json& data_read)
+{
+ IF_FAIL_RETURN(!replied && _reader, true);
+ _reader->reply_result(_req_id, error, _zone_name.c_str(), &request_result, &data_read);
+ return (replied = true);
+}
+
+bool ctx::fact_request::publish(int error, ctx::json& data)
+{
+ IF_FAIL_RETURN(_reader, true);
+ _reader->publish_fact(_req_id, error, _zone_name.c_str(), _subject.c_str(), &get_description(), &data);
+ return true;
+}
+
+void ctx::fact_request::set_zone_name(const char* zone_name)
+{
+ if (zone_name)
+ _zone_name = zone_name;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_TRIGGER_FACT_REQUEST_H__
+#define __CONTEXT_TRIGGER_FACT_REQUEST_H__
+
+#include "fact_reader.h"
+#include "../request.h"
+
+namespace ctx {
+
+ class fact_request : public request_info {
+ public:
+ fact_request(int type, const char* client, int req_id, const char* subj, const char* desc, const char* zone, fact_reader* reader);
+ ~fact_request();
+
+ void set_zone_name(const char* zone_name);
+ bool reply(int error);
+ bool reply(int error, ctx::json& request_result);
+ bool reply(int error, ctx::json& request_result, ctx::json& data_read);
+ bool publish(int error, ctx::json& data);
+
+ private:
+ fact_reader *_reader;
+ bool replied;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_TRIGGER_FACT_REQUEST_H__ */
--- /dev/null
+/*
+ * context-service
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <sstream>
+#include <app.h>
+#include <glib.h>
+#include <types_internal.h>
+#include <json.h>
+#include <stdlib.h>
+#include <bundle.h>
+#include <app_control.h>
+#include <appsvc.h>
+#include <app_control_internal.h>
+#include <notification.h>
+#include <notification_internal.h>
+#include <context_trigger_types_internal.h>
+#include <context_trigger.h>
+#include <db_mgr.h>
+#include <zone_util.h>
+#include "../access_control/privilege.h"
+#include "rule_manager.h"
+#include "script_generator.h"
+#include "trigger.h"
+
+#define RULE_TABLE "context_trigger_rule"
+#define EVENT_TABLE "context_trigger_event"
+#define CONDITION_TABLE "context_trigger_condition"
+#define TEMPLATE_TABLE "context_trigger_template"
+
+#define RULE_TABLE_COLUMNS "enabled INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT '', details TEXT DEFAULT '' NOT NULL, zone TEXT DEFAULT '' NOT NULL"
+#define EVENT_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, instance_name TEXT DEFAULT '', zone TEXT DEFAULT '' NOT NULL"
+#define CONDITION_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, option TEXT DEFAULT '', instance_name TEXT DEFAULT '', zone TEXT DEFAULT '' NOT NULL"
+#define CREATE_TEMPLATE_TABLE "CREATE TABLE IF NOT EXISTS context_trigger_template (name TEXT DEFAULT '' NOT NULL PRIMARY KEY, j_template TEXT DEFAULT '' NOT NULL)"
+#define QUERY_TEMPLATE_TABLE "SELECT j_template FROM context_trigger_template"
+#define FOREIGN_KEYS_ON "PRAGMA foreign_keys = ON"
+#define DELETE_RULE_STATEMENT "DELETE FROM 'context_trigger_rule' where row_id = "
+#define UPDATE_RULE_ENABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 1 WHERE row_id = "
+#define UPDATE_RULE_DISABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 0 WHERE row_id = "
+#define QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT "SELECT context_trigger_condition.name, instance_name, j_template as templates FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id = "
+#define QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT "SELECT DISTINCT context_trigger_condition.name, instance_name, option, j_template FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id IN (SELECT row_id FROM context_trigger_rule WHERE enabled = 1 AND row_id IN (SELECT rule_id FROM context_trigger_event WHERE context_trigger_event.instance_name = '"
+#define QUERY_RULE_AND_ZONE_BY_RULE_ID "SELECT details, zone FROM context_trigger_rule WHERE row_id = "
+#define QUERY_EVENT_TEMPLATE_BY_RULE_ID "SELECT j_template FROM context_trigger_template WHERE name IN (SELECT name FROM context_trigger_event WHERE rule_id = "
+#define QUERY_CONDITION_BY_RULE_ID "SELECT name, option FROM context_trigger_condition WHERE rule_id = "
+
+#define INSTANCE_NAME_DELIMITER "/"
+#define EVENT_KEY_PREFIX "?"
+
+static ctx::context_trigger* trigger = NULL;
+
+static int string_to_int(std::string str)
+{
+ int i;
+ std::istringstream convert(str);
+
+ if (!(convert >> i))
+ i = 0;
+
+ return i;
+}
+
+static std::string int_to_string(int i)
+{
+ std::ostringstream convert;
+ convert << i;
+ std::string str = convert.str();
+ return str;
+}
+
+ctx::rule_manager::rule_manager()
+{
+}
+
+ctx::rule_manager::~rule_manager()
+{
+}
+
+bool ctx::rule_manager::init(ctx::context_trigger* tr, ctx::fact_reader* fr)
+{
+ int error;
+ bool ret;
+
+ trigger = tr;
+
+ ret = clips_h.init(this);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "CLIPS handler initialization failed");
+
+ ret = c_monitor.init(fr, tr);
+
+ // Create tables into db (rule, event, condition, action, template)
+ ret = db_manager::create_table(1, RULE_TABLE, RULE_TABLE_COLUMNS, NULL, NULL);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed");
+
+ ret = db_manager::create_table(2, EVENT_TABLE, EVENT_TABLE_COLUMNS, NULL, NULL);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create event table failed");
+
+ ret = db_manager::create_table(3, CONDITION_TABLE, CONDITION_TABLE_COLUMNS, NULL, NULL);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create condition table failed");
+
+ ret = db_manager::execute(4, CREATE_TEMPLATE_TABLE, NULL);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
+
+ // Load all templates from DB
+ std::vector<json> record;
+ ret = db_manager::execute_sync(QUERY_TEMPLATE_TABLE, &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query template table failed");
+
+ // Make scripts for deftemplate, defclass, make-instance and load them to clips
+ std::vector<json>::iterator vec_end = record.end();
+ for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+ std::string tmpl_str;
+ elem.get(NULL, "j_template", &tmpl_str);
+ ctx::json tmpl = tmpl_str;
+
+ std::string deftemplate_str = script_generator::generate_deftemplate(&tmpl);
+ error = clips_h.define_template(deftemplate_str);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Deftemplate failed");
+
+ std::string defclass_str = script_generator::generate_defclass(&tmpl);
+ error = clips_h.define_class(defclass_str);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Defclass failed");
+
+ std::string makeinstance_str = script_generator::generate_makeinstance(&tmpl);
+ error = clips_h.make_instance(makeinstance_str);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Makeinstance failed");
+ }
+
+ // Foreign keys on
+ ret = db_manager::execute_sync(FOREIGN_KEYS_ON, &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Foreign keys on failed");
+
+ ret = reenable_rule();
+
+ return ret;
+}
+
+bool ctx::rule_manager::reenable_rule(void)
+{
+ int error;
+ std::string q = "SELECT row_id FROM context_trigger_rule where enabled = 1";
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_ids of enabled rules failed");
+
+ std::vector<json>::iterator vec_end = record.end();
+ for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+ int row_id;
+ elem.get(NULL, "row_id", &row_id);
+
+ error = enable_rule(row_id);
+ if (error != ERR_NONE) {
+ _E("Re-enable rule%d failed(%d)", row_id, error);
+ } else {
+ _E("Re-enable rule%d succeeded", row_id);
+ }
+ }
+
+ return true;
+}
+
+bool ctx::rule_manager::rule_data_arr_elem_equals(ctx::json& lelem, ctx::json& relem)
+{
+ std::string lkey, rkey;
+ lelem.get(NULL, CT_RULE_DATA_KEY, &lkey);
+ relem.get(NULL, CT_RULE_DATA_KEY, &rkey);
+ if (lkey.compare(rkey))
+ return false;
+
+ int lvc, rvc, lvoc, rvoc;
+ lvc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
+ rvc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
+ lvoc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
+ rvoc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
+ if (!((lvc == rvc) && (lvc == lvoc) && (lvc && rvoc)))
+ return false;
+
+ if (lvc > 1) {
+ std::string lop, rop;
+ lelem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &lop);
+ relem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &rop);
+ if (lop.compare(rop))
+ return false;
+ }
+
+ for (int i = 0; i < lvc; i++) {
+ bool found = false;
+ std::string lv, lvo;
+ lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &lv);
+ lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, i, &lvo);
+
+ for (int j = 0; j < lvc; j++) {
+ std::string rv, rvo;
+ relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &rv);
+ relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &rvo);
+
+ if (!lv.compare(rv) && !lvo.compare(rvo)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+
+ return true;
+}
+
+bool ctx::rule_manager::rule_item_equals(ctx::json& litem, ctx::json& ritem)
+{
+ // Compare item name
+ std::string lei, rei;
+ litem.get(NULL, CT_RULE_EVENT_ITEM, &lei);
+ ritem.get(NULL, CT_RULE_EVENT_ITEM, &rei);
+ if (lei.compare(rei))
+ return false;
+
+ // Compare option
+ ctx::json loption, roption;
+ std::string linst, rinst;
+ litem.get(NULL, CT_RULE_EVENT_OPTION, &loption);
+ ritem.get(NULL, CT_RULE_EVENT_OPTION, &roption);
+ linst = get_instance_name(lei, loption);
+ rinst = get_instance_name(rei, roption);
+ if (linst.compare(rinst))
+ return false;
+
+ int ledac, redac;
+ ledac = litem.array_get_size(NULL, CT_RULE_DATA_ARR);
+ redac = ritem.array_get_size(NULL, CT_RULE_DATA_ARR);
+ if (ledac != redac)
+ return false;
+
+ // Compare item operator;
+ if (ledac > 1 ) {
+ std::string leop, reop;
+ litem.get(NULL, CT_RULE_EVENT_OPERATOR, &leop);
+ ritem.get(NULL, CT_RULE_EVENT_OPERATOR, &reop);
+ if (leop.compare(reop))
+ return false;
+ }
+
+ for (int i = 0; i < ledac; i++) {
+ bool found = false;
+ ctx::json lelem;
+ litem.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &lelem);
+
+ for (int j = 0; j < ledac; j++) {
+ ctx::json relem;
+ ritem.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &relem);
+
+ if (rule_data_arr_elem_equals(lelem, relem)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+
+ return true;
+}
+
+bool ctx::rule_manager::rule_equals(ctx::json& lrule, ctx::json& rrule)
+{
+ // Compare event
+ ctx::json le, re;
+ lrule.get(NULL, CT_RULE_EVENT, &le);
+ rrule.get(NULL, CT_RULE_EVENT, &re);
+ if (!rule_item_equals(le, re))
+ return false;
+
+ // Compare conditions
+ int lcc, rcc;
+ lcc = lrule.array_get_size(NULL, CT_RULE_CONDITION);
+ rcc = rrule.array_get_size(NULL, CT_RULE_CONDITION);
+ if (lcc != rcc)
+ return false;
+
+ if (lcc > 1) {
+ std::string lop, rop;
+ lrule.get(NULL, CT_RULE_OPERATOR, &lop);
+ rrule.get(NULL, CT_RULE_OPERATOR, &rop);
+ if (lop.compare(rop))
+ return false;
+ }
+
+ for (int i = 0; i < lcc; i++) {
+ bool found = false;
+ ctx::json lc;
+ lrule.get_array_elem(NULL, CT_RULE_CONDITION, i, &lc);
+
+ for (int j = 0; j < lcc; j++) {
+ ctx::json rc;
+ rrule.get_array_elem(NULL, CT_RULE_CONDITION, j, &rc);
+
+ if (rule_item_equals(lc, rc)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return false;
+ }
+
+ // Compare action
+ std::string laction, raction;
+ lrule.get(NULL, CT_RULE_ACTION, &laction);
+ rrule.get(NULL, CT_RULE_ACTION, &raction);
+ if (laction.compare(raction))
+ return false;
+
+ return true;
+}
+
+int64_t ctx::rule_manager::get_duplicated_rule(std::string creator, std::string zone, ctx::json& rule)
+{
+ std::string q = "SELECT row_id, details FROM context_trigger_rule WHERE creator = '";
+ q += creator;
+ q += "' AND zone ='";
+ q += zone;
+ q += "'";
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_id, details by creator failed");
+
+ ctx::json r_details;
+ rule.get(NULL, CT_RULE_DETAILS, &r_details);
+ std::vector<json>::iterator vec_end = record.end();
+
+ for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+ std::string details;
+ ctx::json d_details;
+
+ elem.get(NULL, "details", &details);
+ d_details = details;
+
+ if (rule_equals(r_details, d_details)) {
+ int64_t row_id;
+ elem.get(NULL, "row_id", &row_id);
+ return row_id;
+ }
+ }
+
+ return -1;
+}
+
+int ctx::rule_manager::verify_rule(ctx::json& rule, const char* app_id, const char* zone)
+{
+ ctx::json details;
+ rule.get(NULL, CT_RULE_DETAILS, &details);
+
+ std::string e_name;
+ rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
+
+ IF_FAIL_RETURN_TAG(c_monitor.is_supported(e_name, zone), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", e_name.c_str());
+
+ if (app_id) {
+ if (!ctx::privilege_manager::is_allowed(app_id, e_name.c_str())) {
+ _W("Permission denied for '%s'", e_name.c_str());
+ return ERR_PERMISSION_DENIED;
+ }
+ }
+
+ ctx::json it;
+ for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
+ std::string c_name;
+ it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
+
+ IF_FAIL_RETURN_TAG(c_monitor.is_supported(c_name, zone), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", c_name.c_str());
+
+ if (!ctx::privilege_manager::is_allowed(app_id, c_name.c_str())) {
+ _W("Permission denied for '%s'", c_name.c_str());
+ return ERR_PERMISSION_DENIED;
+ }
+ }
+
+ return ERR_NONE;
+}
+
+int ctx::rule_manager::add_rule(std::string creator, ctx::json rule, std::string zone, ctx::json* rule_id)
+{
+ // * Insert rule to DB
+ bool ret;
+ int64_t rid;
+
+ // Check if all items are supported && allowed to access
+ int err = verify_rule(rule, creator.c_str(), zone.c_str());
+ IF_FAIL_RETURN(err==ERR_NONE, err);
+
+ // Check if duplicated rule exits
+ if ((rid = get_duplicated_rule(creator, zone, rule)) > 0) {
+ // Save rule id
+ rule_id->set(NULL, CT_RULE_ID, rid);
+ return ERR_NONE;
+ }
+
+ // Insert rule to rule table, get rule id and save it to json parameter
+ ctx::json r_record;
+ std::string description;
+ ctx::json details;
+ rule.get(NULL, CT_RULE_DESCRIPTION, &description);
+ rule.get(NULL, CT_RULE_DETAILS, &details);
+ r_record.set(NULL, "creator", creator);
+ r_record.set(NULL, "description", description);
+ r_record.set(NULL, "details", details.str());
+ r_record.set(NULL, "zone", zone);
+ ret = db_manager::insert_sync(RULE_TABLE, r_record, &rid);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed");
+
+ // Save rule id
+ rule_id->set(NULL, CT_RULE_ID, rid);
+
+ // Insert event & conditions of a rule into each table
+ ctx::json e_record;
+ std::string e_name;
+ ctx::json e_option_j;
+ std::string e_inst;
+
+ rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
+ rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &e_option_j);
+ e_inst = get_instance_name(e_name, e_option_j);
+
+ e_record.set(NULL, "rule_id", rid);
+ e_record.set(NULL, "name", e_name);
+ e_record.set(NULL, "instance_name", e_inst);
+ e_record.set(NULL, "zone", zone);
+ ret = db_manager::insert(1, EVENT_TABLE, e_record, NULL);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert event to db failed");
+
+ ctx::json it;
+ for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
+ ctx::json c_record;
+ std::string c_name;
+ ctx::json c_option;
+ char* c_option_str;
+ ctx::json tmp_option;
+ std::string c_inst;
+
+ it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
+ it.get(NULL, CT_RULE_CONDITION_OPTION, &tmp_option);
+ c_inst = get_instance_name(c_name, tmp_option);
+ c_option.set(NULL, CT_RULE_CONDITION_OPTION, tmp_option);
+ c_option_str = c_option.dup_cstr();
+
+ c_record.set(NULL, "rule_id", rid);
+ c_record.set(NULL, "name", c_name);
+ c_record.set(NULL, "option", (c_option_str)? c_option_str : "");
+ c_record.set(NULL, "instance_name", c_inst);
+ c_record.set(NULL, "zone", zone);
+
+ ret = db_manager::insert(2, CONDITION_TABLE, c_record, NULL);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert conditions to db failed");
+
+ free(c_option_str);
+ }
+
+ _D("Add rule%d succeeded", (int)rid);
+ return ERR_NONE;
+}
+
+
+int ctx::rule_manager::remove_rule(int rule_id)
+{
+ // Delete rule from DB
+ bool ret;
+
+ std::string query = DELETE_RULE_STATEMENT;
+ query += int_to_string(rule_id);
+ std::vector<json> record;
+ ret = db_manager::execute_sync(query.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
+
+ return ERR_NONE;
+}
+
+
+int ctx::rule_manager::enable_rule(int rule_id)
+{
+ // Subscribe event
+ bool ret;
+ int error;
+ std::string id_str = int_to_string(rule_id);
+
+ // Get rule json by rule id;
+ std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
+ q1 += int_to_string(rule_id);
+ std::vector<json> rule_record;
+ ret = db_manager::execute_sync(q1.c_str(), &rule_record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
+ std::string r1;
+ std::string zone;
+ rule_record[0].get(NULL, "details", &r1);
+ rule_record[0].get(NULL, "zone", &zone);
+ ctx::json rule = r1;
+ ctx::json event;
+ rule.get(NULL, CT_RULE_EVENT, &event);
+
+ // Get event template by rule id
+ std::string q2 = QUERY_EVENT_TEMPLATE_BY_RULE_ID;
+ q2 += int_to_string(rule_id);
+ q2 += ")";
+ std::vector<json> etemplate_record;
+ ret = db_manager::execute_sync(q2.c_str(), &etemplate_record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query event template by rule id failed");
+ std::string r2;
+ etemplate_record[0].get(NULL, "j_template", &r2);
+ ctx::json etemplate = r2;
+
+ // Query name, instance name & template for conditions of the rule
+ std::string q3 = QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT;
+ q3 += id_str;
+ std::vector<json> cond_record;
+ ret = db_manager::execute_sync(q3.c_str(), &cond_record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's names, instance names, templates by rule id failed");
+
+ ctx::json inst_names;
+ std::vector<json>::iterator vec_end = cond_record.end();
+ for (std::vector<json>::iterator vec_pos = cond_record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+
+ std::string cname;
+ std::string ciname;
+ std::string temp;
+ elem.get(NULL, "name", &cname);
+ elem.get(NULL, "instance_name", &ciname);
+ elem.get(NULL, "templates", &temp);
+ ctx::json ctemplate = temp;
+ ctemplate.set(NULL, "instance_name", ciname);
+ // TODO ctemplate (name, instance_name, attributes) now - it is based on form using when templates are inserted into db when rebooting
+
+ // For defrule script generation
+ inst_names.set(NULL, cname.c_str(), ciname);
+
+ if (cname.compare(ciname) != 0) {
+ if (!clips_h.find_instance(ciname)) {
+ std::string makeinst_script = script_generator::generate_makeinstance(&ctemplate);
+ error = clips_h.make_instance(makeinst_script);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Add condition instance([%s]) failed", ciname.c_str());
+
+ cond_cnt_map[ciname] = 1;
+ } else {
+ cond_cnt_map[ciname]++;
+ }
+ }
+ }
+
+ // Subscribe event
+ std::string ename;
+ etemplate.get(NULL, "name", &ename);
+
+ //TODO: set the proper zone
+ error = c_monitor.subscribe(rule_id, ename, event, zone.c_str());
+ IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
+
+ // Generate defrule script and execute it
+ std::string script = script_generator::generate_defrule(id_str, etemplate, rule, &inst_names, zone);
+ error = clips_h.define_rule(script);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Defrule failed");
+
+ // Update db to set 'enabled'
+ std::string q4 = UPDATE_RULE_ENABLED_STATEMENT;
+ q4 += id_str;
+ std::vector<json> record;
+ ret = db_manager::execute_sync(q4.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
+
+ _D(YELLOW("Enable Rule%d succeeded"), rule_id);
+
+ return ERR_NONE;
+}
+
+std::string ctx::rule_manager::get_instance_name(std::string name, ctx::json& option)
+{
+ std::string inst_name = name;
+
+ // Get template for the option
+ std::string q = "SELECT j_template FROM context_trigger_template WHERE name = '";
+ q += name;
+ q += "'";
+ std::vector<json> template_record;
+ db_manager::execute_sync(q.c_str(), &template_record);
+
+ std::string ct_str;
+ template_record[0].get(NULL, "j_template", &ct_str);
+ ctx::json j_template = ct_str;
+
+ std::string option_key;
+ for (int i = 0; j_template.get_array_elem(NULL, "option", i, &option_key); i++) {
+ std::string val_str;
+ int val;
+ if (option.get(NULL, option_key.c_str(), &val_str)) {
+ inst_name += INSTANCE_NAME_DELIMITER;
+ inst_name += val_str;
+ } else if (option.get(NULL, option_key.c_str(), &val)) {
+ inst_name += INSTANCE_NAME_DELIMITER;
+ inst_name += int_to_string(val);
+ } else {
+ inst_name += INSTANCE_NAME_DELIMITER;
+ }
+ }
+
+ return inst_name;
+}
+
+int ctx::rule_manager::disable_rule(int rule_id)
+{
+ int error;
+ bool ret;
+
+ // For event with options
+ // Get rule json by rule id;
+ std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
+ q1 += int_to_string(rule_id);
+ std::vector<json> rule_record;
+ ret = db_manager::execute_sync(q1.c_str(), &rule_record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
+ std::string r1;
+ std::string zone;
+ rule_record[0].get(NULL, "details", &r1);
+ rule_record[0].get(NULL, "zone", &zone);
+ ctx::json rule = r1;
+ ctx::json event;
+ rule.get(NULL, CT_RULE_EVENT, &event);
+ std::string ename;
+ event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
+
+ // Unsubscribe event
+ error = c_monitor.unsubscribe(rule_id, ename, event, zone.c_str());
+ IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
+
+ // Undef rule in clips
+ std::string id_str = int_to_string(rule_id);
+ std::string script = script_generator::generate_undefrule(id_str);
+ error = clips_h.route_string_command(script);
+ IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Undefrule failed");
+
+ // Update db to set 'disabled'
+ std::string q2 = UPDATE_RULE_DISABLED_STATEMENT;
+ q2 += id_str;
+ std::vector<json> record;
+ ret = db_manager::execute_sync(q2.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
+
+ // Remove condition instances TODO
+ std::string q3 = "SELECT name, instance_name FROM context_trigger_condition WHERE rule_id = ";
+ q3 += id_str;
+ std::vector<json> name_record;
+ ret = db_manager::execute_sync(q3.c_str(), &name_record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's name, instance names by rule id failed");
+
+ std::vector<json>::iterator vec_end = name_record.end();
+ for (std::vector<json>::iterator vec_pos = name_record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+
+ std::string cname;
+ std::string ciname;
+ elem.get(NULL, "name", &cname);
+ elem.get(NULL, "instance_name", &ciname);
+
+ if (cname.compare(ciname) != 0) {
+ cond_cnt_map[ciname]--;
+
+ if (cond_cnt_map[ciname] == 0) {
+ error = clips_h.unmake_instance(ciname);
+ IF_FAIL_RETURN(error == ERR_NONE, error);
+
+ cond_cnt_map.erase(ciname);
+ }
+ }
+ }
+
+ return ERR_NONE;
+}
+
+void ctx::rule_manager::make_condition_option_based_on_event_data(ctx::json& ctemplate, ctx::json& edata, ctx::json* coption)
+{
+ std::string option_key;
+ for (int i = 0; ctemplate.get_array_elem(NULL, "option", i, &option_key); i++) {
+ std::string coption_valstr;
+ if (coption->get(NULL, option_key.c_str(), &coption_valstr)) {
+ if (coption_valstr.find(EVENT_KEY_PREFIX) == 0) {
+ std::string event_key = coption_valstr.substr(1, coption_valstr.length() - 1);
+
+ std::string e_valstr;
+ int e_val;
+ if (edata.get(NULL, event_key.c_str(), &e_valstr)) {
+ coption->set(NULL, option_key.c_str(), e_valstr);
+ } else if (edata.get(NULL, event_key.c_str(), &e_val)) {
+ coption->set(NULL, option_key.c_str(), e_val);
+ }
+ }
+ }
+ }
+}
+
+void ctx::rule_manager::on_event_received(std::string item, ctx::json option, ctx::json data, std::string zone)
+{
+ _D(YELLOW("Event(%s(%s) - %s) is invoked."), item.c_str(), option.str().c_str(), data.str().c_str());
+ // TODO: Check permission of an event(item), if permission denied, return
+
+ int err;
+ bool ret;
+ // Set the zone
+ ret = clips_h.set_global_variable_string("zone", zone);
+ if (!ret) {
+ _E("Set clips zone to %s failed", zone.c_str());
+ return;
+ }
+
+ // Generate event fact script
+ std::string q1 = "SELECT j_template FROM context_trigger_template WHERE name = '";
+ q1 += item;
+ q1 += "'";
+ std::vector<json> etemplate_record;
+ db_manager::execute_sync(q1.c_str(), &etemplate_record);
+ std::string r1;
+ etemplate_record[0].get(NULL, "j_template", &r1);
+ ctx::json etemplate = r1;
+
+ std::string eventfact_str = script_generator::generate_fact(item, etemplate, option, data);
+
+ // Get Conditions template of invoked event (db query)
+ std::string e_inst = get_instance_name(item, option);
+ std::string query = QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT;
+ query += e_inst;
+ query += "' AND zone = '";
+ query += zone;
+ query += "'))";
+ std::vector<json> conds;
+ ret = db_manager::execute_sync(query.c_str(), &conds);
+ IF_FAIL_VOID_TAG(ret, _E, "Query condition templates of invoked event failed");
+
+ int cond_num = conds.size();
+ for (int i = 0; i < cond_num; i++) {
+ std::string temp;
+ conds[i].get(NULL, "j_template", &temp);
+ ctx::json ctemplate = temp;
+
+ std::string cname;
+ conds[i].get(NULL, "name", &cname);
+
+ std::string ciname;
+ conds[i].get(NULL, "instance_name", &ciname);
+
+ std::string coption_str;
+ conds[i].get(NULL, "option", &coption_str);
+ ctx::json coption = NULL;
+ if (!coption_str.empty()) {
+ ctx::json coption_tmp = coption_str;
+ coption_tmp.get(NULL, CT_RULE_CONDITION_OPTION, &coption);
+ }
+
+ // Check if the condition uses event data key as an option
+ if (ciname.find(EVENT_KEY_PREFIX) != std::string::npos) {
+ make_condition_option_based_on_event_data(ctemplate, data, &coption);
+ }
+
+ // TODO: Check permission of a condition(cname), if permission granted, read condition data. (or, condition data should be empty json)
+
+ // Get Context Data and Set the proper zone.
+ ctx::json condition_data;
+ err = c_monitor.read(cname, coption, zone.c_str(), &condition_data);
+ if (err != ERR_NONE)
+ return;
+ _D(YELLOW("Condition(%s(%s) - %s)."), cname.c_str(), coption.str().c_str(), condition_data.str().c_str());
+
+ // Generate ModifyInstance script
+ std::string modifyinst_script = script_generator::generate_modifyinstance(ciname, ctemplate, condition_data);
+
+ err = clips_h.route_string_command(modifyinst_script);
+ IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Modify condition instance failed");
+ }
+
+ // Add fact and Run environment
+ err = clips_h.add_fact(eventfact_str);
+ IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Assert event fact failed");
+
+ err = clips_h.run_environment();
+ IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Run environment failed");
+
+ // Retract event fact
+ std::string retract_command = "(retract *)";
+ err = clips_h.route_string_command(retract_command);
+ IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Retract event fact failed");
+}
+
+static void trigger_action_app_control(ctx::json& action, std::string zone)
+{
+ int error;
+ std::string appctl_str;
+ action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str);
+
+ char* str = static_cast<char*>(malloc(appctl_str.length()));
+ if (str == NULL) {
+ _E("Memory allocation failed");
+ return;
+ }
+ appctl_str.copy(str, appctl_str.length(), 0);
+ bundle_raw* encoded = reinterpret_cast<unsigned char*>(str);
+ bundle* appctl_bundle = bundle_decode(encoded, appctl_str.length());
+
+ app_control_h app = NULL;
+ app_control_create(&app);
+ app_control_import_from_bundle(app, appctl_bundle);
+
+ char* op;
+ app_control_get_operation(app, &op);
+ app_control_set_operation(app, APP_SVC_OPERATION_JUMP);
+ app_control_add_extra_data(app, APP_SVC_K_JUMP_ZONE_NAME, zone.c_str());
+ if (op != NULL) {
+ app_control_add_extra_data(app, APP_SVC_K_JUMP_ORIGIN_OPERATION, op);
+ }
+
+ error = app_control_send_launch_request(app, NULL, NULL);
+ if (error != APP_CONTROL_ERROR_NONE) {
+ _E("Launch request failed(%d)", error);
+ } else {
+ _D("Launch request succeeded");
+ }
+ bundle_free(appctl_bundle);
+ free(str);
+ app_control_destroy(app);
+}
+
+static void trigger_action_notification(ctx::json& action, std::string creator, std::string zone)
+{
+ int error;
+ notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI);
+ std::string title;
+ if (action.get(NULL, CT_RULE_ACTION_NOTI_TITLE, &title)) {
+ error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification title failed(%d)", error);
+ }
+ }
+
+ std::string content;
+ if (action.get(NULL, CT_RULE_ACTION_NOTI_CONTENT, &content)) {
+ error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification contents failed(%d)", error);
+ }
+ }
+
+ std::string image_path;
+ if (action.get(NULL, CT_RULE_ACTION_NOTI_ICON_PATH, &image_path)) {
+ error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, image_path.c_str());
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set notification icon image failed(%d)", error);
+ }
+ }
+
+ std::string appctl_str;
+ char* str = NULL;
+ bundle_raw* encoded = NULL;
+ bundle* appctl_bundle = NULL;
+ app_control_h app = NULL;
+ if (action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str)) {
+ str = static_cast<char*>(malloc(appctl_str.length()));
+ if (str == NULL) {
+ _E("Memory allocation failed");
+ notification_free(notification);
+ return;
+ }
+ appctl_str.copy(str, appctl_str.length(), 0);
+ encoded = reinterpret_cast<unsigned char*>(str);
+ appctl_bundle = bundle_decode(encoded, appctl_str.length());
+
+ app_control_create(&app);
+ app_control_import_from_bundle(app, appctl_bundle);
+
+ error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set launch option failed(%d)", error);
+ }
+ }
+
+ error = notification_set_pkgname(notification, creator.c_str());
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Set pkgname(%s) failed(%d)", creator.c_str(), error);
+ }
+
+ ctx::scope_zone_joiner sz(zone.c_str());
+
+ error = notification_post(notification);
+ if (error != NOTIFICATION_ERROR_NONE) {
+ _E("Post notification failed(%d)", error);
+ } else {
+ _D("Post notification succeeded");
+ }
+
+ bundle_free(appctl_bundle);
+ free(str);
+ notification_free(notification);
+ if (app) {
+ app_control_destroy(app);
+ }
+}
+
+void ctx::rule_manager::on_rule_triggered(int rule_id)
+{
+ _D(YELLOW("Rule%d is triggered"), rule_id);
+
+ std::string q = "SELECT details, creator, zone FROM context_trigger_rule WHERE row_id =";
+ q += int_to_string(rule_id);
+
+ std::vector<json> record;
+ db_manager::execute_sync(q.c_str(), &record);
+
+ std::string details_str;
+ record[0].get(NULL, "details", &details_str);
+ ctx::json details = details_str;
+ ctx::json action;
+ details.get(NULL, CT_RULE_ACTION, &action);
+ std::string zone;
+ record[0].get(NULL, "zone", &zone);
+
+ std::string type;
+ if (action.get(NULL, CT_RULE_ACTION_TYPE, &type)) {
+ if (type.compare(CT_RULE_ACTION_TYPE_APP_CONTROL) == 0) {
+ trigger_action_app_control(action, zone);
+ } else if (type.compare(CT_RULE_ACTION_TYPE_NOTIFICATION) == 0) {
+ std::string creator;
+ record[0].get(NULL, "creator", &creator);
+ trigger_action_notification(action, creator, zone);
+ }
+ }
+}
+
+int ctx::rule_manager::check_rule(std::string creator, int rule_id)
+{
+ // Get creator app id
+ std::string q = "SELECT creator FROM context_trigger_rule WHERE row_id =";
+ q += int_to_string(rule_id);
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query creator by rule id failed");
+
+ if (record.size() == 0) {
+ return ERR_NO_DATA;
+ }
+
+ std::string c;
+ record[0].get(NULL, "creator", &c);
+
+ if (c.compare(creator) == 0){
+ return ERR_NONE;
+ }
+
+ return ERR_NO_DATA;
+}
+
+bool ctx::rule_manager::is_rule_enabled(int rule_id)
+{
+ std::string q = "SELECT enabled FROM context_trigger_rule WHERE row_id =";
+ q += int_to_string(rule_id);
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed");
+
+ int enabled;
+ record[0].get(NULL, "enabled", &enabled);
+
+ if (enabled == 1)
+ return true;
+ else
+ return false;
+}
+
+int ctx::rule_manager::get_rule_by_id(std::string creator, int rule_id, ctx::json* request_result)
+{
+// std::string q = "SELECT description, details FROM context_trigger_rule WHERE (creator = '";
+ std::string q = "SELECT description FROM context_trigger_rule WHERE (creator = '";
+ q += creator;
+ q += "') and (row_id = ";
+ q += int_to_string(rule_id);
+ q += ")";
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed");
+
+ if (record.size() == 0) {
+ return ERR_NO_DATA;
+ } else if (record.size() != 1) {
+ return ERR_OPERATION_FAILED;
+ }
+
+ std::string description;
+// std::string details;
+ record[0].get(NULL, "description", &description);
+// record[0].get(NULL, "details", &details);
+
+ (*request_result).set(NULL, CT_RULE_ID, rule_id);
+ (*request_result).set(NULL, CT_RULE_DESCRIPTION, description);
+// (*request_result).set(NULL, CT_RULE_DETAILS, details);
+
+ return ERR_NONE;
+}
+
+int ctx::rule_manager::get_rule_ids(std::string creator, ctx::json* request_result)
+{
+ (*request_result) = "{ \"" CT_RULE_ARRAY_ENABLED "\" : [ ] , \"" CT_RULE_ARRAY_DISABLED "\" : [ ] }";
+
+ std::string q = "SELECT row_id, enabled FROM context_trigger_rule WHERE (creator = '";
+ q += creator;
+ q += "')";
+
+ std::vector<json> record;
+ bool ret = db_manager::execute_sync(q.c_str(), &record);
+ IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed");
+
+ std::vector<json>::iterator vec_end = record.end();
+ for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
+ ctx::json elem = *vec_pos;
+ std::string id;
+ int enabled;
+
+ elem.get(NULL, "row_id", &id);
+ elem.get(NULL, "enabled", &enabled);
+
+ if (enabled == 1) {
+ (*request_result).array_append(NULL, CT_RULE_ARRAY_ENABLED, string_to_int(id));
+ } else if (enabled == 0) {
+ (*request_result).array_append(NULL, CT_RULE_ARRAY_DISABLED, string_to_int(id));
+ }
+ }
+
+ return ERR_NONE;
+}
--- /dev/null
+/*
+* context-service
+*
+* Copyright (c) 2014 Samsung Electronics Co., Ltd.
+*
+* 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.
+*
+*/
+
+#ifndef __RULE_MANAGER_H__
+#define __RULE_MANAGER_H__
+
+#include "clips_handler.h"
+#include "context_monitor.h"
+
+namespace ctx {
+
+ class json;
+ class context_trigger;
+ class fact_reader;
+
+ class rule_manager {
+ public:
+ rule_manager();
+ ~rule_manager();
+ bool init(ctx::context_trigger* tr, ctx::fact_reader* fr);
+ int add_rule(std::string creator, ctx::json rule, std::string zone, ctx::json* rule_id);
+ int remove_rule(int rule_id);
+ int enable_rule(int rule_id);
+ int disable_rule(int rule_id);
+ int get_rule_by_id(std::string creator, int rule_id, ctx::json* request_result);
+ int get_rule_ids(std::string creator, ctx::json* request_result);
+ int check_rule(std::string creator, int rule_id);
+ bool is_rule_enabled(int rule_id);
+
+ void on_event_received(std::string item, ctx::json option, ctx::json data, std::string zone);
+ void on_rule_triggered(int rule_id);
+
+ private:
+ clips_handler clips_h;
+ context_monitor c_monitor;
+
+ bool reenable_rule(void);
+ int verify_rule(ctx::json& rule, const char* app_id, const char* zone);
+ int64_t get_duplicated_rule(std::string creator, std::string zone, ctx::json& rule);
+ bool rule_data_arr_elem_equals(ctx::json& lelem, ctx::json& relem);
+ bool rule_item_equals(ctx::json& litem, ctx::json& ritem);
+ bool rule_equals(ctx::json& lrule, ctx::json& rrule);
+ std::string get_instance_name(std::string name, ctx::json& condition);
+ void make_condition_option_based_on_event_data(ctx::json& ctemplate, ctx::json& edata, ctx::json* coption);
+
+ std::map<std::string, int> cond_cnt_map; // <condition instance name, count>
+
+ }; /* class rule_manager */
+
+} /* namespace ctx */
+
+#endif /* End of __RULE_MANAGER_H__ */
--- /dev/null
+/*
+ * context-service
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <sstream>
+#include <set>
+#include <glib.h>
+#include <string>
+#include <json.h>
+#include <types_internal.h>
+#include <context_trigger_types_internal.h>
+#include "script_generator.h"
+#include "timer_types.h"
+
+#define EVENT_WEEKDAY "(or (eq ?DayOfWeek \"Mon\") (eq ?DayOfWeek \"Tue\") (eq ?DayOfWeek \"Wed\") (eq ?DayOfWeek \"Thu\") (eq ?DayOfWeek \"Fri\"))"
+#define EVENT_WEEKEND "(or (eq ?DayOfWeek \"Sat\") (eq ?DayOfWeek \"Sun\"))"
+#define CONDITION_WEEKDAY "(or (eq (send [%s] get-DayOfWeek) \"Mon\") (eq (send [%s] get-DayOfWeek) \"Tue\") (eq (send [%s] get-DayOfWeek) \"Wed\") (eq (send [%s] get-DayOfWeek) \"Thu\") (eq (send [%s] get-DayOfWeek) \"Fri\"))"
+#define CONDITION_WEEKEND "(or (eq (send [%s] get-DayOfWeek) \"Sat\") (eq (send [%s] get-DayOfWeek) \"Sun\"))"
+
+static std::string generate_initial_fact(ctx::json event_template, ctx::json option);
+static std::string generate_event_data(ctx::json event);
+static std::string generate_condition_data(std::string rule_id, ctx::json conditions, std::string rule_op, ctx::json* inst_names);
+
+static std::string int_to_string(int i)
+{
+ std::ostringstream convert;
+ convert << i;
+ std::string str = convert.str();
+ return str;
+}
+
+static std::string convert_condition_weekday_weekend(std::string inst_name, std::string day)
+{
+ std::string buf = (day.compare(TIMER_WEEKDAY) == 0)? CONDITION_WEEKDAY : CONDITION_WEEKEND;
+
+ size_t pos = 0;
+ while((pos = buf.find("%s", pos)) != std::string::npos) {
+ buf.replace(pos, 2, inst_name);
+ pos += inst_name.length();
+ }
+
+ return buf;
+}
+
+std::string ctx::script_generator::generate_deftemplate(ctx::json* item)
+{
+ std::string script;
+
+ std::string name;
+ item->get(NULL, "name", &name);
+
+ std::set<std::string> slot;
+
+ std::string opt_name;
+ for (int i = 0; item->get_array_elem(NULL, "option", i, &opt_name); i++) {
+ slot.insert(opt_name);
+ }
+
+ std::string attr_name;
+ for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
+ slot.insert(attr_name);
+ }
+
+ //template name is "itemname"
+ script = "(deftemplate ";
+ script += name;
+ script += " ";
+
+ for (std::set<std::string>::iterator it = slot.begin(); it != slot.end(); ++it){
+ script += "(slot ";
+ script += *it;
+ script += " (default null))";
+ }
+ script += ")";
+
+// _D("Deftemplate script is generated: %s", script.c_str());
+ script += "\n";
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_defclass(ctx::json* item)
+{
+ std::string script;
+
+ std::string name;
+ item->get(NULL, "name", &name);
+
+ //class name is "C.itemname"
+ script = "(defclass C.";
+ script += name;
+ script += " (is-a USER) (role concrete) ";
+
+ std::string attr_name;
+ for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
+ script += "(slot ";
+ script += attr_name;
+ script += " (create-accessor read-write))";
+ }
+ script += ")";
+
+// _D("Defclass script is generated: %s", script.c_str());
+ script += "\n";
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_makeinstance(ctx::json* item)
+{
+ std::string script;
+
+ std::string name;
+ item->get(NULL, "name", &name);
+
+ std::string instance_name;
+ if (!item->get(NULL, "instance_name", &instance_name)) {
+ instance_name = name;
+ }
+
+ //instance name is "[itemname]"
+ script = "([";
+ script += instance_name;
+ script += "] of C.";
+ script += name;
+
+ std::string attr_name;
+ for (int i = 0; item->get_array_elem(NULL, "attributes", i, &attr_name); i++) {
+ script += " (";
+ script += attr_name;
+ script += " 0)";
+ }
+ script += ")";
+
+// _D("Makeinstance script is generated: %s", script.c_str());
+ script += "\n";
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_undefrule(std::string rule_id)
+{
+ std::string script;
+ script = "(undefrule rule";
+ script += rule_id;
+ script += ")";
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_defrule(std::string rule_id, ctx::json event_template, ctx::json rule, ctx::json* inst_names, std::string zone)
+{
+ std::string script;
+ ctx::json option = NULL;
+ rule.get(CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &option);
+
+ script = "(defrule rule";
+ script += rule_id;
+ script += " ";
+
+ script += generate_initial_fact(event_template, option);
+ script += " => ";
+
+ int eventdata_num = rule.array_get_size(CT_RULE_EVENT, CT_RULE_DATA_ARR);
+ int condition_num = rule.array_get_size(NULL, CT_RULE_CONDITION);
+
+ if (condition_num > 0) {
+ // case1: condition exists
+ script += "(if (and (eq ?*zone* \"";
+ script += zone;
+ script += "\") ";
+
+ if (eventdata_num > 0) {
+ ctx::json event;
+ rule.get(NULL, CT_RULE_EVENT, &event);
+ script += generate_event_data(event);
+ }
+
+ // condition
+ ctx::json conditions;
+ rule.get(NULL, CT_RULE_CONDITION, &conditions);
+ std::string rule_op;
+ rule.get(NULL, CT_RULE_OPERATOR, &rule_op);
+ script += generate_condition_data(rule_id, conditions, rule_op, inst_names);
+
+ script += ")";
+ script += " then ";
+ script += " (execute_action rule";
+ script += rule_id;
+ script += "))";
+ } else if (eventdata_num > 0) {
+ // case2: no conditions, but event data
+ ctx::json event;
+ rule.get(NULL, CT_RULE_EVENT, &event);
+
+ script += "(if (and (eq ?*zone* \"";
+ script += zone;
+ script += "\") ";
+ script += generate_event_data(event);
+ script += ") then ";
+ script += " (execute_action rule";
+ script += rule_id;
+ script += "))";
+ } else {
+ // case3: only action
+ script += "if (eq ?*zone* \"";
+ script += zone;
+ script += "\") then (execute_action rule";
+ script += rule_id;
+ script += ")";
+ }
+
+ script += ")";
+ _D("Defrule script generated: %s", script.c_str());
+ return script;
+}
+
+std::string generate_initial_fact(ctx::json event_template, ctx::json option)
+{
+ std::string script = "(";
+ std::string e_name;
+ event_template.get(NULL, "name", &e_name);
+
+ script += e_name;
+ script += " ";
+
+ // options
+ std::string opt_key;
+ for (int i = 0; event_template.get_array_elem(NULL, "option", i, &opt_key); i++) {
+ script += "(";
+ script += opt_key;
+ script += " ";
+
+ std::string val_str;
+ int val;
+ if (option.get(NULL, opt_key.c_str(), &val_str)) {
+ script += val_str;
+ } else if (option.get(NULL, opt_key.c_str(), &val)) {
+ script += int_to_string(val);
+ } else {
+ script += "?";
+ script += opt_key;
+ }
+
+ script += ")";
+ }
+
+ // attributes
+ std::string attr;
+ for (int i = 0; event_template.get_array_elem(NULL, "attributes", i, &attr); i++) {
+ script += "(";
+ script += attr;
+ script += " ?";
+ script += attr;
+ script += ")";
+ }
+ script += ")";
+
+// _D("Initial event fact is %s", script.c_str());
+ return script;
+}
+
+std::string generate_event_data(ctx::json event)
+{
+ std::string ename;
+ event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
+
+ std::string script;
+ int edata_count = event.array_get_size(NULL, CT_RULE_DATA_ARR);
+
+ if (edata_count > 1) {
+ std::string item_op;
+ event.get(NULL, CT_RULE_EVENT_OPERATOR, &item_op);
+ script += "(";
+ script += item_op;
+ script += " ";
+ }
+
+ ctx::json edata;
+ for (int i = 0; event.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &edata); i++) {
+ std::string key_name;
+ if (ename.compare(TIMER_EVENT_SUBJECT) == 0) {
+ edata.get(NULL, CT_RULE_DATA_KEY, &key_name);
+ }
+
+ int valuecount = edata.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
+ int opcount = edata.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
+ std::string key;
+ edata.get(NULL, CT_RULE_DATA_KEY, &key);
+
+ if (valuecount != opcount) {
+ _E("Invalid event data. (Value count:%d, Operator count: %d)", valuecount, opcount);
+ return "";
+ }
+
+ if (valuecount > 1) {
+ script += "(";
+
+ std::string key_op;
+ edata.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &key_op);
+ script += key_op;
+ script += " ";
+ }
+
+ for (int j = 0; j < valuecount; j++){
+ std::string val_op;
+ std::string val;
+ edata.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &val_op);
+ edata.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &val);
+
+ if (key_name.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
+ if (val.compare("\"" TIMER_WEEKDAY "\"") == 0) {
+ script += (val_op.compare("eq") == 0)? EVENT_WEEKDAY : EVENT_WEEKEND;
+ continue;
+ } else if (val.compare("\"" TIMER_WEEKEND "\"") == 0) {
+ script += (val_op.compare("eq") == 0)? EVENT_WEEKEND : EVENT_WEEKDAY;
+ continue;
+ }
+ }
+
+ script += "(";
+ script += val_op;
+ script += " ?";
+ script += key;
+ script += " ";
+ script += val;
+ script += ")";
+ }
+
+ if (valuecount > 1) {
+ script += ")";
+ }
+ }
+
+ if (edata_count > 1) {
+ script += ")";
+ }
+
+ return script;
+}
+
+std::string generate_condition_data(std::string rule_id, ctx::json conditions, std::string rule_op, ctx::json* inst_names)
+{
+ std::string script;
+
+ ctx::json conds;
+ conds.set(NULL, CT_RULE_CONDITION, conditions);
+
+ int conds_count = conds.array_get_size(NULL, CT_RULE_CONDITION);
+ if (conds_count > 1) {
+ script += "(";
+ script += rule_op; // operator between each condition item
+ script += " ";
+ }
+
+ ctx::json it;
+ for (int i = 0; conds.get_array_elem(NULL, CT_RULE_CONDITION, i, &it); i++) {
+ std::string cond_name;
+ it.get(NULL, CT_RULE_CONDITION_ITEM, &cond_name);
+
+ std::string inst_name;
+ (inst_names)->get(NULL, cond_name.c_str(), &inst_name);
+
+ int data_count = it.array_get_size(NULL, CT_RULE_DATA_ARR);
+
+ if (data_count > 1) {
+ std::string item_op;
+ it.get(NULL, CT_RULE_CONDITION_OPERATOR, &item_op);
+ script += "(";
+ script += item_op; // operator between data keys of a condition item
+ script += " ";
+ }
+
+ ctx::json data;
+ for (int j = 0; it.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &data); j++) {
+ std::string key_name;
+ data.get(NULL, CT_RULE_DATA_KEY, &key_name);
+ int dval_count = data.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
+ int dvalop_count = data.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
+
+ if (dval_count != dvalop_count) {
+ _E("Invalid condition data. (Data value count %d, Data value operator count %d)", dval_count, dvalop_count);
+ }
+
+ if (dval_count > 1) {
+ std::string dkey_op;
+ data.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &dkey_op);
+
+ script += "(";
+ script += dkey_op; // operator between comparison data values of a condition data key
+ script += " " ;
+ }
+
+ for (int k = 0; k < dval_count; k++) {
+ std::string dval_op;
+ std::string dval;
+ data.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, k, &dval_op);
+ data.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, k, &dval);
+
+ if (inst_name.compare(TIMER_CONDITION_SUBJECT) == 0 && key_name.compare(TIMER_RESPONSE_KEY_DAY_OF_WEEK) == 0) {
+ if (dval.compare("\"" TIMER_WEEKDAY "\"") == 0) {
+ script += convert_condition_weekday_weekend(inst_name, (dval_op.compare("eq") == 0)? TIMER_WEEKDAY : TIMER_WEEKEND);
+ continue;
+ } else if (dval.compare("\"" TIMER_WEEKEND "\"") == 0) {
+ script += convert_condition_weekday_weekend(inst_name, (dval_op.compare("eq") == 0)? TIMER_WEEKEND : TIMER_WEEKDAY);
+ continue;
+ }
+ }
+
+ script += "(";
+ script += dval_op;
+ script += " (send [";
+ script += inst_name;
+ script += "] get-";
+ script += key_name;
+ script += ") ";
+ script += dval;
+ script += ")";
+ }
+
+ if (dval_count > 1) {
+ script += ")";
+ }
+ }
+
+ if (data_count > 1 ) {
+ script += ")";
+ }
+ }
+
+ if (conds_count > 1) {
+ script += ")";
+ }
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_fact(std::string item_name, ctx::json event_template, ctx::json option, ctx::json data)
+{
+ // Generate Fact script for invoked event
+ std::string script = "(";
+ script += item_name;
+ script += " ";
+
+ std::string opt_key;
+ std::string key;
+ std::string val_str;
+ int value;
+
+ for (int i = 0; event_template.get_array_elem(NULL, "option", i, &opt_key); i++) {
+ script += "(";
+ script += opt_key;
+ script += " ";
+ if (option.get(NULL, opt_key.c_str(), &val_str)) { // string type data
+ script += val_str;
+ } else if (option.get(NULL, opt_key.c_str(), &value)) { // integer type data
+ script += int_to_string(value);
+ } else {
+ script += "nil";
+ }
+ script += ")";
+ }
+
+ for (int i = 0; event_template.get_array_elem(NULL, "attributes", i, &key); i++) {
+ script += "(";
+ script += key;
+ script += " ";
+ if (data.get(NULL, key.c_str(), &val_str)) { // string type data
+ script += "\"" + val_str + "\"";
+ } else if (data.get(NULL, key.c_str(), &value)) { // integer type data
+ script += int_to_string(value);
+ } else {
+ script += "nil";
+ }
+ script += ")";
+ }
+ script += ")";
+
+ return script;
+}
+
+std::string ctx::script_generator::generate_modifyinstance(std::string instance_name, ctx::json condition_template, ctx::json data)
+{
+ std::string script = "(modify-instance [";
+ script += instance_name;
+ script += "] ";
+
+ std::string key;
+ std::string val_str;
+ int value;
+ for (int i = 0; condition_template.get_array_elem(NULL, "attributes", i, &key); i++) {
+ if (data.get(NULL, key.c_str(), &val_str)) { // string type data
+ script += "(" + key + " \"" + val_str + "\")";
+ } else if (data.get(NULL, key.c_str(), &value)) { // integer type data
+ script += "(" + key + " " + int_to_string(value) + ")";
+ }
+ // else continue;
+ }
+ script += ")";
+
+ return script;
+}
--- /dev/null
+/*
+ * context-service
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CONTEXT_SCRIPT_GENERATOR_H__
+#define __CONTEXT_SCRIPT_GENERATOR_H__
+
+namespace ctx {
+
+ namespace script_generator {
+
+ std::string generate_deftemplate(ctx::json* item);
+ std::string generate_defclass(ctx::json* item);
+ std::string generate_makeinstance(ctx::json* item);
+ std::string generate_undefrule(std::string rule_id);
+ std::string generate_defrule(std::string rule_id, ctx::json event_template, ctx::json rule, ctx::json* inst_names, std::string zone);
+ std::string generate_fact(std::string item_name, ctx::json event_template, ctx::json option, ctx::json data);
+ std::string generate_modifyinstance(std::string instance_name, ctx::json condition_template, ctx::json data);
+
+ }
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_SCRIPT_GENERATOR_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdlib.h>
+#include <time.h>
+#include <types_internal.h>
+#include <scope_mutex.h>
+#include <timer_mgr.h>
+#include "timer.h"
+#include "trigger.h"
+#include "timer_types.h"
+
+#define MAX_HOUR 24
+#define MAX_DAY 7
+
+using namespace ctx::timer_manager;
+static GMutex timer_mutex;
+
+ctx::trigger_timer::ref_count_array_s::ref_count_array_s()
+{
+ memset(count, 0, sizeof(int) * MAX_DAY);
+}
+
+ctx::trigger_timer::trigger_timer(ctx::context_trigger* tr, std::string z)
+ : trigger(tr)
+ , zone(z)
+{
+}
+
+ctx::trigger_timer::~trigger_timer()
+{
+ clear();
+}
+
+int ctx::trigger_timer::merge_day_of_week(int* ref_cnt)
+{
+ int day_of_week = 0;
+
+ for (int d = 0; d < MAX_DAY; ++d) {
+ if (ref_cnt[d] > 0) {
+ day_of_week |= (0x01 << d);
+ }
+ }
+
+ return day_of_week;
+}
+
+bool ctx::trigger_timer::add(int minute, int day_of_week)
+{
+ IF_FAIL_RETURN_TAG(minute >=0 && minute < 1440 &&
+ day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY,
+ false, _E, "Invalid parameter");
+
+ ctx::scope_mutex sm(&timer_mutex);
+
+ ref_count_array_s &ref = ref_count_map[minute];
+
+ for (int d = 0; d < MAX_DAY; ++d) {
+ if ((day_of_week & (0x01 << d)) != 0) {
+ ref.count[d] += 1;
+ }
+ }
+
+ return reset_timer(minute);
+}
+
+bool ctx::trigger_timer::remove(int minute, int day_of_week)
+{
+ IF_FAIL_RETURN_TAG(minute >=0 && minute < 1440 &&
+ day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY,
+ false, _E, "Invalid parameter");
+
+ ctx::scope_mutex sm(&timer_mutex);
+
+ ref_count_array_s &ref = ref_count_map[minute];
+
+ for (int d = 0; d < MAX_DAY; ++d) {
+ if ((day_of_week & (0x01 << d)) != 0 && ref.count[d] > 0) {
+ ref.count[d] -= 1;
+ }
+ }
+
+ return reset_timer(minute);
+}
+
+bool ctx::trigger_timer::reset_timer(int minute)
+{
+ int day_of_week = merge_day_of_week(ref_count_map[minute].count);
+ timer_state_s &timer = timer_state_map[minute];
+
+ if (day_of_week == timer.day_of_week) {
+ /* Necessary timers are already running... */
+ return true;
+ }
+
+ if (day_of_week == 0 && timer.timer_id > 0) {
+ /* Turn off the timer at hour, if it is not necessray anymore. */
+ timer_manager::remove(timer.timer_id);
+ timer_state_map.erase(minute);
+ ref_count_map.erase(minute);
+ return true;
+ }
+
+ if (timer.timer_id > 0) {
+ /* Turn off the current timer, to set a new one. */
+ timer_manager::remove(timer.timer_id);
+ timer.timer_id = -1;
+ timer.day_of_week = 0;
+ }
+
+ /* Create a new timer, w.r.t. the new day_of_week value. */
+ int h = minute / 60;
+ int m = minute - h * 60;
+ int tid = timer_manager::set_at(h, m, day_of_week, this);
+ IF_FAIL_RETURN_TAG(tid > 0, false, _E, "Timer setting failed");
+
+ timer.timer_id = tid;
+ timer.day_of_week = day_of_week;
+
+ return true;
+}
+
+void ctx::trigger_timer::clear()
+{
+ ctx::scope_mutex sm(&timer_mutex);
+
+ for (timer_state_map_t::iterator it = timer_state_map.begin(); it != timer_state_map.end(); ++it) {
+ if (it->second.timer_id > 0) {
+ timer_manager::remove(it->second.timer_id);
+ }
+ }
+
+ timer_state_map.clear();
+ ref_count_map.clear();
+}
+
+bool ctx::trigger_timer::on_timer_expired(int timer_id, void* user_data)
+{
+ time_t rawtime;
+ struct tm timeinfo;
+
+ time(&rawtime);
+ tzset();
+ localtime_r(&rawtime, &timeinfo);
+
+ int hour = timeinfo.tm_hour;
+ int min = timeinfo.tm_min;
+ int day_of_week = (0x01 << timeinfo.tm_wday);
+
+ on_timer_expired(hour, min, day_of_week);
+
+ return true;
+}
+
+void ctx::trigger_timer::on_timer_expired(int hour, int min, int day_of_week)
+{
+ _I("[Timer-%s] Time: %02d:%02d, Day of Week: %#x", zone.c_str(), hour, min, day_of_week);
+
+ ctx::json result;
+ result.set(NULL, TIMER_RESPONSE_KEY_TIME_OF_DAY, hour * 60 + min);
+ result.set(NULL, TIMER_RESPONSE_KEY_DAY_OF_WEEK, convert_day_of_week_to_string(day_of_week));
+
+ ctx::json dummy = NULL;
+ trigger->push_fact(TIMER_EVENT_REQ_ID, ERR_NONE, TIMER_EVENT_SUBJECT, dummy, result, zone.c_str());
+}
+
+int ctx::trigger_timer::get_day_of_month()
+{
+ time_t rawtime;
+ struct tm timeinfo;
+
+ time(&rawtime);
+ tzset();
+ localtime_r(&rawtime, &timeinfo);
+
+ int day_of_month = timeinfo.tm_mday;
+
+ return day_of_month;
+}
+
+std::string ctx::trigger_timer::get_day_of_week()
+{
+ time_t rawtime;
+ struct tm timeinfo;
+
+ time(&rawtime);
+ tzset();
+ localtime_r(&rawtime, &timeinfo);
+
+ int day_of_week = (0x01 << timeinfo.tm_wday);
+
+ return convert_day_of_week_to_string(day_of_week);
+}
+
+int ctx::trigger_timer::get_minute_of_day()
+{
+ time_t rawtime;
+ struct tm timeinfo;
+
+ time(&rawtime);
+ tzset();
+ localtime_r(&rawtime, &timeinfo);
+
+ int hour = timeinfo.tm_hour;
+ int minute = timeinfo.tm_min;
+
+ return hour * 60 + minute;
+}
+
+int ctx::trigger_timer::convert_string_to_day_of_week(std::string d)
+{
+ int day = 0;
+ d = d.substr(1, d.length() - 2);
+
+ if (d.compare(TIMER_SUN) == 0) {
+ day = SUN;
+ } else if (d.compare(TIMER_MON) == 0) {
+ day = MON;
+ } else if (d.compare(TIMER_TUE) == 0) {
+ day = TUE;
+ } else if (d.compare(TIMER_WED) == 0) {
+ day = WED;
+ } else if (d.compare(TIMER_THU) == 0) {
+ day = THU;
+ } else if (d.compare(TIMER_FRI) == 0) {
+ day = FRI;
+ } else if (d.compare(TIMER_SAT) == 0) {
+ day = SAT;
+ } else if (d.compare(TIMER_WEEKDAY) == 0) {
+ day = WEEKDAY;
+ } else if (d.compare(TIMER_WEEKEND) == 0) {
+ day = WEEKEND;
+ } else if (d.compare(TIMER_EVERYDAY) == 0) {
+ day = EVERYDAY;
+ }
+
+ return day;
+}
+
+std::string ctx::trigger_timer::convert_day_of_week_to_string(int d)
+{
+ std::string day;
+
+ if (d == SUN) {
+ day = TIMER_SUN;
+ } else if (d == MON) {
+ day = TIMER_MON;
+ } else if (d == TUE) {
+ day = TIMER_TUE;
+ } else if (d == WED) {
+ day = TIMER_WED;
+ } else if (d == THU) {
+ day = TIMER_THU;
+ } else if (d == FRI) {
+ day = TIMER_FRI;
+ } else if (d == SAT) {
+ day = TIMER_SAT;
+ } else if (d == WEEKDAY) {
+ day = TIMER_WEEKDAY;
+ } else if (d == WEEKEND) {
+ day = TIMER_WEEKEND;
+ } else if (d == EVERYDAY) {
+ day = TIMER_EVERYDAY;
+ }
+
+ return day;
+}
+
+bool ctx::trigger_timer::empty()
+{
+ return timer_state_map.empty();
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_CONTEXT_TRIGGER_TIMER_H__
+#define __CONTEXT_CONTEXT_TRIGGER_TIMER_H__
+
+#include <timer_mgr.h>
+#include <timer_listener_iface.h>
+#include <string>
+#include <map>
+
+namespace ctx {
+
+ class context_trigger;
+
+ class trigger_timer : public timer_listener_iface {
+ private:
+ struct ref_count_array_s {
+ int count[7]; /* reference counts for days of week*/
+ ref_count_array_s();
+ };
+
+ struct timer_state_s {
+ int timer_id;
+ int day_of_week; /* day of week, merged into one integer */
+ timer_state_s() : timer_id(-1), day_of_week(0) {}
+ };
+
+ typedef std::map<int, ref_count_array_s> ref_count_map_t;
+ typedef std::map<int, timer_state_s> timer_state_map_t;
+
+ ctx::context_trigger *trigger;
+ std::string zone;
+ ref_count_map_t ref_count_map;
+ timer_state_map_t timer_state_map;
+
+ int merge_day_of_week(int *ref_cnt);
+ bool reset_timer(int hour);
+ void on_timer_expired(int hour, int min, int day_of_week);
+
+ protected:
+ bool on_timer_expired(int timer_id, void *user_data);
+
+ public:
+ trigger_timer(ctx::context_trigger *tr, std::string z);
+ ~trigger_timer();
+
+ bool add(int minute, int day_of_week);
+ bool remove(int minute, int day_of_week);
+ void clear();
+ static int get_day_of_month();
+ static std::string get_day_of_week();
+ static int get_minute_of_day();
+ static int convert_string_to_day_of_week(std::string d);
+ static std::string convert_day_of_week_to_string(int d);
+ bool empty();
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_CONTEXT_TRIGGER_TIMER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_TIMER_TYPES_H__
+#define __CONTEXT_TIMER_TYPES_H__
+
+#define TIMER_EVENT_SUBJECT "timer/event"
+#define TIMER_CONDITION_SUBJECT "timer/state"
+
+#define TIMER_RESPONSE_KEY_TIME_OF_DAY "TimeOfDay"
+#define TIMER_RESPONSE_KEY_DAY_OF_WEEK "DayOfWeek"
+#define TIMER_RESPONSE_KEY_DAY_OF_MONTH "DayOfMonth"
+
+#define TIMER_EVENT_REQ_ID -1
+
+#define TIMER_MON "Mon"
+#define TIMER_TUE "Tue"
+#define TIMER_WED "Wed"
+#define TIMER_THU "Thu"
+#define TIMER_FRI "Fri"
+#define TIMER_SAT "Sat"
+#define TIMER_SUN "Sun"
+#define TIMER_WEEKDAY "Weekday"
+#define TIMER_WEEKEND "Weekend"
+#define TIMER_EVERYDAY "Everyday"
+
+#endif //__CONTEXT_TIMER_TYPES_H__
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <types_internal.h>
+#include <context_trigger_types_internal.h>
+#include "fact_reader.h"
+#include "trigger.h"
+#include "rule_manager.h"
+
+ctx::context_trigger::context_trigger()
+ : _reader(NULL)
+{
+}
+
+ctx::context_trigger::~context_trigger()
+{
+}
+
+bool ctx::context_trigger::init(ctx::context_manager_impl* mgr)
+{
+ // Do the necessary initialization process.
+ // This function is called from the main thread during the service launching process.
+ _reader = new(std::nothrow) fact_reader(mgr, this);
+ IF_FAIL_RETURN_TAG(_reader, false, _E, "Memory allocation failed");
+
+ _D("Starting Context Trigger Thread");
+ IF_FAIL_RETURN(start(), false);
+
+ push_thread_event(ETYPE_INITIALIZE, NULL);
+
+ return true;
+}
+
+void ctx::context_trigger::release()
+{
+ _D("Stopping Context Trigger Thread");
+ stop();
+
+ // Release the occupied resources.
+ // This function is called from the main thread during the service termination process.
+ delete _reader;
+ _reader = NULL;
+}
+
+void ctx::context_trigger::on_thread_event_popped(int type, void* data)
+{
+ switch (type) {
+ case ETYPE_REQUEST:
+ IF_FAIL_VOID(data);
+ process_request(static_cast<request_info*>(data));
+ break;
+ case ETYPE_FACT:
+ IF_FAIL_VOID(data);
+ process_fact(static_cast<context_fact*>(data));
+ break;
+ case ETYPE_INITIALIZE:
+ process_initialize();
+ break;
+ default:
+ _W("Unknown event type");
+ return;
+ }
+
+ delete_thread_event(type, data);
+}
+
+void ctx::context_trigger::delete_thread_event(int type, void* data)
+{
+ IF_FAIL_VOID(data);
+
+ switch (type) {
+ case ETYPE_REQUEST:
+ {
+ std::string subject = static_cast<ctx::request_info*>(data)->get_subject();
+ if (subject != CONTEXT_TRIGGER_SUBJECT_ENABLE) {
+ delete (static_cast<request_info*>(data));
+ }
+ }
+ return;
+ case ETYPE_FACT:
+ delete (static_cast<context_fact*>(data));
+ return;
+ case ETYPE_INITIALIZE:
+ return;
+ default:
+ _W("Unknown event type");
+ return;
+ }
+}
+
+bool ctx::context_trigger::assign_request(ctx::request_info* request)
+{
+ std::string subject = request->get_subject();
+ if (subject != CONTEXT_TRIGGER_SUBJECT_ADD && subject != CONTEXT_TRIGGER_SUBJECT_REMOVE &&
+ subject != CONTEXT_TRIGGER_SUBJECT_ENABLE && subject != CONTEXT_TRIGGER_SUBJECT_DISABLE &&
+ subject != CONTEXT_TRIGGER_SUBJECT_GET && subject != CONTEXT_TRIGGER_SUBJECT_GET_RULE_IDS) {
+ return false;
+ }
+
+ push_thread_event(ETYPE_REQUEST, request);
+ return true;
+}
+
+void ctx::context_trigger::process_request(ctx::request_info* request)
+{
+ // Process the request, and reply to the client if necessary.
+ const char* req_sbj = request->get_subject();
+ _D("Request is %s", req_sbj);
+ std::string subject(req_sbj);
+
+ if (subject == CONTEXT_TRIGGER_SUBJECT_ADD) {
+ add_rule(request);
+ } else if (subject == CONTEXT_TRIGGER_SUBJECT_REMOVE) {
+ remove_rule(request);
+ } else if (subject == CONTEXT_TRIGGER_SUBJECT_ENABLE) {
+ enable_rule(request);
+ } else if (subject == CONTEXT_TRIGGER_SUBJECT_DISABLE) {
+ disable_rule(request);
+ } else if (subject == CONTEXT_TRIGGER_SUBJECT_GET) {
+ get_rule_by_id(request);
+ } else if (subject == CONTEXT_TRIGGER_SUBJECT_GET_RULE_IDS) {
+ get_rule_ids(request);
+ } else {
+ _E("Invalid request");
+ }
+}
+
+void ctx::context_trigger::push_fact(int req_id, int error, const char* subject, ctx::json& option, ctx::json& data, const char* zone)
+{
+ context_fact *fact = new(std::nothrow) context_fact(req_id, error, subject, option, data, zone);
+ IF_FAIL_VOID_TAG(fact, _E, "Memory allocation failed");
+
+ push_thread_event(ETYPE_FACT, fact);
+}
+
+void ctx::context_trigger::process_fact(ctx::context_fact* fact)
+{
+ // Process the context fact.
+ rule_mgr->on_event_received(fact->get_subject(), fact->get_option(), fact->get_data(), fact->get_zone_name());
+}
+
+void ctx::context_trigger::process_initialize(void)
+{
+ rule_mgr = new(std::nothrow) rule_manager();
+ IF_FAIL_VOID_TAG(rule_mgr, _E, "Memory allocation failed");
+
+ bool ret = rule_mgr->init(this, _reader);
+ if (!ret) {
+ _E("Context trigger initialization failed.");
+ raise(SIGTERM);
+ }
+}
+
+void ctx::context_trigger::add_rule(ctx::request_info* request)
+{
+ ctx::json rule_id;
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ const char* zone_name = request->get_zone_name();
+ if (zone_name == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ int error = rule_mgr->add_rule(app_id, request->get_description(), zone_name, &rule_id);
+ _I("'%s' adds a rule (Error: %#x)", request->get_client(), error);
+
+ request->reply(error, rule_id);
+}
+
+void ctx::context_trigger::remove_rule(ctx::request_info* request)
+{
+ int id;
+ int error;
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ ctx::json rule_id = request->get_description();
+ rule_id.get(NULL, CT_RULE_ID, &id);
+
+ error = rule_mgr->check_rule(app_id, id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = rule_mgr->is_rule_enabled(id);
+ if (ret) {
+ request->reply(ERR_RULE_ENABLED);
+ return;
+ }
+
+ error = rule_mgr->remove_rule(id);
+ _I("'%s' removes rule%d (Error: %#x)", request->get_client(), id, error);
+ request->reply(error);
+}
+
+void ctx::context_trigger::enable_rule(ctx::request_info* request)
+{
+ int id;
+ int error;
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ ctx::json rule_id = request->get_description();
+ rule_id.get(NULL, CT_RULE_ID, &id);
+
+ error = rule_mgr->check_rule(app_id, id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = rule_mgr->is_rule_enabled(id);
+ if (ret) {
+ request->reply(ERR_RULE_ENABLED);
+ return;
+ }
+
+ error = rule_mgr->enable_rule(id);
+ _I("'%s' enables rule%d (Error: %#x)", request->get_client(), id, error);
+ request->reply(error);
+}
+
+void ctx::context_trigger::disable_rule(ctx::request_info* request)
+{
+ int id;
+ int error;
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ ctx::json rule_id = request->get_description();
+ rule_id.get(NULL, CT_RULE_ID, &id);
+
+ error = rule_mgr->check_rule(app_id, id);
+ if (error != ERR_NONE) {
+ request->reply(error);
+ return;
+ }
+
+ bool ret = rule_mgr->is_rule_enabled(id);
+ if (!ret) {
+ request->reply(ERR_RULE_NOT_ENABLED);
+ return;
+ }
+
+ error = rule_mgr->disable_rule(id);
+ _I("'%s' disables rule%d (Error: %#x)", request->get_client(), id, error);
+ request->reply(error);
+}
+
+void ctx::context_trigger::get_rule_by_id(ctx::request_info* request)
+{
+ int error;
+
+ ctx::json option = request->get_description();
+ int id;
+ option.get(NULL, CT_RULE_ID, &id);
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ ctx::json read_data;
+ error = rule_mgr->get_rule_by_id(app_id, id, &read_data);
+
+ ctx::json dummy;
+ request->reply(error, dummy, read_data);
+}
+
+void ctx::context_trigger::get_rule_ids(ctx::request_info* request)
+{
+ int error;
+
+ const char* app_id = request->get_app_id();
+ if (app_id == NULL) {
+ request->reply(ERR_OPERATION_FAILED);
+ return;
+ }
+
+ ctx::json read_data;
+ error = rule_mgr->get_rule_ids(app_id, &read_data);
+
+ ctx::json dummy;
+ request->reply(error, dummy, read_data);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_CONTEXT_TRIGGER_H__
+#define __CONTEXT_CONTEXT_TRIGGER_H__
+
+#include <event_driven.h>
+#include "../request.h"
+#include "fact.h"
+
+namespace ctx {
+
+ class fact_reader;
+ class rule_manager;
+ class client_request;
+ class context_manager_impl;
+ class context_trigger : public event_driven_thread {
+ public:
+ context_trigger();
+ ~context_trigger();
+
+ bool init(ctx::context_manager_impl* mgr);
+ void release();
+
+ bool assign_request(ctx::request_info* request);
+ void push_fact(int req_id, int error, const char* subject, ctx::json& option, ctx::json& data, const char* zone);
+ bool publish(int rule_id, int error, ctx::json data);
+ bool _publish(int rule_id, int error, ctx::json data);
+
+
+ private:
+ enum event_type_e {
+ ETYPE_REQUEST = 1, // A request received from a client
+ ETYPE_FACT, // A context fact received from a CA
+ ETYPE_INITIALIZE, // Initialization
+ };
+
+ ctx::fact_reader *_reader;
+
+ void on_thread_event_popped(int type, void* data);
+ void delete_thread_event(int type, void* data);
+
+ void process_request(ctx::request_info* request);
+ void process_fact(ctx::context_fact* fact);
+ void process_initialize(void);
+
+ void add_rule(ctx::request_info* request);
+ void remove_rule(ctx::request_info* request);
+ void enable_rule(ctx::request_info* request);
+ void disable_rule(ctx::request_info* request);
+ void get_rule_by_id(ctx::request_info* request);
+ void get_rule_ids(ctx::request_info* request);
+
+ ctx::rule_manager* rule_mgr;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_CONTEXT_TRIGGER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <sys/types.h>
+#include <unistd.h>
+#include <string>
+#include <sstream>
+#include <list>
+#include <scope_mutex.h>
+#include "server.h"
+#include "db_mgr_impl.h"
+
+//TODO: conf file for this kind of env. params.
+#define CONTEXT_DB_PATH "/opt/dbspace/.context-service.db"
+
+static bool initialized = false;
+static GThread *mainthread = NULL;
+static GMutex sync_insert_mutex;
+static GMutex sync_execute_mutex;
+static GCond sync_insert_cond;
+static GCond sync_execute_cond;
+static int64_t sync_insert_row_id = -1;
+static unsigned int sync_insert_qid = 0;
+static int sync_execute_error;
+static std::vector<ctx::json> sync_execute_result;
+static unsigned int sync_execute_qid = 0;
+
+ctx::db_manager_impl::db_manager_impl()
+ : db_handle(NULL)
+{
+}
+
+ctx::db_manager_impl::~db_manager_impl()
+{
+ release();
+}
+
+bool ctx::db_manager_impl::init()
+{
+ IF_FAIL_RETURN_TAG(!initialized, true, _W, "Re-initialization");
+ IF_FAIL_RETURN(open(), false);
+ mainthread = g_thread_self();
+ IF_FAIL_RETURN(start(), false);
+ initialized = true;
+ return true;
+}
+
+void ctx::db_manager_impl::release()
+{
+ IF_FAIL_VOID(initialized);
+ initialized = false;
+ stop();
+ close();
+}
+
+bool ctx::db_manager_impl::open()
+{
+ sqlite3 *db = NULL;
+ int r = sqlite3_open(CONTEXT_DB_PATH, &db);
+
+ IF_FAIL_RETURN_TAG(r == SQLITE_OK, false, _E, "DB Error: %s", sqlite3_errmsg(db));
+
+ db_handle = db;
+ return true;
+}
+
+void ctx::db_manager_impl::close()
+{
+ if (db_handle) {
+ sqlite3_close(db_handle);
+ }
+ db_handle = NULL;
+}
+
+bool ctx::db_manager_impl::is_main_thread()
+{
+ return mainthread == g_thread_self();
+}
+
+void ctx::db_manager_impl::on_thread_event_popped(int type, void* data)
+{
+ IF_FAIL_VOID(data);
+ query_info_s *info = static_cast<query_info_s*>(data);
+
+ switch (type) {
+ case QTYPE_CREATE_TABLE:
+ case QTYPE_INSERT:
+ case QTYPE_EXECUTE:
+ _execute(type, info->id, info->query.c_str(), info->listener);
+ break;
+ default:
+ _W("Unknown type: %d", type);
+ break;
+ }
+
+ delete_thread_event(type, data);
+}
+
+void ctx::db_manager_impl::delete_thread_event(int type, void* data)
+{
+ IF_FAIL_VOID(data);
+ query_info_s *info = static_cast<query_info_s*>(data);
+ delete info;
+}
+
+bool ctx::db_manager_impl::create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option, db_listener_iface* listener)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+
+ query_info_s *info = new(std::nothrow) query_info_s;
+ IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+
+ info->query = "CREATE TABLE IF NOT EXISTS ";
+ info->query = info->query + table_name + " (row_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + columns + ")";
+ if (option) {
+ info->query = info->query + " " + option;
+ }
+ info->query += ";";
+
+ info->id = query_id;
+ info->listener = listener;
+
+ if (!push_thread_event(QTYPE_CREATE_TABLE, info)) {
+ _E("Pushing thread event failed");
+ delete info;
+ return false;
+ }
+
+ return true;
+}
+
+bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+
+ std::list<std::string> keys;
+ IF_FAIL_RETURN_TAG(record.get_keys(&keys), false, _E, "Invalid record");
+
+ std::ostringstream colstream;
+ std::ostringstream valstream;
+
+
+ for (std::list<std::string>::iterator it = keys.begin(); it != keys.end(); ++it) {
+ std::string s;
+ int64_t i;
+ if (record.get(NULL, (*it).c_str(), &s)) {
+ colstream << *it << ",";
+ valstream << "'" << s << "',";
+ } else if (record.get(NULL, (*it).c_str(), &i)) {
+ colstream << *it << ",";
+ valstream << i << ",";
+ }
+ }
+
+ std::string cols = colstream.str();
+ std::string vals = valstream.str();
+
+ IF_FAIL_RETURN_TAG(!cols.empty(), false, _E, "Invalid record");
+
+ cols.erase(cols.size() - 1);
+ vals.erase(vals.size() - 1);
+
+ _D("Columns: %s", cols.c_str());
+ _D("Values : %s", vals.c_str());
+
+ query_info_s *info = new(std::nothrow) query_info_s;
+ IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+
+ info->id = query_id;
+ info->listener = listener;
+
+ info->query = "INSERT INTO ";
+ info->query = info->query + table_name + " (" + cols + ") VALUES (" + vals + ");";
+ info->query = info->query + "SELECT seq FROM sqlite_sequence WHERE name='" + table_name + "';";
+
+ if (!push_thread_event(QTYPE_INSERT, info)) {
+ _E("Pushing thread event failed");
+ delete info;
+ return false;
+ }
+
+ return true;
+}
+
+bool ctx::db_manager_impl::execute(unsigned int query_id, const char* query, db_listener_iface* listener)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+
+ query_info_s *info = new(std::nothrow) query_info_s;
+ IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+
+ info->id = query_id;
+ info->query = query;
+ info->listener = listener;
+
+ if (!push_thread_event(QTYPE_EXECUTE, info)) {
+ _E("Pushing thread event failed");
+ delete info;
+ return false;
+ }
+
+ return true;
+}
+
+void ctx::db_manager_impl::_execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener)
+{
+ _SD("SQL(%d): %s", query_id, query);
+ IF_FAIL_VOID(query);
+ IF_FAIL_VOID_TAG(db_handle, _E, "DB not opened");
+
+ std::vector<json> *query_result = new(std::nothrow) std::vector<json>;
+ IF_FAIL_VOID_TAG(query_result, _E, "Memory allocation failed");
+
+ char *err = NULL;
+
+ int ret = sqlite3_exec(db_handle, query, execution_result_cb, query_result, &err);
+ if (ret != SQLITE_OK) {
+ _E("DB Error: %s", err);
+ sqlite3_free(err);
+ send_result(query_type, query_id, listener, ERR_OPERATION_FAILED, query_result);
+ return;
+ }
+
+ send_result(query_type, query_id, listener, ERR_NONE, query_result);
+ return;
+}
+
+int ctx::db_manager_impl::execution_result_cb(void *user_data, int dim, char **value, char **column)
+{
+ std::vector<json> *records = static_cast<std::vector<json>*>(user_data);
+ json row;
+ bool column_null = false;
+
+ for (int i=0; i<dim; ++i) {
+ _D("[%d] '%s': '%s'", i, column[i], value[i]);
+
+ if (value[i]) {
+ row.set(NULL, column[i], value[i]);
+ } else {
+ column_null = true;
+ }
+ }
+
+ if (!column_null) {
+ records->push_back(row);
+ } else {
+ _W(RED("Null columns exist"));
+ }
+
+ return 0;
+}
+
+void ctx::db_manager_impl::send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result)
+{
+ query_result_s *qr = new(std::nothrow) query_result_s();
+ IF_FAIL_VOID_TAG(qr, _E, "Memory allocation failed");
+
+ qr->type = query_type;
+ qr->id = query_id;
+ qr->listener = listener;
+ qr->error = error;
+ qr->result = result;
+
+ g_idle_add(_send_result, qr);
+}
+
+gboolean ctx::db_manager_impl::_send_result(gpointer data)
+{
+ query_result_s *qr = static_cast<query_result_s*>(data);
+
+ if (qr->listener) {
+ switch (qr->type) {
+ case QTYPE_CREATE_TABLE:
+ qr->listener->on_creation_result_received(qr->id, qr->error);
+ break;
+ case QTYPE_INSERT:
+ {
+ int64_t row_id = -1;
+ if (qr->error == ERR_NONE && qr->result && !qr->result->empty()) {
+ qr->result->at(0).get(NULL, "seq", &row_id);
+ _D("RowId: %d", row_id);
+ }
+ qr->listener->on_insertion_result_received(qr->id, qr->error, row_id);
+ }
+ break;
+ case QTYPE_EXECUTE:
+ qr->listener->on_query_result_received(qr->id, qr->error, *(qr->result));
+ break;
+ default:
+ _W("Unknown query type: %d", qr->type);
+ }
+ }
+
+ delete qr->result;
+ delete qr;
+ return FALSE;
+}
+
+static unsigned int generate_qid()
+{
+ static GMutex mutex;
+ static unsigned int qid = 0;
+
+ ctx::scope_mutex sm(&mutex);
+
+ ++qid;
+
+ if (qid == 0) { // Overflow handling
+ qid = 1;
+ }
+
+ return qid;
+}
+
+bool ctx::db_manager_impl::insert_sync(const char* table_name, json& record, int64_t* row_id)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+ IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+ IF_FAIL_RETURN_TAG(table_name && row_id, false, _E, "Invalid parameter");
+
+ ctx::scope_mutex sm(&sync_insert_mutex);
+
+ unsigned int qid = generate_qid();
+ insert(qid, table_name, record, this);
+
+ while (sync_insert_qid != qid) {
+ g_cond_wait(&sync_insert_cond, &sync_insert_mutex);
+ }
+
+ *row_id = sync_insert_row_id;
+
+ IF_FAIL_RETURN_TAG(*row_id > 0, false, _E, "Insertion failed");
+ return true;
+}
+
+void ctx::db_manager_impl::on_insertion_result_received(unsigned int query_id, int error, int64_t row_id)
+{
+ ctx::scope_mutex sm(&sync_insert_mutex);
+
+ sync_insert_row_id = row_id;
+ sync_insert_qid = query_id;
+
+ g_cond_signal(&sync_insert_cond);
+}
+
+bool ctx::db_manager_impl::execute_sync(const char* query, std::vector<json>* records)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+ IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+ IF_FAIL_RETURN_TAG(query && records, false, _E, "Invalid parameter");
+
+ ctx::scope_mutex sm(&sync_execute_mutex);
+
+ unsigned int qid = generate_qid();
+ execute(qid, query, this);
+
+ while (sync_execute_qid != qid) {
+ g_cond_wait(&sync_execute_cond, &sync_execute_mutex);
+ }
+
+ IF_FAIL_RETURN_TAG(sync_execute_error == ERR_NONE, false, _E, "Query execution failed");
+
+ *records = sync_execute_result;
+ sync_execute_result.clear();
+
+ return true;
+}
+
+void ctx::db_manager_impl::on_query_result_received(unsigned int query_id, int error, std::vector<json>& records)
+{
+ ctx::scope_mutex sm(&sync_execute_mutex);
+
+ sync_execute_error = error;
+ sync_execute_result = records;
+ sync_execute_qid = query_id;
+
+ g_cond_signal(&sync_execute_cond);
+}
+
+void ctx::db_manager_impl::on_creation_result_received(unsigned int query_id, int error)
+{
+ _D("Table Created: QID: %d, Error: %#x", query_id, error);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_DB_MANAGER_IMPL_H__
+#define __CONTEXT_DB_MANAGER_IMPL_H__
+
+#include <vector>
+#include <json.h>
+#include <sqlite3.h>
+
+#include <event_driven.h>
+#include <db_listener_iface.h>
+#include <db_mgr_iface.h>
+
+namespace ctx {
+
+ class db_manager_impl : public event_driven_thread, public db_listener_iface, public db_manager_iface {
+ private:
+ enum query_type_e {
+ QTYPE_CREATE_TABLE = 1,
+ QTYPE_INSERT,
+ QTYPE_EXECUTE,
+ };
+
+ struct query_info_s {
+ unsigned int id;
+ db_listener_iface* listener;
+ std::string query;
+ };
+
+ struct query_result_s {
+ int type;
+ unsigned int id;
+ int error;
+ db_listener_iface* listener;
+ std::vector<json>* result;
+ };
+
+ sqlite3 *db_handle;
+
+ static bool is_main_thread();
+
+ void on_thread_event_popped(int type, void* data);
+ void delete_thread_event(int type, void* data);
+
+ bool open();
+ void close();
+
+ void _execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener);
+ void send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result);
+
+ static int execution_result_cb(void *user_data, int dim, char **value, char **column);
+ static gboolean _send_result(gpointer data);
+
+ void on_creation_result_received(unsigned int query_id, int error);
+ void on_insertion_result_received(unsigned int query_id, int error, int64_t row_id);
+ void on_query_result_received(unsigned int query_id, int error, std::vector<json>& records);
+
+ public:
+ db_manager_impl();
+ ~db_manager_impl();
+
+ bool init();
+ void release();
+
+ bool create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option = NULL, db_listener_iface* listener = NULL);
+ bool insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener = NULL);
+ bool execute(unsigned int query_id, const char* query, db_listener_iface* listener);
+ bool insert_sync(const char* table_name, json& record, int64_t* row_id);
+ bool execute_sync(const char* query, std::vector<json>* records);
+
+ }; /* class db_manager */
+}
+
+#endif /* __CONTEXT_DB_MANAGER_IMPL_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <signal.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <types_internal.h>
+#include <dbus_listener_iface.h>
+#include "server.h"
+#include "client_request.h"
+#include "dbus_server_impl.h"
+
+static ctx::dbus_server_impl *_instance = NULL;
+static GDBusConnection *dbus_connection = NULL;
+static guint dbus_owner_id = 0;
+static GDBusNodeInfo *dbus_node_info = NULL;
+
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='" DBUS_IFACE "'>"
+ " <method name='" METHOD_REQUEST "'>"
+ " <arg type='i' name='" ARG_REQTYPE "' direction='in'/>"
+ " <arg type='s' name='" ARG_COOKIE "' direction='in'/>"
+ " <arg type='i' name='" ARG_REQID "' direction='in'/>"
+ " <arg type='s' name='" ARG_SUBJECT "' direction='in'/>"
+ " <arg type='s' name='" ARG_INPUT "' direction='in'/>"
+ " <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
+ " <arg type='s' name='" ARG_RESULT_ADD "' direction='out'/>"
+ " <arg type='s' name='" ARG_OUTPUT "' direction='out'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+static const char* req_type_to_str(int req_type)
+{
+ switch (req_type) {
+ case REQ_SUBSCRIBE:
+ return "Subscribe";
+ case REQ_UNSUBSCRIBE:
+ return "Unsubscribe";
+ case REQ_READ:
+ return "Read";
+ case REQ_READ_SYNC:
+ return "Read (Sync)";
+ case REQ_WRITE:
+ return "Write";
+ default:
+ return NULL;
+ }
+}
+
+static void handle_request(const char *sender, GVariant *param, GDBusMethodInvocation *invocation)
+{
+ gint req_type = 0;
+ const gchar *cookie = NULL;
+ gint req_id = 0;
+ const gchar *subject = NULL;
+ const gchar *input = NULL;
+
+ g_variant_get(param, "(i&si&s&s)", &req_type, &cookie, &req_id, &subject, &input);
+ IF_FAIL_VOID_TAG(req_type > 0 && req_id > 0 && cookie && subject && input, _E, "Invalid request");
+
+ _SD("Cookie: %s", cookie);
+ _I("[%s] ReqId: %d, Subject: %s", req_type_to_str(req_type), req_id, subject);
+ _SI("Input: %s", input);
+
+ //TODO: Parameter validation
+
+ ctx::client_request *request = NULL;
+ try {
+ request = new ctx::client_request(req_type, sender, req_id, subject, input, cookie, invocation);
+ } catch (std::bad_alloc& ba) {
+ _E("Memory allocation failed");
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ return;
+ } catch (int e) {
+ _E("Caught %d", e);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
+ return;
+ }
+
+ ctx::server::send_request(request);
+}
+
+static void handle_method_call(GDBusConnection *conn, const gchar *sender,
+ const gchar *obj_path, const gchar *iface, const gchar *method_name,
+ GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ IF_FAIL_VOID_TAG(STR_EQ(obj_path, DBUS_PATH), _W, "Invalid path: %s", obj_path);
+ IF_FAIL_VOID_TAG(STR_EQ(iface, DBUS_IFACE), _W, "Invalid interface: %s", obj_path);
+
+ if (STR_EQ(method_name, METHOD_REQUEST)) {
+ handle_request(sender, param, invocation);
+ } else {
+ _W("Invalid method: %s", method_name);
+ }
+}
+
+static void on_bus_acquired(GDBusConnection *conn, const gchar *name, gpointer user_data)
+{
+ GDBusInterfaceVTable vtable;
+ vtable.method_call = handle_method_call;
+ vtable.get_property = NULL;
+ vtable.set_property = NULL;
+
+ guint reg_id = g_dbus_connection_register_object(conn, DBUS_PATH,
+ dbus_node_info->interfaces[0], &vtable, NULL, NULL, NULL);
+
+ if (reg_id <= 0) {
+ _E("Failed to acquire dbus");
+ raise(SIGTERM);
+ }
+
+ dbus_connection = conn;
+}
+
+static void on_name_acquired(GDBusConnection *conn, const gchar *name, gpointer user_data)
+{
+ _SI("Dbus name acquired: %s", name);
+}
+
+static void on_name_lost(GDBusConnection *conn, const gchar *name, gpointer user_data)
+{
+ _E("Dbus name lost");
+ raise(SIGTERM);
+}
+
+ctx::dbus_server_impl::dbus_server_impl()
+{
+}
+
+ctx::dbus_server_impl::~dbus_server_impl()
+{
+ release();
+}
+
+bool ctx::dbus_server_impl::init()
+{
+ IF_FAIL_RETURN_TAG(dbus_node_info == NULL, false, _E, "Re-initialization");
+
+ dbus_node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
+ IF_FAIL_RETURN_TAG(dbus_node_info != NULL, false, _E, "Initialization failed");
+
+ dbus_owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, DBUS_DEST, G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL);
+
+ _instance = this;
+ return true;
+}
+
+void ctx::dbus_server_impl::release()
+{
+ if (dbus_connection) {
+ g_dbus_connection_flush_sync(dbus_connection, NULL, NULL);
+ }
+
+ if (dbus_owner_id > 0) {
+ g_bus_unown_name(dbus_owner_id);
+ dbus_owner_id = 0;
+ }
+
+ if (dbus_connection) {
+ g_dbus_connection_close_sync(dbus_connection, NULL, NULL);
+ g_object_unref(dbus_connection);
+ dbus_connection = NULL;
+ }
+
+ if (dbus_node_info) {
+ g_dbus_node_info_unref(dbus_node_info);
+ dbus_node_info = NULL;
+ }
+}
+
+void ctx::dbus_server_impl::publish(const char* dest, int req_id, const char* subject, int error, const char* data)
+{
+ IF_FAIL_VOID_TAG(dest && subject && data, _E, "Parameter null");
+
+ _SI("Publish: %s, %d, %s, %#x, %s", dest, req_id, subject, error, data);
+
+ GVariant *param = g_variant_new("(isis)", req_id, subject, error, data);
+ IF_FAIL_VOID_TAG(param, _E, "Memory allocation failed");
+
+ GError *err = NULL;
+ g_dbus_connection_call(dbus_connection, dest, DBUS_PATH, DBUS_IFACE,
+ METHOD_RESPOND, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, &err);
+ HANDLE_GERROR(err);
+}
+
+static void handle_signal_received(GDBusConnection *conn, const gchar *sender,
+ const gchar *obj_path, const gchar *iface, const gchar *signal_name,
+ GVariant *param, gpointer user_data)
+{
+ IF_FAIL_VOID_TAG(user_data, _W, "user_data cannot be null");
+ ctx::dbus_listener_iface *listener = static_cast<ctx::dbus_listener_iface*>(user_data);
+ listener->on_signal_received(sender, obj_path, iface, signal_name, param);
+}
+
+int64_t ctx::dbus_server_impl::signal_subscribe(const char* sender, const char* path, const char* iface, const char* name, ctx::dbus_listener_iface* listener)
+{
+ IF_FAIL_RETURN_TAG(dbus_connection, -1, _E, "Dbus not connected");
+ guint sid = g_dbus_connection_signal_subscribe(dbus_connection,
+ sender, iface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ handle_signal_received, listener, NULL);
+ return static_cast<int64_t>(sid);
+}
+
+void ctx::dbus_server_impl::signal_unsubscribe(int64_t subscription_id)
+{
+ IF_FAIL_VOID_TAG(dbus_connection, _E, "Dbus not connected");
+ IF_FAIL_VOID_TAG(subscription_id >= 0, _W, "Invalid parameter");
+ g_dbus_connection_signal_unsubscribe(dbus_connection, static_cast<guint>(subscription_id));
+}
+
+void ctx::dbus_server::publish(const char* dest, int req_id, const char* subject, int error, const char* data)
+{
+ _instance->publish(dest, req_id, subject, error, data);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_DBUS_SERVER_IMPL_H__
+#define __CONTEXT_DBUS_SERVER_IMPL_H__
+
+#include <sys/types.h>
+#include <string>
+#include <dbus_server_iface.h>
+
+namespace ctx {
+ class dbus_server_impl : public dbus_server_iface {
+ public:
+ dbus_server_impl();
+ ~dbus_server_impl();
+
+ bool init();
+ void release();
+
+ void publish(const char* dest, int req_id, const char* subject, int error, const char* data);
+ int64_t signal_subscribe(const char* sender, const char* path, const char* iface, const char* name, dbus_listener_iface* listener);
+ void signal_unsubscribe(int64_t subscription_id);
+
+ }; /* class ctx::dbus_server */
+
+ namespace dbus_server {
+ void publish(const char* dest, int req_id, const char* subject, int error, const char* data);
+ }
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_DBUS_SERVER_IMPL_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <glib.h>
+#include <types_internal.h>
+#include "request.h"
+
+ctx::request_info::request_info(int type, const char* client, int req_id, const char* subj, const char* desc)
+ : _type(type)
+ , _req_id(req_id)
+ , _client(client)
+ , _subject(subj)
+ , _description(desc)
+{
+}
+
+ctx::request_info::~request_info()
+{
+}
+
+int ctx::request_info::get_type()
+{
+ return _type;
+}
+
+int ctx::request_info::get_id()
+{
+ return _req_id;
+}
+
+const char* ctx::request_info::get_zone_name()
+{
+ return _zone_name.c_str();
+}
+
+const char* ctx::request_info::get_client()
+{
+ return _client.c_str();
+}
+
+const char* ctx::request_info::get_subject()
+{
+ return _subject.c_str();
+}
+
+const char* ctx::request_info::get_app_id()
+{
+ return get_client();
+}
+
+ctx::json& ctx::request_info::get_description()
+{
+ return _description;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_REQUEST_INFO_H__
+#define __CONTEXT_REQUEST_INFO_H__
+
+#include <string>
+#include <json.h>
+
+namespace ctx {
+
+ class request_info {
+ public:
+ request_info(int type, const char* client, int req_id, const char* subj, const char* desc);
+ virtual ~request_info();
+
+ int get_type();
+ int get_id();
+ const char* get_zone_name();
+ const char* get_client();
+ const char* get_subject();
+ ctx::json& get_description();
+ virtual const char* get_app_id();
+
+ virtual bool reply(int error) = 0;
+ virtual bool reply(int error, ctx::json& request_result) = 0;
+ virtual bool reply(int error, ctx::json& request_result, ctx::json& data_read) = 0;
+ virtual bool publish(int error, ctx::json& data) = 0;
+
+ protected:
+ int _type;
+ int _req_id;
+ std::string _zone_name;
+ std::string _client;
+ std::string _subject;
+ ctx::json _description;
+ };
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_REQUEST_INFO_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+//#define _USE_ECORE_MAIN_LOOP_
+
+#include <stdlib.h>
+#include <new>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <types_internal.h>
+#include "dbus_server_impl.h"
+#include "db_mgr_impl.h"
+#include "timer_mgr_impl.h"
+#include "context_mgr_impl.h"
+#include "zone_util_impl.h"
+#include "access_control/privilege.h"
+#include "context_trigger/trigger.h"
+#include "server.h"
+
+#ifdef _USE_ECORE_MAIN_LOOP_
+#include <Ecore.h>
+#else
+static GMainLoop *mainloop = NULL;
+#endif
+
+static bool started = false;
+
+static ctx::context_manager_impl *context_mgr = NULL;
+static ctx::timer_manager_impl *timer_mgr = NULL;
+static ctx::db_manager_impl *database_mgr = NULL;
+static ctx::dbus_server_impl *dbus_handle = NULL;
+static ctx::context_trigger *trigger = NULL;
+
+void ctx::server::run()
+{
+ if (started) {
+ _W("Started already");
+ return;
+ }
+
+ _I("Init MainLoop");
+#ifdef _USE_ECORE_MAIN_LOOP_
+ ecore_init();
+ ecore_main_loop_glib_integrate();
+#else
+ mainloop = g_main_loop_new(NULL, FALSE);
+#endif
+
+ bool result = false;
+
+ _I("Init vasum context");
+ result = ctx::zone_util::init();
+ IF_FAIL_CATCH_TAG(result, _E, "Vasum context initialization failed");
+
+ _I("Init access control configuration");
+ result = ctx::privilege_manager::init();
+ IF_FAIL_CATCH_TAG(result, _E, "Access controller initialization failed");
+
+ _I("Init Timer Manager");
+ timer_mgr = new(std::nothrow) ctx::timer_manager_impl();
+ IF_FAIL_CATCH_TAG(timer_mgr, _E, "Memory allocation failed");
+ timer_manager::set_instance(timer_mgr);
+ result = timer_mgr->init();
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Database Manager");
+ database_mgr = new(std::nothrow) ctx::db_manager_impl();
+ IF_FAIL_CATCH_TAG(database_mgr, _E, "Memory allocation failed");
+ db_manager::set_instance(database_mgr);
+ result = database_mgr->init();
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Context Manager");
+ context_mgr = new(std::nothrow) ctx::context_manager_impl();
+ IF_FAIL_CATCH_TAG(context_mgr, _E, "Memory allocation failed");
+ context_manager::set_instance(context_mgr);
+ result = context_mgr->init();
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Context Trigger");
+ trigger = new(std::nothrow) ctx::context_trigger();
+ IF_FAIL_CATCH_TAG(trigger, _E, "Memory allocation failed");
+ result = trigger->init(context_mgr);
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ _I("Init Dbus Connection");
+ dbus_handle = new(std::nothrow) ctx::dbus_server_impl();
+ IF_FAIL_CATCH_TAG(dbus_handle, _E, "Memory allocation failed");
+ dbus_server::set_instance(dbus_handle);
+ result = dbus_handle->init();
+ IF_FAIL_CATCH_TAG(result, _E, "Initialization Failed");
+
+ // Start the main loop
+ started = true;
+ _I(CYAN("Context-Service Launched"));
+#ifdef _USE_ECORE_MAIN_LOOP_
+ ecore_main_loop_begin();
+#else
+ g_main_loop_run(mainloop);
+#endif
+
+ _I(CYAN("Terminating Context-Service"));
+
+ _I("Release Context Trigger");
+ trigger->release();
+
+ _I("Release Analyzer Manager");
+ context_mgr->release();
+
+ _I("Release Dbus Connection");
+ dbus_handle->release();
+
+ _I("Close the Database");
+ database_mgr->release();
+
+ _I("Release Timer Manager");
+ timer_mgr->release();
+
+ _I("Release Access control configuration");
+ ctx::privilege_manager::release();
+
+ _I("Release Vasum context");
+ ctx::zone_util::release();
+
+#ifdef _USE_ECORE_MAIN_LOOP_
+ ecore_shutdown();
+#else
+ g_main_loop_unref(mainloop);
+#endif
+
+ delete trigger;
+ delete context_mgr;
+ delete dbus_handle;
+ delete database_mgr;
+ delete timer_mgr;
+ return;
+
+CATCH:
+ _E(RED("Launching Failed"));
+ delete trigger;
+ delete context_mgr;
+ delete dbus_handle;
+ delete database_mgr;
+ delete timer_mgr;
+}
+
+void ctx::server::send_request(ctx::request_info* request)
+{
+ if (!trigger->assign_request(request)) {
+ context_mgr->assign_request(request);
+ }
+}
+
+static void signal_handler(int signo)
+{
+ _I("SIGNAL %d received", signo);
+
+ // Stop the main loop
+#ifdef _USE_ECORE_MAIN_LOOP_
+ ecore_main_loop_quit();
+#else
+ g_main_loop_quit(mainloop);
+#endif
+}
+
+int main(int argc, char* argv[])
+{
+ static struct sigaction signal_action;
+ signal_action.sa_handler = signal_handler;
+ sigemptyset(&signal_action.sa_mask);
+
+ sigaction(SIGINT, &signal_action, NULL);
+ sigaction(SIGHUP, &signal_action, NULL);
+ sigaction(SIGTERM, &signal_action, NULL);
+ sigaction(SIGQUIT, &signal_action, NULL);
+
+#if !defined(GLIB_VERSION_2_36)
+ g_type_init();
+#endif
+
+ ctx::server::run();
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_SERVER_H__
+#define __CONTEXT_SERVER_H__
+
+namespace ctx {
+
+ class request_info;
+
+ namespace server {
+
+ void run();
+ void send_request(request_info* request);
+
+ }; /* namespace ctx::server */
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_SERVER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <alarm.h>
+#include <scope_mutex.h>
+#include <timer_mgr.h>
+#include "timer_mgr_impl.h"
+
+#define IDENTIFIER "contextd"
+
+struct listener_info_s {
+ int timer_id;
+ ctx::timer_listener_iface* listener;
+ void* user_data;
+};
+
+typedef std::map<alarm_id_t, listener_info_s> listener_map_t;
+static listener_map_t *listener_map = NULL;
+static GMutex listener_map_mutex;
+
+static int generate_timer_id()
+{
+ static int tid = 0;
+
+ tid ++;
+ if (tid < 0) {
+ _W("Overflow");
+ tid = 1;
+ }
+
+ return tid;
+}
+
+static int alarm_expired_cb(alarm_id_t alarm_id, void* cb_data)
+{
+ int timer_id = 0;
+ ctx::timer_listener_iface *listener = NULL;
+ void* user_data;
+
+ {
+ ctx::scope_mutex sm1(&listener_map_mutex);
+ listener_map_t::iterator mit = listener_map->find(alarm_id);
+ IF_FAIL_RETURN_TAG(mit != listener_map->end(), 0, _W, "Unknown Alarm %d", alarm_id);
+ timer_id = mit->second.timer_id;
+ listener = mit->second.listener;
+ user_data = mit->second.user_data;
+ }
+
+ _D("Timer %d expired", timer_id);
+ bool repeat = listener->on_timer_expired(timer_id, user_data);
+
+ if (!repeat) {
+ _D("Stop repeating Timer %d (Alarm %d)", timer_id, alarm_id);
+ ctx::scope_mutex sm2(&listener_map_mutex);
+ alarmmgr_remove_alarm(alarm_id);
+ listener_map->erase(alarm_id);
+ }
+
+ return 0;
+}
+
+ctx::timer_manager_impl::timer_manager_impl()
+ : initialized(false)
+{
+}
+
+ctx::timer_manager_impl::~timer_manager_impl()
+{
+ release();
+}
+
+bool ctx::timer_manager_impl::init()
+{
+ IF_FAIL_RETURN_TAG(!initialized, true, _W, "Re-initialization");
+
+ listener_map = new(std::nothrow) listener_map_t;
+ IF_FAIL_RETURN_TAG(listener_map, false, _E, "Memory allocation failed");
+
+ int result = alarmmgr_init(IDENTIFIER);
+ IF_FAIL_RETURN_TAG(result == ALARMMGR_RESULT_SUCCESS, false, _E, "Alarm manager initialization failed");
+
+ result = alarmmgr_set_cb(alarm_expired_cb, this);
+ if (result != ALARMMGR_RESULT_SUCCESS) {
+ alarmmgr_fini();
+ _E("Alarm callback registration failed");
+ return false;
+ }
+
+ alarmmgr_remove_all();
+ initialized = true;
+ return true;
+}
+
+void ctx::timer_manager_impl::release()
+{
+ if (initialized) {
+ alarmmgr_remove_all();
+ alarmmgr_fini();
+ delete listener_map;
+ listener_map = NULL;
+ initialized = false;
+ }
+}
+
+int ctx::timer_manager_impl::set_for(int interval, timer_listener_iface* listener, void* user_data)
+{
+ IF_FAIL_RETURN_TAG(interval > 0 && listener, false, _E, "Invalid parameter");
+
+ alarm_id_t alarm_id;
+ int result;
+
+#if 0
+ // Implementation for Tizen 2.3
+ time_t trigger_time;
+ time(&trigger_time);
+ // time_t is in seconds.. It is the POSIX specification.
+ trigger_time += (interval * 60);
+
+ result = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, trigger_time, interval * 60, NULL, &alarm_id);
+#endif
+
+ result = alarmmgr_add_periodic_alarm_withcb(interval, QUANTUMIZE, alarm_expired_cb, this, &alarm_id);
+ IF_FAIL_RETURN_TAG(result == ALARMMGR_RESULT_SUCCESS, ERR_OPERATION_FAILED, _E, "Alarm initialization failed");
+
+ ctx::scope_mutex sm(&listener_map_mutex);
+
+ listener_info_s info;
+ info.timer_id = generate_timer_id();
+ info.listener = listener;
+ info.user_data = user_data;
+ (*listener_map)[alarm_id] = info;
+
+ _D("Timer %d was set for %dm interval", info.timer_id, interval);
+
+ return info.timer_id;
+}
+
+int ctx::timer_manager_impl::set_at(int hour, int min, int day_of_week, timer_listener_iface* listener, void* user_data)
+{
+ IF_FAIL_RETURN_TAG(
+ hour < 24 && hour >= 0 &&
+ min < 60 && min >= 0 &&
+ day_of_week > 0 && day_of_week <= timer_manager::EVERYDAY &&
+ listener, false, _E, "Invalid parameter");
+
+ int repeat = 0;
+ if (day_of_week & timer_manager::SUN) repeat |= ALARM_WDAY_SUNDAY;
+ if (day_of_week & timer_manager::MON) repeat |= ALARM_WDAY_MONDAY;
+ if (day_of_week & timer_manager::TUE) repeat |= ALARM_WDAY_TUESDAY;
+ if (day_of_week & timer_manager::WED) repeat |= ALARM_WDAY_WEDNESDAY;
+ if (day_of_week & timer_manager::THU) repeat |= ALARM_WDAY_THURSDAY;
+ if (day_of_week & timer_manager::FRI) repeat |= ALARM_WDAY_FRIDAY;
+ if (day_of_week & timer_manager::SAT) repeat |= ALARM_WDAY_SATURDAY;
+
+ alarm_entry_t *alarm_info = alarmmgr_create_alarm();
+ IF_FAIL_RETURN_TAG(alarm_info, ERR_OPERATION_FAILED, _E, "Memory allocation failed");
+
+ time_t current_time;
+ struct tm current_tm;
+ time(¤t_time);
+ tzset();
+ localtime_r(¤t_time, ¤t_tm);
+
+ alarm_date_t alarm_time;
+ alarm_time.year = current_tm.tm_year + 1900;
+ alarm_time.month = current_tm.tm_mon + 1;
+ alarm_time.day = current_tm.tm_mday;
+ alarm_time.hour = hour;
+ alarm_time.min = min;
+ alarm_time.sec = 0;
+
+ alarmmgr_set_time(alarm_info, alarm_time);
+ alarmmgr_set_repeat_mode(alarm_info, ALARM_REPEAT_MODE_WEEKLY, repeat);
+ alarmmgr_set_type(alarm_info, ALARM_TYPE_VOLATILE);
+
+ alarm_id_t alarm_id;
+ int ret = alarmmgr_add_alarm_with_localtime(alarm_info, NULL, &alarm_id);
+ alarmmgr_free_alarm(alarm_info);
+
+ IF_FAIL_RETURN_TAG(ret == ALARMMGR_RESULT_SUCCESS, ERR_OPERATION_FAILED, _E, "Alarm initialization failed");
+
+ ctx::scope_mutex sm(&listener_map_mutex);
+
+ listener_info_s info;
+ info.timer_id = generate_timer_id();
+ info.listener = listener;
+ info.user_data = user_data;
+
+ (*listener_map)[alarm_id] = info;
+
+ _D("Timer %d was set at %02d:%02d:00 (day of week: %#x)", info.timer_id, hour, min, day_of_week);
+
+ return info.timer_id;
+}
+
+void ctx::timer_manager_impl::remove(int timer_id)
+{
+ ctx::scope_mutex sm(&listener_map_mutex);
+
+ listener_map_t::iterator it;
+ for (it = listener_map->begin(); it != listener_map->end(); ++it) {
+ if (it->second.timer_id == timer_id) {
+ alarmmgr_remove_alarm(it->first);
+ listener_map->erase(it);
+ _D("Timer %d was removed", timer_id);
+ break;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_TIMER_MANAGER_IMPL_H__
+#define __CONTEXT_TIMER_MANAGER_IMPL_H__
+
+#include <timer_listener_iface.h>
+#include <timer_mgr_iface.h>
+
+namespace ctx {
+
+ class timer_manager_impl : public timer_manager_iface {
+ private:
+ bool initialized;
+
+ public:
+ timer_manager_impl();
+ ~timer_manager_impl();
+
+ bool init();
+ void release();
+
+ int set_for(int interval, timer_listener_iface* listener, void* user_data);
+ int set_at(int hour, int min, int day_of_week, timer_listener_iface* listener, void* user_data);
+ void remove(int timer_id);
+
+ }; /* class timer_manager */
+}
+
+#endif /* __CONTEXT_TIMER_MANAGER_IMPL_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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 <unistd.h>
+#include <vasum.h>
+#include <system_info.h>
+#include <types_internal.h>
+#include "zone_util_impl.h"
+
+#define HOST_NAME ""
+
+static bool container_enabled = false;
+static vsm_context_h _vsm_ctx = NULL;
+static ctx::zone_util_impl* _instance = NULL;
+
+const char* ctx::zone_util_impl::default_zone()
+{
+ if (container_enabled)
+ return VSM_DEFAULT_ZONE;
+
+ return HOST_NAME;
+}
+
+void* ctx::zone_util_impl::join_by_name(const char* name)
+{
+ IF_FAIL_RETURN(container_enabled, NULL);
+ IF_FAIL_RETURN_TAG(_vsm_ctx, NULL, _E, "Not initialized");
+
+ if (name == NULL) {
+ _D("NULL zone name. The default zone will be used.");
+ name = VSM_DEFAULT_ZONE;
+ }
+
+ vsm_zone_h target_zone = vsm_lookup_zone_by_name(_vsm_ctx, name);
+ IF_FAIL_RETURN_TAG(target_zone, NULL, _E, RED("Zone lookup failed"));
+
+ vsm_zone_h current_zone = vsm_lookup_zone_by_pid(_vsm_ctx, getpid());
+ IF_FAIL_RETURN_TAG(current_zone, NULL, _E, RED("Zone lookup failed"));
+ IF_FAIL_RETURN_TAG(target_zone != current_zone, NULL, _I, YELLOW("Already in the target zone %s"), name);
+
+ _I(YELLOW("Joining to '%s'"), name);
+ return vsm_join_zone(target_zone);
+}
+
+void* ctx::zone_util_impl::join_to_zone(void* zone)
+{
+ IF_FAIL_RETURN(container_enabled, NULL);
+ IF_FAIL_RETURN_TAG(_vsm_ctx, NULL, _E, "Not initialized");
+ IF_FAIL_RETURN(zone, NULL);
+ vsm_zone_h target = static_cast<vsm_zone_h>(zone);
+ _I(YELLOW("Joining to '%s'"), vsm_get_zone_name(target));
+ return vsm_join_zone(target);
+}
+
+bool ctx::zone_util::init()
+{
+ system_info_get_platform_bool("tizen.org/feature/container", &container_enabled);
+ IF_FAIL_RETURN_TAG(_instance == NULL, true, _W, "Re-initialization");
+
+ _instance = new(std::nothrow) zone_util_impl();
+ IF_FAIL_RETURN_TAG(_instance, false, _E, "Memory allocation failed");
+
+ if (container_enabled) {
+ _vsm_ctx = vsm_create_context();
+ if (!_vsm_ctx) {
+ delete _instance;
+ _E("Memory allocation failed");
+ return false;
+ }
+ }
+
+ zone_util::set_instance(_instance);
+ return true;
+}
+
+void ctx::zone_util::release()
+{
+ zone_util::set_instance(NULL);
+
+ delete _instance;
+ _instance = NULL;
+
+ if (_vsm_ctx)
+ vsm_cleanup_context(_vsm_ctx);
+
+ _vsm_ctx = NULL;
+}
+
+const char* ctx::zone_util::get_name_by_pid(pid_t pid)
+{
+ IF_FAIL_RETURN(container_enabled, HOST_NAME);
+ IF_FAIL_RETURN_TAG(_vsm_ctx, NULL, _E, "Not initialized");
+ vsm_zone_h zn = vsm_lookup_zone_by_pid(_vsm_ctx, pid);
+ return vsm_get_zone_name(zn);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __CONTEXT_VASUM_ZONE_UTIL_IMPL_H__
+#define __CONTEXT_VASUM_ZONE_UTIL_IMPL_H__
+
+#include <sys/types.h>
+#include <zone_util.h>
+#include <zone_util_iface.h>
+
+namespace ctx {
+
+ class zone_util_impl : public zone_util_iface {
+ public:
+ zone_util_impl() {}
+ ~zone_util_impl() {}
+ void* join_by_name(const char* name);
+ void* join_to_zone(void* zone);
+ const char* default_zone();
+ };
+
+ namespace zone_util {
+ bool init();
+ void release();
+ const char* get_name_by_pid(pid_t pid);
+ }
+
+} /* namespace ctx */
+
+#endif /* End of __CONTEXT_VASUM_ZONE_UTIL_IMPL_H__ */