Sophie

Sophie

distrib > Mandriva > mes5 > x86_64 > by-pkgid > d95a60318da7f02f1a7e4951e7c662ea > files > 1

soprano-2.1.1-3mdv2009.0.src.rpm

Index: test/asyncresultwaiter.cpp
===================================================================
--- test/asyncresultwaiter.cpp	(.../tags/soprano/2.1.1)	(revision 0)
+++ test/asyncresultwaiter.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,65 @@
+/*
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <strueg@mandriva.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "asyncresultwaiter.h"
+#include "asyncmodel.h"
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QVariant>
+
+
+class Soprano::Util::AsyncResultWaiter::Private
+{
+public:
+    QEventLoop loop;
+    QVariant value;
+};
+
+
+Soprano::Util::AsyncResultWaiter::AsyncResultWaiter()
+    : d( new Private() )
+{
+}
+
+
+Soprano::Util::AsyncResultWaiter::~AsyncResultWaiter()
+{
+    delete d;
+}
+
+
+void Soprano::Util::AsyncResultWaiter::slotResultReady( AsyncResult* result )
+{
+    d->value = result->value();
+    d->loop.exit();
+}
+
+
+QVariant Soprano::Util::AsyncResultWaiter::waitForResult( AsyncResult* result )
+{
+    AsyncResultWaiter waiter;
+    connect( result, SIGNAL( resultReady( Soprano::Util::AsyncResult* ) ),
+             &waiter, SLOT( slotResultReady( Soprano::Util::AsyncResult* ) ) );
+    waiter.d->loop.exec();
+    return waiter.d->value;
+}
+
+#include "asyncresultwaiter.moc"
Index: test/asyncmodeltest.cpp
===================================================================
--- test/asyncmodeltest.cpp	(.../tags/soprano/2.1.1)	(revision 0)
+++ test/asyncmodeltest.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,226 @@
+/*
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <strueg@mandriva.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "asyncmodeltest.h"
+#include "asyncresultwaiter.h"
+#include "soprano.h"
+
+#include <QtCore/QPointer>
+#include <QtCore/QUuid>
+
+#include <QtTest/QTest>
+
+using namespace Soprano;
+using namespace Soprano::Util;
+
+Q_DECLARE_METATYPE( Soprano::Error::ErrorCode )
+Q_DECLARE_METATYPE( Soprano::StatementIterator )
+Q_DECLARE_METATYPE( Soprano::QueryResultIterator )
+
+
+static QUrl createRandomUri()
+{
+    // FIXME: check if the uri already exists
+    QString uid = QUuid::createUuid().toString();
+    uid = uid.mid( 1, uid.length()-2 );
+    return QUrl( "http://soprano.org/test#" + uid );
+}
+
+
+static QList<Statement> createTestData( const Statement& s, int num )
+{
+    QList<Statement> sl;
+    for( int i = 0; i < num; ++i ) {
+        sl.append( Statement( s.subject().isEmpty() ? Node( createRandomUri() ) : s.subject(),
+                              s.predicate().isEmpty() ? Node( createRandomUri() ) : s.predicate(),
+                              s.object().isEmpty() ? Node( createRandomUri() ) : s.object(),
+                              s.context() ) );
+    }
+    return sl;
+}
+
+
+void AsyncModelTest::initTestCase()
+{
+    Soprano::Model* model = Soprano::createModel();
+    QVERIFY( model );
+    m_asyncModel = new Soprano::Util::AsyncModel( model );
+    m_asyncModel->setMode( Soprano::Util::AsyncModel::MultiThreaded );
+
+
+    Node subject1( QUrl("http://soprano.sf.net#init:test1") );
+    Node subject2( QUrl("http://soprano.sf.net#init:test2") );
+
+    Node predicate1( QUrl( "http://soprano.sf.net#predicate1" ) );
+    Node predicate2( QUrl( "http://soprano.sf.net#predicate2" ) );
+
+    Node object1( LiteralValue( "Literal value1" ) );
+    Node object2( LiteralValue( "Literal value2" ) );
+
+    m_s1 = Soprano::Statement( subject1, predicate1, object1 );
+    m_s2 = Soprano::Statement( subject2, predicate2, object2 );
+}
+
+
+void AsyncModelTest::testAddStatement()
+{
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->addStatementAsync( m_s1 ) );
+    QVERIFY( result.value<Soprano::Error::ErrorCode>() == Soprano::Error::ErrorNone );
+    QVERIFY( m_asyncModel->containsStatement( m_s1 ) );
+
+    QVERIFY( AsyncResultWaiter::waitForResult( m_asyncModel->containsStatementAsync( m_s1 ) ).toBool() );
+}
+
+
+void AsyncModelTest::testCountStatements()
+{
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->statementCountAsync() );
+    int c = result.toInt();
+    if ( c != -1 ) {
+        QCOMPARE( c, 1 );
+    }
+}
+
+
+void AsyncModelTest::testListStatements()
+{
+    m_asyncModel->removeAllStatements();
+    m_asyncModel->addStatement( m_s1 );
+    m_asyncModel->addStatement( m_s2 );
+
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->listStatementsAsync() );
+    QVERIFY( result.userType() == qMetaTypeId<Soprano::StatementIterator>() );
+    Soprano::StatementIterator it = result.value<Soprano::StatementIterator>();
+    QVERIFY( it.next() );
+    QVERIFY( *it == m_s1 || *it == m_s2 );
+    QVERIFY( it.next() );
+    QVERIFY( *it == m_s1 || *it == m_s2 );
+    QVERIFY( !it.next() );
+}
+
+
+void AsyncModelTest::testSelectQuery()
+{
+    m_asyncModel->removeAllStatements();
+    m_asyncModel->addStatement( m_s1 );
+    m_asyncModel->addStatement( m_s2 );
+
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->executeQueryAsync( "select ?r ?p ?o where { ?r ?p ?o . }",  Query::QueryLanguageSparql ) );
+    QVERIFY( result.userType() == qMetaTypeId<Soprano::QueryResultIterator>() );
+    Soprano::QueryResultIterator it = result.value<Soprano::QueryResultIterator>();
+    QVERIFY( !it.isGraph() );
+    QVERIFY( !it.isBool() );
+    QVERIFY( it.isBinding() );
+    QVERIFY( it.next() );
+    QCOMPARE( it.bindingCount(), 3 );
+    QCOMPARE( it.bindingNames()[0], QString( "r" ) );
+    QCOMPARE( it.bindingNames()[1], QString( "p" ) );
+    QCOMPARE( it.bindingNames()[2], QString( "o" ) );
+    QVERIFY( it.binding( 0 ) == m_s1.subject() || it.binding(0) == m_s2.subject() );
+    QVERIFY( it.next() );
+    QCOMPARE( it.bindingCount(), 3 );
+    QVERIFY( it.binding(0) == m_s1.subject() || it.binding(0) == m_s2.subject() );
+    QVERIFY( !it.next() );
+}
+
+
+void AsyncModelTest::testConstructQuery()
+{
+    m_asyncModel->removeAllStatements();
+    m_asyncModel->addStatement( m_s1 );
+    m_asyncModel->addStatement( m_s2 );
+
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->executeQueryAsync( "construct { ?r ?p ?o } where { ?r ?p ?o . }",  Query::QueryLanguageSparql ) );
+    QVERIFY( result.userType() == qMetaTypeId<Soprano::QueryResultIterator>() );
+    Soprano::QueryResultIterator it = result.value<Soprano::QueryResultIterator>();
+    QVERIFY( it.isGraph() );
+    QVERIFY( !it.isBool() );
+    QVERIFY( !it.isBinding() );
+    QVERIFY( it.next() );
+    QVERIFY( it.currentStatement() == m_s1 || it.currentStatement() == m_s2 );
+    QVERIFY( it.next() );
+    QVERIFY( it.currentStatement() == m_s1 || it.currentStatement() == m_s2 );
+    QVERIFY( !it.next() );
+}
+
+
+void AsyncModelTest::testAskQuery()
+{
+    m_asyncModel->removeAllStatements();
+    m_asyncModel->addStatement( m_s1 );
+
+    QVariant result = AsyncResultWaiter::waitForResult( m_asyncModel->executeQueryAsync( "ask where { ?r ?p ?o . }",  Query::QueryLanguageSparql ) );
+    QVERIFY( result.userType() == qMetaTypeId<Soprano::QueryResultIterator>() );
+    Soprano::QueryResultIterator it = result.value<Soprano::QueryResultIterator>();
+    QVERIFY( it.isBool() );
+    QVERIFY( !it.isGraph() );
+    QVERIFY( !it.isBinding() );
+    QVERIFY( it.boolValue() );
+}
+
+
+void AsyncModelTest::testListAndAdd()
+{
+    // perform a list and then an add. The add should be postponed until after the list
+    Soprano::StatementIterator it = AsyncResultWaiter::waitForResult( m_asyncModel->listStatementsAsync() ).value<Soprano::StatementIterator>();
+    QPointer<AsyncResult> addResult = m_asyncModel->addStatementAsync( m_s2 );
+    QVERIFY( it.next() );
+    it.close();
+    QVERIFY( addResult );
+    QVERIFY( AsyncResultWaiter::waitForResult( addResult ).value<Soprano::Error::ErrorCode>() == Soprano::Error::ErrorNone );
+}
+
+
+void AsyncModelTest::testMultiAdd()
+{
+    m_asyncModel->removeAllStatements();
+
+    // start a bunch of commands...
+    QList<QPointer<AsyncResult> > results;
+    QList<Statement> data = createTestData( Statement(), 20 );
+    foreach( const Statement& s, data ) {
+        results.append( m_asyncModel->addStatementAsync( s ) );
+    }
+
+    // ...wait for them...
+    foreach( QPointer<AsyncResult> r, results ) {
+        qApp->processEvents();
+        if ( r )
+            AsyncResultWaiter::waitForResult( r );
+    }
+
+    // ...and then check for all the statements
+    foreach( const Statement& s, data ) {
+        QVERIFY( m_asyncModel->containsStatement( s ) );
+    }
+
+
+    Soprano::StatementIterator it = AsyncResultWaiter::waitForResult( m_asyncModel->listStatementsAsync() ).value<Soprano::StatementIterator>();
+    int cnt = 0;
+    while ( it.next() )
+        ++cnt;
+    QCOMPARE( cnt, data.count() );
+}
+
+
+QTEST_MAIN( AsyncModelTest )
+
+#include "asyncmodeltest.moc"
Index: test/asyncresultwaiter.h
===================================================================
--- test/asyncresultwaiter.h	(.../tags/soprano/2.1.1)	(revision 0)
+++ test/asyncresultwaiter.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,54 @@
+/*
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <strueg@mandriva.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _SOPRANO_ASYNC_RESULT_WAITER_H_
+#define _SOPRANO_ASYNC_RESULT_WAITER_H_
+
+#include <QtCore/QObject>
+
+class QVariant;
+
+namespace Soprano {
+    namespace Util {
+
+        class AsyncResult;
+
+        class AsyncResultWaiter : public QObject
+        {
+            Q_OBJECT
+
+        public:
+            ~AsyncResultWaiter();
+
+            static QVariant waitForResult( AsyncResult* result );
+
+        private Q_SLOTS:
+            void slotResultReady( Soprano::Util::AsyncResult* );
+
+        private:
+            AsyncResultWaiter();
+
+            class Private;
+            Private* const d;
+        };
+    }
+}
+#endif
Index: test/asyncmodeltest.h
===================================================================
--- test/asyncmodeltest.h	(.../tags/soprano/2.1.1)	(revision 0)
+++ test/asyncmodeltest.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,52 @@
+/* 
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <strueg@mandriva.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SOPRANO_ASYNC_MODEL_TEST_H
+#define SOPRANO_ASYNC_MODEL_TEST_H
+
+#include <QtCore/QObject>
+
+#include "asyncmodel.h"
+#include "statement.h"
+
+
+class AsyncModelTest: public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase();
+    void testAddStatement();
+    void testCountStatements();
+    void testListStatements();
+    void testSelectQuery();
+    void testConstructQuery();
+    void testAskQuery();
+    void testListAndAdd();
+    void testMultiAdd();
+
+private:
+    Soprano::Util::AsyncModel* m_asyncModel;
+    Soprano::Statement m_s1;
+    Soprano::Statement m_s2;
+};
+
+#endif
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt	(.../tags/soprano/2.1.1)	(revision 846898)
+++ test/CMakeLists.txt	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -101,7 +101,7 @@
 #target_link_libraries(queryapitest soprano ${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY})
 #add_test(queryapitest ${EXECUTABLE_OUTPUT_PATH}/queryapitest)
 
-if(JNI_1_6_FOUND)
+if(JNI_1_4_FOUND)
   # Sesame2 model tests
   qt4_automoc(sesame2backendtest sesame2backendtest.cpp)
   add_executable(sesame2backendtest sesame2backendtest.cpp)
@@ -112,7 +112,7 @@
   add_executable(sesame2multithreadtest sesame2multithreadtest.cpp)
   target_link_libraries(sesame2multithreadtest soprano multithreadingtest ${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY})
   add_test(sesame2multithreadtest ${EXECUTABLE_OUTPUT_PATH}/sesame2multithreadtest)
-endif(JNI_1_6_FOUND)
+endif(JNI_1_4_FOUND)
 
 # parser test
 qt4_automoc(parsertest parsertest.cpp)
@@ -191,3 +191,9 @@
 qt4_automoc(serveroperatortest.cpp)
 add_executable(serveroperatortest serveroperatortest.cpp ../server/datastream.cpp)
 target_link_libraries(serveroperatortest soprano ${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY})
+
+# async model test
+set(asyncmodeltest_SRC asyncresultwaiter.cpp asyncmodeltest.cpp)
+qt4_automoc(${asyncmodeltest_SRC})
+add_executable(asyncmodeltest ${asyncmodeltest_SRC})
+target_link_libraries(asyncmodeltest soprano ${QT_QTCORE_LIBRARY} ${QT_QTTEST_LIBRARY})
Index: test/parsertest.cpp
===================================================================
--- test/parsertest.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ test/parsertest.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -84,6 +84,14 @@
                 QVERIFY( all.contains( s ) );
             }
 
+            QFile file( filename );
+            file.open( QIODevice::ReadOnly );
+            QByteArray data = file.readAll();
+            QTextStream bs( data );
+            it = parser->parseStream( bs, QUrl("http://soprano.sf.net/testdata/"), serialization );
+            all = it.allStatements();
+            QCOMPARE( all.count(), testStatements.count() );
+
             // test serialization
 //             it = SimpleStatementIterator( testStatements );
 //             QString serializedData;
Index: soprano/iterator.h
===================================================================
--- soprano/iterator.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/iterator.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -65,8 +65,10 @@
      * This can either be achieved by deleting the iterator, finishing it (next() does return \p false),
      * or calling close(). Before that other operations on the Model may block.
      *
-     * Iterators are not thread-safe. Two threads using the same iterator at the same time may result
-     * in undefined behaviour and even crashes.
+     * Iterators are not thread-safe. Two threads using the same iterator may result
+     * in undefined behaviour and even crashes. An iterator needs to be closed by the
+     * same thread that opened it (except if the iterator contains special code to handle such
+     * a situation.)
      *
      * \warning Be aware that iterators in Soprano are shared objects which means
      * that copies of one iterator object work on the same data.
Index: soprano/global.cpp
===================================================================
--- soprano/global.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/global.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -58,7 +58,7 @@
 }
 
 
-Soprano::Model* Soprano::createModel( const QList<BackendSetting>& settings )
+Soprano::Model* Soprano::createModel( const BackendSettings& settings )
 {
     initSoprano();
 
Index: soprano/filtermodel.h
===================================================================
--- soprano/filtermodel.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/filtermodel.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -178,6 +178,13 @@
         virtual Node createBlankNode();
         //@}
 
+        using Model::addStatement;
+        using Model::removeStatement;
+        using Model::removeAllStatements;
+        using Model::listStatements;
+        using Model::containsStatement;
+        using Model::containsAnyStatement;
+
     protected:
         /**
          * Create an empty filter model.
Index: soprano/queryresultiterator.h
===================================================================
--- soprano/queryresultiterator.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/queryresultiterator.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -93,8 +93,10 @@
      * This can either be achieved by deleting the iterator, finishing it (next() does return \p false),
      * or calling close(). Before that other operations on the Model may block.
      *
-     * Iterators are not thread-safe. Two threads using the same iterator at the same time may result
-     * in undefined behaviour and even crashes.
+     * Iterators are not thread-safe. Two threads using the same iterator may result
+     * in undefined behaviour and even crashes. An iterator needs to be closed by the
+     * same thread that opened it (except if the iterator contains special code to handle such
+     * a situation.)
      *
      * \warning Be aware that iterators in Soprano are shared objects which means
      * that copies of one iterator object work on the same data.
Index: soprano/nodeiterator.h
===================================================================
--- soprano/nodeiterator.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/nodeiterator.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -57,8 +57,10 @@
      * This can either be achieved by deleting the iterator, finishing it (next() does return \p false),
      * or calling close(). Before that other operations on the Model may block.
      *
-     * Iterators are not thread-safe. Two threads using the same iterator at the same time may result
-     * in undefined behaviour and even crashes.
+     * Iterators are not thread-safe. Two threads using the same iterator may result
+     * in undefined behaviour and even crashes. An iterator needs to be closed by the
+     * same thread that opened it (except if the iterator contains special code to handle such
+     * a situation.)
      *
      * \warning Be aware that iterators in Soprano are shared objects which means
      * that copies of one iterator object work on the same data.
Index: soprano/global.h
===================================================================
--- soprano/global.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/global.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -70,9 +70,9 @@
      *  should never ignore settings but rather return 0 if an option is not supported. Backends can,
      * however, define their own default settings.
      *
-     * \sa Model, Backend::createModel
+     * \sa Model, Backend::createModel, BackendSetting
      */
