00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "repository.h"
00016 #include "nepomukstorage-config.h"
00017 #include "modelcopyjob.h"
00018
00019 #ifdef HAVE_CLUCENE
00020 #include "cluceneanalyzer.h"
00021 #endif
00022
00023 #include <Soprano/Backend>
00024 #include <Soprano/Global>
00025 #include <Soprano/Version>
00026 #include <Soprano/StorageModel>
00027 #include <Soprano/Error/Error>
00028 #include <Soprano/Vocabulary/Xesam>
00029 #include <Soprano/Vocabulary/RDF>
00030
00031 #ifdef HAVE_SOPRANO_INDEX
00032 #include <Soprano/Index/IndexFilterModel>
00033 #include <Soprano/Index/CLuceneIndex>
00034 #endif
00035
00036 #include <KStandardDirs>
00037 #include <KDebug>
00038 #include <KConfigGroup>
00039 #include <KSharedConfig>
00040 #include <KLocale>
00041 #include <KNotification>
00042 #include <KIcon>
00043
00044 #include <QtCore/QTimer>
00045 #include <QtCore/QThread>
00046 #include <QtCore/QCoreApplication>
00047
00048
00049 namespace {
00050 QString createStoragePath( const QString& repositoryId )
00051 {
00052 return KStandardDirs::locateLocal( "data", "nepomuk/repository/" + repositoryId + "/" );
00053 }
00054
00055 #if defined(HAVE_SOPRANO_INDEX) && defined(HAVE_CLUCENE) && SOPRANO_IS_VERSION(2,1,64)
00056 class RebuildIndexThread : public QThread
00057 {
00058 public:
00059 RebuildIndexThread( Soprano::Index::IndexFilterModel* model )
00060 : m_model( model ) {
00061 }
00062
00063 void run() {
00064 m_model->rebuildIndex();
00065 }
00066
00067 private:
00068 Soprano::Index::IndexFilterModel* m_model;
00069 };
00070 #endif
00071 }
00072
00073
00074 Nepomuk::Repository::Repository( const QString& name )
00075 : m_name( name ),
00076 m_state( CLOSED ),
00077 m_model( 0 ),
00078 m_analyzer( 0 ),
00079 m_index( 0 ),
00080 m_indexModel( 0 )
00081 {
00082 }
00083
00084
00085 Nepomuk::Repository::~Repository()
00086 {
00087 close();
00088 }
00089
00090
00091 void Nepomuk::Repository::close()
00092 {
00093 if ( m_state == OPEN ) {
00094 #ifdef HAVE_SOPRANO_INDEX
00095 delete m_indexModel;
00096 delete m_index;
00097 m_indexModel = 0;
00098 m_index = 0;
00099 #ifdef HAVE_CLUCENE
00100 delete m_analyzer;
00101 m_analyzer = 0;
00102 #endif
00103 #endif
00104 delete m_model;
00105 m_model = 0;
00106
00107 m_state = CLOSED;
00108 }
00109 }
00110
00111
00112 void Nepomuk::Repository::open()
00113 {
00114 Q_ASSERT( m_state == CLOSED );
00115
00116 m_state = OPENING;
00117
00118
00119
00120 const Soprano::Backend* backend = activeSopranoBackend();
00121 if ( !backend ) {
00122 m_state = CLOSED;
00123 emit opened( this, false );
00124 return;
00125 }
00126
00127
00128
00129 KConfigGroup repoConfig = KSharedConfig::openConfig( "nepomukserverrc" )->group( name() + " Settings" );
00130 QString oldBackendName = repoConfig.readEntry( "Used Soprano Backend", backend->pluginName() );
00131 QString oldBasePath = repoConfig.readPathEntry( "Storage Dir", QString() );
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 m_basePath = oldBasePath.isEmpty() ? createStoragePath( name() ) : oldBasePath;
00144 QString indexPath = m_basePath + "index";
00145 QString storagePath = m_basePath + "data/" + backend->pluginName();
00146
00147 KStandardDirs::makeDir( indexPath );
00148 KStandardDirs::makeDir( storagePath );
00149
00150 kDebug(300002) << "opening repository '" << name() << "' at '" << m_basePath << "'";
00151
00152
00153
00154
00155 m_model = backend->createModel( QList<Soprano::BackendSetting>() << Soprano::BackendSetting( Soprano::BackendOptionStorageDir, storagePath ) );
00156 if ( !m_model ) {
00157 kDebug(300002) << "Unable to create model for repository" << name();
00158 m_state = CLOSED;
00159 emit opened( this, false );
00160 return;
00161 }
00162
00163 kDebug(300002) << "Successfully created new model for repository" << name();
00164
00165 #if defined(HAVE_SOPRANO_INDEX) && defined(HAVE_CLUCENE)
00166 m_analyzer = new CLuceneAnalyzer();
00167 m_index = new Soprano::Index::CLuceneIndex( m_analyzer );
00168
00169 if ( m_index->open( indexPath, true ) ) {
00170 kDebug(300002) << "Successfully created new index for repository" << name();
00171 m_indexModel = new Soprano::Index::IndexFilterModel( m_index, m_model );
00172
00173
00174 m_indexModel->setTransactionCacheSize( 100 );
00175
00176 #if SOPRANO_IS_VERSION(2,0,99)
00177
00178
00179 m_indexModel->addIndexOnlyPredicate( Soprano::Vocabulary::Xesam::asText() );
00180 #endif
00181 #if SOPRANO_IS_VERSION(2,1,64)
00182 m_indexModel->addForceIndexPredicate( Soprano::Vocabulary::RDF::type() );
00183 #endif
00184
00185 setParentModel( m_indexModel );
00186 }
00187 else {
00188 kDebug(300002) << "Unable to open CLucene index for repo '" << name() << "': " << m_index->lastError();
00189 delete m_index;
00190 delete m_model;
00191 m_index = 0;
00192 m_model = 0;
00193
00194 m_state = CLOSED;
00195 emit opened( this, false );
00196 return;
00197 }
00198 #else
00199 setParentModel( m_model );
00200 #endif
00201
00202
00203
00204 bool convertingData = false;
00205
00206
00207
00208
00209 if ( oldBackendName != backend->pluginName() ||
00210 oldBasePath.isEmpty() ) {
00211
00212 kDebug() << "Previous backend:" << oldBackendName << "- new backend:" << backend->pluginName();
00213 kDebug() << "Old path:" << oldBasePath << "- new path:" << m_basePath;
00214
00215 if ( oldBasePath.isEmpty() ) {
00216
00217
00218 m_oldStoragePath = createStoragePath( name() );
00219 }
00220 else {
00221 m_oldStoragePath = m_basePath + "data/" + oldBackendName;
00222 }
00223
00224
00225 Soprano::Model* oldModel = 0;
00226 m_oldStorageBackend = Soprano::discoverBackendByName( oldBackendName );
00227 if ( m_oldStorageBackend ) {
00228
00229 oldModel = m_oldStorageBackend->createModel( QList<Soprano::BackendSetting>() << Soprano::BackendSetting( Soprano::BackendOptionStorageDir, m_oldStoragePath ) );
00230 }
00231
00232 if ( oldModel ) {
00233 if ( !oldModel->isEmpty() ) {
00234 kDebug() << "Starting model conversion";
00235
00236 convertingData = true;
00237
00238 ModelCopyJob* copyJob = new ModelCopyJob( oldModel, m_model, this );
00239 connect( copyJob, SIGNAL( result( KJob* ) ), this, SLOT( copyFinished( KJob* ) ) );
00240 copyJob->start();
00241 }
00242 else {
00243 m_state = OPEN;
00244 }
00245 }
00246 else {
00247
00248 kDebug( 300002 ) << "Unable to convert old model.";
00249 m_state = OPEN;
00250 }
00251 }
00252 else {
00253 kDebug() << "no need to convert" << name();
00254 m_state = OPEN;
00255 }
00256
00257
00258
00259
00260
00261 if ( !convertingData ) {
00262 repoConfig.writeEntry( "Used Soprano Backend", backend->pluginName() );
00263 repoConfig.writePathEntry( "Storage Dir", m_basePath );
00264 repoConfig.sync();
00265
00266 if( m_state == OPEN ) {
00267 if ( !rebuildIndexIfNecessary() ) {
00268 emit opened( this, true );
00269 }
00270 }
00271 }
00272 else {
00273 KNotification::event( "convertingNepomukData",
00274 i18nc("@info - notification message",
00275 "Converting Nepomuk data to a new backend. This might take a while."),
00276 KIcon( "nepomuk" ).pixmap( 32, 32 ) );
00277 }
00278 }
00279
00280
00281 void Nepomuk::Repository::rebuildingIndexFinished()
00282 {
00283 KNotification::event( "rebuldingNepomukIndexDone",
00284 i18nc("@info - notification message",
00285 "Rebuilding Nepomuk full text search index for new features done."),
00286 KIcon( "nepomuk" ).pixmap( 32, 32 ) );
00287
00288
00289 KConfigGroup repoConfig = KSharedConfig::openConfig( "nepomukserverrc" )->group( name() + " Settings" );
00290 repoConfig.writeEntry( "rebuilt index for type indexing", true );
00291
00292
00293 m_state = OPEN;
00294 emit opened( this, true );
00295 }
00296
00297
00298 void Nepomuk::Repository::copyFinished( KJob* job )
00299 {
00300 if ( job->error() ) {
00301 KNotification::event( "convertingNepomukDataFailed",
00302 i18nc("@info - notification message",
00303 "Converting Nepomuk data to the new backend failed. Data may still be recovered manually though."),
00304 KIcon( "nepomuk" ).pixmap( 32, 32 ) );
00305
00306 kDebug( 300002 ) << "Converting old model failed.";
00307 }
00308 else {
00309 KNotification::event( "convertingNepomukDataDone",
00310 i18nc("@info - notification message",
00311 "Successfully converted Nepomuk data to the new backend."),
00312 KIcon( "nepomuk" ).pixmap( 32, 32 ) );
00313
00314 kDebug() << "Successfully converted model data for repo" << name();
00315
00316
00317 ModelCopyJob* copyJob = qobject_cast<ModelCopyJob*>( job );
00318 delete copyJob->source();
00319
00320
00321 m_oldStorageBackend->deleteModelData( QList<Soprano::BackendSetting>() << Soprano::BackendSetting( Soprano::BackendOptionStorageDir, m_oldStoragePath ) );
00322
00323
00324 KConfigGroup repoConfig = KSharedConfig::openConfig( "nepomukserverrc" )->group( name() + " Settings" );
00325 repoConfig.writeEntry( "Used Soprano Backend", activeSopranoBackend()->pluginName() );
00326 repoConfig.writePathEntry( "Storage Dir", m_basePath );
00327 repoConfig.sync();
00328
00329 if ( rebuildIndexIfNecessary() ) {
00330
00331 return;
00332 }
00333 }
00334
00335
00336 m_state = OPEN;
00337 emit opened( this, true );
00338 }
00339
00340
00341 void Nepomuk::Repository::optimize()
00342 {
00343 QTimer::singleShot( 0, this, SLOT( slotDoOptimize() ) );
00344 }
00345
00346
00347 void Nepomuk::Repository::slotDoOptimize()
00348 {
00349 #ifdef HAVE_SOPRANO_INDEX
00350 #if SOPRANO_IS_VERSION(2,1,60)
00351 m_index->optimize();
00352 #endif
00353 #endif
00354 }
00355
00356
00357 bool Nepomuk::Repository::rebuildIndexIfNecessary()
00358 {
00359 #if defined(HAVE_SOPRANO_INDEX) && defined(HAVE_CLUCENE) && SOPRANO_IS_VERSION(2,1,64)
00360 KConfigGroup repoConfig = KSharedConfig::openConfig( "nepomukserverrc" )->group( name() + " Settings" );
00361 if( !repoConfig.readEntry( "rebuilt index for type indexing", false ) ) {
00362 KNotification::event( "rebuldingNepomukIndex",
00363 i18nc("@info - notification message",
00364 "Rebuilding Nepomuk full text search index for new features. This will only be done once and might take a while."),
00365 KIcon( "nepomuk" ).pixmap( 32, 32 ) );
00366 RebuildIndexThread* rit = new RebuildIndexThread( m_indexModel );
00367 connect( rit, SIGNAL( finished() ), this, SLOT( rebuildingIndexFinished() ) );
00368 connect( rit, SIGNAL( finished() ), rit, SLOT( deleteLater() ) );
00369 rit->start();
00370 return true;
00371 }
00372 #endif
00373 return false;
00374 }
00375
00376
00377 const Soprano::Backend* Nepomuk::Repository::activeSopranoBackend()
00378 {
00379 QString backendName = KSharedConfig::openConfig( "nepomukserverrc" )->group( "Basic Settings" ).readEntry( "Soprano Backend", "sesame2" );
00380 const Soprano::Backend* backend = ::Soprano::discoverBackendByName( backendName );
00381 if ( !backend ) {
00382 kDebug(300002) << "(Nepomuk::Core::Core) could not find backend" << backendName << ". Falling back to default.";
00383 backend = ::Soprano::usedBackend();
00384 }
00385 if ( !backend ) {
00386 kDebug(300002) << "(Nepomuk::Core::Core) could not find a backend.";
00387 }
00388 return backend;
00389 }
00390
00391 #include "repository.moc"