utilities/downloadmanager/src/clientdownload.cpp
changeset 16 3c88a81ff781
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utilities/downloadmanager/src/clientdownload.cpp	Fri Oct 15 17:30:59 2010 -0400
@@ -0,0 +1,573 @@
+/**
+   This file is part of CWRT package **
+
+   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). **
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU (Lesser) General Public License as 
+   published by the Free Software Foundation, version 2.1 of the License. 
+   This program 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 
+   (Lesser) General Public License for more details. You should have 
+   received a copy of the GNU (Lesser) General Public License along 
+   with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "clientdownload.h"
+#include "downloadbackend.h"
+#include "downloadfactory.h"
+#include "downloadcoremanager.h"
+#include "downloadcore.h"
+#include "downloadmanager.h"
+#include "downloadevent.h"
+#include "downloadinfo.h"
+#include "sequentialdownloadmanager.h"
+#include <QNetworkReply>
+#include <QFileInfo>
+#include <QCoreApplication>
+
+#define PROGRESS_MINKB 5120 //Minimum KB to send progress events
+
+// private implementation
+class ClientDownloadPrivate
+{
+    DM_DECLARE_PUBLIC(ClientDownload);
+public:
+    ClientDownloadPrivate();
+    ~ClientDownloadPrivate();
+    int m_downloadId;
+    QString m_url;  // url
+    DownloadManager *m_downloadManager; // not owned, only reference
+    DownloadBackend *m_downloadBackend;
+    DownloadCore *m_downloadCore; // not owned
+    EventReceiverList m_eventReceiverList; // list of event listeners
+    DownloadInfo *m_dlInfo;         // not owned  
+    bool m_createdByDlInfo; // flag to indicate persistant ClientDownload
+    int m_parentId; // to set parent id
+    QMap<DownloadAttribute, QVariant> m_downloadAttrMap; // the map of attributes can be set by client
+};
+
+ClientDownloadPrivate::ClientDownloadPrivate():m_downloadId(-1)
+                                              ,m_url("")
+                                              ,m_downloadManager(0)
+                                              ,m_downloadBackend(0)
+                                              ,m_downloadCore(0)
+                                              ,m_dlInfo(0)
+                                              ,m_createdByDlInfo(false)
+                                              ,m_parentId(INVALID_DL_ID)
+{ }
+
+ClientDownloadPrivate::~ClientDownloadPrivate()
+{
+    if(m_downloadBackend)
+    {
+         delete m_downloadBackend;
+         m_downloadBackend = 0;
+    }
+}
+
+/*!
+ * \class ClientDownload
+ *
+ * \brief The public APIs for managing a ClientDownload
+ *
+ * This class has the public APIs for managing a single ClientDownload
+ */
+
+// note that parentdlId is id of the parent download which is applicable in the case
+// where parent download is oma download and child is media download
+ClientDownload::ClientDownload(DownloadManager *mgr, const QString& url
+                                                   , int dlId
+                                                   , DownloadType type/*=Parallel*/
+                                                   , int parentdlId /*=INVALID_DL_ID*/)
+{
+    DM_INITIALIZE(ClientDownload);
+    priv->m_downloadId = dlId;
+    priv->m_downloadManager = mgr;
+    priv->m_url = url;
+    priv->m_dlInfo = priv->m_downloadManager->downloadInfo();
+    if (parentdlId > INVALID_DL_ID)
+        setParentId(parentdlId);
+
+    // set the default destination path
+    priv->m_downloadAttrMap.insert(DlDestPath, mgr->getAttribute(DlMgrDestPath));
+    // set the default filename from url
+    QUrl urlToDownload(url);
+    QFileInfo fileUrl(urlToDownload.path());
+    QString fileName = fileUrl.fileName();
+    priv->m_downloadAttrMap.insert(DlFileName, fileName);
+    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EFileName, fileName, parentdlId);
+    // set 5Kb as minimum size to send the progress event
+    priv->m_downloadAttrMap.insert(DlProgressInterval, PROGRESS_MINKB);
+    // set the download type
+    priv->m_downloadAttrMap.insert(DlDownloadType, type);
+    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EType, (long)type, parentdlId);
+    // set the download scope
+    priv->m_downloadAttrMap.insert(DlDownloadScope, Normal);
+    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EScope, (long)Normal, parentdlId);
+
+    // create ClientDownload core for network transactions
+    priv->m_downloadCore = priv->m_downloadManager->downloadCoreManager()->createDownloadCore(url);
+    // set the proxy
+    priv->m_downloadCore->setProxy(mgr->proxy());
+    connect(priv->m_downloadCore, SIGNAL(metaDataChanged()), this, SLOT(createDownloadImplementation()));
+}
+
+// note that parentdlId is id of the parent download which is applicable in the case
+// where parent download is oma download and child is media download
+ClientDownload::ClientDownload(DownloadManager *mgr, QNetworkReply *reply
+                                                   , int dlId
+                                                   , int parentdlId /*=INVALID_DL_ID*/)
+{
+    DM_INITIALIZE(ClientDownload);
+    priv->m_downloadManager = mgr;
+    priv->m_downloadId = dlId;
+    priv->m_dlInfo = priv->m_downloadManager->downloadInfo();
+    if (parentdlId > INVALID_DL_ID)
+        setParentId(parentdlId);
+
+    // set the default destination path
+    priv->m_downloadAttrMap.insert(DlDestPath, mgr->getAttribute(DlMgrDestPath));
+    if (reply) {
+        // set the default filename from url
+        QUrl urlToDownload(reply->url());
+        QFileInfo fileUrl(urlToDownload.path());
+        QString fileName = fileUrl.fileName();
+        priv->m_downloadAttrMap.insert(DlFileName, fileName);
+        priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EFileName, fileName, parentdlId);
+    }
+    // set 5Kb as minimum size to send the progress event
+    priv->m_downloadAttrMap.insert(DlProgressInterval, PROGRESS_MINKB);
+    // set the download type as parallel
+    priv->m_downloadAttrMap.insert(DlDownloadType, Parallel);
+    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EType, (long)Parallel, parentdlId);
+        // set the download scope
+    priv->m_downloadAttrMap.insert(DlDownloadScope, Normal);
+    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EScope, (long)Normal, parentdlId);
+    // create ClientDownload core for network transactions
+    priv->m_downloadCore = priv->m_downloadManager->downloadCoreManager()->createDownloadCore(reply);
+    // create actual implementation class based on content type of the ClientDownload
+    priv->m_downloadBackend = DownloadAbstractFactory::createDownloadImplementation(priv->m_downloadCore, this);
+    priv->m_downloadBackend->setStartTime();
+ }
+
+// this is the case for reading the persistant  ClientDownload information of last session and 
+// creating ClientDownload object
+ClientDownload::ClientDownload(DownloadManager *mgr, int dlId, int parentdlId)
+{
+    DM_INITIALIZE(ClientDownload);
+    priv->m_downloadManager = mgr;
+    priv->m_downloadId = dlId;
+    priv->m_createdByDlInfo =  true;
+    priv->m_dlInfo = priv->m_downloadManager->downloadInfo();
+    if (parentdlId > INVALID_DL_ID)
+         setParentId(parentdlId);
+
+    // read the path from persistant
+    QString path;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EFinalPath, path, parentdlId);
+    priv->m_downloadAttrMap.insert(DlDestPath, path);
+
+    // set 5Kb as minimum size to send the progress event
+    priv->m_downloadAttrMap.insert(DlProgressInterval, PROGRESS_MINKB);
+    
+    // set the download type parallel/sequential
+    long type;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EType, type, parentdlId);
+    priv->m_downloadAttrMap.insert(DlDownloadType, (DownloadType)type);
+
+    // set the priority
+    long priority;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EPriority, priority, parentdlId);
+    priv->m_downloadAttrMap.insert(DlPriority, (DownloadPriority)priority);
+
+    // fetching url
+    QString url;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EUrl, url, parentdlId);
+    // create ClientDownload core for network transactions
+    priv->m_downloadCore = priv->m_downloadManager->downloadCoreManager()->createDownloadCore(url);
+    // set the proxy
+    QNetworkProxy *proxy = priv->m_downloadCore->proxy();
+    if(!proxy && priv->m_downloadCore && priv->m_downloadManager) {
+         //set ClientDownload core's proxy as ClientDownload manager's proxy, if its not already set
+         priv->m_downloadCore->setProxy(priv->m_downloadManager->proxy());
+    }
+    // fetch the content type
+    QString contentType;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EContentType, contentType, parentdlId);
+    priv->m_downloadCore->setContentType(contentType);
+
+    // fetch ETag header value
+    QString entityTag;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EETag, entityTag, parentdlId);
+    priv->m_downloadCore->setEntityTag(entityTag);
+
+    // create actual implementation class based on content type of the ClientDownload
+    priv->m_downloadBackend = DownloadAbstractFactory::createDownloadImplementation(priv->m_downloadCore, this);
+    priv->m_downloadBackend->init();
+
+    long size = 0;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::ETotalSize, size, parentdlId);
+    priv->m_downloadBackend->setTotalSize(size);
+
+    long state = 0;
+    priv->m_dlInfo->getValue(priv->m_downloadId, DownloadInfo::EDlState, state, parentdlId);
+    if (state == DlCompleted) 
+        priv->m_downloadBackend->setDownloadedDataSize(size);
+    else {
+        // fetch the already downloaded data size
+        qint64 currentSize = priv->m_downloadBackend->storedDataSize();    
+        priv->m_downloadBackend->setDownloadedDataSize(currentSize);
+    }
+    
+    if (state  == DlInprogress)
+        priv->m_downloadBackend->setDownloadState(DlPaused);
+    else
+        priv->m_downloadBackend->setDownloadState((DownloadState)state);       
+}
+ 
+ClientDownload::~ClientDownload()
+{ 
+    DM_UNINITIALIZE(ClientDownload);
+}
+
+/*!
+  returns id of the ClientDownload
+*/
+int ClientDownload::id()
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_downloadId;
+}
+
+/*!
+  starts the ClientDownload, returns the success status
+*/
+int ClientDownload::start()
+{
+    DM_PRIVATE(ClientDownload);
+    DownloadType type = (DownloadType)((priv->m_downloadAttrMap.value(DlDownloadType)).toInt());
+    if(type == Sequential)
+        priv->m_downloadManager->sequentialManager()->process(priv->m_downloadId);
+    else
+        startDownload(); // starts the download parallely
+    return 0;
+}
+
+/*!
+  sets the attribute for the ClientDownload
+  \a attr indicates attribute
+  \a value indicates value for the ClientDownload
+*/
+int ClientDownload::setAttribute(DownloadAttribute attr, const QVariant& value)
+{
+    //sets the attribute to ClientDownload backend
+    DM_PRIVATE(ClientDownload);
+    switch(attr)
+    {
+        case DlFileName:
+        case DlDestPath:
+        {            
+            // download is just created but not started
+            // filename, destination path can be set only before the download has started
+            if(!priv->m_downloadBackend)
+            {
+                QString strValue = value.toString();       
+                if(strValue.length() != 0)
+                    priv->m_downloadAttrMap.insert(attr, value);
+                return 0;
+            }
+            else
+                return -1;
+        }
+        case DlPriority:
+            {
+                // cannot change the priority once the download has started
+                if(!priv->m_downloadBackend)
+                {
+                    priv->m_downloadAttrMap.insert(attr, value);
+                    priv->m_dlInfo->setValue(priv->m_downloadId, DownloadInfo::EPriority, (long)(value.toInt()), parentId());
+                    // reshuffle the download queue based on the priority
+                    if((DownloadType)(priv->m_downloadAttrMap.value(DlDownloadType).toInt()) == Sequential)
+                        priv->m_downloadManager->sequentialManager()->addToSequentialDownload(this);
+                    return 0;
+                }
+            }
+        case DlProgressInterval:
+        {
+            qlonglong val = value.toLongLong() * 1024;
+            if (val >= PROGRESS_MINKB) {
+                priv->m_downloadAttrMap.insert(attr, val);
+                return 0;
+            }
+        }
+                
+        default:
+            if(priv->m_downloadBackend)
+                return priv->m_downloadBackend->setAttribute(attr, value);
+    }
+    return 0;
+}
+
+/*!
+  fetches the attribute of the ClientDownload
+  \a attr indicates ClientDownload attribute
+*/
+QVariant ClientDownload::getAttribute(DownloadAttribute attr)
+{
+    //gets attribute
+    DM_PRIVATE(ClientDownload);
+    switch(attr)
+    {
+        case DlFileName:
+        {
+            if(priv->m_downloadBackend) // download is already started
+                return priv->m_downloadBackend->getAttribute(attr);
+            else
+                return priv->m_downloadAttrMap.value(DlFileName);
+        }
+        case DlDestPath:
+        {
+            return priv->m_downloadAttrMap.value(DlDestPath);
+        }
+        case DlPriority:
+        {
+            return priv->m_downloadAttrMap.value(DlPriority);
+        }
+        case DlDownloadType:
+        {
+            return priv->m_downloadAttrMap.value(DlDownloadType);
+        }
+        case DlProgressInterval:
+        {
+            qlonglong val = priv->m_downloadAttrMap.value(DlProgressInterval).toLongLong() / 1024;
+            return val;
+        }
+        default:
+        {
+            if(priv->m_downloadBackend)
+                return priv->m_downloadBackend->getAttribute(attr);
+        }
+    }  
+    return QVariant();
+}
+
+/*!
+  pauses the ClientDownload
+*/
+int ClientDownload::pause()
+{
+    DM_PRIVATE(ClientDownload);
+    DownloadType type = (DownloadType)((priv->m_downloadAttrMap.value(DlDownloadType)).toInt());
+    if(type == Sequential)
+        priv->m_downloadManager->sequentialManager()->pauseDownload(priv->m_downloadId);
+    else
+        pauseDownload(); // pauses the download parallely
+    return 0;
+}
+
+/*!
+  resumes the ClientDownload
+*/
+int ClientDownload::resume()
+{
+    DM_PRIVATE(ClientDownload);
+    DownloadType type = (DownloadType)((priv->m_downloadAttrMap.value(DlDownloadType)).toInt());
+    if(type == Sequential)
+        priv->m_downloadManager->sequentialManager()->resumeDownload(priv->m_downloadId);
+    else
+        resumeDownload(); // resumes the download parallely
+    return 0;
+}
+
+/*!
+  cancels the ClientDownload
+*/
+int ClientDownload::cancel()
+{
+    DM_PRIVATE(ClientDownload);
+    DownloadType type = (DownloadType)((priv->m_downloadAttrMap.value(DlDownloadType)).toInt());
+    if(type == Sequential)
+        priv->m_downloadManager->sequentialManager()->cancelDownload(priv->m_downloadId);
+    else
+        cancelDownload(); // cancels the download parallely
+    return 0;
+}
+
+/*!
+  registers receiver for the ClientDownload events
+  \a reciever indicates reciever which listen to ClientDownload events
+*/
+void ClientDownload::registerEventReceiver(QObject *receiver)
+{
+    DM_PRIVATE(ClientDownload);
+    if(receiver)
+        if (!priv->m_eventReceiverList.contains(receiver))
+            priv->m_eventReceiverList.append(receiver);
+}
+
+/*!
+  unregisters the event listener
+  \a receiver indicates listener which will be unregistered
+*/
+void ClientDownload::unregisterEventReceiver(QObject *receiver)
+{
+    DM_PRIVATE(ClientDownload);
+    priv->m_eventReceiverList.removeOne(receiver);
+}
+
+EventReceiverList& ClientDownload::eventReceivers()
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_eventReceiverList;
+}
+
+/*!
+  returns ClientDownload manager
+*/
+DownloadManager* ClientDownload::downloadManager()
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_downloadManager;
+}
+
+/*!
+  returns the child downloads i.e if ClientDownload has any media objects
+  \a list indicates list of child downloads
+*/
+void ClientDownload::getChildren(QList<Download*>& list)
+{
+    DM_PRIVATE(ClientDownload);
+    if(priv->m_downloadBackend)
+       priv->m_downloadBackend->getChildren(list);
+}
+
+DownloadInfo* ClientDownload::downloadInfo()
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_dlInfo;
+}
+
+void ClientDownload::createDownloadImplementation()
+{
+    DM_PRIVATE(ClientDownload);
+    //ClientDownload backend is created based on the content type
+    if(!priv->m_downloadBackend) {
+        priv->m_downloadBackend = DownloadAbstractFactory::createDownloadImplementation(priv->m_downloadCore, this);
+        priv->m_downloadBackend->setStartTime();
+        postEvent(HeaderReceived, NULL);
+    }
+}
+
+void ClientDownload::postEvent(DEventType type, DlEventAttributeMap* attrMap)
+{
+    DM_PRIVATE(ClientDownload);
+    EventReceiverList list = eventReceivers();
+    for(int i=0; i<list.size(); i++) {
+        if(list[i]) {
+            DownloadEvent *event = new DownloadEvent(type, attrMap, priv->m_downloadId);
+            QCoreApplication::postEvent(list[i], event);
+        }
+    }
+}
+
+void ClientDownload::setError(const QString& errorStr)
+{
+    DM_PRIVATE(ClientDownload);
+    priv->m_downloadCore->setLastErrorString(errorStr);
+    priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
+}
+
+void ClientDownload::setDownloadState(DownloadState state)
+{
+    DM_PRIVATE(ClientDownload);
+    priv->m_downloadBackend->setDownloadState(state);
+}
+
+bool ClientDownload::isCreatedByDlInfo(void)
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_createdByDlInfo;
+}
+
+void ClientDownload::setParentId(int parentId)
+{
+    DM_PRIVATE(ClientDownload);
+    priv->m_parentId = parentId;
+}
+
+int ClientDownload::parentId()
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_parentId;
+}
+
+QMap<DownloadAttribute, QVariant>& ClientDownload::attributes(void)
+{
+    DM_PRIVATE(ClientDownload);
+    return priv->m_downloadAttrMap;
+}
+
+// starts the ClientDownload, returns the success status
+int ClientDownload::startDownload()
+{
+    DM_PRIVATE(ClientDownload);
+    if (!(priv->m_downloadCore))
+        return -1;  
+    QNetworkProxy *proxy = priv->m_downloadCore->proxy();
+    if(!proxy && priv->m_downloadManager) {
+         //set ClientDownload core's proxy as ClientDownload manager's proxy, if its not already set
+         priv->m_downloadCore->setProxy(priv->m_downloadManager->proxy());
+    }
+    priv->m_downloadCore->doDownload();
+
+    return 0;
+}
+
+int ClientDownload::pauseDownload()
+{
+    DM_PRIVATE(ClientDownload);
+    if( priv->m_downloadBackend ) {
+        DownloadState state = (DownloadState)priv->m_downloadBackend->getAttribute(DlDownloadState).toInt();
+        if( state != DlInprogress)
+            return 0;
+        return priv->m_downloadBackend->pause();
+    }
+    else
+        priv->m_downloadCore->abort();
+    return 0;
+}
+
+int ClientDownload::resumeDownload()
+{
+    DM_PRIVATE(ClientDownload);
+    QNetworkProxy *proxy = priv->m_downloadCore->proxy();
+    if(!proxy && priv->m_downloadCore && priv->m_downloadManager) {
+         //set ClientDownload core's proxy as ClientDownload manager's proxy, if its not already set
+         priv->m_downloadCore->setProxy(priv->m_downloadManager->proxy());
+    }
+    if(priv->m_downloadBackend) {
+        DownloadState state = (DownloadState)priv->m_downloadBackend->getAttribute(DlDownloadState).toInt();
+        if((state != DlPaused) && (state != DlCancelled))
+            return 0;
+        return priv->m_downloadBackend->resume();
+    }
+    else
+        startDownload(); // This means, ClientDownload has just been created but never started
+    return 0;
+}
+
+int ClientDownload::cancelDownload()
+{
+    // cancels the ClientDownload
+    DM_PRIVATE(ClientDownload);
+    if( priv->m_downloadBackend ) {
+        DownloadState state = (DownloadState)priv->m_downloadBackend->getAttribute(DlDownloadState).toInt();
+        if((state == DlCompleted) || (state == DlFailed) || (state == DlCancelled))
+            return 0; 
+        return priv->m_downloadBackend->cancel();
+    }
+    return 0;
+}
+