/home/croftj/photogrotto/dbPhotoService.cpp

00001 /*********************************************************************************
00002 **
00003 **   $Id: //depot/WorkInProgress/photogrotto/dbPhotoService.cpp#4 $
00004 **   Copyright (c) 2007 Joe Croft joe@croftj.net
00005 **   
00006 **   This file is part of Photogrotto
00007 **
00008 **   Photogrotto is free software; you can redistribute it and/or modify
00009 **   it under the terms of the GNU General Public License as published by
00010 **   the Free Software Foundation; either version 2 of the License, or
00011 **   (at your option) any later version.
00012 **
00013 **   Foobar is distributed in the hope that it will be useful,
00014 **   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 **   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 **   GNU General Public License for more details.
00017 **
00018 **   You should have received a copy of the GNU General Public License
00019 **   along with Foobar; if not, write to the Free Software
00020 **   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 **
00022 *********************************************************************************/
00023 
00024 # include <Magick++.h>
00025 # include <QBuffer>
00026 # include <QBuffer>
00027 # include <QDir>
00028 # include <QImage>
00029 # include <QImageReader>
00030 # include <QSqlDatabase>
00031 # include <QSqlError>
00032 # include <QSqlQuery>
00033 # include "dbPhotoService.h"
00034 
00035 
00036 using namespace Magick;
00037 
00038 
00039 static QHash<QString, Image>        photoCache;
00040 static QHash<QString, Image>        photoResizeCache;
00041 static int                          maxPhotos = 250;
00042 static int                          maxResizePhotos = 1000;
00043 static QList<QString>               photoList;
00044 static QList<QString>               photoResizeList;
00045 static QMutex                       photoLock;
00046 static QMutex                       dbLock;
00047 
00048 extern FILE *logfp;
00049 
00050 /*!
00051       \class DbPhotoService
00052       
00053       \brief Class for processing individual photo requests.
00054       
00055       The      DbPhotoService    class    is a subclass for the
00056       QcjHttpService  class. It handles requests for individual
00057       photos.  It  will  resize  and properly set the number of
00058       colors as requested.
00059 */ 
00060 
00061 
00062 /*!
00063       \fn void DbPhotoService::setMaxCache(int n)
00064 
00065        Sets  the maximum number of entries allowed in the photo cache.
00066        The  photo  resize  cache  is  set  to 5 times the value of the
00067        parameter <em>n</em> as well.
00068 */ 
00069 void DbPhotoService::setMaxCache(int n)
00070 {
00071    maxPhotos = n;
00072    maxResizePhotos = n * 5;
00073 }
00074 
00075 /*!
00076        This  function  has proven useless, kept just in case it can be
00077        made  to work later. The point of it is to clear any locks that
00078        may   be   set  for  this  object.  Unfortunately,  you  cannot
00079        arbitarely  clear unlocked locks, nor can you test is a lock is
00080        locked.
00081 */ 
00082 void DbPhotoService::clearLocks()
00083 {
00084    fprintf(logfp, "DbPhotoService::clearLocks(%s): Enter, unlocking db and photo locks\n", qPrintable(QString::number(currentThreadId())));
00085    fflush(logfp);
00086 # if 0
00087    if ( dbLock.isLocked() ) 
00088       dbLock.unlock();
00089    if ( photoLock.isLocked() ) 
00090       photoLock.unlock();
00091 # endif
00092    fprintf(logfp, "DbPhotoService::clearLocks(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00093    fflush(logfp);
00094 }
00095 
00096 
00097 /*!
00098       \fn void DbPhotoService::processRequest(QMap<QString, QVariant> *req, QMap<QString, QVariant> *rsp)
00099 
00100        Processes  the incoming request parameter <em>req</em>. It then
00101        formulates  a  response  and puts it into the map pointed to by
00102        the  parameter  <em>req</em>.  Both  parameters  must  point to
00103        valid, though possibly emtpy QMaps.
00104 */ 
00105 void DbPhotoService::processRequest(QMap<QString, QVariant> *req, QMap<QString, QVariant> *rsp)
00106 {
00107    int t_height, t_width;
00108 
00109    fprintf(logfp, "DbPhotoService::processRequest(%s): Enter\n", qPrintable(QString::number(currentThreadId())));
00110    fflush(logfp);
00111 
00112    QMapIterator<QString, QVariant> i(*req);
00113    while (i.hasNext()) 
00114    {
00115       i.next();
00116       fprintf(logfp, "DbPhotoService::processRequest(%s): req: |%s| = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(i.key()), qPrintable(i.value().toString()));
00117       fflush(logfp);
00118    }
00119 
00120    /***********************************************/
00121    /*   Get  the  values  from  the  request map  */
00122    /*   which   are   required  to  satisfy  the  */
00123    /*   request                                   */
00124    /***********************************************/
00125    QString method = req->value("Method").toString();
00126    QString resource = req->value("Resource").toString();
00127    QString args = req->value("Arguments").toString();
00128    QString host = req->value("Host").toString();
00129 
00130    /***********************************************/
00131    /*   Parse out the arguments from the request  */
00132    /*   line                                      */
00133    /***********************************************/
00134    QMap<QString, QString> arguments = parseArguments(args);
00135 
00136    QString fileType;
00137    QString fileBase;
00138 
00139    /***********************************************/
00140    /*   Here we handle the GET requests.          */
00141    /***********************************************/
00142    if ( method == "GET" ) 
00143    {
00144       QRegExp re("(.*)\\.(jpg|png|jpeg|ppm|xpm|xbm|bmp|htm|html|pl)");
00145       re.setCaseSensitive(false);
00146       re.setMinimal(true);
00147       if ( re.indexIn(resource) >= 0 ) 
00148       {
00149          fprintf(logfp, "DbPhotoService::processRequest(%s): Found name and extension\n", qPrintable(QString::number(currentThreadId())));
00150          fflush(logfp);
00151          fileType = re.cap(2).toLower();
00152          fileBase = re.cap(1);
00153          fileBase.remove(QRegExp("^/"));
00154       }
00155       else 
00156       {
00157          fprintf(logfp, "DbPhotoService::processRequest(%s): Error in resource, exiting\n", qPrintable(QString::number(currentThreadId())));
00158          fflush(logfp);
00159          errorResponse(QcjHttpService::NotFound, "Requested resource not found");
00160          return;
00161       }
00162 
00163       /***********************************************/
00164       /*   If  it  a  pl extension, assume it is an  */
00165       /*   action  an  not  just  a  request  for a  */
00166       /*   picture                                   */
00167       /*   Currently untested.                       */
00168       /***********************************************/
00169       if ( fileType == "pl" ) 
00170       {
00171          fprintf(logfp, "DbPhotoService::processRequest(%s): have %s file type!\n", qPrintable(QString::number(currentThreadId())), qPrintable(fileType));
00172          fflush(logfp);
00173          if ( fileBase.toLower() == "import" ) 
00174          {
00175             fprintf(logfp, "DbPhotoService::processRequest(%s): request for import\n", qPrintable(QString::number(currentThreadId())));
00176             fflush(logfp);
00177             int count = 0;
00178             QString dir;
00179             QString sfilters;
00180             if ( arguments.contains("filters") ) 
00181                sfilters = arguments.value("filters");
00182             if ( arguments.contains("dir") ) 
00183             {
00184                dir = arguments.value("dir");
00185                fprintf(logfp, "DbPhotoService::processRequest(%s): Looking in directory |%s| for files\n", qPrintable(QString::number(currentThreadId())), qPrintable(dir));
00186                fflush(logfp);
00187                QDir dn(dir);
00188                if ( dn.exists() ) 
00189                {
00190                   fprintf(logfp, "DbPhotoService::processRequest(%s): Getting filenames using filter of: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(sfilters));
00191                   fflush(logfp);
00192 
00193 
00194                   dbLock.lock();
00195                   db = getServerParms(host);
00196                   dbLock.unlock();
00197 
00198                   QMutexLocker lock(&photoLock);
00199                   QStringList filters = sfilters.split(",");
00200                   QStringList files = dn.entryList(filters, QDir::Files|QDir::Readable);
00201                   QStringList::Iterator it = files.begin();
00202                   while( it != files.end() ) {
00203                      fprintf(logfp, "DbPhotoService::processRequest(%s): Have name: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(*it));
00204                      QFileInfo fi(*it);
00205                      QString fn = dn.absoluteFilePath(fi.fileName());
00206                      QImage img;
00207                      fprintf(logfp, "DbPhotoService::processRequest(%s): Reading image |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(fn));
00208                      if ( img.load(fn) )
00209                      {
00210                         QByteArray ba;
00211                         QBuffer buffer(&ba);
00212                         buffer.open(QIODevice::WriteOnly);
00213                         fprintf(logfp, "DbPhotoService::processRequest(%s): Converting image to PNG\n", qPrintable(QString::number(currentThreadId())));
00214                         img.save(&buffer, "PNG");
00215                         buffer.close();
00216 
00217                         dbLock.lock();
00218                         QSqlQuery q;
00219                         QString sql = "insert into " + photoTable + " (fn, pic) values (:fn, :pic)"; 
00220                         q.prepare(sql);
00221                         q.bindValue(":pic", QVariant(ba));
00222                         q.bindValue(":fn", QVariant(fn));
00223                         fprintf(logfp, "DbPhotoService::processRequest(%s): Inserting picture into database using |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(sql));
00224                         if (! q.exec()) 
00225                         {
00226                            fprintf(logfp, "DbPhotoService::processRequest(%s): Error inserting picture: %s - %s\n", qPrintable(QString::number(currentThreadId())),
00227                                                             qPrintable(q.lastError().driverText()), 
00228                                                             qPrintable(q.lastError().databaseText()));
00229                            fprintf(logfp, "DbPhotoService::processRequest(%s): Query was |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(q.executedQuery()));
00230                         }
00231 
00232                         QStringList textKeys = img.textKeys();
00233                         QStringListIterator keys(textKeys);
00234                         fprintf(logfp, "DbPhotoService::processRequest(%s): Have %d text values\n", qPrintable(QString::number(currentThreadId())), textKeys.count());
00235                         while (keys.hasNext()) 
00236                         {
00237                            QString name = keys.next();
00238                            QString val = img.text(name);
00239                            fprintf(logfp, "DbPhotoService::processRequest(%s): Have key: |%s|, value: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(name), qPrintable(val));
00240                            q.prepare("insert into " + photoTable + "_text (photo, name, val) values (:fn, :name, :val)");
00241                            q.bindValue(":fn", QVariant(fn));
00242                            q.bindValue(":name", QVariant(name));
00243                            q.bindValue(":val", QVariant(val));
00244                            if (! q.exec()) 
00245                            {
00246                               fprintf(logfp, "DbPhotoService::processRequest(%s): Error inserting image: %s - %s", qPrintable(QString::number(currentThreadId())),
00247                                                             qPrintable(q.lastError().driverText()), 
00248                                                             qPrintable(q.lastError().databaseText()));
00249                            }
00250                         }
00251                         dbLock.unlock();
00252                      }
00253                      else 
00254                      {
00255                         fprintf(logfp, "DbPhotoService::processRequest(%s): error reading picture\n", qPrintable(QString::number(currentThreadId())));
00256                      }
00257                      count++;
00258                      fprintf(logfp, "DbPhotoService::processRequest(%s): Moving to next picture\n", qPrintable(QString::number(currentThreadId())));
00259                      ++it;
00260                   }
00261                }
00262             }
00263             else 
00264             {
00265                fprintf(logfp, "DbPhotoService::processRequest(%s): Error in request, exiting\n", qPrintable(QString::number(currentThreadId())));
00266                fflush(logfp);
00267                errorResponse(QcjHttpService::NotFound, "Required parmaeter, dir, not specified");
00268                return;
00269             }
00270             fprintf(logfp, "DbPhotoService::processRequest(%s): Inserted %d photos\n", qPrintable(QString::number(currentThreadId())), count);
00271             fflush(logfp);
00272             QByteArray ba;
00273             QDataStream buf(&ba, QIODevice::WriteOnly);
00274             buf <<  "<html>\n";
00275             buf <<  "   <body>\n";
00276             buf <<  "      <h2>Inserted " + QString::number(count) + " Photos into the database successfully</h2>\n";
00277             buf <<  "   </body>\n";
00278             buf <<  "</html>\n";
00279             rsp->insert("Status", QcjHttpService::OK);
00280             rsp->insert("Content-Length", QVariant(ba.size()));
00281             rsp->insert("Content-Type", QVariant("text/html"));
00282             rsp->insert("Request-Body", QVariant(ba));
00283          }
00284          else
00285          {
00286             errorResponse(QcjHttpService::BadRequest, "Requested action not recognized");
00287          }
00288          return;
00289       }
00290 
00291 //      QMutexLocker lock(&photoLock);
00292 
00293 
00294       /***********************************************/
00295       /*   Here we handle the requests for images    */
00296       /***********************************************/
00297       int width = 0;
00298       int height = 0;
00299       QString colors;
00300 
00301       /***********************************************/
00302       /*   Get  any  arguments passed (at least the  */
00303       /*   ones we want)                             */
00304       /***********************************************/
00305       if ( arguments.contains("width") ) 
00306          width = arguments.value("width").toInt();
00307       if ( arguments.contains("height") ) 
00308          height = arguments.value("height").toInt();
00309       if ( arguments.contains("colors") ) 
00310          colors = arguments.value("colors");
00311 
00312       /***********************************************/
00313       /*   append  the file name to the server name  */
00314       /*   to be used as a key.                      */
00315       /***********************************************/
00316       QString url = req->value("Host").toString() + "/" + fileBase;
00317       fprintf(logfp, "DbPhotoService::processRequest(%s): file type = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(fileType));
00318       fflush(logfp);
00319       fprintf(logfp, "DbPhotoService::processRequest(%s): file base = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(fileBase));
00320       fflush(logfp);
00321 
00322       /***********************************************/
00323       /*   Process the image requests here           */
00324       /***********************************************/
00325       if ( fileType != "html" && fileType != "htm") 
00326       {
00327 
00328          /***********************************************/
00329          /*   Get  the  database  info and other parms  */
00330          /*   from the config file                      */
00331          /***********************************************/
00332          fprintf(logfp, "DbPhotoService::processRequest(%s): locking db lock\n", qPrintable(QString::number(currentThreadId())));
00333          fflush(logfp);
00334          dbLock.lock();
00335          db = getServerParms(host);
00336 
00337          if ( ! db.isOpen() || db.isOpenError() ) 
00338          {
00339             fprintf(logfp, "DbPhotoService::processRequest(%s): Error opening database\n", qPrintable(QString::number(currentThreadId())));
00340             fflush(logfp);
00341             errorResponse(QcjHttpService::ServiceUnavailable, "Could not connect to database");
00342             fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking db lock\n", qPrintable(QString::number(currentThreadId())));
00343             fflush(logfp);
00344             dbLock.unlock();
00345             return;
00346          }
00347          fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking db lock\n", qPrintable(QString::number(currentThreadId())));
00348          fflush(logfp);
00349          dbLock.unlock();
00350 
00351          /***********************************************/
00352          /*   build a key using the server name, image  */
00353          /*   name  and  dimension info for the resize  */
00354          /*   cache                                     */
00355          /***********************************************/
00356          /*   If  the  image  is  not  in  the  resize  */
00357          /*   cache...                                  */
00358          /***********************************************/
00359          QString url1 = url + "?width=" + QString::number(width) + "&height=" + QString::number(height);
00360          fprintf(logfp, "DbPhotoService::processRequest(%s): looking for url1 |%s| in resize cache\n", qPrintable(QString::number(currentThreadId())), qPrintable(url1));
00361          fflush(logfp);
00362 
00363          /***********************************************/
00364          /*   This  object is the image to be read in,  */
00365          /*   maniputated and sent out.                 */
00366          /***********************************************/
00367          Image image;
00368 
00369          fprintf(logfp, "DbPhotoService::processRequest(%s): have method: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(method));
00370          fflush(logfp);
00371     
00372          if ( ! photoResizeCache.contains(url1) ) 
00373          {
00374             fprintf(logfp, "DbPhotoService::processRequest(%s): looking for url |%s| in cache\n", qPrintable(QString::number(currentThreadId())), qPrintable(url));
00375             fflush(logfp);
00376 
00377             /***********************************************/
00378             /*   Check if is is in the image cache         */
00379             /***********************************************/
00380             if ( photoCache.contains(url) ) 
00381             {
00382                /***********************************************/
00383                /*   We found the image in the image cache...  */
00384                /*   get  it  and move it to the front of the  */
00385                /*   list                                      */
00386                /***********************************************/
00387                fprintf(logfp, "DbPhotoService::processRequest(%s): found resource in cache\n", qPrintable(QString::number(currentThreadId())));
00388                fflush(logfp);
00389 
00390                /***********************************************/
00391                /*   Lock the caches for this threads use      */
00392                /***********************************************/
00393                fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00394                fflush(logfp);
00395                photoLock.lock();
00396          
00397                image = photoCache.value(url);
00398                photoList.removeAll(url);
00399                photoList.insert(0, url);
00400 
00401                fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00402                fflush(logfp);
00403                photoLock.unlock();
00404          
00405             }
00406             else 
00407             {
00408                QByteArray ba;
00409               
00410                /***********************************************/
00411                /*   Obtain the db lock for our thread         */
00412                /***********************************************/
00413                fprintf(logfp, "DbPhotoService::processRequest(%s): locking db lock\n", qPrintable(QString::number(currentThreadId())));
00414                fflush(logfp);
00415                dbLock.lock();
00416 
00417                /***********************************************/
00418                /*   Get  the sql statement needed to get the  */
00419                /*   photo from the database                   */
00420                /***********************************************/
00421                QString sql = sqlTemplate;
00422                fprintf(logfp, "DbPhotoService::processRequest(%s): sql = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(sql));
00423                fflush(logfp);
00424                QSqlQuery q(db);
00425                q.prepare(sqlTemplate);
00426 
00427                /***********************************************/
00428                /*   Bind the image name to the :resource tag  */
00429                /***********************************************/
00430                q.bindValue(":resource", fileBase + ".jpg");
00431                fprintf(logfp, "DbPhotoService::processRequest(%s): sql = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(q.lastQuery()));
00432                fflush(logfp);
00433                q.exec();
00434                fprintf(logfp, "DbPhotoService::processRequest(%s): fetching image\n", qPrintable(QString::number(currentThreadId())));
00435                fflush(logfp);
00436                if ( q.next() ) 
00437                {
00438                   /***********************************************/
00439                   /*   If  we found the image, load it into the  */
00440                   /*   image object as an Imagemagick Blob       */
00441                   /***********************************************/
00442                   fprintf(logfp, "DbPhotoService::processRequest(%s): getting image\n", qPrintable(QString::number(currentThreadId())));
00443                   fflush(logfp);
00444                   ba = q.value(0).toByteArray();
00445                }
00446                else 
00447                {
00448                   /***********************************************/
00449                   /*   Otherwise,  if  the image was not found,  */
00450                   /*   build an error and return                 */
00451                   /***********************************************/
00452                   fprintf(logfp, "DbPhotoService::processRequest(%s): Did not find resource\n", qPrintable(QString::number(currentThreadId())));
00453                   fflush(logfp);
00454                   errorResponse(QcjHttpService::NotFound, "Requested resource not found");
00455 
00456                   fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking db lock\n", qPrintable(QString::number(currentThreadId())));
00457                   fflush(logfp);
00458                   dbLock.unlock();
00459                   return;
00460                }
00461 
00462                /***********************************************/
00463                /*   Release  the database lock for the other  */
00464                /*   threads to use                            */
00465                /***********************************************/
00466                fprintf(logfp, "DbPhotoService::processRequest(%s): Unlocking db lock\n", qPrintable(QString::number(currentThreadId())));
00467                fflush(logfp);
00468 
00469                dbLock.unlock();
00470 
00471                fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00472                fflush(logfp);
00473                photoLock.lock();
00474 
00475                /*
00476                     Create the image object and get it's geometry
00477                */ 
00478                image.read(Blob(ba.data(), ba.size()));
00479                Geometry geom(image.size());
00480 
00481                fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00482                fflush(logfp);
00483                photoLock.unlock();
00484 
00485                fprintf(logfp, "DbPhotoService::processRequest(%s): Checking for resource in cache\n", qPrintable(QString::number(currentThreadId())));
00486                fflush(logfp);
00487 
00488                /***********************************************/
00489                /*   Resize   the  image  to  the  dimensions  */
00490                /*   specified in the definition file          */
00491                /***********************************************/
00492 
00493                /***********************************************/
00494                /*   Work with the largest side setting it to  */
00495                /*   the specified size                        */
00496                /***********************************************/
00497                fprintf(logfp, "DbPhotoService::processRequest(%s): resizing image for the cache, cacheDimension = %d\n", qPrintable(QString::number(currentThreadId())), cacheDimension);
00498                fprintf(logfp, "DbPhotoService::processRequest(%s): original image, width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00499                if ( geom.width() > cacheDimension || geom.height() > cacheDimension ) 
00500                {
00501                   fprintf(logfp, "DbPhotoService::processRequest(%s): One side or another is larger than the cache size...\n", qPrintable(QString::number(currentThreadId())));
00502                   if ( geom.width() > geom.height() ) 
00503                   {
00504                      t_height = (int)( (double)cacheDimension / (double)geom.width() * (double)geom.height() );
00505                      geom.height(t_height);
00506                      fprintf(logfp, "DbPhotoService::processRequest(%s): width larger, height scaled to %d\n", qPrintable(QString::number(currentThreadId())), t_height);
00507                      geom.width(cacheDimension);
00508                   }
00509                   else if ( geom.height() > geom.width() )
00510                   {
00511                      t_width = (int)( (double)cacheDimension / (double)geom.height() * (double)geom.width() );
00512                      geom.width(t_width);
00513                      fprintf(logfp, "DbPhotoService::processRequest(%s): height larger, width scaled to %d\n", qPrintable(QString::number(currentThreadId())), t_width);
00514                      geom.height(cacheDimension);
00515                   }
00516                   else
00517                   {
00518                      fprintf(logfp, "DbPhotoService::processRequest(%s): height == width\n", qPrintable(QString::number(currentThreadId())));
00519                      geom.width(cacheDimension);
00520                      geom.height(cacheDimension);
00521                   }
00522                   fprintf(logfp, "DbPhotoService::processRequest(%s): cached image size, width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00523                   fflush(logfp);
00524 
00525                   fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00526                   fflush(logfp);
00527                   photoLock.lock();
00528 
00529                   image.zoom(geom);
00530 
00531                   fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00532                   fflush(logfp);
00533                   photoLock.unlock();
00534 
00535                   fprintf(logfp, "DbPhotoService::processRequest(%s): cached Image scaled\n", qPrintable(QString::number(currentThreadId())));
00536                   fflush(logfp);
00537                }
00538 
00539                /***********************************************/
00540                /*   If  we  find  the  image  in  the cache,  */
00541                /*   remove it, it shouldn;t be there anyways  */
00542                /***********************************************/
00543                if ( photoList.contains(url) ) 
00544                {
00545                   fprintf(logfp, "DbPhotoService::processRequest(%s): removing from cache, url |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(url));
00546                   fflush(logfp);
00547                   /***********************************************/
00548                   /*   Lock the caches for this threads use      */
00549                   /***********************************************/
00550                   fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00551                   fflush(logfp);
00552                   photoLock.lock();
00553          
00554                   photoList.removeAll(url);
00555 
00556                   fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00557                   fflush(logfp);
00558                   photoLock.unlock();
00559                }
00560 
00561                /***********************************************/
00562                /*   If the cache is already full, remove the  */
00563                /*   the  oldest  used photos until the cache  */
00564                /*   can fit ours                              */
00565                /***********************************************/
00566                if ( photoCache.size() > maxPhotos ) 
00567                {
00568                   fprintf(logfp, "DbPhotoService::processRequest(%s): Removing items from cache, current size = %d\n", qPrintable(QString::number(currentThreadId())), photoCache.size());
00569                   fflush(logfp);
00570                   /***********************************************/
00571                   /*   Lock the caches for this threads use      */
00572                   /***********************************************/
00573                   fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00574                   fflush(logfp);
00575                   photoLock.lock();
00576                   while (photoCache.size() - maxPhotos) 
00577                   {
00578                      QString name = photoList.takeLast();
00579                      photoCache.remove(name);
00580                      fprintf(logfp, "DbPhotoService::processRequest(%s): item removed current size = %d\n", qPrintable(QString::number(currentThreadId())), photoCache.size());
00581                      fflush(logfp);
00582                   }
00583                   fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00584                   fflush(logfp);
00585                   photoLock.unlock();
00586          
00587                }
00588                fprintf(logfp, "DbPhotoService::processRequest(%s): Inserting resource into cache\n", qPrintable(QString::number(currentThreadId())));
00589                fflush(logfp);
00590 
00591                /***********************************************/
00592                /*   Insert  the  image  into  the  cache and  */
00593                /*   place  it's  key  in  the list up at the  */
00594                /*   front                                     */
00595                /***********************************************/
00596                /***********************************************/
00597                /*   Lock the caches for this threads use      */
00598                /***********************************************/
00599                fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00600                fflush(logfp);
00601                photoLock.lock();
00602          
00603                photoCache.insert(url, image);
00604                photoList.insert(0, url);
00605                /***********************************************/
00606                /*   Lock the caches for this threads use      */
00607                /***********************************************/
00608                fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00609                fflush(logfp);
00610                photoLock.unlock();
00611 
00612             }
00613 
00614             fprintf(logfp, "DbPhotoService::processRequest(%s): Creating image\n", qPrintable(QString::number(currentThreadId())));
00615             fflush(logfp);
00616 
00617             fprintf(logfp, "DbPhotoService::processRequest(%s): scaling image? width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), width, height);
00618             fflush(logfp);
00619 
00620             /***********************************************/
00621             /*   Determine  the   dimensions of the image  */
00622             /*   as  requested  by  the user. If only one  */
00623             /*   side  is  specified, calculate the other  */
00624             /*   side's length                             */
00625             /***********************************************/
00626             Geometry geom(image.size());
00627             fprintf(logfp, "DbPhotoService::processRequest(%s): setting image geometry to requested size, image size currently width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00628 
00629             if ( width > 0 && height > 0 ) 
00630             {
00631                geom.width(width);
00632                geom.height(height);
00633                fprintf(logfp, "DbPhotoService::processRequest(%s): setting image geometery to width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00634                geom.aspect(true);
00635             }
00636             else if ( width > 0 )
00637             {
00638                int height = geom.height();
00639                height = (int)( ((double)width / geom.width()) * height);
00640                geom.width(width);
00641                geom.height(height);
00642                fprintf(logfp, "DbPhotoService::processRequest(%s): setting image geometery to width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00643             }
00644             else if (height > 0 )
00645             {
00646                int width = geom.width();
00647                geom.width(width);
00648                geom.height(height);
00649                fprintf(logfp, "DbPhotoService::processRequest(%s): setting image geometery to width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00650             }
00651 
00652             /***********************************************/
00653             /*   Ensure    that   the   image's   maximum  */
00654             /*   dimension is not larger than the maximum  */
00655             /*   for the server                            */
00656             /***********************************************/
00657             fprintf(logfp, "DbPhotoService::processRequest(%s): Ensuring max size, maxDimension = %d\n", qPrintable(QString::number(currentThreadId())), maxDimension);
00658             fprintf(logfp, "DbPhotoService::processRequest(%s): image size now width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00659             fflush(logfp);
00660             if ( geom.width() > maxDimension || geom.height() > maxDimension ) 
00661             {
00662                fprintf(logfp, "DbPhotoService::processRequest(%s): One side or another is too large...\n", qPrintable(QString::number(currentThreadId())));
00663 
00664                if ( geom.width() > geom.height() ) 
00665                {
00666                   t_height = (int)( (double)maxDimension / (double)geom.width() * (double)geom.height() );
00667                   geom.height(t_height);
00668                   fprintf(logfp, "DbPhotoService::processRequest(%s): width larger, height scaled to %d\n", qPrintable(QString::number(currentThreadId())), t_height);
00669                   geom.width(maxDimension);
00670                }
00671                else if ( geom.height() > geom.width() ) 
00672                {
00673                   t_width = (int)( (double)maxDimension / (double)geom.height() * (double)geom.width() );
00674                   geom.width(t_width);
00675                   fprintf(logfp, "DbPhotoService::processRequest(%s): height larger, width scaled to %d\n", qPrintable(QString::number(currentThreadId())), t_width);
00676                   geom.height(maxDimension);
00677                }
00678                else
00679                {
00680                   fprintf(logfp, "DbPhotoService::processRequest(%s): width == height\n", qPrintable(QString::number(currentThreadId())));
00681                   geom.width(maxDimension);
00682                   geom.height(maxDimension);
00683                }
00684                /***********************************************/
00685                /*   Lock the caches for this threads use      */
00686                /***********************************************/
00687                fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00688                fflush(logfp);
00689                photoLock.lock();
00690 
00691                photoCache.insert(url, image);
00692                photoList.insert(0, url);
00693 
00694                fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00695                fflush(logfp);
00696                photoLock.unlock();
00697             }
00698             fprintf(logfp, "DbPhotoService::processRequest(%s): Scaling image, width = %d, height = %d\n", qPrintable(QString::number(currentThreadId())), geom.width(), geom.height());
00699             fflush(logfp);
00700 
00701             fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00702             fflush(logfp);
00703             photoLock.lock();
00704             image.zoom(geom);
00705             fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00706             fflush(logfp);
00707             photoLock.unlock();
00708 
00709             /***********************************************/
00710             /*   Place  the  image  into the resize cache  */
00711             /*   for later.                                */
00712             /***********************************************/
00713             fprintf(logfp, "DbPhotoService::processRequest(%s): checking resize cache size, currently %d photos\n", qPrintable(QString::number(currentThreadId())), photoResizeCache.size());
00714             fflush(logfp);
00715 
00716             /***********************************************/
00717             /*   Lock the caches for this threads use      */
00718             /***********************************************/
00719             fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00720             fflush(logfp);
00721             photoLock.lock();
00722 
00723             /***********************************************/
00724             /*   If  the resize cache is full, remove the  */
00725             /*   images  from  the  bottom  of  the cache  */
00726             /*   until there is room for the new picture   */
00727             /***********************************************/
00728             if ( photoResizeCache.size() > maxResizePhotos ) 
00729             {
00730                fprintf(logfp, "DbPhotoService::processRequest(%s): Removing items from resize cache, current size = %d\n", qPrintable(QString::number(currentThreadId())), photoResizeCache.size());
00731                fflush(logfp);
00732                while (photoResizeCache.size() - maxResizePhotos) 
00733                {
00734                   QString name = photoResizeList.takeLast();
00735                   fprintf(logfp, "DbPhotoService::processRequest(%s): removing item |%s| from resize cache\n", qPrintable(QString::number(currentThreadId())), qPrintable(name));
00736                   fflush(logfp);
00737                   photoResizeCache.remove(name);
00738                   fprintf(logfp, "DbPhotoService::processRequest(%s): item removed current size = %d\n", qPrintable(QString::number(currentThreadId())), photoResizeCache.size());
00739                   fflush(logfp);
00740                }
00741             }
00742             fprintf(logfp, "DbPhotoService::processRequest(%s): Inserting resource with url of |%s| into resize cache\n", qPrintable(QString::number(currentThreadId())), qPrintable(url1));
00743             fflush(logfp);
00744             photoResizeCache.insert(url1, image);
00745             photoResizeList.insert(0, url1);
00746 
00747             fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00748             fflush(logfp);
00749             photoLock.unlock();
00750          }
00751 
00752          /***********************************************/
00753          /*   If  the  image  was in the resize cache,  */
00754          /*   use it sight unseen                       */
00755          /*   Pull it from its current position in the  */
00756          /*   list and put it back on top so the least  */
00757          /*   used will settle to the bottom.           */
00758          /***********************************************/
00759          else 
00760          {
00761             fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00762             fflush(logfp);
00763             photoLock.lock();
00764             image = photoResizeCache.value(url1);
00765             photoResizeList.removeAll(url1);
00766             photoResizeList.insert(0, url1);
00767             fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00768             fflush(logfp);
00769             photoLock.unlock();
00770          }
00771 
00772          /***********************************************/
00773          /*   Here  we  create  the acutal image to be  */
00774          /*   sent  in  the  format  specified  by the  */
00775          /*   extension on the request                  */
00776          /***********************************************/
00777          fprintf(logfp, "DbPhotoService::processRequest(%s): Creating to send \n", qPrintable(QString::number(currentThreadId())));
00778          fflush(logfp);
00779          Blob imgBlob;
00780          fprintf(logfp, "DbPhotoService::processRequest(%s): Saving image with type |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(fileType.toUpper()));
00781          fflush(logfp);
00782          image.magick(qPrintable(fileType.toUpper()));
00783 
00784          fprintf(logfp, "DbPhotoService::processRequest(%s): colors = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(colors));
00785          fflush(logfp);
00786 
00787          /***********************************************/
00788          /*   Make  the  image  BW or reduce the color  */
00789          /*   palette if either were requested          */
00790          /***********************************************/
00791          if ( colors == "monochrome" ) 
00792          {
00793             fprintf(logfp, "DbPhotoService::processRequest(%s): Making bw\n", qPrintable(QString::number(currentThreadId())));
00794             fflush(logfp);
00795             image.monochrome(true);
00796             image.type( GrayscaleType );
00797          }
00798          else if (colors.length() > 0 )
00799          {
00800             bool good;
00801             int x = colors.toInt(&good);
00802             if ( good ) 
00803             {
00804                fprintf(logfp, "DbPhotoService::processRequest(%s): Setting colors to: %d\n", qPrintable(QString::number(currentThreadId())), x);
00805                fflush(logfp);
00806                image.quantizeColors(x);
00807                image.quantize();
00808             }
00809             else 
00810             {
00811                fprintf(logfp, "DbPhotoService::processRequest(%s): error converting size, x = %d\n", qPrintable(QString::number(currentThreadId())), x);
00812                fflush(logfp);
00813             }
00814          }
00815 
00816          /***********************************************/
00817          /*   Save the image into an ImageMagick Blob   */
00818          /***********************************************/
00819          fprintf(logfp, "DbPhotoService::processRequest(%s): Writing image to blob\n", qPrintable(QString::number(currentThreadId())));
00820          fflush(logfp);
00821 
00822          fprintf(logfp, "DbPhotoService::processRequest(%s): locking photo lock\n", qPrintable(QString::number(currentThreadId())));
00823          fflush(logfp);
00824          photoLock.lock();
00825          image.write(&imgBlob);
00826          fprintf(logfp, "DbPhotoService::processRequest(%s): unlocking photo lock\n", qPrintable(QString::number(currentThreadId())));
00827          fflush(logfp);
00828          photoLock.unlock();
00829          
00830          fprintf(logfp, "DbPhotoService::processRequest(%s): Image written\n", qPrintable(QString::number(currentThreadId())));
00831          fflush(logfp);
00832 
00833          if ( fileType == "jpg" ) 
00834             fileType = "jpeg";
00835 
00836          /***********************************************/
00837          /*   Now make a QByteArray out of it           */
00838          /***********************************************/
00839          QByteArray newImage((char*)imgBlob.data(), imgBlob.length());
00840 
00841          /***********************************************/
00842          /*   Build the response.                       */
00843          /***********************************************/
00844          rsp->insert("Status", QcjHttpService::OK);
00845          rsp->insert("Content-Length", QVariant(newImage.size()));
00846          rsp->insert("Content-Type", QVariant("image/" + fileType));
00847          rsp->insert("Request-Body", QVariant(newImage));
00848       }
00849    }
00850    fprintf(logfp, "DbPhotoService::processRequest(%s): Exit\n", qPrintable(QString::number(currentThreadId())));
00851    fflush(logfp);
00852 }
00853 
00854 
00855 /*!
00856       \fn QSqlDatabase DbPhotoService::getServerParms(QString host)
00857 
00858        Retrieves  the  parameters from the XML definition file for the
00859        host  named  by  the parameter \a host and returns a pointer to
00860        the QSqlDatabase object for accessing it.
00861 */ 
00862 QSqlDatabase DbPhotoService::getServerParms(QString host)
00863 {
00864    QSqlDatabase rv;
00865 
00866    fprintf(logfp, "DbPhotoService::getServerParms(%s): Enter, host = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(host));
00867    fflush(logfp);
00868    QDomElement docElem = doc.documentElement();
00869    QDomNode n = docElem.firstChild();
00870    while ( ! n.isNull() ) 
00871    {
00872       QDomElement e = n.toElement();
00873       fprintf(logfp, "DbPhotoService::getServerParms(%s): Have node: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(e.tagName()));
00874       fflush(logfp);
00875       if ( e.tagName() == "server" ) 
00876       {
00877          QString sName = e.attribute("name");
00878          fprintf(logfp, "DbPhotoService::getServerParms(%s): Have server tag, name = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(sName));
00879          fflush(logfp);
00880          if ( sName == host ) 
00881          {
00882             /***********************************************/
00883             /*   If we find the database in the cache and  */
00884             /*   it is open return it                      */
00885             /***********************************************/
00886             if ( dbCache.contains(host) && dbCache.value(host).isOpen() ) 
00887             {
00888                fprintf(logfp, "DbPhotoService::getServerParms(%s): Found database in cache\n", qPrintable(QString::number(currentThreadId())));
00889                fflush(logfp);
00890                rv = dbCache.value(host);
00891             }
00892 
00893             if ( ! rv.isOpen() && dbCache.contains(host) )
00894             {
00895                fprintf(logfp, "DbPhotoService::getServerParms(%s): Removing database from cache\n", qPrintable(QString::number(currentThreadId())));
00896                fflush(logfp);
00897                dbCache.remove(host);
00898             }
00899 
00900             QString type = e.attribute("type");
00901             fprintf(logfp, "DbPhotoService::getServerParms(%s): have type: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(type));
00902             fflush(logfp);
00903             if ( type.size() == 0 ) 
00904                type = "QPSQL";
00905 
00906             fprintf(logfp, "DbPhotoService::getServerParms(%s): have type: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(type));
00907             fflush(logfp);
00908             if ( ! rv.isOpen() ) 
00909                rv =  QSqlDatabase::addDatabase(type);
00910 
00911             QDomNode n1 = e.firstChild();
00912             while ( ! n1.isNull() ) 
00913             {
00914                /***********************************************/
00915                /*   If  the database is not open and we have  */
00916                /*   a database definition, get the infor for  */
00917                /*   the  database and try to open it. Ignore  */
00918                /*   any  errors,  assume  they will be dealt  */
00919                /*   with by the caller                        */
00920                /***********************************************/
00921                QDomElement e1 = n1.toElement();
00922                if ( e1.tagName() == "database" ) 
00923                {
00924                   QString name = e1.attribute("name");
00925 
00926                   fprintf(logfp, "DbPhotoService::getServerParms(%s): have database node, name = |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(name));
00927                   fflush(logfp);
00928                   QDomNode n2 = e1.firstChild();
00929                   while ( ! n2.isNull() ) 
00930                   {
00931                      QDomElement e2 = n2.toElement();
00932 
00933                      /***********************************************/
00934                      /*   Open the connection                       */
00935                      /***********************************************/
00936                      if ( ! rv.isOpen() && e2.tagName() == "connection" ) 
00937                      {
00938                         fprintf(logfp, "DbPhotoService::getServerParms(%s): have connection node\n", qPrintable(QString::number(currentThreadId())));
00939                         fflush(logfp);
00940                         rv.setUserName(e2.attribute("user"));
00941                         rv.setPassword(e2.attribute("password"));
00942                         rv.setPort(e2.attribute("port").toInt());
00943                         rv.setHostName(e2.attribute("host"));
00944                         photoTable = e2.attribute("table");
00945                         rv.setDatabaseName(name);
00946                         fprintf(logfp, "DbPhotoService::getServerParms(%s): user: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(e2.attribute("user")));
00947                         fprintf(logfp, "DbPhotoService::getServerParms(%s): password: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(e2.attribute("password")));
00948                         fprintf(logfp, "DbPhotoService::getServerParms(%s): port: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(e2.attribute("port")));
00949                         fprintf(logfp, "DbPhotoService::getServerParms(%s): host: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(e2.attribute("host")));
00950                         fflush(logfp);
00951 
00952                         if ( ! rv.open() )
00953                         {
00954                            fprintf(logfp, "DbPhotoService::getServerParms(%s): failed opening db, %s - %s\n", qPrintable(QString::number(currentThreadId())), 
00955                                        qPrintable(rv.lastError().databaseText()),
00956                                        qPrintable(rv.lastError().driverText()));
00957                            fflush(logfp);
00958                            
00959                         }
00960                         else
00961                            dbCache.insert(host, rv);
00962                      }
00963                      else if ( e2.tagName() == "sql" ) 
00964                      {
00965                         QDomNode cdata = n2.firstChild();
00966                         if ( cdata.isText() ) 
00967                            sqlTemplate = cdata.nodeValue();
00968                         fprintf(logfp, "DbPhotoService::getServerParms(%s): sql: |%s|\n", qPrintable(QString::number(currentThreadId())), qPrintable(sqlTemplate));
00969                      }
00970 
00971                      n2 = n2.nextSibling();
00972                   }
00973                }
00974 
00975                /***********************************************/
00976                /*   Here  we get the html template if it was  */
00977                /*   defined                                   */
00978                /***********************************************/
00979                else if ( e1.tagName() == "html_template" ) 
00980                {
00981                   QDomNode cdata = n1.firstChild();
00982                   if ( cdata.isText() ) 
00983                      htmlTemplate = cdata.nodeValue();
00984                }
00985                /***********************************************/
00986                /*   Get the image dimensions                  */
00987                /***********************************************/
00988                else if ( e1.tagName() == "image" ) 
00989                {
00990                   fprintf(logfp, "DbPhotoService::getServerParms(%s): have image node\n", qPrintable(QString::number(currentThreadId())));
00991                   fflush(logfp);
00992                   if ( e1.attribute("cache_dimension") != QString::null ) 
00993                      cacheDimension = e1.attribute("cache_dimension").toInt();
00994                   if ( e1.attribute("max_dimension") != QString::null ) 
00995                      maxDimension = e1.attribute("max_dimension").toInt();
00996                   fprintf(logfp, "DbPhotoService::getServerParms(%s): maxDimension = %d\n", qPrintable(QString::number(currentThreadId())), maxDimension);
00997                   fprintf(logfp, "DbPhotoService::getServerParms(%s): cacheDimension = %d\n", qPrintable(QString::number(currentThreadId())), cacheDimension);
00998                }
00999                n1 = n1.nextSibling();
01000             }
01001             break;
01002          }
01003       }
01004       n = n.nextSibling();
01005    }
01006    fprintf(logfp, "DbPhotoService::getServerParms(%s): Exit, db is open? %d\n", qPrintable(QString::number(currentThreadId())), rv.isOpen());
01007    fflush(logfp);
01008    return(rv);
01009 }

Generated on Fri May 4 11:21:12 2007 for PhotoGrotto by  doxygen 1.5.0