-    SOPRANO_EXPORT Model* createModel( const QList<BackendSetting>& settings = QList<BackendSetting>() );
+    SOPRANO_EXPORT Model* createModel( const BackendSettings& settings = BackendSettings() );
 }
 
 #endif // SOPRANO_H
Index: soprano/statementiterator.h
===================================================================
--- soprano/statementiterator.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/statementiterator.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -60,8 +60,10 @@
      * This can either be achieved by deleting the iterator, finishing it (next() does return \p false),
      * or calling close(). Before that other operations on the Model may block.
      *
-     * Iterators are not thread-safe. Two threads using the same iterator at the same time may result
-     * in undefined behaviour and even crashes.
+     * Iterators are not thread-safe. Two threads using the same iterator may result
+     * in undefined behaviour and even crashes. An iterator needs to be closed by the
+     * same thread that opened it (except if the iterator contains special code to handle such
+     * a situation.)
      *
      * \warning Be aware that iterators in Soprano are shared objects which means
      * that copies of one iterator object work on the same data.
Index: soprano/util/asyncmodel.cpp
===================================================================
--- soprano/util/asyncmodel.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asyncmodel.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -32,15 +32,36 @@
 #include "queryresultiterator.h"
 
 #include <QtCore/QTimer>
+#include <QtCore/QThreadPool>
 
 
-void Soprano::Util::AsyncModelPrivate::addIterator( AsyncIteratorBase* it )
+Q_DECLARE_METATYPE( Soprano::Statement )
+
+
+Soprano::Util::AsyncModelPrivate::AsyncModelPrivate( AsyncModel* parent )
+    : mode( AsyncModel::SingleThreaded ),
+      m_model( parent )
 {
+}
+
+
+Soprano::Util::AsyncModelPrivate::~AsyncModelPrivate()
+{
+    foreach( AsyncIteratorHandle* it, openIterators ) {
+        it->setModelGone();
+    }
+}
+
+
+// only called in SingleThreaded mode
+void Soprano::Util::AsyncModelPrivate::addIterator( AsyncIteratorHandle* it )
+{
     openIterators.append( it );
 }
 
 
