/* * 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$ */ /** * A partitioner component implementation which forwards data access requests to a * dynamically selected data store component. The selection is externalized, performed * by a selector component, responsible for selecting the target data stores given the * data access request key and a list of references to available data store components. * This pattern can be used for sharding or load balancing for example. */ #define WANT_HTTPD_LOG 1 #include "string.hpp" #include "function.hpp" #include "list.hpp" #include "value.hpp" #include "monad.hpp" namespace tuscany { namespace partitioner { /** * Return a list of target partitions for a key. */ const failable > partition(const value& key, const lvvlambda& selector, const list& partitions) { // Call the selector component to convert the given key to a list of partitions const value p = selector(mklist("get", key, partitions)); if (isNull(p)) { ostringstream os; os << "Couldn't get partition: " << key; return mkfailure >(str(os), -1, false); } return (list)p; } /** * Get lists of items from a list of partitions. */ const failable > getlist(const value& key, const list& partitions) { if (isNull(partitions)) return nilListValue; const lvvlambda l = car(partitions); const value val = l(mklist("get", key)); if (isNull(val)) return getlist(key, cdr(partitions)); if (!isList(val)) { ostringstream os; os << "Couldn't get list of entries from partition: " << key; return mkfailure >(str(os), 500, false); } const failable > cdrval = getlist(key, cdr(partitions)); if (!hasContent(cdrval)) return cdrval; return append((list)val, content(cdrval)); } /** * Get an item from a partition. */ const failable get(const value& key, const lvvlambda& selector, const list& partitions) { // Select partition const failable > fp = partition(key, selector, partitions); if (!hasContent(fp)) return mkfailure(fp); const list p = content(fp); // Get a single item from the selected partition if (length(p) == 1) { const lvvlambda l = car(p); const value val = l(mklist("get", key)); if (isNull(val)) { ostringstream os; os << "Couldn't get entry from partition: " << key; return mkfailure(str(os), 404, false); } return val; } // Get list of items from the list of selected partitions const failable > val = getlist(key, p); if (!hasContent(val)) return mkfailure(val); return (value)content(val); } /** * Post an item to a partition. */ const failable post(const value& key, const value& val, const lvvlambda& selector, const list& partitions) { const value id = append(key, mklist(mkuuid())); // Select partition const failable > p = partition(id, selector, partitions); if (!hasContent(p)) return mkfailure(p); // Put into select partition const lvvlambda l = car(content(p)); l(mklist("post", id, val)); return id; } /** * Put an item into a partition. */ const failable put(const value& key, const value& val, const lvvlambda& selector, const list& partitions) { // Select partition const failable > p = partition(key, selector, partitions); if (!hasContent(p)) return mkfailure(p); // Put into selected partition const lvvlambda l = car(content(p)); l(mklist("put", key, val)); return trueValue; } /** * Patch an item in a partition. */ const failable patch(const value& key, const value& val, const lvvlambda& selector, const list& partitions) { // Select partition const failable > p = partition(key, selector, partitions); if (!hasContent(p)) return mkfailure(p); // Path item in selected partition const lvvlambda l = car(content(p)); l(mklist("patch", key, val)); return trueValue; } /** * Delete an item from a partition. */ const failable del(const value& key, const lvvlambda& selector, const list& partitions) { // Select partition const failable > p = partition(key, selector, partitions); if (!hasContent(p)) return mkfailure(p); // Delete from selected partition const lvvlambda l = car(content(p)); l(mklist("delete", key)); return trueValue; } } } extern "C" { const tuscany::value apply(const tuscany::list& params) { const tuscany::value func(car(params)); if (func == "get") return tuscany::partitioner::get(cadr(params), caddr(params), cdddr(params)); if (func == "post") return tuscany::partitioner::post(cadr(params), caddr(params), cadddr(params), cddddr(params)); if (func == "put") return tuscany::partitioner::put(cadr(params), caddr(params), cadddr(params), cddddr(params)); if (func == "patch") return tuscany::partitioner::patch(cadr(params), caddr(params), cadddr(params), cddddr(params)); if (func == "delete") return tuscany::partitioner::del(cadr(params), caddr(params), cdddr(params)); return tuscany::mkfailure(); } }