![jsdelfino](/assets/img/avatar_default.png)
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1517422 13f79535-47bb-0310-9956-ffa450edef68
279 lines
8.1 KiB
C++
279 lines
8.1 KiB
C++
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
/* $Rev$ $Date$ */
|
|
|
|
#ifndef tuscany_filedb_hpp
|
|
#define tuscany_filedb_hpp
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "string.hpp"
|
|
#include "list.hpp"
|
|
#include "value.hpp"
|
|
#include "monad.hpp"
|
|
#include "fstream.hpp"
|
|
#include "element.hpp"
|
|
#include "../../modules/scheme/eval.hpp"
|
|
#include "../../modules/xml/xml.hpp"
|
|
#include "../../modules/json/json.hpp"
|
|
|
|
namespace tuscany {
|
|
namespace filedb {
|
|
|
|
/**
|
|
* Convert a database name to an absolute path.
|
|
*/
|
|
const string absdbname(const string& name) {
|
|
if (length(name) == 0 || c_str(name)[0] == '/')
|
|
return name;
|
|
char cwd[512];
|
|
if (getcwd(cwd, sizeof(cwd)) == NULL)
|
|
return name;
|
|
return string(cwd) + "/" + name;
|
|
}
|
|
|
|
/**
|
|
* Represents a FileDB connection.
|
|
*/
|
|
class FileDB {
|
|
public:
|
|
FileDB() : owner(false) {
|
|
}
|
|
|
|
FileDB(const string& name, const string& format) : owner(true), name(absdbname(name)), format(format) {
|
|
debug(name, "filedb::filedb::name");
|
|
debug(format, "filedb::filedb::format");
|
|
}
|
|
|
|
FileDB(const FileDB& c) : owner(false), name(c.name), format(c.format) {
|
|
debug("filedb::filedb::copy");
|
|
}
|
|
|
|
FileDB& operator=(const FileDB& c) = delete;
|
|
|
|
~FileDB() {
|
|
}
|
|
|
|
private:
|
|
unused const bool owner;
|
|
const string name;
|
|
const string format;
|
|
|
|
friend const failable<bool> write(const value& v, ostream& os, const string& format);
|
|
friend const failable<value> read(istream& is, const string& format);
|
|
friend const failable<bool> post(const value& key, const value& val, const FileDB& db);
|
|
friend const failable<bool> put(const value& key, const value& val, const FileDB& db);
|
|
friend const failable<bool> patch(const value& key, const value& val, const FileDB& db);
|
|
friend const failable<value> get(const value& key, const FileDB& db);
|
|
friend const failable<bool> del(const value& key, const FileDB& db);
|
|
};
|
|
|
|
/**
|
|
* Convert a key to a file name.
|
|
*/
|
|
const string filename(const list<value>& path, const string& root) {
|
|
if (isNull(path))
|
|
return root;
|
|
const string name = root + "/" + (isString(car(path))? (string)car(path) : write(content(scheme::writeValue(car(path)))));
|
|
return filename(cdr(path), name);
|
|
}
|
|
|
|
const string filename(const value& key, const string& root) {
|
|
if (!isList(key))
|
|
return filename(mklist(key), root);
|
|
return filename((list<value>)key, root);
|
|
}
|
|
|
|
/**
|
|
* Make the parent directories of a keyed file.
|
|
*/
|
|
const failable<bool> mkdirs(const list<value>& path, const string& root) {
|
|
if (isNull(cdr(path)))
|
|
return true;
|
|
const string dir = root + "/" + (isString(car(path))? (string)car(path) : write(content(scheme::writeValue(car(path)))));
|
|
mkdir(c_str(dir), S_IRWXU);
|
|
return mkdirs(cdr(path), dir);
|
|
}
|
|
|
|
/**
|
|
* Write a value to a database file.
|
|
*/
|
|
const failable<bool> write(const value& v, ostream& os, const string& format) {
|
|
if (format == "scheme") {
|
|
const string vs(write(content(scheme::writeValue(v))));
|
|
os << vs;
|
|
return true;
|
|
}
|
|
if (format == "xml") {
|
|
failable<list<string> > s = xml::writeElements(valuesToElements(v));
|
|
if (!hasContent(s))
|
|
return mkfailure<bool>(s);
|
|
write(content(s), os);
|
|
return true;
|
|
}
|
|
if (format == "json") {
|
|
failable<list<string> > s = json::writeValue(v);
|
|
if (!hasContent(s))
|
|
return mkfailure<bool>(s);
|
|
write(content(s), os);
|
|
return true;
|
|
}
|
|
return mkfailure<bool>(string("Unsupported database format: ") + format);
|
|
}
|
|
|
|
/**
|
|
* Read a value from a database file.
|
|
*/
|
|
const failable<value> read(istream& is, const string& format) {
|
|
if (format == "scheme") {
|
|
return scheme::readValue(streamList(is));
|
|
}
|
|
if (format == "xml") {
|
|
const failable<list<value> > fv = xml::readElements(streamList(is));
|
|
if (!hasContent(fv))
|
|
return mkfailure<value>(fv);
|
|
const value v = elementsToValues(content(fv));
|
|
return v;
|
|
}
|
|
if (format == "json") {
|
|
return json::readValue(streamList(is));
|
|
}
|
|
return mkfailure<value>(string("Unsupported database format: ") + format);
|
|
}
|
|
|
|
/**
|
|
* Post a new item to the database.
|
|
*/
|
|
const failable<bool> post(const value& key, const value& val, const FileDB& db) {
|
|
debug(key, "filedb::post::key");
|
|
debug(val, "filedb::post::value");
|
|
debug(db.name, "filedb::post::dbname");
|
|
|
|
if (isList(key))
|
|
mkdirs(key, db.name);
|
|
const string fn = filename(key, db.name);
|
|
debug(fn, "filedb::post::filename");
|
|
ofstream os(fn);
|
|
if (os.fail()) {
|
|
ostringstream os;
|
|
os << "Couldn't post file database entry: " << key;
|
|
return mkfailure<bool>(str(os));
|
|
}
|
|
const failable<bool> r = write(val, os, db.format);
|
|
|
|
debug(r, "filedb::post::result");
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Update an item in the database. If the item doesn't exist it is added.
|
|
*/
|
|
const failable<bool> put(const value& key, const value& val, const FileDB& db) {
|
|
debug(key, "filedb::put::key");
|
|
debug(val, "filedb::put::value");
|
|
debug(db.name, "filedb::put::dbname");
|
|
|
|
if (isList(key))
|
|
mkdirs(key, db.name);
|
|
const string fn = filename(key, db.name);
|
|
debug(fn, "filedb::put::filename");
|
|
ofstream os(fn);
|
|
if (os.fail()) {
|
|
ostringstream os;
|
|
os << "Couldn't put file database entry: " << key;
|
|
return mkfailure<bool>(str(os));
|
|
}
|
|
const failable<bool> r = write(val, os, db.format);
|
|
|
|
debug(r, "filedb::put::result");
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Patch an item in the database. If the item doesn't exist it is added.
|
|
*/
|
|
const failable<bool> patch(const value& key, const value& val, const FileDB& db) {
|
|
debug(key, "filedb::patch::key");
|
|
debug(val, "filedb::patch::value");
|
|
debug(db.name, "filedb::patch::dbname");
|
|
|
|
if (isList(key))
|
|
mkdirs(key, db.name);
|
|
const string fn = filename(key, db.name);
|
|
debug(fn, "filedb::patch::filename");
|
|
ofstream os(fn);
|
|
if (os.fail()) {
|
|
ostringstream os;
|
|
os << "Couldn't patch file database entry: " << key;
|
|
return mkfailure<bool>(str(os));
|
|
}
|
|
const failable<bool> r = write(val, os, db.format);
|
|
|
|
debug(r, "filedb::patch::result");
|
|
return r;
|
|
}
|
|
|
|
/**
|
|
* Get an item from the database.
|
|
*/
|
|
const failable<value> get(const value& key, const FileDB& db) {
|
|
debug(key, "filedb::get::key");
|
|
debug(db.name, "filedb::get::dbname");
|
|
|
|
const string fn = filename(key, db.name);
|
|
debug(fn, "filedb::get::filename");
|
|
ifstream is(fn);
|
|
if (is.fail()) {
|
|
ostringstream os;
|
|
os << "Couldn't get file database entry: " << key;
|
|
return mkfailure<value>(str(os), 404, false);
|
|
}
|
|
const failable<value> val = read(is, db.format);
|
|
|
|
debug(val, "filedb::get::result");
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* Delete an item from the database
|
|
*/
|
|
const failable<bool> del(const value& key, const FileDB& db) {
|
|
debug(key, "filedb::delete::key");
|
|
debug(db.name, "filedb::delete::dbname");
|
|
|
|
const string fn = filename(key, db.name);
|
|
debug(fn, "filedb::del::filename");
|
|
const int rc = unlink(c_str(fn));
|
|
if (rc == -1) {
|
|
ostringstream os;
|
|
os << "Couldn't delete file database entry: " << key;
|
|
return errno == ENOENT? mkfailure<bool>(str(os), 404, false) : mkfailure<bool>(str(os));
|
|
}
|
|
|
|
debug(true, "filedb::delete::result");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif /* tuscany_filedb_hpp */
|