00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "itemserializer_p.h"
00022 #include "item.h"
00023 #include "itemserializerplugin.h"
00024 #include "attributefactory.h"
00025
00026
00027 #include <kdebug.h>
00028 #include <kmimetype.h>
00029 #include <kglobal.h>
00030
00031
00032 #include <QtCore/QBuffer>
00033 #include <QtCore/QFile>
00034 #include <QtCore/QIODevice>
00035 #include <QtCore/QHash>
00036 #include <QtCore/QString>
00037 #include <QtCore/QStringList>
00038
00039 #include <boost/graph/adjacency_list.hpp>
00040 #include <boost/graph/topological_sort.hpp>
00041
00042
00043 #include "pluginloader_p.h"
00044
00045
00046
00047 namespace Akonadi {
00048
00049 class DefaultItemSerializerPlugin;
00050
00051 class DefaultItemSerializerPlugin : public ItemSerializerPlugin
00052 {
00053 public:
00054 DefaultItemSerializerPlugin() { }
00055
00056 bool deserialize( Item& item, const QByteArray& label, QIODevice& data, int )
00057 {
00058 if ( label != Item::FullPayload )
00059 return false;
00060 item.setPayload( data.readAll() );
00061 return true;
00062 }
00063
00064 void serialize( const Item& item, const QByteArray& label, QIODevice& data, int& )
00065 {
00066 Q_ASSERT( label == Item::FullPayload );
00067 if ( item.hasPayload<QByteArray>() )
00068 data.write( item.payload<QByteArray>() );
00069 }
00070
00071 };
00072
00073 K_GLOBAL_STATIC( DefaultItemSerializerPlugin, s_defaultItemSerializerPlugin )
00074
00075 }
00076
00077 using namespace Akonadi;
00078
00079 class PluginEntry
00080 {
00081 public:
00082 PluginEntry()
00083 : mPlugin( 0 )
00084 {
00085 }
00086
00087 explicit PluginEntry( const QString &identifier, ItemSerializerPlugin *plugin = 0 )
00088 : mIdentifier( identifier ), mPlugin( plugin )
00089 {
00090 }
00091
00092 inline ItemSerializerPlugin* plugin() const
00093 {
00094 if ( mPlugin )
00095 return mPlugin;
00096
00097 QObject *object = PluginLoader::self()->createForName( mIdentifier );
00098 if ( !object ) {
00099 kWarning( 5250 ) << "ItemSerializerPluginLoader: "
00100 << "plugin" << mIdentifier << "is not valid!" << endl;
00101
00102
00103 mPlugin = s_defaultItemSerializerPlugin;
00104 }
00105
00106 mPlugin = qobject_cast<ItemSerializerPlugin*>( object );
00107 if ( !mPlugin ) {
00108 kWarning( 5250 ) << "ItemSerializerPluginLoader: "
00109 << "plugin" << mIdentifier << "doesn't provide interface ItemSerializerPlugin!" << endl;
00110
00111
00112 mPlugin = s_defaultItemSerializerPlugin;
00113 }
00114
00115 Q_ASSERT( mPlugin );
00116
00117 return mPlugin;
00118 }
00119
00120 QString type() const { return mIdentifier; }
00121
00122 bool operator<( const PluginEntry &other ) const
00123 {
00124 return mIdentifier < other.mIdentifier;
00125 }
00126 bool operator<( const QString &type ) const
00127 {
00128 return mIdentifier < type;
00129 }
00130
00131 private:
00132 QString mIdentifier;
00133 mutable ItemSerializerPlugin *mPlugin;
00134 };
00135
00136 static bool operator<( const QString &type, const PluginEntry &entry )
00137 {
00138 return type < entry.type();
00139 }
00140
00141
00142 class PluginRegistry
00143 {
00144 public:
00145 PluginRegistry() :
00146 mDefaultPlugin( PluginEntry( QLatin1String("application/octet-stream"), s_defaultItemSerializerPlugin ) )
00147 {
00148 const PluginLoader* pl = PluginLoader::self();
00149 if ( !pl ) {
00150 kWarning( 5250 ) << "Cannot instantiate plugin loader!" << endl;
00151 return;
00152 }
00153 const QStringList types = pl->types();
00154 kDebug( 5250 ) << "ItemSerializerPluginLoader: "
00155 << "found" << types.size() << "plugins." << endl;
00156 allPlugins.reserve( types.size() + 1 );
00157 foreach ( const QString &type, types )
00158 allPlugins.append( PluginEntry( type ) );
00159 allPlugins.append( mDefaultPlugin );
00160 std::sort( allPlugins.begin(), allPlugins.end() );
00161 }
00162
00163 const PluginEntry& findBestMatch( const QString &type )
00164 {
00165 KMimeType::Ptr mimeType = KMimeType::mimeType( type, KMimeType::ResolveAliases );
00166 if ( mimeType.isNull() )
00167 return mDefaultPlugin;
00168
00169
00170 QVector<int> matchingIndexes;
00171 for ( int i = 0, end = allPlugins.size(); i < end; ++i ) {
00172 if ( mimeType->is( allPlugins[i].type() ) )
00173 matchingIndexes.append( i );
00174 }
00175
00176
00177 if ( matchingIndexes.isEmpty() )
00178 return mDefaultPlugin;
00179
00180 if ( matchingIndexes.size() == 1 )
00181 return allPlugins[matchingIndexes.first()];
00182
00183
00184 boost::adjacency_list<> graph( matchingIndexes.size() );
00185 for ( int i = 0, end = matchingIndexes.size() ; i != end ; ++i ) {
00186 KMimeType::Ptr mimeType = KMimeType::mimeType( allPlugins[matchingIndexes[i]].type(), KMimeType::ResolveAliases );
00187 if ( mimeType.isNull() )
00188 continue;
00189 for ( int j = 0; j != end; ++j ) {
00190 if ( i != j && mimeType->is( allPlugins[matchingIndexes[j]].type() ) )
00191 boost::add_edge( j, i, graph );
00192 }
00193 }
00194
00195 QVector<int> order;
00196 order.reserve( allPlugins.size() );
00197 try {
00198 boost::topological_sort( graph, std::back_inserter( order ) );
00199 } catch ( boost::not_a_dag &e ) {
00200 kWarning() << "Mimetype tree is not a DAG!";
00201 return mDefaultPlugin;
00202 }
00203
00204 return allPlugins[matchingIndexes[order.first()]];
00205 }
00206
00207 QVector<PluginEntry> allPlugins;
00208 QHash<QString, ItemSerializerPlugin*> cachedPlugins;
00209
00210 private:
00211 PluginEntry mDefaultPlugin;
00212 };
00213
00214 K_GLOBAL_STATIC( PluginRegistry, s_pluginRegistry )
00215
00216
00217
00218 void ItemSerializer::deserialize( Item& item, const QByteArray& label, const QByteArray& data, int version, bool external )
00219 {
00220
00221 if ( external ) {
00222 QFile file( QString::fromUtf8(data) );
00223 if ( file.open( QIODevice:: ReadOnly ) ) {
00224 deserialize( item, label, file, version );
00225 file.close();
00226 }
00227 } else {
00228 QBuffer buffer;
00229 buffer.setData( data );
00230 buffer.open( QIODevice::ReadOnly );
00231 buffer.seek( 0 );
00232 deserialize( item, label, buffer, version );
00233 buffer.close();
00234 }
00235 }
00236
00237
00238 void ItemSerializer::deserialize( Item& item, const QByteArray& label, QIODevice& data, int version )
00239 {
00240 if ( !ItemSerializer::pluginForMimeType( item.mimeType() ).deserialize( item, label, data, version ) )
00241 kWarning() << "Unable to deserialize payload part:" << label;
00242 }
00243
00244
00245 void ItemSerializer::serialize( const Item& item, const QByteArray& label, QByteArray& data, int &version )
00246 {
00247 QBuffer buffer;
00248 buffer.setBuffer( &data );
00249 buffer.open( QIODevice::WriteOnly );
00250 buffer.seek( 0 );
00251 serialize( item, label, buffer, version );
00252 buffer.close();
00253 }
00254
00255
00256 void ItemSerializer::serialize( const Item& item, const QByteArray& label, QIODevice& data, int &version )
00257 {
00258 if ( !item.hasPayload() )
00259 return;
00260 ItemSerializerPlugin& plugin = pluginForMimeType( item.mimeType() );
00261 plugin.serialize( item, label, data, version );
00262 }
00263
00264 QSet<QByteArray> ItemSerializer::parts(const Item & item)
00265 {
00266 if ( !item.hasPayload() )
00267 return QSet<QByteArray>();
00268 return pluginForMimeType( item.mimeType() ).parts( item );
00269 }
00270
00271
00272 ItemSerializerPlugin& ItemSerializer::pluginForMimeType( const QString & mimetype )
00273 {
00274
00275 if ( s_pluginRegistry->cachedPlugins.contains( mimetype ) )
00276 return *(s_pluginRegistry->cachedPlugins.value( mimetype ));
00277
00278 ItemSerializerPlugin *plugin = 0;
00279
00280
00281 const QVector<PluginEntry>::const_iterator it
00282 = qBinaryFind( s_pluginRegistry->allPlugins.constBegin(), s_pluginRegistry->allPlugins.constEnd(), mimetype );
00283 if ( it != s_pluginRegistry->allPlugins.constEnd() ) {
00284 plugin = (*it).plugin();
00285 } else {
00286
00287 const PluginEntry &entry = s_pluginRegistry->findBestMatch( mimetype );
00288 kDebug( 5250 ) << "Did not find exactly matching serializer plugin for type" << mimetype
00289 << ", taking" << entry.type() << "as the closest match";
00290 plugin = entry.plugin();
00291 }
00292
00293 Q_ASSERT(plugin);
00294 s_pluginRegistry->cachedPlugins.insert( mimetype, plugin );
00295 return *plugin;
00296 }