-void Soprano::Util::AsyncModelPrivate::removeIterator( AsyncIteratorBase* it )
+// only called in SingleThreaded mode
+void Soprano::Util::AsyncModelPrivate::removeIterator( AsyncIteratorHandle* it )
 {
     Q_ASSERT( openIterators.contains( it ) );
     openIterators.removeAll( it );
@@ -50,14 +71,21 @@
 
 void Soprano::Util::AsyncModelPrivate::enqueueCommand( Command* command )
 {
-    commandQueue.append( command );
+    if ( mode == AsyncModel::SingleThreaded ) {
+        commandQueue.append( command );
 
-    // it is important to not call _s_executeNextCommand directly to let
-    // the client the time to connect to the resultReady signal
-    QTimer::singleShot( 0, m_model, SLOT( _s_executeNextCommand() ) );
+        // it is important to not call _s_executeNextCommand directly to let
+        // the client the time to connect to the resultReady signal
+        QTimer::singleShot( 0, m_model, SLOT( _s_executeNextCommand() ) );
+    }
+    else {
+        // the underlying model is thread-safe
+        QThreadPool::globalInstance()->start( command );
+    }
 }
 
 
+// only called in SingleThreaded mode
 void Soprano::Util::AsyncModelPrivate::_s_executeNextCommand()
 {
     for ( QLinkedList<Command*>::iterator it = commandQueue.begin();
@@ -65,7 +93,7 @@
         Command* c = *it;
         if ( openIterators.isEmpty() ||
              c->type() == Command::ReadCommand ) {
-            c->execute( m_model );
+            c->execute();
             commandQueue.erase( it );
             delete c;
 
@@ -83,6 +111,8 @@
     : FilterModel( parent ),
       d( new AsyncModelPrivate( this ) )
 {
+    // Model signals are delivered queued in MultiThreaded mode
+    qRegisterMetaType<Soprano::Statement>();
 }
 
 
@@ -93,18 +123,54 @@
 }
 
 
+void Soprano::Util::AsyncModel::setMode( AsyncModelMode mode )
+{
+    d->mode = mode;
+}
+
+
+Soprano::Util::AsyncModel::AsyncModelMode Soprano::Util::AsyncModel::mode() const
+{
+    return d->mode;
+}
+
+
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::addStatementAsync( const Statement& statement )
 {
+    return addStatementsAsync( QList<Statement>() << statement );
+}
+
+
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::addStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context )
+{
+    return addStatementAsync( Statement( subject, predicate, object, context ) );
+}
+
+
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::addStatementsAsync( const QList<Statement>& statements )
+{
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new AddStatementCommand( result, statement ) );
+    d->enqueueCommand( new AddStatementCommand( result, this, statements ) );
     return result;
 }
 
 
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::removeStatementAsync( const Statement& statement )
 {
+    return removeStatementsAsync( QList<Statement>() << statement );
+}
+
+
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::removeStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context )
+{
+    return removeStatementAsync( Statement( subject, predicate, object, context ) );
+}
+
+
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::removeStatementsAsync( const QList<Statement>& statements )
+{
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new RemoveStatementCommand( result, statement ) );
+    d->enqueueCommand( new RemoveStatementCommand( result, this, statements ) );
     return result;
 }
 
@@ -112,15 +178,21 @@
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::removeAllStatementsAsync( const Statement& statement )
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new RemoveAllStatementsCommand( result, statement ) );
+    d->enqueueCommand( new RemoveAllStatementsCommand( result, this, statement ) );
     return result;
 }
 
 
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::removeAllStatementsAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context )
+{
+    return removeAllStatementsAsync( Statement( subject, predicate, object, context ) );
+}
+
+
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::isEmptyAsync() const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new IsEmptyCommand( result ) );
+    d->enqueueCommand( new IsEmptyCommand( result, const_cast<AsyncModel*>(this) ) );
     return result;
 }
 
@@ -128,7 +200,7 @@
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::statementCountAsync() const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new StatementCountCommand( result ) );
+    d->enqueueCommand( new StatementCountCommand( result, const_cast<AsyncModel*>(this) ) );
     return result;
 }
 
@@ -136,15 +208,27 @@
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::listStatementsAsync( const Statement& statement ) const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new ListStatementsCommand( d, result, statement ) );
+    d->enqueueCommand( new ListStatementsCommand( d, result, const_cast<AsyncModel*>(this), statement ) );
     return result;
 }
 
 
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::listStatementsAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context ) const
+{
+    return listStatementsAsync( Statement( subject, predicate, object, context ) );
+}
+
+
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::listStatementsAsync() const
+{
+    return listStatementsAsync( Statement() );
+}
+
+
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::listContextsAsync() const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new ListContextsCommand( d, result ) );
+    d->enqueueCommand( new ListContextsCommand( d, result, const_cast<AsyncModel*>(this) ) );
     return result;
 }
 
@@ -154,7 +238,7 @@
                                                                           const QString& userQueryLanguage ) const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new ExecuteQueryCommand( d, result, query, language, userQueryLanguage ) );
+    d->enqueueCommand( new ExecuteQueryCommand( d, result, const_cast<AsyncModel*>(this), query, language, userQueryLanguage ) );
     return result;
 }
 
@@ -162,23 +246,35 @@
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::containsStatementAsync( const Statement& statement ) const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new ContainsStatementCommand( result, statement ) );
+    d->enqueueCommand( new ContainsStatementCommand( result, const_cast<AsyncModel*>(this), statement ) );
     return result;
 }
 
 
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::containsStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context ) const
+{
+    return containsStatementAsync( Statement( subject, predicate, object, context ) );
+}
+
+
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::containsAnyStatementAsync( const Statement& statement ) const
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new ContainsAnyStatementCommand( result, statement ) );
+    d->enqueueCommand( new ContainsAnyStatementCommand( result, const_cast<AsyncModel*>(this), statement ) );
     return result;
 }
 
 
+Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::containsAnyStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context ) const
+{
+    return containsAnyStatementAsync( Statement( subject, predicate, object, context ) );
+}
+
+
 Soprano::Util::AsyncResult* Soprano::Util::AsyncModel::createBlankNodeAsync()
 {
     AsyncResult* result = new AsyncResult();
-    d->enqueueCommand( new CreateBlankNodeCommand( result ) );
+    d->enqueueCommand( new CreateBlankNodeCommand( result, this ) );
     return result;
 }
 
Index: soprano/util/asynciteratorbackend.cpp
===================================================================
--- soprano/util/asynciteratorbackend.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asynciteratorbackend.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -22,29 +22,33 @@
 #include "asynciteratorbackend.h"
 #include "asyncmodel_p.h"
 
-Soprano::Util::AsyncIteratorBase::AsyncIteratorBase( AsyncModelPrivate* d )
+
+Soprano::Util::AsyncIteratorHandle::AsyncIteratorHandle( AsyncModelPrivate* d )
     : m_asyncModelPrivate( d )
 {
-    m_asyncModelPrivate->addIterator( this );
+    if ( d->mode == AsyncModel::SingleThreaded ) {
+        m_asyncModelPrivate->addIterator( this );
+    }
 }
 
 
-Soprano::Util::AsyncIteratorBase::~AsyncIteratorBase()
+Soprano::Util::AsyncIteratorHandle::~AsyncIteratorHandle()
 {
     remove();
 }
 
 
-void Soprano::Util::AsyncIteratorBase::setModelGone()
+void Soprano::Util::AsyncIteratorHandle::setModelGone()
 {
     m_asyncModelPrivate = 0;
 }
 
 
