IBR-DTNSuite  0.8
ibrcommon/ibrcommon/data/BLOB.cpp
Go to the documentation of this file.
00001 /*
00002  * BLOB.cpp
00003  *
00004  *  Created on: 15.12.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/data/BLOB.h"
00009 #include "ibrcommon/thread/MutexLock.h"
00010 #include "ibrcommon/Exceptions.h"
00011 #include "ibrcommon/Logger.h"
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <cstring>
00016 #include <cerrno>
00017 
00018 #ifdef __DEVELOPMENT_ASSERTIONS__
00019 #include <cassert>
00020 #endif
00021 
00022 namespace ibrcommon
00023 {
00024         // maximum of concurrent opened files
00025         ibrcommon::Semaphore BLOB::_filelimit(10);
00026 
00027         // default BLOB provider - memory based; auto deletion enabled
00028         ibrcommon::BLOB::ProviderRef BLOB::provider(new ibrcommon::MemoryBLOBProvider(), true);
00029 
00030         BLOB::BLOB()
00031         { }
00032 
00033         BLOB::~BLOB()
00034         {
00035         }
00036 
00037         std::ostream& BLOB::copy(std::ostream &output, std::istream &input, const size_t size, const size_t buffer_size)
00038         {
00039                 // read payload
00040                 char buffer[buffer_size];
00041                 size_t remain = size;
00042 
00043                 while (remain > 0)
00044                 {
00045                         // something bad happened, abort!
00046                         if (input.bad())
00047                         {
00048                                 std::stringstream errmsg; errmsg << "input stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00049                                 throw ibrcommon::IOException(errmsg.str());
00050                         }
00051 
00052                         // reached EOF too early
00053                         if (input.eof())
00054                         {
00055                                 std::stringstream errmsg; errmsg << "input stream reached EOF [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00056                                 throw ibrcommon::IOException(errmsg.str());
00057                         }
00058 
00059                         // check if the destination stream is ok
00060                         if (output.bad())
00061                         {
00062                                 std::stringstream errmsg; errmsg << "output stream went bad [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied";
00063                                 throw ibrcommon::IOException(errmsg.str());
00064                         }
00065 
00066                         // retry if the read failed
00067                         if (input.fail())
00068                         {
00069                                 IBRCOMMON_LOGGER(warning) << "input stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00070                                 input.clear();
00071                         }
00072 
00073                         // if the last write failed, then retry
00074                         if (output.fail())
00075                         {
00076                                 IBRCOMMON_LOGGER(warning) << "output stream failed [" << std::strerror(errno) << "]; " << (size-remain) << " of " << size << " bytes copied" << IBRCOMMON_LOGGER_ENDL;
00077                                 output.clear();
00078                         }
00079                         else
00080                         {
00081                                 // read the full buffer size of less?
00082                                 if (remain > buffer_size)
00083                                 {
00084                                         input.read(buffer, buffer_size);
00085                                 }
00086                                 else
00087                                 {
00088                                         input.read(buffer, remain);
00089                                 }
00090 
00091                                 // retry if the read failed
00092                                 if (input.fail()) continue;
00093                         }
00094 
00095                         // write the bytes to the BLOB
00096                         output.write(buffer, input.gcount());
00097 
00098                         // shrink the remaining bytes by the red bytes
00099                         remain -= input.gcount();
00100                 }
00101 
00102                 return output;
00103         }
00104 
00105         ibrcommon::BLOB::Reference BLOB::create()
00106         {
00107                 return ibrcommon::BLOB::provider.create();
00108         }
00109 
00110         ibrcommon::BLOB::Reference BLOB::open(const ibrcommon::File &f)
00111         {
00112                 return ibrcommon::BLOB::Reference(new ibrcommon::FileBLOB(f));
00113         }
00114 
00115         void BLOB::changeProvider(BLOB::Provider *p, bool auto_delete)
00116         {
00117                 ibrcommon::BLOB::provider.change(p, auto_delete);
00118         }
00119 
00120         BLOB::Provider::~Provider()
00121         { };
00122 
00123         BLOB::ProviderRef::ProviderRef(Provider *provider, bool auto_delete)
00124          : _provider(provider), _auto_delete(auto_delete)
00125         {
00126         }
00127 
00128         BLOB::ProviderRef::~ProviderRef()
00129         {
00130                 if (_auto_delete)
00131                 {
00132                         delete _provider;
00133                 }
00134         }
00135 
00136         void BLOB::ProviderRef::change(BLOB::Provider *p, bool auto_delete)
00137         {
00138                 if (_auto_delete)
00139                 {
00140                         delete _provider;
00141                 }
00142 
00143                 _provider = p;
00144                 _auto_delete = auto_delete;
00145         }
00146 
00147         BLOB::Reference BLOB::ProviderRef::create()
00148         {
00149                 return _provider->create();
00150         }
00151 
00152         MemoryBLOBProvider::MemoryBLOBProvider()
00153         {
00154         }
00155 
00156         MemoryBLOBProvider::~MemoryBLOBProvider()
00157         {
00158         }
00159 
00160         ibrcommon::BLOB::Reference MemoryBLOBProvider::create()
00161         {
00162                 return StringBLOB::create();
00163         }
00164 
00165         FileBLOBProvider::FileBLOBProvider(const File &path)
00166          : _tmppath(path)
00167         {
00168         }
00169 
00170         FileBLOBProvider::~FileBLOBProvider()
00171         {
00172         }
00173 
00174         ibrcommon::BLOB::Reference FileBLOBProvider::create()
00175         {
00176                 return ibrcommon::BLOB::Reference(new TmpFileBLOB(_tmppath));
00177         }
00178 
00179         BLOB::Reference::Reference(const Reference &ref)
00180          : _blob(ref._blob)
00181         {
00182         }
00183 
00184         BLOB::Reference::~Reference()
00185         {
00186         }
00187 
00188         BLOB::iostream BLOB::Reference::iostream()
00189         {
00190                 return BLOB::iostream(*_blob);
00191         }
00192 
00193         BLOB::Reference::Reference(BLOB *blob)
00194          : _blob(blob)
00195         {
00196         }
00197 
00198         const BLOB& BLOB::Reference::operator*() const
00199         {
00200                 return *_blob;
00201         }
00202 
00203         BLOB::Reference MemoryBLOBProvider::StringBLOB::create()
00204         {
00205                 BLOB::Reference ref(new MemoryBLOBProvider::StringBLOB());
00206                 return ref;
00207         }
00208 
00209         void MemoryBLOBProvider::StringBLOB::clear()
00210         {
00211                 _stringstream.str("");
00212         }
00213 
00214         MemoryBLOBProvider::StringBLOB::StringBLOB()
00215          : BLOB(), _stringstream()
00216         {
00217 
00218         }
00219 
00220         MemoryBLOBProvider::StringBLOB::~StringBLOB()
00221         {
00222         }
00223 
00224         void MemoryBLOBProvider::StringBLOB::open()
00225         {
00226                 // set pointer to the beginning of the stream and remove any error flags
00227                 _stringstream.clear();
00228                 _stringstream.seekp(0);
00229                 _stringstream.seekg(0);
00230         }
00231 
00232         void MemoryBLOBProvider::StringBLOB::close()
00233         {
00234         }
00235 
00236         size_t MemoryBLOBProvider::StringBLOB::__get_size()
00237         {
00238                 // store current position
00239                 size_t pos = _stringstream.tellg();
00240 
00241                 _stringstream.seekg(0, std::ios_base::end);
00242                 size_t size = _stringstream.tellg();
00243                 _stringstream.seekg(pos);
00244 
00245                 return size;
00246         }
00247 
00248         void FileBLOB::clear()
00249         {
00250                 throw ibrcommon::IOException("clear is not possible on a read only file");
00251         }
00252 
00253         FileBLOB::FileBLOB(const File &f)
00254          : ibrcommon::BLOB(), _filestream(), _file(f)
00255         {
00256                 if (!f.exists())
00257                 {
00258                         throw ibrcommon::FileNotExistsException(f);
00259                 }
00260         }
00261 
00262         FileBLOB::~FileBLOB()
00263         {
00264         }
00265 
00266         void FileBLOB::open()
00267         {
00268                 BLOB::_filelimit.wait();
00269 
00270                 // open the file
00271                 _filestream.open(_file.getPath().c_str(), ios::in|ios::binary);
00272 
00273                 if (!_filestream.is_open())
00274                 {
00275                         throw ibrcommon::CanNotOpenFileException(_file);
00276                 }
00277         }
00278 
00279         void FileBLOB::close()
00280         {
00281                 // close the file
00282                 _filestream.close();
00283 
00284                 BLOB::_filelimit.post();
00285         }
00286 
00287         size_t FileBLOB::__get_size()
00288         {
00289                 return _file.size();
00290         }
00291 
00292         void FileBLOBProvider::TmpFileBLOB::clear()
00293         {
00294                 // close the file
00295                 _filestream.close();
00296 
00297                 // open temporary file
00298                 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::trunc | ios::binary );
00299 
00300                 if (!_filestream.is_open())
00301                 {
00302                         IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00303                         throw ibrcommon::CanNotOpenFileException(_tmpfile);
00304                 }
00305         }
00306 
00307         FileBLOBProvider::TmpFileBLOB::TmpFileBLOB(const File &tmppath)
00308          : BLOB(), _filestream()
00309         {
00310                 // check if path is a directory
00311                 if (!tmppath.isDirectory())
00312                 {
00313                         throw ibrcommon::IOException("BLOB::tmppath not initialized or path is not a directory.");
00314                 }
00315 
00316                 _tmpfile = ibrcommon::TemporaryFile(tmppath, "blob");
00317                 _tmpfile.update();
00318         }
00319 
00320         FileBLOBProvider::TmpFileBLOB::~TmpFileBLOB()
00321         {
00322                 // delete the file if the last reference is destroyed
00323                 _tmpfile.remove();
00324         }
00325 
00326         void FileBLOBProvider::TmpFileBLOB::open()
00327         {
00328                 BLOB::_filelimit.wait();
00329 
00330                 // open temporary file
00331                 _filestream.open(_tmpfile.getPath().c_str(), ios::in | ios::out | ios::binary );
00332 
00333                 if (!_filestream.is_open())
00334                 {
00335                         IBRCOMMON_LOGGER(error) << "can not open temporary file " << _tmpfile.getPath() << IBRCOMMON_LOGGER_ENDL;
00336                         throw ibrcommon::CanNotOpenFileException(_tmpfile);
00337                 }
00338         }
00339 
00340         void FileBLOBProvider::TmpFileBLOB::close()
00341         {
00342                 // flush the filestream
00343                 _filestream.flush();
00344 
00345                 // close the file
00346                 _filestream.close();
00347 
00348                 BLOB::_filelimit.post();
00349         }
00350 
00351         size_t FileBLOBProvider::TmpFileBLOB::__get_size()
00352         {
00353                 return _tmpfile.size();
00354         }
00355 }