This commit is contained in:
2015-05-21 02:05:38 +02:00
parent 37ebf68d6b
commit 19cb6e5cbe
49 changed files with 21669 additions and 687 deletions
+202
View File
@@ -0,0 +1,202 @@
cmake_minimum_required(VERSION 2.8.3)
project(hos_cosgi_core)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
hos_celix
roscpp
hos_cpp_utils
hos_libvariant
)
## System dependencies are found with CMake's conventions
find_package(Boost REQUIRED)
find_package(APR REQUIRED)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependencies might have been
## pulled in transitively but can be declared for certainty nonetheless:
## * add a build_depend tag for "message_generation"
## * add a run_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# std_msgs # Or other packages containing msgs
# )
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
INCLUDE_DIRS include/${PROJECT_NAME}/
# LIBRARIES hos_cosgi_launcher
CATKIN_DEPENDS hos_celix
# DEPENDS system_lib
)
###########
## Build ##
###########
add_definitions(
-std=c++11
)
## Specify additional locations of header files
## Your package locations should be listed before other locations
# include_directories(include)
include_directories(
${catkin_INCLUDE_DIRS}
${APR_INCLUDE_DIR}
${APR_INCLUDE_DIR}/apr-1.0
include/${PROJECT_NAME}/
)
add_executable(hos_cosgi_launcher
src/launcher.cpp
src/hos/cosgi/service/core/core_serviceimpl.cpp
)
target_link_libraries(hos_cosgi_launcher
${catkin_LIBRARIES}
${APR_LIBRARIES}
)
## Declare a cpp library
# add_library(hos_osgi_launcher
# src/${PROJECT_NAME}/hos_osgi_launcher.cpp
# )
## Declare a cpp executable
# add_executable(hos_osgi_launcher_node src/hos_osgi_launcher_node.cpp)
## Add cmake target dependencies of the executable/library
## as an example, message headers may need to be generated before nodes
# add_dependencies(hos_osgi_launcher_node hos_osgi_launcher_generate_messages_cpp)
## Specify libraries to link a library or executable target against
# target_link_libraries(hos_osgi_launcher_node
# ${catkin_LIBRARIES}
# )
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables and/or libraries for installation
install(TARGETS hos_cosgi_launcher
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
## Mark cpp header files for installation
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
OPTIONAL
)
## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_hos_osgi_launcher.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
###################
## Documentation ##
###################
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
endif(DOXYGEN_FOUND)
+248
View File
@@ -0,0 +1,248 @@
# Doxyfile 1.8.8
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = hos_cosgi_core
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include \
@CMAKE_CURRENT_SOURCE_DIR@/src
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf \
*.as \
*.js
RECURSIVE = YES
EXCLUDE_SYMLINKS = NO
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = YES
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHDATA_FILE = searchdata.xml
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
@@ -0,0 +1,268 @@
#pragma once
#include "Interface.h"
#include <mutex>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
// main namespace
namespace hos {
namespace cosgi{
namespace service {
namespace implementation {
/**
* Template holding information about a service.
*
* Works in conjunction with the Service class below which is the implementation of interface::Service.
* Concrete services need to inherit the Service class and specialize this template.
*/
template<class _Service>
struct ServiceInfo {
static const char* name /** Service name. */;
static const int major /** Version major number. */;
static const int minor /** Version minor number. */;
};
/**
* Implementation of interface::Service.
*/
template<class _Service>
class Service
: public virtual interface::Service {
public:
/**
* Returns the name of the service.
*
* \return service name.
**/
virtual const char* getServiceName() {
return ServiceInfo<_Service>::name;
};
/**
* Returns the version of the service.
*
* \param[out] major version major number.
* \param[out] minor version minor number.
*/
virtual void getServiceVersion(int& major, int& minor) override {
major = ServiceInfo<_Service>::major;
minor = ServiceInfo<_Service>::minor;
}
};
/**
* Implementation of interface::Observable.
*
* This template does not provide any functionality, so do not use it but use only its specializations.
*/
template <class... _Args> class Observable {};
/**
* Implementation of interface::Observable<_Event>.
*
* Observers are stored in an std::unordered_set.
*/
template<class _Event>
class Observable<_Event>
: public virtual interface::Observable<_Event> {
protected:
typedef std::unordered_set<typename interface::Observable<_Event>::observer_type*> observers_type;
std::mutex _observersMutex;
observers_type _observers;
public:
virtual ~Observable() {}
/**
* Registers an observer.
*
* \param[in] o observer to be registered.
*/
virtual void addObserver(typename interface::Observable<_Event>::observer_type* o) override {
std::lock_guard<std::mutex> lock(_observersMutex);
if (o != nullptr) {
auto elem = _observers.find(o);
if (elem == _observers.end()) {
_observers.insert(o);
}
}
}
/**
* Unregisters an observer.
*
* \param[in] o observer to be unregistered.
*/
virtual void deleteObserver(typename interface::Observable<_Event>::observer_type* o) override {
std::lock_guard<std::mutex> lock(_observersMutex);
if (o != nullptr) {
auto elem = _observers.find(o);
if (elem != _observers.end()) {
_observers.erase(elem);
}
}
}
/**
* Unregisters all observers.
*/
virtual void deleteObservers() override {
std::lock_guard<std::mutex> lock(_observersMutex);
_observers.clear();
};
/**
* Returns the number of registered observers.
*
* \return number of registered observers.
*/
virtual size_t countObservers() override {
std::lock_guard<std::mutex> lock(_observersMutex);
return _observers.size();
}
/**
* Notify observers of a new event.
*
* \param[in] e event.
*/
virtual void notifyObservers(const _Event* e) override {
std::lock_guard<std::mutex> lock(_observersMutex);
for (auto l : _observers) {
l->notificationReceived(this, e);
}
}
};
/**
* Implementation of interface::Observable<_Key, _Event>.
*
* Observers are stored in an std::unordered_map using the filter key as map key.
*/
template<class _Key, class _Event>
class Observable<_Key, _Event>
: public virtual interface::Observable<_Key, _Event> {
protected:
typedef std::unordered_multimap<_Key, typename interface::Observable<_Key, _Event>::observer_type*> observers_type;
std::mutex _observersMutex;
observers_type _observers;
public:
virtual ~Observable() {}
/**
* Registers an observer.
*
* \param[in] k filter key.
* \param[in] o observer to be registered.
*/
virtual void addObserver(_Key k, typename interface::Observable<_Key, _Event>::observer_type* o) override {
std::lock_guard<std::mutex> lock(_observersMutex);
if (o != nullptr) {
bool _found = false;
auto range = _observers.equal_range(k);
for (auto i = range.first; i != range.second; i++) {
if (i.second == o) {
_found = true;
break;
}
}
if (!_found) {
_observers.insert({k, o});
}
}
}
/**
* Unregisters an observer.
*
* \param[in] k filter key.
* \param[in] o observer to be unregistered.
*/
virtual void deleteObserver(_Key k, typename interface::Observable<_Key, _Event>::observer_type* o) override {
std::lock_guard<std::mutex> lock(_observersMutex);
if (o != nullptr) {
bool _found = false;
auto range = _observers.equal_range(k);
for (auto i = range.first; i != range.second; i++) {
if (i.second == o) {
_observers.erase(i);
break;
}
}
}
}
/**
* Unregisters all observers.
*/
virtual void deleteObservers() override {
std::lock_guard<std::mutex> lock(_observersMutex);
_observers.clear();
}
/**
* Returns the number of registered observers.
*
* \return number of registered observers.
*/
virtual size_t countObservers() override {
std::lock_guard<std::mutex> lock(_observersMutex);
return _observers.size();
}
/**
* Notify observers of a new event.
*
* \param[in] k observer filter key.
* \param[in] e event.
*/
void notifyObservers(_Key k, const _Event* e) override {
std::lock_guard<std::mutex> lock(_observersMutex);
auto ol = _observers.equal_range(k);
std::for_each(ol.first, ol.second, [&](const typename interface::Observable<_Key, _Event>::observer_type::value_type& o) {
o.second->notificationReceived(this, k, e);
});
}
};
} // namespace implementation
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -0,0 +1,271 @@
#pragma once
#include <cstddef>
// main namespace
namespace hos {
namespace cosgi{
namespace service {
namespace interface {
/**
* Basic public OSGI interface class.
*
* Every public OSGI interface class needs to inherit from this class.
* At the moment it only defines an empty virtual destructor.
*/
class Object {
public:
virtual ~Object() {}
};
/**
* Basic public OSGI service interface class.
*
* Every public OSGI service interface class needs to inherit from this class.
* Defines generic methods to get information about a service.
*/
class Service
: public virtual Object {
public:
/**
* Returns the name of the service.
*
* The service name is used to register a service in the OSGI framework.
*
* \return service name.
**/
virtual const char* getServiceName() = 0;
/**
* Returns the version of the service.
*
* The version numbers are used to determine compatibility. Different major numbers are incompatible with each other.
* Different minor numbers are backwards compatible (e.g. a mininum requirement of 1.2 means that service version 1.3 is compatible
* but service version 1.1 is incompatible).
*
* \param[out] major version major number.
* \param[out] minor version minor number.
*/
virtual void getServiceVersion(int& major, int& minor) = 0;
};
/**
* Public OSGI interface template implementing the observer from the observer-pattern.
*
* This template does not provide any functionality, so do not use it but use only its specializations.
*/
template<class...> class Observer {};
/**
* Public OSGI interface template implementing the observable from the observer-pattern.
*
* This template does not provide any functionality, so do not use it but use only its specializations.
*/
template<class...> class Observable {};
/**
* Convenience template merging the Object class and the Observable template into a single template.
*/
template<class... _Args> class ObservableObject
: public virtual Object,
public virtual Observable<_Args...> {};
/**
* Convenience template merging the Service class and the Observable template into a single template.
*/
template<class... _Args> class ObservableService
: public virtual Service,
public virtual Observable<_Args...> {};
/**
* Specialization of the Observer template with one template argument (the event emitted from the observable).
*/
template<class _Event>
class Observer<_Event>
: public virtual Object {
public:
/**
* Specifies the type of compatible observables.
*/
typedef Observable<_Event> observable_type;
/**
* Function that is called when an event is emitted by the observable object.
*
* \param[in] o observable object emitting the event.
* \param[in] e the event (can be null).
*/
virtual void notificationReceived(observable_type* o, const _Event* e) = 0;
};
/**
* Specialization of the Observer template with two template arguments (the key used to filter observers,
* and the event emitted from the observable).
*/
template<class _Key, class _Event>
class Observer<_Key, _Event>
: public virtual Object {
public:
/**
* Specifies the type of compatible observables.
*/
typedef Observable<_Key, _Event> observable_type;
/**
* Function that is called when an event is emitted by the observable object.
*
* \param[in] o observable object emitting the event.
* \param[in] key the filter key.
* \param[in] e the event (can be null).
*/
virtual void notificationReceived(observable_type* o, const _Key& key, const _Event* e) = 0;
};
/**
* Specialization of the Observable template with one template argument (the event emitted from the observable).
*
* When an event is emitted, all registered observers will be notified.
*/
template<class _Event>
class Observable<_Event>
: public virtual Object {
public:
/**
* Specifies the type of compatible observers.
*/
typedef Observer<_Event> observer_type;
/**
* Registers an observer.
*
* \param[in] o observer to be registered.
*/
virtual void addObserver(observer_type* o) = 0;
/**
* Unregisters an observer.
*
* \param[in] o observer to be unregistered.
*/
virtual void deleteObserver(observer_type* o) = 0;
/**
* Unregisters all observers.
*/
virtual void deleteObservers() = 0;
/**
* Returns the number of registered observers.
*
* \return number of registered observers.
*/
virtual size_t countObservers() = 0;
/**
* Notify observers of a new event.
*
* \param[in] e event.
*/
virtual void notifyObservers(const _Event* e) = 0;
};
/**
* Specialization of the Observable template with two template arguments (the key used to filter observers,
* and the event emitted from the observable).
*
* When an event is emitted, only observers registered under the specified key will be notified.
*/
template<class _Key, class _Event>
class Observable<_Key, _Event>
: public virtual Object {
public:
/**
* Specifies the type of compatible observers.
*/
typedef Observer<_Key, _Event> observer_type;
/**
* Registers an observer.
*
* \param[in] key filter key.
* \param[in] o observer to be registered.
*/
virtual void addObserver(_Key& key, observer_type* o) = 0;
/**
* Unregisters an observer.
*
* \param[in] key filter key.
* \param[in] o observer to be unregistered.
*/
virtual void deleteObserver(_Key& key, observer_type* o) = 0;
/**
* Unregisters all observers.
*/
virtual void deleteObservers() = 0;
/**
* Returns the number of registered observers.
*
* \return number of registered observers.
*/
virtual size_t countObservers() = 0;
/**
* Notify observers of a new event.
*
* \param[in] key observer filter key.
* \param[in] e event.
*/
virtual void notifyObservers(const _Key& key, const _Event* e) = 0;
};
} // namespace interface
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -0,0 +1,127 @@
#pragma once
#include <hos/cosgi/service/Interface.h>
// Forward declarations
namespace ros { class NodeHandle; }
// Service Namespace
namespace hos {
namespace cosgi {
namespace service {
namespace core {
/**
* Base class for events emitted by the CoreService.
*/
class CoreServiceEvent {
public:
/**
* CoreService event types.
*/
enum class EventType : int { STARTUP_FINISHED = 1, SHUTDOWN = 2 };
/**
* Event type.
*/
const EventType eventType;
/**
* Constructor.
*/
CoreServiceEvent(EventType type) : eventType(type) {}
};
/**
* Startup finished event.
*
* This event is emitted when all autostart bundles have been started and hos_cosgi_launcher is about to enter the main loop.
*/
class StartupFinishedEvent
: public CoreServiceEvent {
public:
StartupFinishedEvent() : CoreServiceEvent(EventType::STARTUP_FINISHED) {}
};
/**
* Shutdown event.
*
* This event is emitted when hos_cosgi_launcher is about to exit.
*/
class ShutdownEvent
: public CoreServiceEvent {
public:
ShutdownEvent() : CoreServiceEvent(EventType::SHUTDOWN) {}
};
/**
* Public COSGI interface of the CoreService.
*
* The CoreService is directly provided by hos_cosgi_launcher. The best way to test whether a bundle was started by
* hos_cosgi_launcher is to try to retrieve the CoreService.
*
* It offers following functionality:
* - Events indicating system events (currently startup, shutdown)
* - Request application shutdown.
* - Get ROS node handles.
*/
class CoreService
: public virtual interface::ObservableService<CoreServiceEvent> {
public:
/**
* The service name.
*/
static constexpr const char* SERVICE_NAME = "hos_core_service";
/**
* Returns a reference to a node handle with public namespace.
*
* The node handle was created using the default constructor.
*
* \return public node handle
*/
virtual ros::NodeHandle& getPublicNodeHandle() = 0;
/**
* Returns a reference to a node handle with private namespace.
*
* The node handle was created using namespace "~".
*
* \return private node handle
*/
virtual ros::NodeHandle& getPrivateNodeHandle() = 0;
/**
* Request an application shutdown
*/
virtual void requestShutdown() = 0;
};
} // namespace core
} // namespace service
} // namespace cosgi
} // namespace hos
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0"?>
<package>
<name>hos_cosgi_core</name>
<version>0.0.0</version>
<description>The hos_cosgi_core package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
<maintainer email="matzman@todo.todo">matzman</maintainer>
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>TODO</license>
<!-- Url tags are optional, but mutiple are allowed, one per tag -->
<!-- Optional attribute type can be: website, bugtracker, or repository -->
<!-- Example: -->
<!-- <url type="website">http://wiki.ros.org/hos_osgi_launcher</url> -->
<!-- Author tags are optional, mutiple are allowed, one per tag -->
<!-- Authors do not have to be maintianers, but could be -->
<!-- Example: -->
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
<!-- The *_depend tags are used to specify dependencies -->
<!-- Dependencies can be catkin packages or system dependencies -->
<!-- Examples: -->
<!-- Use build_depend for packages you need at compile time: -->
<!-- <build_depend>message_generation</build_depend> -->
<!-- Use buildtool_depend for build tool packages: -->
<!-- <buildtool_depend>catkin</buildtool_depend> -->
<!-- Use run_depend for packages you need at runtime: -->
<!-- <run_depend>message_runtime</run_depend> -->
<!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> -->
<buildtool_depend>catkin</buildtool_depend>
<build_depend>hos_celix</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>hos_cpp_utils</build_depend>
<build_depend>hos_libvariant</build_depend>
<run_depend>hos_celix</run_depend>
<run_depend>roscpp</run_depend>
<run_depend>hos_cpp_utils</run_depend>
<run_depend>hos_libvariant</run_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- You can specify that this package is a metapackage here: -->
<!-- <metapackage/> -->
<!-- Other tools can request additional information be placed here -->
</export>
</package>
@@ -0,0 +1,43 @@
/*
* hos_core_service_impl.cpp
*
* Created on: 05.04.2015
* Author: matzman
*/
#include <ros/ros.h>
#include "core_serviceimpl.h"
namespace hos {
namespace cosgi{
namespace service {
namespace core {
template<> const char* implementation::ServiceInfo<CoreServiceImpl>::name = service::core::CoreService::SERVICE_NAME;
template<> const int implementation::ServiceInfo<CoreServiceImpl>::major = 0;
template<> const int implementation::ServiceInfo<CoreServiceImpl>::minor = 3;
CoreServiceImpl::CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle)
: publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {}
ros::NodeHandle& CoreServiceImpl::getPublicNodeHandle() {
return publicNodeHandle;
}
ros::NodeHandle& CoreServiceImpl::getPrivateNodeHandle() {
return privateNodeHandle;
}
void CoreServiceImpl::requestShutdown() {
ROS_INFO("Received shutdown request");
ros::shutdown();
}
} // namespace core
} // namespace service
} // namespace cosgi
} // namespace hos
@@ -0,0 +1,42 @@
/*
* hos_core_service_private.h
*
* Created on: 05.04.2015
* Author: matzman
*/
#ifndef SRC_CORE_SERVICEIMPL_H_
#define SRC_CORE_SERVICEIMPL_H_
#include <hos/cosgi/service/core/CoreService.h>
#include <hos/cosgi/service/Implementation.h>
// Service Namespace
namespace hos {
namespace cosgi{
namespace service {
namespace core {
class CoreServiceImpl;
class CoreServiceImpl : public virtual CoreService, public virtual implementation::Service<CoreServiceImpl>, public virtual implementation::Observable<CoreServiceEvent> {
private:
ros::NodeHandle publicNodeHandle;
ros::NodeHandle privateNodeHandle;
public:
CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle);
virtual ros::NodeHandle& getPublicNodeHandle();
virtual ros::NodeHandle& getPrivateNodeHandle();
virtual void requestShutdown();
};
} // namespace core
} // namespace service
} // namespace cosgi
} // namespace hos
#endif /* SRC_CORE_SERVICEIMPL_H_ */
+232
View File
@@ -0,0 +1,232 @@
#include <cstdlib>
#include "ros/ros.h"
#include <apr_general.h>
#include <apr_strings.h>
#include "hos/cosgi/service/core/core_serviceimpl.h"
extern "C" { // celix does not provide C++ ready headers
#include "celix/framework.h"
#include "celix/linked_list_iterator.h"
}
#include <exception>
#include <sstream>
#include <boost/format.hpp>
#include <signal.h>
#include <string>
using namespace hos::cosgi::service::core;
std::function<void(int)> signalHandler;
int main(int argc, char **argv) {
bool apr_initialized = false;
apr_pool_t* memoryPool = nullptr;
framework_pt framework = nullptr;
bundle_pt fwBundle = nullptr;
properties_pt properties = nullptr;
int loop_frequency = 100;
std::string autostart_bundles;
try {
// Initialize ROS
ros::init(argc, argv, "hos_osgi_launcher", ros::init_options::AnonymousName | ros::init_options::NoSigintHandler);
// Create public node-handle
ros::NodeHandle rosPublicNodeHandle;
// Create private node-handle
ros::NodeHandle rosPrivateNodeHandle("~");
if (!ros::ok()) {
throw std::runtime_error(boost::format("Could not initialize ROS.").str());
}
ROS_INFO("ROS initialized");
// Retrieve ROS parameter
rosPrivateNodeHandle.getParam("loop_frequency", loop_frequency);
rosPrivateNodeHandle.getParam("autostart_bundles", autostart_bundles);
// Initialize APR and APR memory pool
apr_status_t astatus = apr_initialize();
if (astatus != APR_SUCCESS) {
throw std::runtime_error((boost::format("Could not initialize APR (%1%).") % astatus).str());
}
apr_initialized = true;
astatus = apr_pool_create(&memoryPool, nullptr);
if (astatus != APR_SUCCESS) {
memoryPool = nullptr;
throw std::runtime_error((boost::format("Could not create APR memory pool (%1%).") % astatus).str());
}
ROS_INFO("APR initialized");
// Create celix properties
properties = properties_create();
//properties = properties_load((char*)"config.properties");
if (properties == nullptr) {
throw std::runtime_error(boost::format("Could not create celix properties.").str());
}
properties_store(properties, (char*)"config.properties", nullptr);
// Create and initialize celix framework
celix_status_t cstatus = framework_create(&framework, memoryPool, properties);
if (cstatus != CELIX_SUCCESS) {
framework = nullptr;
throw std::runtime_error((boost::format("Could not create celix framework (%1%).") % cstatus).str());
}
cstatus = fw_init(framework);
if (cstatus != CELIX_SUCCESS) {
framework = nullptr;
throw std::runtime_error((boost::format("Could not initialize celix framework (%1%).") % cstatus).str());
}
ROS_INFO("Celix initialized");
// Get and start framework bundle
cstatus = framework_getFrameworkBundle(framework, &fwBundle);
if (cstatus != CELIX_SUCCESS) {
fwBundle = nullptr;
throw std::runtime_error((boost::format("Could not find framework bundle (%1%).") % cstatus).str());
}
cstatus = bundle_start(fwBundle);
if (cstatus != CELIX_SUCCESS) {
fwBundle = nullptr;
throw std::runtime_error((boost::format("Could not start framework bundle (%1%).") % cstatus).str());
}
ROS_INFO("Framework bundle started");
// Create bundle context
bundle_context_pt context = nullptr;
bundle_getContext(fwBundle, &context);
// Create and register hos-core-service
CoreServiceImpl hosCoreService(rosPublicNodeHandle, rosPrivateNodeHandle);
service_registration_pt reg = nullptr;
bundleContext_registerService(context, (char*)CoreService::SERVICE_NAME, static_cast<CoreService*>(&hosCoreService), nullptr, &reg);
ROS_INFO("HOS core service registered");
// Auto-start bundles
// #### Copied from celix launcher ####
apr_pool_t *pool = nullptr;
cstatus = apr_pool_create(&pool, memoryPool);
if (cstatus == APR_SUCCESS) {
ROS_INFO("Starting auto-start bundles");
char* autoStart;
// ROS param overrides config file
if (!autostart_bundles.empty()) {
autoStart = (char*)autostart_bundles.c_str();
} else {
autoStart = properties_get(properties, (char*)"cosgi.auto.start.1");
}
ROS_INFO_STREAM("Autostart bundles: " << autoStart);
char delims[] = " ";
char *result = nullptr;
linked_list_pt bundles;
array_list_pt installed = nullptr;
bundle_pt bundle = nullptr;
bundle_context_pt context = nullptr;
linked_list_iterator_pt iter = nullptr;
unsigned int i;
if (linkedList_create(&bundles) != CELIX_SUCCESS) {
ROS_ERROR("Could not create linked list.");
exit(1);
}
result = strtok(autoStart, delims);
while (result != nullptr) {
char * location = apr_pstrdup(memoryPool, result);
linkedList_addElement(bundles, location);
result = strtok(nullptr, delims);
}
// First install all bundles
// Afterwards start them
arrayList_create(&installed);
framework_getFrameworkBundle(framework, &bundle);
bundle_getContext(bundle, &context);
iter = linkedListIterator_create(bundles, 0);
while (linkedListIterator_hasNext(iter)) {
bundle_pt current = nullptr;
char *location = (char *) linkedListIterator_next(iter);
if (bundleContext_installBundle(context, location, &current) == CELIX_SUCCESS) {
// Only add bundle if it is installed correctly
arrayList_add(installed, current);
ROS_INFO("Installed bundle %p from %s", current, location);
} else {
ROS_ERROR("Could not install bundle from %s", location);
}
linkedListIterator_remove(iter);
}
linkedListIterator_destroy(iter);
for (i = 0; i < arrayList_size(installed); i++) {
bundle_pt bundle = (bundle_pt) arrayList_get(installed, i);
if (bundle_startWithOptions(bundle, 0) == CELIX_SUCCESS) {
ROS_INFO("Started bundle %p", bundle);
} else {
ROS_ERROR("Could not start bundle %p", bundle);
}
}
arrayList_destroy(installed);
apr_pool_destroy(pool);
// #### End Copied from celix launcher ####
} else {
throw std::runtime_error((boost::format("Could not create temporary APR memory pool.") % cstatus).str());
}
// Send startup finished event
{
StartupFinishedEvent event;
hosCoreService.notifyObservers(&event);
}
// main loop
ROS_INFO("Entering main loop");
signalHandler = [&](int signum) {
hosCoreService.requestShutdown();
};
signal(SIGINT, [](int signum) { signalHandler(signum); });
ros::Rate loop_rate(loop_frequency);
while (ros::ok()) {
ros::spinOnce();
loop_rate.sleep();
}
ROS_INFO("Exiting main loop");
} catch (std::exception &ex) {
std::stringstream ss;
ss << "ERROR: " << ex.what() << std::endl;
ROS_ERROR_STREAM(ss.str());
std::cerr << ss.str();
}
// Deinitialize celix frameork
if (fwBundle != nullptr) {
bundle_stop(fwBundle);
framework_waitForStop(framework);
}
if (framework != nullptr) {
framework_destroy(framework);
}
if (properties != nullptr) {
properties_destroy(properties);
}
ROS_INFO("Celix Framework is shut down");
// Deinitialize APR
if (memoryPool != nullptr) {
apr_pool_destroy(memoryPool);
}
if (apr_initialized) {
apr_terminate();
}
ROS_INFO("APR Framework is shut down");
ROS_INFO("Exiting ...");
return 0;
}