-void Soprano::Util::AsyncIteratorBase::remove()
+void Soprano::Util::AsyncIteratorHandle::remove()
 {
-    if( m_asyncModelPrivate ) {
-        m_asyncModelPrivate->removeIterator( this );
+    if ( m_asyncModelPrivate ) {
+        if ( m_asyncModelPrivate->mode == AsyncModel::SingleThreaded )
+            m_asyncModelPrivate->removeIterator( this );
         m_asyncModelPrivate = 0;
     }
 }
Index: soprano/util/asyncmodel.h
===================================================================
--- soprano/util/asyncmodel.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asyncmodel.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -23,6 +23,8 @@
 #define _SOPRANO_ASYNC_MODEL_H_
 
 #include "filtermodel.h"
+#include "asyncresult.h" // backwards comp when AsyncResult was defined in this header
+
 #include "soprano_export.h"
 
 
@@ -36,67 +38,6 @@
 
     namespace Util {
 
-        class AsyncModel;
-
-        /**
-         * \class AsyncResult asyncmodel.h Soprano/Util/AsyncResult
-         *
-         * \brief A delayed result as returned by AsyncModel.
-         *
-         * \author Sebastian Trueg <trueg@kde.org>
-         *
-         * \since 2.1
-         */
-        class SOPRANO_EXPORT AsyncResult : public QObject, public Error::ErrorCache
-        {
-            Q_OBJECT
-
-        Q_SIGNALS:
-            /**
-             * Emitted once the async operation is completed
-             * and the result can be read.
-             *
-             * The result will delete itself.
-             */
-            void resultReady( Soprano::Util::AsyncResult* );
-
-        public:
-            /**
-             * The result of the async operation. Its type is dependent
-             * on the operation (for example Error::ErrorCode for 
-             * AsyncModel::addStatementAsync or StatementIterator for 
-             * AsyncModel::listStatementsAsync). Types may need to be
-             * registered with Q_DECLARE_METATYPE.
-             *
-             * Use Error::ErrorCache::lastError() to check
-             * for error details.
-             *
-             * This value is not ready before resultReady()
-             * as been emitted.
-             */
-            QVariant value() const { return m_result; }
-
-            /** \cond internal_asyncresult_members */
-            /**
-             * Internal method. Do not call.
-             */
-            void setResult( const QVariant& result, const Error::Error& error ) {
-                m_result = result;
-                setError( error );
-                emit resultReady( this );
-                deleteLater();
-            }
-            /** \endcond */
-
-        private:
-            AsyncResult()
-                : QObject( 0 ) {}
-
-            QVariant m_result;
-
-            friend class AsyncModel;
-        };
-
         class AsyncModelPrivate;
 
         /**
@@ -105,9 +46,13 @@
          * \brief Filter model that allows to perform operations
          * asyncroneously.
          *
-         * The main purpose is to protect a Model against deadlocks
-         * in a single threaded situation.
+         * AsyncModel has two modes: AsyncModel::SingleThreaded and AsyncModel::MultiThreaded.
+         * The main purpose of the AsyncModel::SingleThreaded mode is to protect a
+         * Model against deadlocks in a single threaded situation.
          *
+         * AsyncModel::MultiThreaded mode provides real asyncroneous execution of
+         * Model commands.
+         *
          * Usage:
          * \code
          * AsyncResult* result = model->listStatementsAsync( s );
@@ -137,6 +82,46 @@
             ~AsyncModel();
 
             /**
+             * The mode of the model, single vs. multi threaded execution.
+             *
+             * \since 2.2
+             */
+            enum AsyncModelMode {
+                /**
+                 * The model uses a single thread. Thus, commands are executed in the
+                 * same thread but no two commands will ever block each other.
+                 * This is the default mode for historical reasons.
+                 */
+                SingleThreaded,
+
+                /**
+                 * The model uses multiple threads through QThreadPool.
+                 * Commands are executed in parallel.
+                 * Be aware that the parent model needs to be thread-safe.
+                 */
+                MultiThreaded
+            };
+
+            /**
+             * Set the mode to be used. For historical reasons the default mode is
+             * SingleThreaded.
+             *
+             * \sa mode
+             *
+             * \since 2.2
+             */
+            void setMode( AsyncModelMode mode );
+
+            /**
+             * The mode used by this model.
+             *
+             * \sa setMode
+             *
+             * \since 2.2
+             */
+            AsyncModelMode mode() const;
+            
+            /**
              * Asyncroneously add the Statement to the Model.
              *
              * \param statement The Statement to add.
@@ -149,6 +134,20 @@
             AsyncResult* addStatementAsync( const Statement& statement );
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* addStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() );
+
+            /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* addStatementsAsync( const QList<Statement>& statements );
+
+            /**
              * Asyncroneously remove one statement. For removing statements
              * with wildward matching see removeAllStatementsAsync().
              *
@@ -163,6 +162,20 @@
             AsyncResult* removeStatementAsync( const Statement& statement );
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* removeStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() );
+
+            /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* removeStatementsAsync( const QList<Statement>& statements );
+
+            /**
              * Asyncroneously remove all statements that match the partial statement.
              * For removing one specific statement see removeStatement().
              *
@@ -177,6 +190,13 @@
             AsyncResult* removeAllStatementsAsync( const Statement& statement );
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* removeAllStatementsAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() );
+
+            /**
              * Asyncroneously check if the Model does contain any Statement.
              *
              * \sa isEmpty
@@ -210,6 +230,22 @@
             AsyncResult* listStatementsAsync( const Statement& statement ) const;
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* listStatementsAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() ) const;
+
+            /**
+             * \overload
+             *
+             * Lists all statements in the Model asyncroneously.
+             *
+             * \since 2.2
+             */
+            AsyncResult* listStatementsAsync() const;
+
+            /**
              * Asyncroneously list all contexts in the model, i.e. all named graphs.
              *
              * \sa listContexts
@@ -256,6 +292,13 @@
             AsyncResult* containsStatementAsync( const Statement& statement ) const;
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* containsStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() ) const;
+
+            /**
              * Asyncroneously check if the model contains certain statements.
              *
              * \param statement A partially defined statement that serves as
@@ -269,6 +312,13 @@
             AsyncResult* containsAnyStatementAsync( const Statement& statement ) const;
 
             /**
+             * \overload
+             *
+             * \since 2.2
+             */
+            AsyncResult* containsAnyStatementAsync( const Node& subject, const Node& predicate, const Node& object, const Node& context = Node() ) const;
+
+            /**
              * Asyncroneously create a new blank node with a unique identifier.
              *
              * \sa createBlankNode
@@ -278,6 +328,13 @@
              */
             AsyncResult* createBlankNodeAsync();
 
+            using FilterModel::addStatement;
+            using FilterModel::removeStatement;
+            using FilterModel::removeAllStatements;
+            using FilterModel::listStatements;
+            using FilterModel::containsStatement;
+            using FilterModel::containsAnyStatement;
+
         private:
             AsyncModelPrivate* const d;
 
Index: soprano/util/asynciteratorbackend.h
===================================================================
--- soprano/util/asynciteratorbackend.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asynciteratorbackend.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -24,55 +24,243 @@
 
 #include "iteratorbackend.h"
 #include "iterator.h"
+#include "asyncmodel_p.h"
 
+#include <QtCore/QQueue>
+#include <QtCore/QMutex>
+#include <QtCore/QMutexLocker>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QDebug>
 
+
+namespace {
+    const int s_cacheSize = 10;
+}
+
 namespace Soprano {
     namespace Util {
-
-        class AsyncModelPrivate;
-
-        class AsyncIteratorBase
+        /**
+         * The sole purpose of this class is to provide a single
+         * interface to all interators for the AsyncModel
+         */
+        class AsyncIteratorHandle
         {
         public:
-            AsyncIteratorBase( AsyncModelPrivate* d );
-            virtual ~AsyncIteratorBase();
+            AsyncIteratorHandle( AsyncModelPrivate* d );
+            virtual ~AsyncIteratorHandle();
+
+            /**
+             * Simply set m_asyncModelPrivate to 0. used
+             * by the model in single thread mode.
+             */
             void setModelGone();
 
         protected:
+            /**
+             * remove this iterator, ie. close it and remove it from the
+             * model in single threaded mode
+             */
             void remove();
 
+            AsyncModelPrivate* modelPrivate() const { return m_asyncModelPrivate; }
+
         private:
             AsyncModelPrivate* m_asyncModelPrivate;
         };
 
 
-        template<typename T> class AsyncIteratorBackend : public IteratorBackend<T>, public AsyncIteratorBase
+        /**
+         * Base class for the iterators which does the communications between the
+         * main thread and the work thread to make sure iterators are only used
+         * in the thread that created them.
+         *
+         * For that results are cached in a queue and communicated via the m_current
+         * variable.
+         */
+        template<typename T> class AsyncIteratorBase : public AsyncIteratorHandle
         {
         public:
+            AsyncIteratorBase( AsyncModelPrivate* d, const Iterator<T>& it )
+                : AsyncIteratorHandle( d ),
+                m_iterator( it ) {
+            }
+
+            virtual ~AsyncIteratorBase() {}
+
+            virtual void initWorkThread() {}
+
+            // called in work thread by the AsyncCommand
+            void iterate() {
+                //qDebug() << "iterate";
+                m_atEnd = false;
+                while( !m_atEnd ) {
+                    // wait for cache space to become avilable
+                    m_mutex.lock();
+                    if ( cacheFillState() >= s_cacheSize ) {
+                        //qDebug() << "waiting for cache space";
+                        m_iterateWc.wait( &m_mutex );
+                    }
+                    m_mutex.unlock();
+
+                    // check if we have more data and if so, cache it
+                    bool haveNext = false;
+                    while ( m_iterator.next() ) {
+                        QMutexLocker lock( &m_mutex );
+                        //qDebug() << "iterate: filling cache";
+                        enqueueCurrent();
+                        if( m_iterator.lastError() ) {
+                            //qDebug() << "iterate: error";
+                            m_error = m_iterator.lastError();
+                            haveNext = false;
+                            break;
+                        }
+                        if ( cacheFillState() >= s_cacheSize ) {
+                            haveNext = true;
+                            break;
+                        }
+                    }
+
+                    QMutexLocker lock( &m_mutex );
+                    m_atEnd = !haveNext;
+
+                    // tell the waiting thread that data is available
+                    //qDebug() << "iterate: waking consumer";
+                    m_nextWc.wakeAll();
+                }
+
+                // close the iterator
+                m_iterator.close();
+            }
+
+        protected:
+            // called in main thread by IteratorBackend::next
+            bool getNext() {
+                //qDebug() << "getNext";
+                if( modelPrivate() ) {
+                    if( modelPrivate()->mode == AsyncModel::MultiThreaded ) {
+                        m_mutex.lock();
+
+                        // wait for data to become available
+                        if ( !cacheFillState() && !m_atEnd ) {
+                            //qDebug() << "getNext: Waiting for data";
+                            m_iterateWc.wakeAll();
+                            m_nextWc.wait( &m_mutex );
+                        }
+
+                        if( m_error ) {
+                            //qDebug() << "getNext: error";
+                            m_mutex.unlock();
+                            return false;
+                        }
+
+                        // get the new data
+                        else if ( cacheFillState() != 0 ) {
+                            //qDebug() << "getNext: got data";
+                            dequeueFirst();
+                            m_mutex.unlock();
+                            return true;
+                        }
+                        else {
+                            //qDebug() << "getNext: got no data";
+                            m_mutex.unlock();
+                            return false;
+                        }
+                    }
+                    else {
+                        return m_iterator.next();
+                    }
+                }
+                else {
+                    return false;
+                }
+            }
+
+            void closeIterator() {
+                //qDebug() << "closeIterator";
+                if( modelPrivate() ) {
+                    if( modelPrivate()->mode == AsyncModel::MultiThreaded ) {
+                        stopIterating();
+                    }
+                    else {
+                        m_iterator.close();
+                        remove();
+                    }
+                }
+            }
+
+            // called in the main thread by IteratorBackend::close
+            void stopIterating() {
+                //qDebug() << "stopIterating";
+                QMutexLocker lock( &m_mutex );
+                m_atEnd = true;
+                m_iterateWc.wakeAll();
+            }
+
+            // called in the main thread by IteratorBackend::current
+            T getCurrent() const { 
+                if( modelPrivate() ) {
+                    if( modelPrivate()->mode == AsyncModel::MultiThreaded )
+                        return m_current;
+                    else
+                        return m_iterator.current();
+                }
+                else {
+                    return T();
+                }
+            }
+
+            virtual int cacheFillState() const {
+                return m_cache.size();
+            }
+            
+            virtual void enqueueCurrent() {
+                m_cache.enqueue( m_iterator.current() );
+            }
+
+            virtual void dequeueFirst() {
+                m_current = m_cache.dequeue();
+            }
+
+            Iterator<T> m_iterator;
+            Error::Error m_error;
+
+        private:
+            bool m_atEnd;
+            QQueue<T> m_cache;
+            T m_current;
+
+            QMutex m_mutex;
+            QWaitCondition m_nextWc;
+            QWaitCondition m_iterateWc;
+        };
+
+
+        template<typename T> class AsyncIteratorBackend : public AsyncIteratorBase<T>, public IteratorBackend<T>
+        {
+        public:
             AsyncIteratorBackend( AsyncModelPrivate* d, const Iterator<T>& it )
-                : AsyncIteratorBase( d ),
-                  m_iterator( it ) {
+                : AsyncIteratorBase<T>( d, it ) {
             }
 
             bool next() {
-                return m_iterator.next();
+                return AsyncIteratorBase<T>::getNext();
             }
             
             T current() const {
-                return m_iterator.current();
+                return AsyncIteratorBase<T>::getCurrent();
             }
             
             void close() {
-                m_iterator.close();
-                remove();
+                AsyncIteratorBase<T>::closeIterator();
             }
 
             Error::Error lastError() const {
-                return m_iterator.lastError();
+                if( AsyncIteratorHandle::modelPrivate() && 
+                    AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return AsyncIteratorBase<T>::m_iterator.lastError();
+                else
+                    return AsyncIteratorBase<T>::m_error;
             }
-
-        private:
-            Iterator<T> m_iterator;
         };
     }
 }
Index: soprano/util/asyncresult.cpp
===================================================================
--- soprano/util/asyncresult.cpp	(.../tags/soprano/2.1.1)	(revision 0)
+++ soprano/util/asyncresult.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,79 @@
+/*
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <trueg@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "asyncresult.h"
+#include "node.h"
+#include "nodeiterator.h"
+#include "statementiterator.h"
+#include "queryresultiterator.h"
+
+
+Q_DECLARE_METATYPE( Soprano::Error::ErrorCode )
+Q_DECLARE_METATYPE( Soprano::Node )
+Q_DECLARE_METATYPE( Soprano::StatementIterator )
+Q_DECLARE_METATYPE( Soprano::NodeIterator )
+Q_DECLARE_METATYPE( Soprano::QueryResultIterator )
+
+
+Soprano::Util::AsyncResult::AsyncResult()
+    : QObject( 0 ) {
+    // a little hack to ensure that results are delivered in the calling thread
+    connect( this,SIGNAL(emitReady()),
+             SLOT(slotEmitReady()),
+             Qt::QueuedConnection );
+}
+
+
+Soprano::Util::AsyncResult::~AsyncResult()
+{
+}
+
+
+Soprano::Error::ErrorCode Soprano::Util::AsyncResult::errorCode() const
+{
+    return value().value<Error::ErrorCode>();
+}
+
+
+Soprano::StatementIterator Soprano::Util::AsyncResult::statementIterator() const
+{
+    return value().value<StatementIterator>();
+}
+
+
+Soprano::NodeIterator Soprano::Util::AsyncResult::nodeIterator() const
+{
+    return value().value<NodeIterator>();
+}
+
+
+Soprano::QueryResultIterator Soprano::Util::AsyncResult::queryResultIterator() const
+{
+    return value().value<QueryResultIterator>();
+}
+
+
+Soprano::Node Soprano::Util::AsyncResult::node() const
+{
+    return value().value<Node>();
+}
+
+#include "asyncresult.moc"
Index: soprano/util/asynccommand.cpp
===================================================================
--- soprano/util/asynccommand.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asynccommand.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -36,8 +36,10 @@
 Q_DECLARE_METATYPE(Soprano::NodeIterator)
 Q_DECLARE_METATYPE(Soprano::QueryResultIterator)
 
-Soprano::Util::Command::Command( Type type )
-    : m_type( type )
+Soprano::Util::Command::Command( AsyncResult* result, Model* model, Type type )
+    : m_result( result ),
+      m_model( model ),
+      m_type( type )
 {
 }
 
@@ -48,159 +50,162 @@
 
 
 
-Soprano::Util::StatementCountCommand::StatementCountCommand( AsyncResult* result )
-    : Command( ReadCommand ),
-      m_result( result )
+Soprano::Util::StatementCountCommand::StatementCountCommand( AsyncResult* result, Model* model )
+    : Command( result, model, ReadCommand )
 {
 }
 
 
-void Soprano::Util::StatementCountCommand::execute( Model* model )
+void Soprano::Util::StatementCountCommand::execute()
 {
-    int cnt = model->statementCount();
-    m_result->setResult( cnt, model->lastError() );
+    int cnt = model()->statementCount();
+    result()->setResult( cnt, model()->lastError() );
 }
 
 
-Soprano::Util::IsEmptyCommand::IsEmptyCommand( AsyncResult* result )
-    : Command( ReadCommand ),
-      m_result( result )
+Soprano::Util::IsEmptyCommand::IsEmptyCommand( AsyncResult* result, Model* model )
+    : Command( result, model, ReadCommand )
 {
 }
 
 
-void Soprano::Util::IsEmptyCommand::execute( Model* model )
+void Soprano::Util::IsEmptyCommand::execute()
 {
-    bool r = model->isEmpty();
-    m_result->setResult( r, model->lastError() );
+    bool r = model()->isEmpty();
+    result()->setResult( r, model()->lastError() );
 }
 
 
-Soprano::Util::StatementCommand::StatementCommand( const Statement& s, Type type )
-    : Command( type ),
-      m_statement( s )
+Soprano::Util::StatementCommand::StatementCommand( AsyncResult* result, Model* model, const Statement& s, Type type )
+    : Command( result, model, type )
 {
+    m_statements << s;
 }
 
 
-Soprano::Util::AddStatementCommand::AddStatementCommand( AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, WriteCommand ),
-      m_result( result )
+Soprano::Util::StatementCommand::StatementCommand( AsyncResult* result, Model* model, const QList<Statement>& s, Type type )
+    : Command( result, model, type ),
+      m_statements( s )
 {
 }
 
 
-void Soprano::Util::AddStatementCommand::execute( Model* model )
+Soprano::Util::AddStatementCommand::AddStatementCommand( AsyncResult* result, Model* model, const QList<Statement>& statements )
+    : StatementCommand( result, model, statements, WriteCommand )
 {
-    Error::ErrorCode r = model->addStatement( statement() );
-    m_result->setResult( QVariant::fromValue( r ), model->lastError() );
 }
 
 
-Soprano::Util::RemoveStatementCommand::RemoveStatementCommand( AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, WriteCommand ),
-      m_result( result )
+void Soprano::Util::AddStatementCommand::execute()
 {
+    Error::ErrorCode r = model()->addStatements( statements() );
+    result()->setResult( QVariant::fromValue( r ), model()->lastError() );
 }
 
 
-void Soprano::Util::RemoveStatementCommand::execute( Model* model )
+Soprano::Util::RemoveStatementCommand::RemoveStatementCommand( AsyncResult* result, Model* model, const QList<Statement>& statements )
+    : StatementCommand( result, model, statements, WriteCommand )
 {
-    Error::ErrorCode r = model->removeStatement( statement() );
-    m_result->setResult( QVariant::fromValue( r ), model->lastError() );
 }
 
 
-Soprano::Util::RemoveAllStatementsCommand::RemoveAllStatementsCommand( AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, WriteCommand ),
-      m_result( result )
+void Soprano::Util::RemoveStatementCommand::execute()
 {
+    Error::ErrorCode r = model()->removeStatements( statements() );
+    result()->setResult( QVariant::fromValue( r ), model()->lastError() );
 }
 
 
-void Soprano::Util::RemoveAllStatementsCommand::execute( Model* model )
+Soprano::Util::RemoveAllStatementsCommand::RemoveAllStatementsCommand( AsyncResult* result, Model* model, const Statement& statement )
+    : StatementCommand( result, model, statement, WriteCommand )
 {
-    Error::ErrorCode r = model->removeAllStatements( statement() );
-    m_result->setResult( QVariant::fromValue( r ), model->lastError() );
 }
 
 
-Soprano::Util::ContainsStatementCommand::ContainsStatementCommand( AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, ReadCommand ),
-      m_result( result )
+void Soprano::Util::RemoveAllStatementsCommand::execute()
 {
+    Error::ErrorCode r = model()->removeAllStatements( statement() );
+    result()->setResult( QVariant::fromValue( r ), model()->lastError() );
 }
 
 
-void Soprano::Util::ContainsStatementCommand::execute( Model* model )
+Soprano::Util::ContainsStatementCommand::ContainsStatementCommand( AsyncResult* result, Model* model, const Statement& statement )
+    : StatementCommand( result, model, statement, ReadCommand )
 {
-    bool r = model->containsStatement( statement() );
-    m_result->setResult( r, model->lastError() );
 }
 
 
-Soprano::Util::ContainsAnyStatementCommand::ContainsAnyStatementCommand( AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, ReadCommand ),
-      m_result( result )
+void Soprano::Util::ContainsStatementCommand::execute()
 {
+    bool r = model()->containsStatement( statement() );
+    result()->setResult( r, model()->lastError() );
 }
 
 
-void Soprano::Util::ContainsAnyStatementCommand::execute( Model* model )
+Soprano::Util::ContainsAnyStatementCommand::ContainsAnyStatementCommand( AsyncResult* result, Model* model, const Statement& statement )
+    : StatementCommand( result, model, statement, ReadCommand )
 {
-    bool r = model->containsAnyStatement( statement() );
-    m_result->setResult( r, model->lastError() );
 }
 
 
-Soprano::Util::ListStatementsCommand::ListStatementsCommand( AsyncModelPrivate* d, AsyncResult* result, const Statement& statement )
-    : StatementCommand( statement, ReadCommand ),
-      m_result( result ),
+void Soprano::Util::ContainsAnyStatementCommand::execute()
+{
+    bool r = model()->containsAnyStatement( statement() );
+    result()->setResult( r, model()->lastError() );
+}
+
+
+Soprano::Util::ListStatementsCommand::ListStatementsCommand( AsyncModelPrivate* d, AsyncResult* result, Model* model, const Statement& statement )
+    : StatementCommand( result, model, statement, ReadCommand ),
       m_asyncModelPrivate( d )
 {
 }
 
 
-void Soprano::Util::ListStatementsCommand::execute( Model* model )
+void Soprano::Util::ListStatementsCommand::execute()
 {
-    StatementIterator r = model->listStatements( statement() );
+    StatementIterator r = model()->listStatements( statement() );
     if ( r.isValid() ) {
         AsyncIteratorBackend<Statement>* b = new AsyncIteratorBackend<Statement>( m_asyncModelPrivate, r );
-        m_result->setResult( QVariant::fromValue( StatementIterator( b ) ), model->lastError() );
+        result()->setResult( QVariant::fromValue( StatementIterator( b ) ), model()->lastError() );
+        if ( m_asyncModelPrivate->mode == AsyncModel::MultiThreaded )
+            b->iterate();
     }
     else {
-        m_result->setResult( QVariant::fromValue( r ), model->lastError() );
+        result()->setResult( QVariant::fromValue( r ), model()->lastError() );
     }
 }
 
 
-Soprano::Util::ListContextsCommand::ListContextsCommand( AsyncModelPrivate* d, AsyncResult* result )
-    : Command( ReadCommand ),
-      m_result( result ),
+Soprano::Util::ListContextsCommand::ListContextsCommand( AsyncModelPrivate* d, AsyncResult* result, Model* model )
+    : Command( result, model, ReadCommand ),
       m_asyncModelPrivate( d )
 {
 }
 
-void Soprano::Util::ListContextsCommand::execute( Model* model )
+
+void Soprano::Util::ListContextsCommand::execute()
 {
-    NodeIterator r = model->listContexts();
+    NodeIterator r = model()->listContexts();
     if ( r.isValid() ) {
         AsyncIteratorBackend<Node>* b = new AsyncIteratorBackend<Node>( m_asyncModelPrivate, r );
-        m_result->setResult( QVariant::fromValue( NodeIterator( b ) ), model->lastError() );
+        result()->setResult( QVariant::fromValue( NodeIterator( b ) ), model()->lastError() );
+        if ( m_asyncModelPrivate->mode == AsyncModel::MultiThreaded )
+            b->iterate();
     }
     else {
-        m_result->setResult( QVariant::fromValue( r ), model->lastError() );
+        result()->setResult( QVariant::fromValue( r ), model()->lastError() );
     }
 }
 
 
 Soprano::Util::ExecuteQueryCommand::ExecuteQueryCommand( AsyncModelPrivate* d,
                                                          AsyncResult* result,
+                                                         Model* model,
                                                          const QString& query,
                                                          Query::QueryLanguage lang,
                                                          const QString& userQueryLang )
-    : Command( ReadCommand ),
-      m_result( result ),
+    : Command( result, model, ReadCommand ),
       m_query( query ),
       m_queryLanguage( lang ),
       m_userQueryLanguage( userQueryLang ),
@@ -208,27 +213,30 @@
 {
 }
 
-void Soprano::Util::ExecuteQueryCommand::execute( Model* model )
+void Soprano::Util::ExecuteQueryCommand::execute()
 {
-    QueryResultIterator r = model->executeQuery( m_query, m_queryLanguage, m_userQueryLanguage );
+    QueryResultIterator r = model()->executeQuery( m_query, m_queryLanguage, m_userQueryLanguage );
     if ( r.isValid() ) {
         AsyncQueryResultIteratorBackend* b = new AsyncQueryResultIteratorBackend( m_asyncModelPrivate, r );
-        m_result->setResult( QVariant::fromValue( QueryResultIterator( b ) ), model->lastError() );
+        if ( m_asyncModelPrivate->mode == AsyncModel::MultiThreaded )
+            b->initWorkThread();
+        result()->setResult( QVariant::fromValue( QueryResultIterator( b ) ), model()->lastError() );
+        if ( m_asyncModelPrivate->mode == AsyncModel::MultiThreaded )
+            b->iterate();
     }
     else {
-        m_result->setResult( QVariant::fromValue( r ), model->lastError() );
+        result()->setResult( QVariant::fromValue( r ), model()->lastError() );
     }
 }
 
 
-Soprano::Util::CreateBlankNodeCommand::CreateBlankNodeCommand( AsyncResult* result )
-    : Command( WriteCommand ),
-      m_result( result )
+Soprano::Util::CreateBlankNodeCommand::CreateBlankNodeCommand( AsyncResult* result, Model* model )
+    : Command( result, model, WriteCommand )
 {
 }
 
-void Soprano::Util::CreateBlankNodeCommand::execute( Model* model )
+void Soprano::Util::CreateBlankNodeCommand::execute()
 {
-    Node r = model->createBlankNode();
-    m_result->setResult( QVariant::fromValue( r ), model->lastError() );
+    Node r = model()->createBlankNode();
+    result()->setResult( QVariant::fromValue( r ), model()->lastError() );
 }
Index: soprano/util/asyncresult.h
===================================================================
--- soprano/util/asyncresult.h	(.../tags/soprano/2.1.1)	(revision 0)
+++ soprano/util/asyncresult.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -0,0 +1,175 @@
+/* 
+ * This file is part of Soprano Project.
+ *
+ * Copyright (C) 2008 Sebastian Trueg <trueg@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _SOPRANO_ASYNC_RESULT_H_
+#define _SOPRANO_ASYNC_RESULT_H_
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+
+#include "error.h"
+#include "soprano_export.h"
+
+
+namespace Soprano {
+
+    class StatementIterator;
+    class Node;
+    class NodeIterator;
+    class QueryResultIterator;
+
+    namespace Util {
+
+        class AsyncModel;
+
+        /**
+         * \class AsyncResult asyncmodel.h Soprano/Util/AsyncResult
+         *
+         * \brief A delayed result as returned by AsyncModel.
+         *
+         * \author Sebastian Trueg <trueg@kde.org>
+         *
+         * \since 2.1
+         */
+        class SOPRANO_EXPORT AsyncResult : public QObject, public Error::ErrorCache
+        {
+            Q_OBJECT
+
+        Q_SIGNALS:
+            /**
+             * Emitted once the async operation is completed
+             * and the result can be read.
+             *
+             * The result will delete itself.
+             */
+            void resultReady( Soprano::Util::AsyncResult* );
+
+        public:
+            ~AsyncResult();
+
+            /**
+             * The result of the async operation. Its type is dependent
+             * on the operation (for example Error::ErrorCode for 
+             * AsyncModel::addStatementAsync or StatementIterator for 
+             * AsyncModel::listStatementsAsync). Types may need to be
+             * registered with Q_DECLARE_METATYPE.
+             *
+             * Use Error::ErrorCache::lastError() to check
+             * for error details.
+             *
+             * This value is not ready before resultReady()
+             * has been emitted. <b>Do only use this in a slot connected to
+             * resultReady.</b>
+             *
+             * \sa errorCode, statementIterator, nodeIterator, queryResultIterator, node
+             */
+            QVariant value() const { return m_result; }
+
+            /**
+             * Convinience method which converts value() into
+             * a Error::ErrorCode as returned for the following AsyncModel methods:
+             * \li AsyncModel::addStatementAsync
+             * \li AsyncModel::removeStatementAsync
+             * \li AsyncModel::removeAllStatementsAsync
+             *
+             * \sa value()
+             *
+             * \since 2.2
+             */
+            Error::ErrorCode errorCode() const;
+
+            /**
+             * Convinience method which converts value() into
+             * a StatementIterator as returned AsyncModel::listStatementsAsync.
+             *
+             * \sa value()
+             *
+             * \since 2.2
+             */
+            StatementIterator statementIterator() const;
+
+            /**
+             * Convinience method which converts value() into
+             * a StatementIterator as returned AsyncModel::listContextsAsync.
+             *
+             * \sa value()
+             *
+             * \since 2.2
+             */
+            NodeIterator nodeIterator() const;
+
+            /**
+             * Convinience method which converts value() into
+             * a StatementIterator as returned AsyncModel::executeQueryAsync.
+             *
+             * \sa value()
+             *
+             * \since 2.2
+             */
+            QueryResultIterator queryResultIterator() const;
+
+            /**
+             * Convinience method which converts value() into
+             * a StatementIterator as returned AsyncModel::createBlankNodeAsync.
+             *
+             * \sa value()
+             *
+             * \since 2.2
+             */
+            Node node() const;
+
+            /** \cond internal_asyncresult_members */
+            /**
+             * Internal method. Do not call.
+             */
+            void setResult( const QVariant& result, const Error::Error& error ) {
+                m_result = result;
+                setError( error );
+                emit emitReady();
+            }
+
+        Q_SIGNALS:
+#ifndef Q_MOC_RUN
+        private: // don't tell moc, but this signal is in fact private
+#endif
+            /**
+             * Private signal used internally.
+             */
+            void emitReady();
+            /** \endcond */
+
+        private Q_SLOTS:
+            void slotEmitReady() {
+                emit resultReady( this );
+                delete this;
+            }
+
+        private:
+            AsyncResult();
+
+            QVariant m_result;
+
+            friend class AsyncModel;
+        };
+    }
+}
+
+#endif
Index: soprano/util/asynccommand.h
===================================================================
--- soprano/util/asynccommand.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asynccommand.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -22,6 +22,8 @@
 #ifndef _SOPRANO_UTIL_ASYNC_COMMAND_H_
 #define _SOPRANO_UTIL_ASYNC_COMMAND_H_
 
+#include <QtCore/QRunnable>
+
 #include "asyncmodel.h"
 #include "statement.h"
 #include "node.h"
@@ -37,7 +39,7 @@
 
         class AsyncModelPrivate;
 
-        class Command
+        class Command : public QRunnable
         {
         public:
             enum Type {
@@ -45,14 +47,21 @@
                 WriteCommand
             };
 
-            Command( Type type );
+            Command( AsyncResult* result, Model* model, Type type );
             virtual ~Command();
 
             Type type() const { return m_type; }
+            AsyncResult* result() const { return m_result; }
+            Model* model() const { return m_model; }
 
-            virtual void execute( Model* ) = 0;
+            virtual void execute() = 0;
 
+            // reimplemented from QRunnable
+            void run() { execute(); }
+
         private:
+            AsyncResult* m_result;
+            Model* m_model;
             Type m_type;
         };
 
@@ -60,24 +69,18 @@
         class StatementCountCommand : public Command
         {
         public:
-            StatementCountCommand( AsyncResult* result );
+            StatementCountCommand( AsyncResult* result, Model* model );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class IsEmptyCommand : public Command
         {
         public:
-            IsEmptyCommand( AsyncResult* result );
+            IsEmptyCommand( AsyncResult* result, Model* model );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
@@ -86,86 +89,71 @@
         public:
             virtual ~StatementCommand() {}
 
-            Statement statement() const { return m_statement; }
+            Statement statement() const { return m_statements.first(); }
+            QList<Statement> statements() const { return m_statements; }
 
         protected:
-            StatementCommand( const Statement&, Type type );
+            StatementCommand( AsyncResult* result, Model* model, const Statement&, Type type );
+            StatementCommand( AsyncResult* result, Model* model, const QList<Statement>&, Type type );
 
         private:
-            Statement m_statement;
+            QList<Statement> m_statements;
         };
 
 
         class AddStatementCommand : public StatementCommand
         {
         public:
-            AddStatementCommand( AsyncResult* result, const Statement& );
+            AddStatementCommand( AsyncResult* result, Model* model, const QList<Statement>& );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class RemoveStatementCommand : public StatementCommand
         {
         public:
-            RemoveStatementCommand( AsyncResult* result, const Statement& );
+            RemoveStatementCommand( AsyncResult* result, Model* model, const QList<Statement>& );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class RemoveAllStatementsCommand : public StatementCommand
         {
         public:
-            RemoveAllStatementsCommand( AsyncResult* result, const Statement& );
+            RemoveAllStatementsCommand( AsyncResult* result, Model* model, const Statement& );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class ContainsStatementCommand : public StatementCommand
         {
         public:
-            ContainsStatementCommand( AsyncResult* result, const Statement& );
+            ContainsStatementCommand( AsyncResult* result, Model* model, const Statement& );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class ContainsAnyStatementCommand : public StatementCommand
         {
         public:
-            ContainsAnyStatementCommand( AsyncResult* result, const Statement& );
+            ContainsAnyStatementCommand( AsyncResult* result, Model* model, const Statement& );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
 
 
         class ListStatementsCommand : public StatementCommand
         {
         public:
-            ListStatementsCommand( AsyncModelPrivate*, AsyncResult* result, const Statement& );
+            ListStatementsCommand( AsyncModelPrivate*, AsyncResult* result, Model* model, const Statement& );
 
-            void execute( Model* );
+            void execute();
 
         private:
-            AsyncResult* m_result;
-
             AsyncModelPrivate* m_asyncModelPrivate;
         };
 
@@ -173,13 +161,11 @@
         class ListContextsCommand : public Command
         {
         public:
-            ListContextsCommand( AsyncModelPrivate*, AsyncResult* result );
+            ListContextsCommand( AsyncModelPrivate*, AsyncResult* result, Model* model );
 
-            void execute( Model* );
+            void execute();
 
         private:
-            AsyncResult* m_result;
-
             AsyncModelPrivate* m_asyncModelPrivate;
         };
 
@@ -187,13 +173,11 @@
         class ExecuteQueryCommand : public Command
         {
         public:
-            ExecuteQueryCommand( AsyncModelPrivate*, AsyncResult* result, const QString&, Query::QueryLanguage lang, const QString& userQueryLang );
+            ExecuteQueryCommand( AsyncModelPrivate*, AsyncResult* result, Model* model, const QString&, Query::QueryLanguage lang, const QString& userQueryLang );
 
-            void execute( Model* );
+            void execute();
 
         private:
-            AsyncResult* m_result;
-
             QString m_query;
             Query::QueryLanguage m_queryLanguage;
             QString m_userQueryLanguage;
@@ -205,12 +189,9 @@
         class CreateBlankNodeCommand : public Command
         {
         public:
-            CreateBlankNodeCommand( AsyncResult* result );
+            CreateBlankNodeCommand( AsyncResult* result, Model* model );
 
-            void execute( Model* );
-
-        private:
-            AsyncResult* m_result;
+            void execute();
         };
     }
 }
Index: soprano/util/asyncmodel_p.h
===================================================================
--- soprano/util/asyncmodel_p.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asyncmodel_p.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -24,7 +24,6 @@
 
 #include "asyncmodel.h"
 #include "asynccommand.h"
-#include "asynciteratorbackend.h"
 #include "iteratorbackend.h"
 
 #include <QtCore/QLinkedList>
@@ -32,25 +31,24 @@
 
 namespace Soprano {
     namespace Util {
+
+        class AsyncIteratorHandle;
+
         class AsyncModelPrivate
         {
         public:
-            AsyncModelPrivate( AsyncModel* parent )
-                : m_model( parent ) {
-            }
+            AsyncModelPrivate( AsyncModel* parent );
+            ~AsyncModelPrivate();
 
-            ~AsyncModelPrivate() {
-                foreach( AsyncIteratorBase* it, openIterators ) {
-                    it->setModelGone();
-                }
-            }
+            AsyncModel::AsyncModelMode mode;
 
             QLinkedList<Command*> commandQueue;
 
-            QList<AsyncIteratorBase*> openIterators;
+            // only used for single threaded mode
+            QList<AsyncIteratorHandle*> openIterators;
 
-            void addIterator( AsyncIteratorBase* );
-            void removeIterator( AsyncIteratorBase* );
+            void addIterator( AsyncIteratorHandle* );
+            void removeIterator( AsyncIteratorHandle* );
             void enqueueCommand( Command* );
 
             void _s_executeNextCommand();
Index: soprano/util/asyncqueryresultiteratorbackend.h
===================================================================
--- soprano/util/asyncqueryresultiteratorbackend.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/util/asyncqueryresultiteratorbackend.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -29,69 +29,139 @@
 
 namespace Soprano {
     namespace Util {
-        class AsyncQueryResultIteratorBackend : public QueryResultIteratorBackend, public AsyncIteratorBase
+        class AsyncQueryResultIteratorBackend : public QueryResultIteratorBackend, public AsyncIteratorBase<Soprano::BindingSet>
         {
         public:
             AsyncQueryResultIteratorBackend( AsyncModelPrivate* d, const QueryResultIterator& it )
-                : AsyncIteratorBase( d ),
-                  m_iterator( it ) {
+                : AsyncIteratorBase<BindingSet>( d, it ),
+                m_iterator( it ) {
             }
 
+            // called in work thread
+            void initWorkThread() {
+                m_isGraph = m_iterator.isGraph();
+                m_isBinding = m_iterator.isBinding();
+                m_isBool = m_iterator.isBool();
+                if( m_isBool ) {
+                    m_boolVal = m_iterator.boolValue();
+                    m_iterator.close();
+                }
+            }
+
             bool next() {
-                return m_iterator.next();
+                return AsyncIteratorBase<BindingSet>::getNext();
             }
             
             BindingSet current() const {
-                return m_iterator.current();
+                return AsyncIteratorBase<BindingSet>::getCurrent();
             }
             
             Statement currentStatement() const {
-                return m_iterator.currentStatement();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.currentStatement();
+                else
+                    return m_currentStatement;
             }
 
             Node binding( const QString& name ) const {
-                return m_iterator.binding( name );
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.binding( name );
+                else
+                    return current()[ name ];
             }
 
             Node binding( int offset ) const {
-                return m_iterator.binding( offset );
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.binding( offset );
+                else
+                    return current()[ offset ];
             }
 
             int bindingCount() const {
-                return m_iterator.bindingCount();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.bindingCount();
+                else
+                    return current().count();
             }
 
             QStringList bindingNames() const {
-                return m_iterator.bindingNames();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.bindingNames();
+                else
+                    return current().bindingNames();
             }
 
             bool isGraph() const {
-                return m_iterator.isGraph();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.isGraph();
+                else
+                    return m_isGraph;
             }
 
             bool isBinding() const {
-                return m_iterator.isBinding();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.isBinding();
+                else
+                    return m_isBinding;
             }
 
             bool isBool() const {
-                return m_iterator.isBool();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.isBool();
+                else
+                    return m_isBool;
             }
 
             bool boolValue() const {
-                return m_iterator.boolValue();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.boolValue();
+                else
+                    return m_boolVal;
             }
 
             void close() {
-                m_iterator.close();
-                remove();
+                AsyncIteratorBase<BindingSet>::closeIterator();
             }
 
             Error::Error lastError() const {
-                return m_iterator.lastError();
+                if( AsyncIteratorHandle::modelPrivate() && AsyncIteratorHandle::modelPrivate()->mode == AsyncModel::SingleThreaded )
+                    return m_iterator.lastError();
+                else
+                    return AsyncIteratorBase<BindingSet>::m_error;
             }
 
         private:
+            void enqueueCurrent() {
+                if( isGraph() )
+                    m_statementCache.enqueue( m_iterator.currentStatement() );
+                else if( isBinding() )
+                    AsyncIteratorBase<BindingSet>::enqueueCurrent();
+            }
+
+            void dequeueFirst() {
+                if( isGraph() )
+                    m_currentStatement = m_statementCache.dequeue();
+                else if( isBinding() )
+                    AsyncIteratorBase<BindingSet>::dequeueFirst();
+            }
+
+            int cacheFillState() const {
+                if( isGraph() )
+                    return m_statementCache.size();
+                else if( isBinding() )
+                    return AsyncIteratorBase<BindingSet>::cacheFillState();
+                else
+                    return 0;
+            }
+
             QueryResultIterator m_iterator;
+            bool m_isGraph;
+            bool m_isBinding;
+            bool m_isBool;
+            bool m_boolVal;
+
+            QQueue<Statement> m_statementCache;
+            Statement m_currentStatement;
         };
     }
 }
Index: soprano/CMakeLists.txt
===================================================================
--- soprano/CMakeLists.txt	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/CMakeLists.txt	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -91,6 +91,7 @@
   util/signalcachemodel.cpp
   util/readonlymodel.cpp
   util/asyncmodel.cpp
+  util/asyncresult.cpp
   util/asynccommand.cpp
   util/asynciteratorbackend.cpp
   )
@@ -166,4 +167,5 @@
   util/signalcachemodel.h
   util/readonlymodel.h
   util/asyncmodel.h
+  util/asyncresult.h
   DESTINATION include/soprano)
Index: soprano/sopranotypes.h
===================================================================
--- soprano/sopranotypes.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ soprano/sopranotypes.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -31,6 +31,8 @@
 {
     /**
      * Different types of RDF serialization.
+     *
+     * \sa serializationMimeType, mimeTypeToSerialization
      */
     // FIXME: what about the used charsets? Should we and if so, how should we include them?
     // FIXME: SerializationUnknown and SerializationUser should become the same, i.e. one should become deprecated
Index: ChangeLog
===================================================================
--- ChangeLog	(.../tags/soprano/2.1.1)	(revision 846898)
+++ ChangeLog	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -1,3 +1,7 @@
+2.2
+	* The AsyncModel now has a "real" asyncroneous mode which uses multiple threads to execute the
+	  commands.
+
 2.1
 	* SignalCacheModel to restrict the number of emitted statementsAdded and statementsRemoved signals
 	  in a certain timeframe.
Index: includes/Util/AsyncResult
===================================================================
--- includes/Util/AsyncResult	(.../tags/soprano/2.1.1)	(revision 846898)
+++ includes/Util/AsyncResult	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -1 +1 @@
-#include "../../soprano/asyncmodel.h"
+#include "../../soprano/asyncresult.h"
Index: index/indexfiltermodel.cpp
===================================================================
--- index/indexfiltermodel.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ index/indexfiltermodel.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -262,3 +262,9 @@
 {
     return d->indexOnlyPredicates.toList();
 }
+
+
+void Soprano::Index::IndexFilterModel::optimizeIndex()
+{
+    d->index->optimize();
+}
Index: index/indexfiltermodel.h
===================================================================
--- index/indexfiltermodel.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ index/indexfiltermodel.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -179,6 +179,16 @@
             void rebuildIndex();
 
             /**
+             * Optimize the index for search. This makes sense after adding or
+             * removing a large number of statements.
+             *
+             * \sa CLuceneIndex::optimize
+             *
+             * \since 2.2
+             */
+            void optimizeIndex();
+
+            /**
              * Add a predicate which should only be indexed. This might be useful
              * for very large literals whose value is of no interest but which
              * should be searchable.
Index: index/cluceneindex.cpp
===================================================================
--- index/cluceneindex.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ index/cluceneindex.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -694,3 +694,9 @@
     }
     d->closeReader();
 }
+
+
+void Soprano::Index::CLuceneIndex::optimize()
+{
+    d->getIndexWriter()->optimize();
+}
Index: index/cluceneindex.h
===================================================================
--- index/cluceneindex.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ index/cluceneindex.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -244,6 +244,14 @@
              * \since 2.1
              */
             void clear();
+
+            /**
+             * Optimize the index for search. This makes sense after adding or
+             * removing a large number of statements.
+             *
+             * \since 2.2
+             */
+            void optimize();
             //@}
 
         private:
Index: backends/sesame2/sesame2backend.cpp
===================================================================
--- backends/sesame2/sesame2backend.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/sesame2/sesame2backend.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -63,7 +63,7 @@
 }
 
 
-Soprano::StorageModel* Soprano::Sesame2::BackendPlugin::createModel( const QList<BackendSetting>& settings ) const
+Soprano::StorageModel* Soprano::Sesame2::BackendPlugin::createModel( const BackendSettings& settings ) const
 {
     m_mutex.lock();
     if ( !m_jniWrapper ) {
Index: backends/sesame2/sesame2backend.h
===================================================================
--- backends/sesame2/sesame2backend.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/sesame2/sesame2backend.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -41,7 +41,7 @@
             BackendPlugin();
             ~BackendPlugin();
 
-            StorageModel* createModel( const QList<BackendSetting>& settings = QList<BackendSetting>() ) const;
+            StorageModel* createModel( const BackendSettings& settings = BackendSettings() ) const;
 
             bool deleteModelData( const BackendSettings& settings ) const;
 
Index: backends/sesame2/jniwrapper.cpp
===================================================================
--- backends/sesame2/jniwrapper.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/sesame2/jniwrapper.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -66,12 +66,14 @@
     if ( !s_instance ) {
         // prepare the VM options
         JavaVMInitArgs vmArgs;
-        JavaVMOption vmOptions[2];
+        JavaVMOption vmOptions[4];
         vmOptions[0].optionString = ( char* )"-Djava.class.path="SESAME2_CLASSPATH;
         vmOptions[1].optionString = ( char* )"-verbose:jni,gc,class";
+        vmOptions[2].optionString = ( char* )"-Xms256m";
+        vmOptions[3].optionString = ( char* )"-Xmx256m";
         vmArgs.version = JNI_VERSION_1_4;
         vmArgs.options = vmOptions;
-        vmArgs.nOptions = 2;
+        vmArgs.nOptions = 4;
 
         // create the VM
         JavaVM* jvm = 0;
Index: backends/redland/redlandbackend.cpp
===================================================================
--- backends/redland/redlandbackend.cpp	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/redland/redlandbackend.cpp	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -56,7 +56,7 @@
 }
 
 
-Soprano::StorageModel* Soprano::Redland::BackendPlugin::createModel( const QList<BackendSetting>& settings ) const
+Soprano::StorageModel* Soprano::Redland::BackendPlugin::createModel( const BackendSettings& settings ) const
 {
     QMutexLocker lock( &m_mutex );
 
Index: backends/redland/redlandbackend.h
===================================================================
--- backends/redland/redlandbackend.h	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/redland/redlandbackend.h	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -47,7 +47,7 @@
              *     contexts=yes, new=no. Soprano::BackendOptions Soprano::BackendOptionStorageDir and
              *     Soprano::BackendOptionStorageMemory change the values of redland options "dir" and "has-type".
              */
-            StorageModel* createModel( const QList<BackendSetting>& settings = QList<BackendSetting>() ) const;
+            StorageModel* createModel( const BackendSettings& settings = BackendSettings() ) const;
 
             bool deleteModelData( const BackendSettings& settings ) const;
 
Index: backends/CMakeLists.txt
===================================================================
--- backends/CMakeLists.txt	(.../tags/soprano/2.1.1)	(revision 846898)
+++ backends/CMakeLists.txt	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -4,6 +4,6 @@
   add_subdirectory(redland)
 endif(REDLAND_FOUND)
 
-if(JNI_1_6_FOUND)
+if(JNI_1_4_FOUND)
   add_subdirectory(sesame2)
-endif(JNI_1_6_FOUND)
+endif(JNI_1_4_FOUND)
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt	(.../tags/soprano/2.1.1)	(revision 846898)
+++ CMakeLists.txt	(.../trunk/kdesupport/soprano)	(revision 846898)
@@ -2,7 +2,7 @@
 
 set(CMAKE_SOPRANO_VERSION_MAJOR 2 CACHE INT "Major Soprano version number" FORCE)
 set(CMAKE_SOPRANO_VERSION_MINOR 1 CACHE INT "Minor Soprano version number" FORCE)
-set(CMAKE_SOPRANO_VERSION_RELEASE 1 CACHE INT "Release Soprano version number" FORCE)
+set(CMAKE_SOPRANO_VERSION_RELEASE 61 CACHE INT "Release Soprano version number" FORCE)
 set(CMAKE_SOPRANO_VERSION_STRING "${CMAKE_SOPRANO_VERSION_MAJOR}.${CMAKE_SOPRANO_VERSION_MINOR}.${CMAKE_SOPRANO_VERSION_RELEASE}" CACHE STRING "Soprano version string" FORCE)
 
 enable_testing()
@@ -21,14 +21,17 @@
 find_package(JNI)
 if(JAVA_INCLUDE_PATH AND JAVA_JVM_LIBRARY)
   file(READ ${JAVA_INCLUDE_PATH}/jni.h jni_header_data)
-  string(REGEX MATCH "JNI_VERSION_1_6" JNI_1_6_FOUND "${jni_header_data}")
-  if(JNI_1_6_FOUND)
-    message(STATUS "Found Java JNI >= 1.6: ${JAVA_INCLUDE_PATH}, ${JAVA_JVM_LIBRARY}")
-  else(JNI_1_6_FOUND)
-    message( "Need JRE version 1.6 or higher for the Sesame2 backend.")
-  endif(JNI_1_6_FOUND)
+  string(REGEX MATCH "JNI_VERSION_1_4" JNI_1_4_FOUND "${jni_header_data}")
+  if(JNI_1_4_FOUND)
+    message(STATUS "Found Java JNI >= 1.4: ${JAVA_INCLUDE_PATH}, ${JAVA_JVM_LIBRARY}")
+  else(JNI_1_4_FOUND)
+    message( "Need JNI version 1.4 or higher for the Sesame2 backend.")
+  endif(JNI_1_4_FOUND)
 else(JAVA_INCLUDE_PATH AND JAVA_JVM_LIBRARY)
   message(STATUS "Could not find Java JNI")
+  if("$ENV{JAVA_HOME}" STREQUAL "")
+    message("Make sure JAVA_HOME is set")
+  endif("$ENV{JAVA_HOME}" STREQUAL "")
 endif(JAVA_INCLUDE_PATH AND JAVA_JVM_LIBRARY)
 
 set (LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
@@ -99,16 +102,16 @@
 
 message("---------------------------------------------------------------------------------------")
 message("-- Soprano Components that will be built:")
-if(NOT REDLAND_FOUND AND NOT JNI_1_6_FOUND)
+if(NOT REDLAND_FOUND AND NOT JNI_1_4_FOUND)
   message("   WARNING: No Soprano backends will be compiled due to missing dependencies!")
   message("   WARNING: Soprano will not be very useful without storage backends!")
-endif(NOT REDLAND_FOUND AND NOT JNI_1_6_FOUND)
+endif(NOT REDLAND_FOUND AND NOT JNI_1_4_FOUND)
 if(REDLAND_FOUND)
   message("   * Redland storage backend")
 endif(REDLAND_FOUND)
-if(JNI_1_6_FOUND)
+if(JNI_1_4_FOUND)
   message("   * Sesame2 storage backend (java-based)")
-endif(JNI_1_6_FOUND)
+endif(JNI_1_4_FOUND)
 
 if(REDLAND_FOUND)
   message("   * Raptor RDF parser")
@@ -131,9 +134,9 @@
 if(NOT REDLAND_FOUND)
   message("   * Redland storage backend")
 endif(NOT REDLAND_FOUND)
-if(NOT JNI_1_6_FOUND)
+if(NOT JNI_1_4_FOUND)
   message("   * Sesame2 storage backend (java-based)")
-endif(NOT JNI_1_6_FOUND)
+endif(NOT JNI_1_4_FOUND)
 
 if(NOT REDLAND_FOUND)
   message("   * Raptor RDF parser")