37 #include <QWaitCondition> 38 #include <QThreadStorage> 40 #include <QCoreApplication> 42 #include <QMetaObject> 49 #include <QStringList> 57 class ArnThreadComStorage :
public QThreadStorage<ArnThreadCom*> {};
61 ArnThreadComStorage* ArnThreadCom::getThreadComStorage()
63 static ArnThreadComStorage threadComStorage;
65 return &threadComStorage;
69 ArnThreadCom* ArnThreadCom::getThreadCom()
71 ArnThreadComStorage* threadComStorage = getThreadComStorage();
72 if (!threadComStorage->hasLocalData()) {
73 threadComStorage->setLocalData(
new ArnThreadCom);
75 return threadComStorage->localData();
79 ArnThreadComCaller::ArnThreadComCaller()
81 _p = ArnThreadCom::getThreadCom();
87 ArnThreadComCaller::~ArnThreadComCaller()
94 void ArnThreadComCaller::waitCommandEnd()
96 _p->_commandEnd.wait( &_p->_mutex);
100 ArnThreadCom* ArnThreadComCaller::p()
106 ArnThreadComProxyLock::ArnThreadComProxyLock( ArnThreadCom* threadCom) :
115 ArnThreadComProxyLock::~ArnThreadComProxyLock()
117 _p->_commandEnd.wakeOne();
125 int ArnM::_countFolder(0);
126 int ArnM::_countLeaf(0);
127 QAtomicInt ArnM::_countRef(0);
133 ArnLink::arnM(
this);
138 _countFolderLink = arnNullptr;
139 _countLeafLink = arnNullptr;
140 _countRefLink = arnNullptr;
141 _timerMetrics =
new QTimer(
this);
143 _defaultIgnoreSameValue =
false;
144 _skipLocalSysLoading =
false;
145 _isThreadedApp =
false;
146 _mainThread = QThread::currentThread();
149 #if QT_VERSION >= 0x050a00 151 qsrand( uint(QDateTime::currentMSecsSinceEpoch()));
154 qRegisterMetaType<ArnThreadCom*>();
155 qRegisterMetaType<ArnLinkHandle>(
"ArnLinkHandle");
156 qRegisterMetaType<QVariant>(
"QVariant");
159 _consoleError =
true;
160 _errorLogger = arnNullptr;
185 qDebug() <<
"====== Arn Sizes ======";
186 qDebug() <<
"QObject: " <<
sizeof(QObject);
187 qDebug() <<
" QScopedPtr: " <<
sizeof(QScopedPointer<QObjectData>);
188 qDebug() <<
" QObjectData: " <<
sizeof(QObjectData);
189 qDebug() <<
" QObjectList: " <<
sizeof(QObjectList);
190 qDebug() <<
"QString: " <<
sizeof(QString);
191 qDebug() <<
"QVariant: " <<
sizeof(QVariant);
192 qDebug() <<
"ArnLink: " <<
sizeof(ArnLink);
193 qDebug() <<
" AnrLinkList: " <<
sizeof(
ArnLinkList);
194 qDebug() <<
"ArnItemB: " <<
sizeof(
ArnItemB);
195 qDebug() <<
"ArnItem: " <<
sizeof(
ArnItem);
198 qDebug() <<
"=======================";
201 QTimer::singleShot( 0,
this, SLOT(postSetup()));
205 void ArnM::postSetup()
210 #if defined(ARNLIB_COMPILE) 213 setValue( legalPath +
"ArnLib_LGPL/value", lgplStat);
214 setValue( legalPath +
"ArnLib_LGPL/set",
"0=Seemes_Ok 1=Not_Ok,_statically_linked_to_application");
220 _timerMetrics->start( 5000);
221 connect( _timerMetrics, SIGNAL(timeout()),
this, SLOT(onTimerMetrics()));
224 if (_skipLocalSysLoading)
return;
227 QString licensesPath = legalPath +
"Licenses/";
249 int retVal = link->toInt();
266 ARNREAL retVal = link->toReal();
275 if (!link)
return QString();
277 QString retVal = link->toString();
286 if (!link)
return QByteArray();
288 QByteArray retVal = link->toByteArray();
297 if (!link)
return QVariant();
299 QVariant retVal = link->toVariant();
305 void ArnM::itemsProxy( ArnThreadCom* threadCom,
const QString& path)
307 ArnThreadComProxyLock proxyLock( threadCom);
310 threadCom->_retStringList = itemsMain( path);
318 return itemsMain( path);
321 ArnThreadComCaller threadCom;
323 threadCom.p()->_retStringList.clear();
325 QMetaObject::invokeMethod( &
instance(),
327 Qt::QueuedConnection,
328 Q_ARG( ArnThreadCom*, threadCom.p()),
329 Q_ARG( QString, path));
330 threadCom.waitCommandEnd();
331 QStringList retStringList = threadCom.p()->_retStringList;
332 threadCom.p()->_retStringList.clear();
333 if (
Arn::debugThreading) qDebug() <<
"items-thread: end stringList=" << threadCom.p()->_retStringList;
335 return retStringList;
340 QStringList ArnM::itemsMain(
const ArnLink *parent)
343 qWarning() <<
"items: empty path";
344 return QStringList();
348 QStringList childnames;
350 for (
int i = 0; i < children.size(); i++) {
351 ArnLink* childLink = children.at(i);
353 if (childLink != arnNullptr) {
354 if (childLink->isFolder()) {
355 childnames << childLink->objectName() +
"/";
358 childnames << childLink->objectName();
367 QStringList ArnM::itemsMain(
const QString& path)
370 QStringList retVal = itemsMain( link);
381 QThread* mainThread =
instance()._mainThread;
383 qDebug() <<
"isMainThread: appThr=" << QCoreApplication::instance()->thread()
384 <<
" mainThr=" << mainThread
385 <<
" curThr=" << QThread::currentThread()
386 <<
" ArnMThr=" <<
instance().thread();
388 if (QThread::currentThread() != mainThread) {
405 ArnLink* link = ArnM::link( path, flags.
SilentError);
407 if (!link)
return false;
418 if (!link)
return false;
430 if (!link)
return false;
443 link->setAtomicOpProvider(
true);
455 if (!link)
return false;
456 bool retVal = link->isAtomicOpProvider();
467 link->setValue( value);
478 link->setValue( value);
489 link->setValue( value);
500 link->setValue( value);
506 void ArnM::setValue(
const QString& path,
const QVariant& value,
const char* typeName)
512 if (typeName && *typeName)
513 valueType = QMetaType::type( typeName);
516 link->setValue( value);
518 QVariant val = value;
519 if (val.convert( QVariant::Type( valueType))) {
520 link->setValue( val);
523 errorLog( QString(tr(
"Can't convert variant', Path:")) + path +
" type=" + typeName,
534 setValue( path, QString::fromUtf8( value));
540 bool isText = coding.is( coding.
Text);
542 QFile file( fileName);
543 if (!file.open( QIODevice::ReadOnly))
return false;
544 file.setTextModeEnabled( isText);
545 QByteArray data = file.readAll();
548 ArnM::setValue( path, QString::fromUtf8( data.constData(), data.size()));
567 bool isText = coding.is( coding.
Text);
569 QFile file( fileName);
570 if (!file.open( QIODevice::WriteOnly))
return false;
571 file.setTextModeEnabled( isText);
574 return (file.write( data) >= 0);
580 ArnLink* ArnM::root()
586 void ArnM::linkProxy( ArnThreadCom* threadCom,
const QString& path,
int flagValue,
int syncMode)
588 ArnThreadComProxyLock proxyLock( threadCom);
591 threadCom->_retObj = linkMain( path, Arn::LinkFlags::fromInt( flagValue),
592 Arn::ObjectSyncMode::fromInt( syncMode));
599 if (
isMainThread())
return linkMain( path, flags, syncMode);
600 else return linkThread( path, flags, syncMode);
609 ArnThreadComCaller threadCom;
611 threadCom.p()->_retObj = arnNullptr;
613 QMetaObject::invokeMethod( &
instance(),
615 Qt::QueuedConnection,
616 Q_ARG( ArnThreadCom*, threadCom.p()),
617 Q_ARG( QString, path), Q_ARG(
int, flags.toInt()),
618 Q_ARG(
int, syncMode.toInt()));
620 threadCom.waitCommandEnd();
621 ArnLink* retLink =
static_cast<ArnLink*
>( threadCom.p()->_retObj);
622 if (retLink)
if (
Arn::debugThreading) qDebug() <<
"link-thread: end path=" << retLink->linkPath();
632 if (pathNorm.endsWith(
"/")) {
634 pathNorm.resize( pathNorm.size() - 1);
637 ArnLink* currentLink = root();
638 QStringList pathlist = pathNorm.split(
"/");
639 QString growPath =
"/";
640 int pathListSize = pathlist.size();
642 for (
int i = 1; i < pathListSize; ++i) {
644 subFlags.f = flags.f | flags.flagIf( i < pathListSize - 1, flags.
Folder);
645 subFlags.set( flags.
LastLink, i == pathListSize - 1);
646 QString subPath = pathlist.at(i);
649 if (subFlags.is( subFlags.
Folder))
652 currentLink = ArnM::linkMain( growPath, currentLink, subPath, subFlags, syncMode);
653 if (currentLink == arnNullptr) {
663 ArnLink* ArnM::linkMain(
const QString& path, ArnLink *parent,
const QString& name,
Arn::LinkFlags flags,
668 errorLog( QString(tr(
"Can't handle SubItem:")) + name,
674 QString nameNorm = name;
675 if (nameNorm.endsWith(
"/")) {
677 nameNorm.resize( nameNorm.size() - 1);
681 child = getRawLink( parent, nameNorm, flags);
686 if (!flags.is( flags.
Folder)
687 && nameNorm.endsWith(
'!')
690 addTwinMain( path, child, syncMode, flags);
693 child->setupEnd( path, syncMode, flags);
698 ArnLink* ArnM::addTwin(
const QString& path, ArnLink* link,
701 if (!link)
return arnNullptr;
704 ArnLink* retLink = addTwinMain( path, link, syncMode, flags);
705 if (retLink) retLink->ref();
710 if (!link->twinLink()) {
711 ArnLink* parent = link->parent();
712 QString
twinPath = parent->linkPath() + link->twinName();
717 return link->twinLink();
721 ArnLink* ArnM::addTwinMain(
const QString& path, ArnLink* link,
728 if (!link->twinLink()) {
729 QString twinName = link->twinName();
730 ArnLink* parent = link->parent();
732 twinLink = getRawLink( parent, twinName, flags.f | flags.
CreateAllowed);
735 bool isThreaded =
false;
736 if (link->isThreaded()
737 || twinLink->isThreaded()
741 twinLink->setThreaded();
745 twinLink->_twin = link;
746 link->_twin = twinLink;
753 link->doModeChanged();
757 return link->twinLink();
762 ArnLink* ArnM::getRawLink( ArnLink *parent,
const QString& name,
Arn::LinkFlags flags)
767 errorLog( QString(tr(
"Can't handle SubItem:")) + name,
772 if (parent->isRetired()) {
774 errorLog( QString(tr(
"parent:")) + parent->linkPath(),
780 ArnLink *child = parent->findLink( name);
782 if (child == arnNullptr) {
786 errorLog( QString(tr(
"Path:")) + parent->linkPath() +
787 QString(tr(
" Item:")) + name,
792 if (name.isEmpty() && !flags.is( flags.
Folder)) {
795 errorLog( QString(tr(
"Empty leaf name, Path:")) + parent->linkPath(),
800 if (name.endsWith(
"!!")) {
803 errorLog( QString(tr(
"Invalid name, Path:")) + parent->linkPath(),
809 child =
new ArnLink( parent, name, flags);
810 if (flags.is( flags.
Folder))
816 if (child->isRetired()) {
818 errorLog( QString(tr(
"child:")) + child->linkPath(),
823 if (child->isFolder() != flags.is( flags.
Folder)) {
827 if (flags.is( flags.
Folder)) {
828 errorLog( QString(tr(
"Is not folder, Path:")) + child->linkPath(),
832 errorLog( QString(tr(
"Is folder, Path:")) + child->linkPath(),
842 child->setThreaded();
844 child->_twin->setThreaded();
859 destroyLinkMain( link, link, isGlobal);
872 ArnLink* link = ArnM::link( path, flags.
SilentError);
876 destroyLinkMain( link, link, isGlobal);
883 QMetaObject::invokeMethod( &
instance(),
885 Qt::QueuedConnection,
886 Q_ARG( QString, path),
887 Q_ARG(
bool, isGlobal));
892 void ArnM::destroyLinkMain( ArnLink* link, ArnLink* startLink,
bool isGlobal)
895 if (link->isRetired())
return;
898 ArnLink::RetireType rt;
899 rt = startLink->isFolder() ? rt.Tree
900 : isGlobal ? rt.LeafGlobal
902 ArnLink* twin = link->twinLink();
903 link->setRetired( rt);
905 twin->setRetired( rt);
909 for (
int i = 0; i < link->children().size();) {
910 ArnLink* dLink = link->children().at( i);
911 if (dLink->isRetired())
914 destroyLinkMain( dLink, startLink, isGlobal);
918 link->doRetired( startLink, isGlobal);
920 twin->doRetired( startLink, isGlobal);
926 void ArnM::doZeroRefLink( ArnLink* link)
930 if (!link->isLastZeroRef())
return;
932 link->setRefCount( -1);
935 while (link->isRetired() &&
936 link->refCount() < 0 &&
937 link->children().size() == 0) {
938 ArnLink* parent = link->parent();
941 if (link->isFolder())
945 if (link->isBiDirMode())
955 void ArnM::changeRefCounter(
int step)
957 _countRef.fetchAndAddRelaxed( step);
963 return QString(tr(
"Arn"));
969 return QByteArray(
"Name=ArnLib Ver=" ARNLIBVER
" Date=" ARNBUILDDATE
" Time=" ARNBUILDTIME);
981 QMetaObject::invokeMethod( errLog,
983 Qt::QueuedConnection,
987 for (
int code = 0; code <
instance()._errTextTab.size(); ++code) {
988 QMetaObject::invokeMethod( errLog,
990 Qt::QueuedConnection,
991 Q_ARG( uint, uint( code)),
992 Q_ARG( QString,
instance()._errTextTab.at( code)));
997 errLog, SLOT(add(QString,uint,
void*)));
1001 void ArnM::onTimerMetrics()
1003 _countFolderLink->setValue( _countFolder);
1004 _countLeafLink->setValue( _countLeaf);
1005 _countRefLink->setValue( _countRef);
1009 void ArnM::customEvent( QEvent* ev)
1030 if (err.e < err.
Err_N) {
1031 errTextSum +=
instance()._errTextTab.at( err.e);
1034 errTextSum += QString(tr(
"Error ")) + QString::number( err.e);
1036 if (!errTextSum.isEmpty()) errTextSum +=
": ";
1038 errTextSum += errText;
1041 std::cerr << errTextSum.toUtf8().constData()
1042 << (QString(tr(
" In ")) +
errorSysName()).toUtf8().constData() << std::endl;
1050 static ArnM instance_;
1058 instance()._consoleError = isConsoleError;
1064 instance()._defaultIgnoreSameValue = isIgnore;
1070 return instance()._defaultIgnoreSameValue;
1076 return _skipLocalSysLoading;
Data type of an Arn Data Object
static int baseType(int setVal=-1)
static bool isMainThread()
static bool isFolder(const QString &path)
static QByteArray info()
Give information about this library.
static void setValue(const QString &path, int value)
Assign an integer to an Arn Data Object at path
static bool isThreadedApp()
const QString resourceArnRoot
static void setConsoleError(bool isConsoleError)
static bool exist(const QString &path)
static void setAtomicOpProvider(const QString &path)
Set this Arn Data Object as Atomic Operator Provider
static int valueInt(const QString &path)
Get the value of Arn Data Object at path
QString fullPath(const QString &path)
Convert a path to a full absolute path.
static ARNREAL valueReal(const QString &path)
Get the value of Arn Data Object at path
static bool loadFromFile(const QString &path, const QString &fileName, Arn::Coding coding)
Load from a file to an Arn Data Object at path
const QString pathLocalSys
static bool loadFromDirRoot(const QString &path, const QDir &dirRoot, Arn::Coding coding)
Load relative a directory root to an Arn Data Object at path
static QString valueString(const QString &path)
Get the value of Arn Data Object at path
static void setupErrorlog(QObject *errLog)
Only on path, no effect on discrete names. "/test/value" ==> "test/value".
static bool saveToFile(const QString &path, const QString &fileName, Arn::Coding coding)
Save to a file from an Arn Data Object at path
static double valueDouble(const QString &path)
Get the value of Arn Data Object at path
static QStringList items(const QString &path)
Get the childrens of the folder at path
void setSkipLocalSysLoading(bool skipLocalSysLoading)
Set mode skip "/Local/Sys/" loading.
Text coding, can be any character set.
Link flags when accessing an Arn Data Object
static bool isLeaf(const QString &path)
static QVariant valueVariant(const QString &path)
Get the value of Arn Data Object at path
static QByteArray valueByteArray(const QString &path)
Get the value of Arn Data Object at path
QString convertPath(const QString &path, Arn::NameF nameF)
Convert a path to a specific format.
static void setDefaultIgnoreSameValue(bool isIgnore=true)
Set system default skipping of equal assignment value.
QString twinPath(const QString &path)
Get the bidirectional twin to a given path
void errorLogSig(const QString &errText, uint errCode, void *reference)
static bool defaultIgnoreSameValue()
bool skipLocalSysLoading() const
Return mode skip "/Local/Sys/" loading.
Base class handle for an Arn Data Object.
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
static void destroyLink(const QString &path, bool isGlobal=true)
Destroy the Arn Data Object at path
QList< ArnLink * > ArnLinkList
ArnLink * arnLink() const
bool isFolderPath(const QString &path)
Test if path is a folder path
static QString errorSysName()
static bool isAtomicOpProvider(const QString &path)
Handle for an Arn Data Object.