20#include <boost/date_time/posix_time/posix_time_types.hpp>
21#include <boost/date_time/posix_time/time_formatters.hpp>
22#include <boost/date_time/posix_time/time_parsers.hpp>
23#include <boost/interprocess/sync/file_lock.hpp>
46 "<!DOCTYPE oks-schema [\n"
48 " <!ELEMENT oks-schema (info, (include)?, (comments)?, (class)+)>\n"
50 " <!ELEMENT info EMPTY>\n"
52 " name CDATA #IMPLIED\n"
53 " type CDATA #IMPLIED\n"
54 " num-of-items CDATA #REQUIRED\n"
55 " oks-format CDATA #FIXED \"schema\"\n"
56 " oks-version CDATA #REQUIRED\n"
57 " created-by CDATA #IMPLIED\n"
58 " created-on CDATA #IMPLIED\n"
59 " creation-time CDATA #IMPLIED\n"
60 " last-modified-by CDATA #IMPLIED\n"
61 " last-modified-on CDATA #IMPLIED\n"
62 " last-modification-time CDATA #IMPLIED\n"
65 " <!ELEMENT include (file)+>\n"
66 " <!ELEMENT file EMPTY>\n"
68 " path CDATA #REQUIRED\n"
71 " <!ELEMENT comments (comment)+>\n"
72 " <!ELEMENT comment EMPTY>\n"
73 " <!ATTLIST comment\n"
74 " creation-time CDATA #REQUIRED\n"
75 " created-by CDATA #REQUIRED\n"
76 " created-on CDATA #REQUIRED\n"
77 " author CDATA #REQUIRED\n"
78 " text CDATA #REQUIRED\n"
81 " <!ELEMENT class (superclass | attribute | relationship | method)*>\n"
83 " name CDATA #REQUIRED\n"
84 " description CDATA \"\"\n"
85 " is-abstract (yes|no) \"no\"\n"
88 " <!ELEMENT superclass EMPTY>\n"
89 " <!ATTLIST superclass name CDATA #REQUIRED>\n"
91 " <!ELEMENT attribute EMPTY>\n"
92 " <!ATTLIST attribute\n"
93 " name CDATA #REQUIRED\n"
94 " description CDATA \"\"\n"
95 " type (bool|s8|u8|s16|u16|s32|u32|s64|u64|float|double|date|time|string|uid|enum|class) #REQUIRED\n"
97 " format (dec|hex|oct) \"dec\"\n"
98 " is-multi-value (yes|no) \"no\"\n"
99 " init-value CDATA \"\"\n"
100 " is-not-null (yes|no) \"no\"\n"
101 " ordered (yes|no) \"no\"\n"
104 " <!ELEMENT relationship EMPTY>\n"
105 " <!ATTLIST relationship\n"
106 " name CDATA #REQUIRED\n"
107 " description CDATA \"\"\n"
108 " class-type CDATA #REQUIRED\n"
109 " low-cc (zero|one) #REQUIRED\n"
110 " high-cc (one|many) #REQUIRED\n"
111 " is-composite (yes|no) #REQUIRED\n"
112 " is-exclusive (yes|no) #REQUIRED\n"
113 " is-dependent (yes|no) #REQUIRED\n"
114 " ordered (yes|no) \"no\"\n"
117 " <!ELEMENT method (method-implementation*)>\n"
118 " <!ATTLIST method\n"
119 " name CDATA #REQUIRED\n"
120 " description CDATA \"\"\n"
123 " <!ELEMENT method-implementation EMPTY>\n"
124 " <!ATTLIST method-implementation\n"
125 " language CDATA #REQUIRED\n"
126 " prototype CDATA #REQUIRED\n"
133 "<!DOCTYPE oks-data [\n"
135 " <!ELEMENT oks-data (info, (include)?, (comments)?, (obj)+)>\n"
137 " <!ELEMENT info EMPTY>\n"
139 " name CDATA #IMPLIED\n"
140 " type CDATA #IMPLIED\n"
141 " num-of-items CDATA #REQUIRED\n"
142 " oks-format CDATA #FIXED \"data\"\n"
143 " oks-version CDATA #REQUIRED\n"
144 " created-by CDATA #IMPLIED\n"
145 " created-on CDATA #IMPLIED\n"
146 " creation-time CDATA #IMPLIED\n"
147 " last-modified-by CDATA #IMPLIED\n"
148 " last-modified-on CDATA #IMPLIED\n"
149 " last-modification-time CDATA #IMPLIED\n"
152 " <!ELEMENT include (file)*>\n"
153 " <!ELEMENT file EMPTY>\n"
155 " path CDATA #REQUIRED\n"
158 " <!ELEMENT comments (comment)*>\n"
159 " <!ELEMENT comment EMPTY>\n"
160 " <!ATTLIST comment\n"
161 " creation-time CDATA #REQUIRED\n"
162 " created-by CDATA #REQUIRED\n"
163 " created-on CDATA #REQUIRED\n"
164 " author CDATA #REQUIRED\n"
165 " text CDATA #REQUIRED\n"
168 " <!ELEMENT obj (attr | rel)*>\n"
170 " class CDATA #REQUIRED\n"
171 " id CDATA #REQUIRED\n"
173 " <!ELEMENT attr (data)*>\n"
175 " name CDATA #REQUIRED\n"
176 " type (bool|s8|u8|s16|u16|s32|u32|s64|u64|float|double|date|time|string|uid|enum|class|-) \"-\"\n"
179 " <!ELEMENT data EMPTY>\n"
181 " val CDATA #REQUIRED\n"
183 " <!ELEMENT rel (ref)*>\n"
185 " name CDATA #REQUIRED\n"
186 " class CDATA \"\"\n"
189 " <!ELEMENT ref EMPTY>\n"
191 " class CDATA #REQUIRED\n"
192 " id CDATA #REQUIRED\n"
200 return ( std::string(
"Failed to add include \'") + include_name +
"\' to file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
206 return ( std::string(
"Failed to remove include \'") + include_name +
"\' from file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
212 return ( std::string(
"Failed to rename include of \'") + file.get_full_file_name() +
"\' from \'" + from +
"\' to \'" + to +
"\' because:\n" + reason);
218 return ( std::string(
"Failed to add new comment to file \'") + file.get_full_file_name() +
"\' because:\n" + reason);
224 return ( std::string(
"Failed to remove comment created at \'") + creation_time +
"\' from file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
230 return ( std::string(
"Failed to change comment created at \'") + creation_time +
"\' from file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
236 return ( std::string(
"Failed to ") + (lock_action ?
"" :
"un") +
"lock file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
242 return ( std::string(
"Failed to ") + action +
" of file \'" + file.get_full_file_name() +
"\' because:\n" + reason);
248 return ( std::string(
"Failed to compare file \'") + src +
"\' with \'" + dest +
"\' because:\n" + reason);
258 p_number_of_items (0),
260 p_created_by (
OksKernel::get_user_name()),
261 p_creation_time (
boost::posix_time::second_clock::universal_time()),
262 p_created_on (
OksKernel::get_host_name()),
263 p_last_modification_time (p_creation_time),
265 p_is_updated (false),
266 p_is_read_only (true),
268 p_repository_last_modified (0),
269 p_is_on_disk (false),
282 for(std::map<std::string, oks::Comment *>::iterator i =
p_comments.begin(); i !=
p_comments.end(); ++i) {
330 for (
const auto& i : f.p_comments)
348 p_creation_time (
boost::posix_time::not_a_date_time),
349 p_last_modification_time (
boost::posix_time::not_a_date_time),
351 p_is_updated (false),
352 p_is_read_only (true),
354 p_repository_last_modified (0),
359 const char * fname =
"OksFile::OksFile()";
372 const char * tag_start = xmls->get_tag_start();
375 xmls->throw_unexpected_tag(tag_start,
"?xml");
396 Oks::warning_msg(fname) <<
" Unexpected attribute \'" << attr.
name() <<
"\' in the xml file header. Either \'version\' or \'encoding\' is expected.\n";
405 catch (std::exception & e) {
415 const char * dtd = xmls->get_tag();
416 const char dtd_start[] =
"<!DOCTYPE ";
417 if(!strncmp(dtd_start, dtd,
sizeof(dtd_start) - 1)) {
424 catch (std::exception & e) {
434 xmls->store_position();
436 const char * a_tag = xmls->get_tag();
438 const char xml_stylesheet_start[] =
"<?xml-stylesheet";
439 if(strncmp(xml_stylesheet_start, a_tag,
sizeof(xml_stylesheet_start) - 1)) {
440 xmls->restore_position();
446 catch (std::exception & e) {
453 xmls->get_tag_start();
458 catch (std::exception & e) {
466 const char * tag_start = xmls->get_tag_start();
475 catch (std::exception & e) {
480 std::string oks_version;
509 xmls->throw_unexpected_tag(attr.
name(),
"info\'s tags");
516 catch (std::exception & e) {
522 xmls->store_position();
524 bool read_include =
false;
527 const char * tag_start = xmls->get_tag_start();
530 else { xmls->restore_position();
return; }
535 catch (std::exception & e) {
544 const char * tag_start = xmls->get_tag_start();
561 xmls->throw_unexpected_tag(attr.
name(),
"path");
569 catch (std::exception & e) {
579 const char * tag_start = xmls->get_tag_start();
586 std::unique_ptr<oks::Comment> comment(
new oks::Comment() );
587 std::string creation_time;
603 xmls->throw_unexpected_tag(attr.
name(),
"comment\'s tags");
607 comment->validate(creation_time);
610 std::ostringstream text;
611 text <<
"The comment created at \'" << creation_time <<
"\' was already defined in this file";
612 throw std::runtime_error(text.str().c_str());
615 p_comments[creation_time] = comment.release();
621 catch (std::exception & e) {
634 if( creation_time.size() != 15 || creation_time[8] !=
'T' ) {
635 std::ostringstream msg;
636 msg <<
"the creation time \'" << creation_time <<
"\' is not an ISO-8601 date-time";
637 throw std::runtime_error(msg.str().c_str());
647 throw std::runtime_error(
"text is empty");
652 p_created_by (
OksKernel::get_user_name()),
654 p_created_on (
OksKernel::get_host_name()),
661 p_created_by (src.p_created_by),
662 p_author (src.p_author),
663 p_created_on (src.p_created_on),
678 boost::posix_time::ptime
now = boost::posix_time::second_clock::universal_time();
679 std::string creation_time = boost::posix_time::to_iso_string(
now);
682 std::unique_ptr<oks::Comment> comment(
new oks::Comment(text, author) );
689 x = comment.release();
697 catch(std::exception & ex) {
707 std::map<std::string, oks::Comment *>::const_iterator i = p_comments.find(creation_time);
708 return (i == p_comments.end()) ? 0: i->second;
722 std::string saved_author(comment->p_author);
723 std::string saved_text(comment->p_text);
725 comment->p_author = author;
726 comment->p_text = text;
731 catch(std::exception& ex) {
732 comment->p_author = saved_author;
733 comment->p_text = saved_text;
769 const static std::string __data(
"data");
770 const static std::string __schema(
"schema");
774 const char __oks_data[] =
"oks-data";
775 const char __oks_schema[] =
"oks-schema";
777 const char * id(__oks_data);
778 long id_len(
sizeof(__oks_data) - 1);
787 id_len =
sizeof(__oks_schema) - 1;
793 throw std::runtime_error(
"bad oks format");
798 const char __hdr_start[] =
"\n\n<!-- ";
799 const char __hdr_end[] =
" version 2.2 -->\n\n\n";
802 header.append(__hdr_start,
sizeof(__hdr_start) - 1);
803 header.append(
id, id_len);
804 header.append(__hdr_end,
sizeof(__hdr_end) - 1);
805 header.append(dtd, dtd_len);
807 xmls.
put_raw(header.c_str(), header.size());
820 std::string created_c_str;
845 if (!created_c_str.empty())
846 xmls.
put_attribute(
"creation-time",
sizeof(
"creation-time") - 1, created_c_str.c_str());
851 xmls.
put_attribute(
"last-modification-time",
sizeof(
"last-modification-time") - 1, last_modified_c_str.c_str());
886 xmls.
put_attribute(
"creation-time",
sizeof(
"creation-time") - 1, i.first.c_str());
887 xmls.
put_attribute(
"created-by",
sizeof(
"created-by") - 1, i.second->p_created_by.c_str());
888 xmls.
put_attribute(
"created-on",
sizeof(
"created-on") - 1, i.second->p_created_on.c_str());
889 xmls.
put_attribute(
"author",
sizeof(
"author") - 1, i.second->p_author.c_str());
890 xmls.
put_attribute(
"text",
sizeof(
"text") - 1, i.second->p_text.c_str());
900 catch (std::exception& ex)
927 if(
size_t len = s.size()) {
962 const char _prefix_str[] =
".oks-lock-";
967 if(idx == std::string::npos) {
988 lock_file_contents.clear();
993 if(stat(lock_name, &buf) == 0) {
994 std::ifstream f(lock_name);
997 std::getline(f, lock_file_contents);
1001 lock_file_contents =
"unknown [cannot read lock file \'";
1003 lock_file_contents +=
"\']";
1046 std::string lock_file_contents;
1054 if (
lock.try_lock() ==
false)
1056 std::ostringstream text;
1057 text <<
"file is already locked by \"" << lock_file_contents <<
'\"';
1066 catch (
const boost::interprocess::interprocess_exception& ex)
1068 std::ostringstream text;
1069 text <<
"boost::interprocess::unlock() failed: \"" << ex.what() <<
'\"';
1075 Oks::warning_msg(
"OksFile::lock()") <<
"Remove obsolete lock of file \'" <<
p_full_name <<
"\' created by \n\"" << lock_file_contents <<
"\"\n";
1080 std::ostringstream text;
1086 catch (
const boost::interprocess::interprocess_exception& ex)
1088 std::ostringstream text;
1089 text <<
"boost::interprocess::try_lock() failed: \"" << ex.what() <<
'\"';
1103 std::ostringstream text;
1110 boost::posix_time::ptime
now(boost::posix_time::second_clock::universal_time());
1115 catch (std::exception& ex)
1117 std::ostringstream text;
1118 text <<
"failed to write lock file \'" <<
p_lock_file_name <<
"\': " << ex.what();
1128 if (
p_lock->try_lock() ==
false)
1130 throw std::runtime_error(
"file is locked by another process");
1133 catch (
const std::exception& ex)
1135 std::ostringstream text;
1136 text <<
"boost::interprocess::try_lock() failed: \"" << ex.what() <<
'\"';
1152 catch (
const boost::interprocess::interprocess_exception& ex)
1154 std::ostringstream text;
1155 text <<
"boost::interprocess::unlock() failed: \"" << ex.what() <<
'\"';
1164 std::ostringstream text;
1171std::list<std::string>::iterator
1212 catch(std::exception& ex) {
1253 if(old_s == new_s)
return;
1313 s <<
"user \"" << c.get_created_by() <<
"\" (" << c.get_author() <<
")"
1314 <<
" on \"" << c.get_created_on() <<
"\" wrote: \"" << c.get_text() <<
"\"";
1324 " short file name: \'" << f.get_short_file_name() <<
"\'\n"
1325 " full file name: \'" << f.get_full_file_name() <<
"\'\n"
1326 " lock file name: \'" << f.get_lock_file() <<
"\'\n"
1327 " logical name: \'" << f.get_logical_name() <<
"\'\n"
1328 " type: \'" << f.get_type() <<
"\'\n"
1329 " oks format: \'" << f.get_oks_format() <<
"\'\n"
1330 " number of items: " << f.get_number_of_items() <<
"\n"
1331 " created by: " << f.get_created_by() <<
"\n"
1332 " creation time: " << boost::posix_time::to_simple_string(f.get_creation_time()) <<
"\n"
1333 " created on: " << f.get_created_on() <<
"\n"
1334 " last modified by: \'" << f.get_last_modified_by() <<
"\'\n"
1335 " last modification time: " << boost::posix_time::to_simple_string(f.get_last_modification_time()) <<
"\'\n"
1336 " last modified on: " << f.get_last_modified_on() <<
"\'\n"
1337 " is " << (f.is_read_only() ?
"read-only" :
"read-write") <<
"\n"
1338 " is " << (f.is_locked() ?
"" :
"not ") <<
"locked\n"
1339 " is " << (f.is_updated() ?
"" :
"not ") <<
"updated\n";
1342 size_t num_of_includes = f.get_include_files().size();
1344 if (num_of_includes)
1346 s <<
" contains " << num_of_includes <<
" include file(s)";
1347 for (
const auto& i : f.get_include_files())
1348 s <<
" - \'" << i <<
"\'\n";
1352 s <<
" contains no include files\n";
1357 size_t num_of_comments = f.get_comments().size();
1359 if (num_of_comments)
1361 s <<
" contains " << num_of_comments <<
" comment(s)";
1362 for (
const auto& i : f.get_comments())
1363 s <<
" - " << boost::posix_time::to_simple_string(boost::posix_time::from_iso_string(i.first)) <<
": \'" << *i.second <<
"\'\n";
1367 s <<
" contains no comments\n";
1371 s <<
"END of oks file\n";
1402 if(update_repository ==
true ) {
1405 if(!full_repository_name.empty() && stat(full_repository_name.c_str(), &buf) == 0) {
1474 OksFile::Map::const_iterator j = data_files.find(&s);
1475 if(j != data_files.end()) {
1476 if(
out.find(j->second) !=
out.end()) {
continue; }
1477 out.insert(j->second);
1480 j = schema_files.find(&s);
1481 if(j != schema_files.end()) {
1482 if(
out.find(j->second) !=
out.end()) {
continue; }
1483 out.insert(j->second);
1490 j->second->get_all_include_files(kernel,
out);
1501 static const char start_tag[] =
"<info ";
1502 static const char last_tag[] =
"last-modification-time=\"yyyymmddThhmmss\"/>";
1504 const std::string::size_type len = line.length();
1507 ( len < (
sizeof(start_tag) +
sizeof(last_tag)) ) ||
1508 ( line.compare(0,
sizeof(start_tag)-1, start_tag,
sizeof(start_tag)-1) != 0 ) ||
1509 ( line.compare(len -
sizeof(last_tag) + 1, 24, last_tag, 24) != 0 )
1516 std::ifstream f1(file1_name);
1517 std::ifstream f2(file2_name);
1534 if (f1.eof() && f2.eof())
1539 std::getline(f1, line1);
1540 std::getline(f2, line2);
Cannot add include file. Such exception is thrown when OKS cannot add include file.
static std::string fill(const OksFile &file, const std::string &include_name, const std::string &reason) noexcept
Cannot remove include file. Such exception is thrown when OKS cannot remove include file.
static std::string fill(const OksFile &file, const std::string &include_name, const std::string &reason) noexcept
Cannot rename include file. Such exception is thrown when OKS cannot rename include file.
static std::string fill(const OksFile &file, const std::string &from, const std::string &to, const std::string &reason) noexcept
static std::string fill(const OksFile &file, const std::string &action, const std::string &reason) noexcept
static std::string fill(const std::string &src, const std::string &dest, const std::string &reason) noexcept
Cannot add include file. Such exception is thrown when OKS cannot add include file.
static std::string fill(const OksFile &file, bool lock_action, const std::string &reason) noexcept
Provides interface to the OKS XML schema and data files.
static bool compare(const char *file1_name, const char *file2_name)
Compare two files.
static const char xml_schema_file_dtd[]
std::shared_ptr< boost::interprocess::file_lock > p_lock
std::string p_lock_file_name
std::list< std::string >::iterator find_include_file(const std::string &)
static const char xml_comments_tag[]
void unlock()
Unlock OKS file.
void add_include_file(const std::string &name)
Add include file.
time_t p_repository_last_modified
OksFile(const std::string &, const std::string &, const std::string &, const std::string &, OksKernel *)
oks::Comment * get_comment(const std::string &creation_time) noexcept
void get_all_include_files(const OksKernel *kernel, std::set< OksFile * > &out)
Get all include files.
void lock()
Lock OKS file.
void write(OksXmlOutputStream &)
void set_type(const std::string &type)
Set file type.
void init_lock_name() const
bool get_lock_string(std::string &info) const
Return lock status of OKS file and if the file is locked, get information string about process which ...
static const char xml_data_file_dtd[]
std::string make_repository_name() const
static bool p_nolock_mode
std::map< std::string, oks::Comment * > p_comments
boost::posix_time::ptime p_last_modification_time
std::list< std::string > p_list_of_include_files
boost::posix_time::ptime p_creation_time
std::string p_logical_name
const std::string & get_repository_name() const
Get name of file inside repository.
void remove_comment(const std::string &creation_time)
Modify existing comment.
void set_logical_name(const std::string &name)
Set logical name of file.
std::string p_repository_name
std::string p_last_modified_by
void add_comment(const std::string &text, const std::string &author)
Add new comment to file.
void update_status_of_file(bool update_local=true, bool update_repository=true)
Update status of file.
bool is_repository_file() const
Get information about repository, the file belongs to.
void clear_comments() noexcept
static const char xml_file_tag[]
OksFile * check_parent(const OksFile *parent_h)
Set given parent, if this file is not yet included.
const OksFile * p_included_by
static const char xml_comment_tag[]
std::string p_last_modified_on
OksFile & operator=(const OksFile &)
void modify_comment(const std::string &creation_time, const std::string &text, const std::string &author)
void rename_include_file(const std::string &from, const std::string &to)
Rename include file.
static const char xml_file_header[]
FileStatus get_status_of_file() const
Return update status of file.
static const char xml_include_tag[]
void rename(const std::string &short_name, const std::string &full_name)
void remove_include_file(const std::string &name)
Remove include file.
static const char xml_info_tag[]
std::map< const std::string *, OksFile *, SortByName > Map
Provides interface to the OKS kernel.
const std::string & get_user_repository_root() const
Get user OKS repository root.
static std::string & get_host_name()
Get hostname of given process.
static std::string & get_user_name()
Get username of given process.
static bool check_read_only(OksFile *f)
Check if the OKS file is read-only.
const OksFile::Map & data_files() const
Get all data files.
void k_close_dangling_includes()
Close files which lost their parent.
OksFile * k_load_file(const std::string &name, bool bind, const OksFile *parent, OksPipeline *pipeline)
std::string get_file_path(const std::string &path, const OksFile *parent_file=0, bool strict_paths=true) const
Calculates full path to file.
static const std::string & get_repository_root()
Get OKS repository root.
static const char * GetVersion()
Get OKS version. The method returns string containing CVS tag and date of OKS build.
bool get_silence_mode() const
Get status of silence mode. The method returns true, if the silence mode is switched 'On'....
const OksFile::Map & schema_files() const
Get all schema files.
void put_last_tag(const char *, size_t len)
void put_attribute(const char *, size_t len, const char *)
void put_start_tag(const char *, size_t len)
static std::ostream & warning_msg(const char *)
virtual const char * what() const noexcept
#define TLOG_DEBUG(lvl,...)
bool cmp_str8(const char *s1, const char s2[9])
const std::string strerror(int error)
Convert C error number to string.
bool cmp_str1(const char *s1, const char s2[2])
bool cmp_str4(const char *s1, const char s2[5])
bool cmp_str6(const char *s1, const char s2[7])
bool cmp_str10(const char *s1, const char s2[11])
static bool is_not_info(const std::string &line)
bool cmp_str9(const char *s1, const char s2[10])
boost::posix_time::ptime str2time(const char *value, size_t len, const char *file_name=nullptr)
std::ostream & operator<<(std::ostream &s, const oks::exception &ex)
bool cmp_str13(const char *s1, const char s2[14])
bool cmp_str16(const char *s1, const char s2[17])
bool cmp_str15(const char *s1, const char s2[16])
bool cmp_str11(const char *s1, const char s2[12])
bool cmp_str12(const char *s1, const char s2[13])
bool cmp_str7(const char *s1, const char s2[8])
FELIX Initialization std::string initerror FELIX queue timed out