--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include <anna/core/core.hpp>
+#include <anna/app/app.hpp>
+
+#include <anna/io/Directory.hpp>
+#include <anna/io/functions.hpp>
+
+#include <anna/xml/Compiler.hpp>
+#include <anna/xml/Node.hpp>
+
+#include <anna/dbos/Repository.hpp>
+#include <anna/dbos/AutoObject.hpp>
+
+#include "filesystem/Directory.hpp"
+#include "filesystem/File.hpp"
+
+#include "storage/Directory.hpp"
+#include "storage/File.hpp"
+
+using namespace std;
+using namespace workdir;
+
+template <typename T> void message (const char* text, T* tt) throw () {
+ if (Logger::isActive (Logger::Debug) == false)
+ return;
+
+ cout << " " << text << " (";
+ cout << anna::functions::asHexString (anna_ptrnumber_cast (tt));
+ cout << "): ";
+
+ if (tt != NULL)
+ cout << tt->asString ();
+ else
+ cout << "<null>";
+
+ cout << endl;
+}
+
+class WorkDirectory : public Application {
+public:
+ struct Flags { enum _v { None = 0, Clear = 1 }; };
+
+ WorkDirectory ();
+
+ xml::Node* asXML (xml::Node* parent) const throw ();
+
+private:
+ typedef vector <storage::File*> file_container;
+ typedef file_container::iterator file_iterator;
+ typedef file_container::reverse_iterator file_reverse_iterator;
+
+ dbos::Repository a_repository;
+ filesystem::Directory* a_root;
+ file_container a_files;
+
+ void initialize () throw (RuntimeException);
+ void run () throw (RuntimeException);
+
+ void forward (filesystem::Directory*) throw (RuntimeException);
+ void instantiateOne (filesystem::Directory*) throw (RuntimeException);
+ void fullCache (filesystem::Directory*, file_container&, const int flags) throw (RuntimeException);
+ void reuseHoles (filesystem::Directory*, file_container&) throw (RuntimeException);
+ void destroyObjects (filesystem::Directory* dir, file_container&) throw (RuntimeException);
+ void clear (file_container&) throw ();
+
+ static void load (filesystem::Directory* parent, const int maxLevel, const int level = 0) throw (RuntimeException);
+};
+
+using namespace std;
+
+int main (int argc, const char** argv)
+{
+ CommandLine& commandLine (CommandLine::instantiate ());
+ WorkDirectory storageNull;
+
+ try {
+ commandLine.initialize (argv, argc);
+ commandLine.verify ();
+
+ Logger::setLevel (Logger::Local6);
+ Logger::initialize ("workdir", new TraceWriter ("file.trace", 4 * 1024 * 1024));
+
+ storageNull.start ();
+ }
+ catch (Exception& ex) {
+ cout << ex.asString () << endl;
+ }
+
+ return 0;
+}
+
+WorkDirectory::WorkDirectory () :
+ Application ("workdir", "Dbos workdir", "1.0.0"),
+ a_repository ("workdir")
+{
+ CommandLine& cl (CommandLine::instantiate ());
+
+ cl.add ("dir", CommandLine::Argument::Mandatory, "Nombre del directorio a procesar");
+ cl.add ("l", CommandLine::Argument::Optional, "Numero maximo de niveles de profundidad");
+ cl.add ("trace", CommandLine::Argument::Optional, "Nivel de trazado");
+ cl.add ("s", CommandLine::Argument::Mandatory, "Cache size");
+}
+
+void WorkDirectory::initialize ()
+ throw (RuntimeException)
+{
+}
+
+void WorkDirectory::run ()
+ throw (RuntimeException)
+{
+ LOGMETHOD (TraceMethod tm ("WorkDirectory", "run", ANNA_FILE_LOCATION));
+
+ CommandLine& cl (CommandLine::instantiate ());
+
+ const std::string& dir = cl.getValue ("dir");
+ const int maxLevel = cl.exists ("l") ? cl.getIntegerValue ("l"): -1;
+
+ if (cl.exists ("trace") == true)
+ Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
+
+ const int cacheSize = cl.getIntegerValue ("s");
+
+ storage::Directory::setup (a_repository, cacheSize);
+ storage::File::setup (a_repository, cacheSize);
+
+ a_root = new filesystem::Directory (dir);
+
+ load (a_root, maxLevel);
+
+ a_root->print ();
+ cout << endl;
+
+ forward (a_root);
+
+ writeContext ("file.context");
+}
+
+xml::Node* WorkDirectory::asXML (xml::Node* parent) const
+ throw ()
+{
+ xml::Node* result = app::Application::asXML (parent);
+ a_repository.asXML (result);
+ return result;
+}
+
+void WorkDirectory::forward (filesystem::Directory* dir)
+ throw (RuntimeException)
+{
+ cout << "forward: " << dir->getPath () << endl;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ dir = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
+
+ if (dir == NULL)
+ continue;
+
+ try {
+ instantiateOne (dir);
+ fullCache (dir, a_files, Flags::Clear);
+ reuseHoles (dir, a_files);
+ destroyObjects (dir, a_files);
+ forward (dir);
+ }
+ catch (RuntimeException& ex) {
+ ex.trace ();
+ }
+ }
+}
+
+/*
+ * Crea una serie de instancia simultáneas sobre el mismo objeto para verificar que sólo lo carga
+ * de verdad sea necesario.
+ */
+void WorkDirectory::instantiateOne (filesystem::Directory* dir)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "instantiateOne", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::instantiateOne: Instancia varias veces la misma instancia para verificar el reuso" << endl;
+
+ storage::Directory* aux;
+
+ {
+ dbos::AutoObject <storage::Directory> root1;
+ aux = root1 = storage::Directory::instantiate (dir);
+ message ("Root1", aux);
+
+ dbos::AutoObject <storage::Directory> root2;
+ aux = root2 = storage::Directory::instantiate (dir);
+ message ("Root2", aux);
+ }
+
+ dbos::AutoObject <storage::Directory> root3;
+ aux = root3 = storage::Directory::instantiate (dir);
+ message ("Root3", aux);
+
+ message ("StorageArea", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+void WorkDirectory::fullCache (filesystem::Directory* dir, WorkDirectory::file_container& files, const int flags)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "fullCache", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::fullCache: Llena la cache de objetos para verificar que crece tanto como sea necesario" << endl;
+
+ filesystem::File* file;
+
+ int maxSize = storage::File::getMaxSize ();
+
+ maxSize += rand () % maxSize;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ file = filesystem::File::down_cast (filesystem::Directory::child (ii));
+
+ if (file != NULL) {
+ storage::File* storageFile = storage::File::instantiate (file);
+ message ("File", storageFile);
+ files.push_back (storageFile);
+
+// if (files.size () >= maxSize)
+// break;
+ }
+ }
+
+ message ("StorageArea (full)", storage::File::getStorageArea ());
+
+ if (flags & Flags::Clear)
+ clear (files);
+
+ message ("StorageArea (empty)", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+void WorkDirectory::reuseHoles (filesystem::Directory* dir, WorkDirectory::file_container& files)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "reuseHoles", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::reuseHoles: Invoca dos veces a fullCache para verificar que el tamano se mantiene la segunda vez" << endl;
+ fullCache (dir, files, Flags::Clear);
+ fullCache (dir, files, Flags::Clear);
+ cout << endl;
+}
+
+void WorkDirectory::destroyObjects (filesystem::Directory* dir, WorkDirectory::file_container& files)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "destroyObjects", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::destroyObjects: Carga un directorio distinto, para verificar que destruye los objetos segun se dejan de utilizar" << endl;
+ filesystem::File* file;
+ filesystem::Directory* other = NULL;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii && other == NULL; ii ++)
+ other = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
+
+ if (other == NULL) {
+ cout << dir->getPath () << ": No se puede realizar esta prueba" << endl << endl;
+ return;
+ }
+
+ cout << "New Directory: " << other->getPath () << endl;
+ dir = other;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ file = filesystem::File::down_cast (filesystem::Directory::child (ii));
+
+ if (file != NULL) {
+ storage::File* storageFile = storage::File::instantiate (file);
+ message ("File", storageFile);
+ storage::File::release (storageFile);
+ }
+ }
+
+ message ("StorageArea", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+
+void WorkDirectory::clear (WorkDirectory::file_container& files)
+ throw ()
+{
+ storage::File* file;
+
+ /* Libera los objetos en distinto orden para empeorar el tratamiento huecos */
+
+ if ((anna::functions::millisecond () % 2) == 0) {
+ cout << "Clear directo" << endl;
+ for (file_iterator ii = files.begin (), maxii = files.end (); ii != maxii; ii ++) {
+ file = *ii;
+ storage::File::release (file);
+ }
+ }
+ else {
+ cout << "Clear inverso" << endl;
+ for (file_reverse_iterator ii = files.rbegin (), maxii = files.rend (); ii != maxii; ii ++) {
+ file = *ii;
+ storage::File::release (file);
+ }
+ }
+
+ files.clear ();
+}
+
+/*static*/
+void WorkDirectory::load (filesystem::Directory* parent, const int maxLevel, const int level)
+ throw (RuntimeException)
+{
+ if (level == maxLevel)
+ return;
+
+ io::Directory directory;
+ string fullPath;
+
+ directory.read (parent->getPath (), io::Directory::Mode::ShortPath);
+
+ for (io::Directory::const_iterator ii = directory.begin (), maxii = directory.end (); ii != maxii; ii ++) {
+ const std::string& name = io::Directory::data (ii);
+
+ fullPath = filesystem::Abstract::calculePath (parent, name);
+
+ if (io::functions::isADirectory (fullPath)) {
+ try {
+ filesystem::Directory* dd = new filesystem::Directory (parent, name);
+ load (dd, maxLevel, level + 1);
+ }
+ catch (RuntimeException& ex) {
+ ex.trace ();
+ }
+ }
+ else {
+ //Auto association to the parent:
+ new filesystem::File (parent, name);
+ }
+ }
+}