kde-playground/kdepim-runtime/migration/kres/kresmigrator.h
2015-04-14 22:08:21 +00:00

322 lines
12 KiB
C++

/*
Copyright (c) 2008 Volker Krause <vkrause@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 KRESMIGRATOR_H
#define KRESMIGRATOR_H
#include "kresmigratorbase.h"
#include <akonadi/agentmanager.h>
#include <kresources/manager.h>
#include <kresources/resource.h>
#include <QFile>
#include <KConfigGroup>
#include <KDebug>
#include <KGlobal>
#include <KStandardDirs>
using namespace Akonadi;
template <typename T> class KResMigrator : public KResMigratorBase
{
public:
KResMigrator( const QString &type, const QString &bridgeType ) :
KResMigratorBase( type, bridgeType ),
mConfig( 0 ),
mManager( 0 ),
mBridgeManager( 0 ),
mClientBridgeFound( false )
{
}
virtual ~KResMigrator()
{
delete mBridgeManager;
mBridgeManager = 0;
delete mManager;
mManager = 0;
delete mConfig;
mConfig = 0;
}
void migrate()
{
const QString kresCfgFile = KStandardDirs::locateLocal( "config", QString::fromLatin1( "kresources/%1/stdrc" ).arg( mType ) );
mConfig = new KConfig( kresCfgFile );
const KConfigGroup generalGroup( mConfig, QLatin1String( "General" ) );
mUnknownTypeResources = QSet<QString>::fromList( generalGroup.readEntry( QLatin1String( "ResourceKeys" ), QStringList() ) );
mManager = new KRES::Manager<T>( mType );
mManager->readConfig();
{
ResourceIterator it = mManager->begin();
while ( it != mManager->end() ) {
mResourcesToMigrate.append( *it );
++it;
}
mIt = mResourcesToMigrate.constBegin();
}
migrateNext();
}
void migrateNext()
{
while ( mIt != mResourcesToMigrate.constEnd() ) {
mUnknownTypeResources.remove( ( *mIt )->identifier() );
if ( ( *mIt )->type() == QLatin1String("akonadi") ) {
mClientBridgeIdentifier = ( *mIt )->identifier();
mClientBridgeFound = true;
emit message( Skip, i18n( "Client-side bridge already set up." ) );
++mIt;
continue;
}
//KConfigGroup cfg( KGlobal::config(), QLatin1String("Resource ") + ( *mIt )->identifier() );
kDebug() << "migrateNext:" << ( *mIt )->identifier();
if ( migrationState( ( *mIt )->identifier() ) == None ) {
emit message( Info, i18n( "Trying to migrate '%1'...", ( *mIt )->resourceName() ) );
mPendingBridgedResources.removeAll( ( *mIt )->identifier() );
T* res = *mIt;
mCurrentKResource = res;
++mIt;
if ( res->type() == QLatin1String("imap") ) {
createKolabResource( res->identifier(), res->resourceName() );
} else {
bool nativeAvailable = mBridgeOnly ? false : migrateResource( res );
if ( !nativeAvailable ) {
emit message( Info, i18n( "No native backend for '%1' available.", res->resourceName() ) );
migrateToBridge( res, mBridgeType );
}
}
return;
}
if ( migrationState( ( *mIt )->identifier() ) == Bridged &&
!mPendingBridgedResources.contains( ( *mIt )->identifier() ) )
mPendingBridgedResources << ( *mIt )->identifier();
if ( migrationState( ( *mIt )->identifier() ) == Complete )
emit message( Skip, i18n( "'%1' has already been migrated.", ( *mIt )->resourceName() ) );
++mIt;
}
if ( !mBridgeType.isEmpty() ) {
if ( mIt == mResourcesToMigrate.constEnd() ) {
migrateBridged();
if ( mPendingBridgedResources.isEmpty() ) {
migrateUnknown();
if ( mUnknownTypeResources.isEmpty() ) {
deleteLater();
}
}
}
} else {
migrateUnknown();
if ( mUnknownTypeResources.isEmpty() ) {
deleteLater();
}
}
}
void migrateBridged()
{
delete mBridgeManager;
mBridgeManager = 0;
if ( mPendingBridgedResources.isEmpty() ) {
setupClientBridge();
return;
}
const QString resId = mPendingBridgedResources.takeFirst();
KConfigGroup resMigrationCfg( KGlobal::config(), QLatin1String("Resource ") + resId );
const QString akoResId = resMigrationCfg.readEntry( "ResourceIdentifier", "" );
if ( akoResId.isEmpty() ) {
mUnknownTypeResources.remove( resId );
emit message( Error, i18n( "No Akonadi agent identifier specified for previously bridged resource '%1'", resId ) );
migrateNext();
return;
}
const QString bridgedCfgFile = KStandardDirs::locateLocal( "config", QString::fromLatin1( "%1rc" ).arg( akoResId ) );
kDebug() << bridgedCfgFile;
if ( !QFile::exists( bridgedCfgFile ) ) {
emit message( Info, i18n( "Bridged resource %1 does not exist anymore, trying a direct migration", akoResId ) );
setMigrationState( resId /*old id*/, None,
QString() /*akonadi id*/, mType );
ResourceIterator it = mManager->begin();
while ( it != mManager->end() ) {
if ( ( *it )->identifier() == resId ) {
mResourcesToMigrate.append( *it );
break;
}
++it;
}
migrateNext();
return;
}
mUnknownTypeResources.remove( resId );
delete mConfig;
mConfig = new KConfig( bridgedCfgFile );
mBridgeManager = new KRES::Manager<T>( mType );
mBridgeManager->readConfig( mConfig );
if ( !mBridgeManager->standardResource() ) {
// the plugin for this type might no longer be available
const KConfigGroup kresCfgGroup( mConfig, QString::fromLatin1( "Resource_%1" ).arg( resId ) );
const QString resourceType = kresCfgGroup.readEntry( QLatin1String( "ResourceType" ), QString() );
if ( !resourceType.isEmpty() ) {
if ( resourceType == QLatin1String( "imap" ) ) {
createKolabResource( resId, kresCfgGroup.readEntry( QLatin1String( "ResourceName" ), QString() ) );
return;
}
if ( migrateUnknownResource( resId, resourceType, kresCfgGroup ) ) {
migrateNext();
return;
}
}
emit message( Error, i18n( "Bridged resource '%1' has no standard resource.", resId ) );
migrateNext();
return;
}
T *res = mBridgeManager->standardResource();
emit message( Info, i18n( "Trying to migrate '%1' from compatibility bridge to native backend...", res->resourceName() ) );
mCurrentKResource = res;
bool nativeAvailable = migrateResource( res );
if ( !nativeAvailable ) {
emit message( Skip, i18n( "No native backend available, keeping compatibility bridge for '%1'.", res->resourceName() ) );
migrateNext();
}
}
virtual bool migrateResource( T *res ) = 0;
virtual bool migrateUnknownResource( const QString &kresId, const QString &kresType, const KConfigGroup &kresConfig )
{
Q_UNUSED( kresId );
Q_UNUSED( kresType );
Q_UNUSED( kresConfig );
migrateNext();
return false;
}
KConfigGroup kresConfig( KRES::Resource* res ) const
{
return KConfigGroup( mConfig, QLatin1String("Resource_") + res->identifier() );
}
T* currentResource()
{
T* res = dynamic_cast<T*>( mCurrentKResource );
Q_ASSERT( res );
return res;
}
void migrationCompleted( const Akonadi::AgentInstance &instance )
{
KResMigratorBase::migrationCompleted( instance, mCurrentKResource->identifier(), mCurrentKResource->resourceName() );
migrationCompletedHelper( instance );
}
void migratedToBridge(const Akonadi::AgentInstance & instance)
{
mBridgingInProgress = false;
setMigrationState( mCurrentKResource->identifier(), Bridged, instance.identifier(), mType );
emit message( Success, i18n( "Migration of '%1' to compatibility bridge succeeded.", mCurrentKResource->resourceName() ) );
migrationCompletedHelper( instance );
}
private:
// This is called when a native migration or a migration to a bridged resource is
// successfully completed.
void migrationCompletedHelper( const Akonadi::AgentInstance & instance )
{
if ( mManager->standardResource() == mCurrentKResource ) {
mAgentForOldDefaultResource = instance.identifier();
}
mManager->setActive( mCurrentKResource, false );
mCurrentKResource = 0;
migrateNext();
}
void setupClientBridge()
{
if ( !mOmitClientBridge ) {
if ( !mClientBridgeFound ) {
emit message( Info, i18n( "Setting up client-side bridge..." ) );
T* clientBridge = mManager->createResource( QLatin1String("akonadi") );
if ( clientBridge ) {
mClientBridgeIdentifier = clientBridge->identifier();
clientBridge->setResourceName( i18n( "Akonadi Compatibility Resource" ) );
mManager->add( clientBridge );
mManager->setStandardResource( clientBridge );
emit message( Info, i18n( "Client-side bridge set up successfully." ) );
} else {
emit message( Error, i18n( "Could not create client-side bridge, check if Akonadi KResource bridge is installed." ) );
}
}
mManager->writeConfig();
const QString keyName( QLatin1String("DefaultAkonadiResourceIdentifier") );
KConfigGroup clientBridgeConfig( mConfig, QLatin1String("Resource_") + mClientBridgeIdentifier );
if ( !clientBridgeConfig.hasKey( keyName ) &&
!mAgentForOldDefaultResource.isEmpty() ) {
clientBridgeConfig.writeEntry( keyName, mAgentForOldDefaultResource );
}
}
}
void migrateUnknown()
{
if ( mUnknownTypeResources.isEmpty() ) {
return;
}
QSet<QString>::iterator setIt = mUnknownTypeResources.begin();
const QString kresId = *setIt;
mUnknownTypeResources.erase( setIt );
const KConfigGroup kresCfgGroup( mConfig, QString::fromLatin1( "Resource_%1" ).arg( kresId ) );
const QString resourceType = kresCfgGroup.readEntry( QLatin1String( "ResourceType" ), QString() );
const QString resourceName = kresCfgGroup.readEntry( QLatin1String( "ResourceName" ), QString() );
kDebug() << "migrating Unknown" << resourceName << ", type=" << resourceType << ",id=" << kresId;
if ( resourceType == QLatin1String( "imap" ) ) {
createKolabResource( kresId, resourceName );
} else {
migrateUnknownResource( kresId, resourceType, kresCfgGroup );
}
}
private:
KConfig *mConfig;
KRES::Manager<T> *mManager, *mBridgeManager;
typedef typename KRES::Manager<T>::Iterator ResourceIterator;
typename QList<T*>::const_iterator mIt;
QList<T*> mResourcesToMigrate;
bool mClientBridgeFound;
QString mClientBridgeIdentifier;
QString mAgentForOldDefaultResource;
QSet<QString> mUnknownTypeResources;
};
#endif