blob: 47c2382330dd896c57a0475159f62ba0dbd8d8cd [file] [log] [blame]
/*
* 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.
*/
#include "CacheXmlParser.hpp"
#include <chrono>
#include <cinttypes>
#include <geode/PoolFactory.hpp>
#include <geode/PoolManager.hpp>
#include <geode/internal/chrono/duration.hpp>
#include "AutoDelete.hpp"
#include "CacheImpl.hpp"
#include "CacheRegionHelper.hpp"
#include "util/string.hpp"
#if defined(_WIN32)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
namespace apache {
namespace geode {
namespace client {
namespace {
/** The name of the <code>cache</code> element */
auto CACHE = "cache";
auto CLIENT_CACHE = "client-cache";
auto PDX = "pdx";
/** The name of the <code>redundancy-level</code> element */
auto REDUNDANCY_LEVEL = "redundancy-level";
/** The name of the <code>region</code> element */
auto REGION = "region";
/** The name of the <code>root-region</code> element */
auto ROOT_REGION = "root-region";
/** The name of the <code>region-attributes</code> element */
auto REGION_ATTRIBUTES = "region-attributes";
auto LRU_ENTRIES_LIMIT = "lru-entries-limit";
auto DISK_POLICY = "disk-policy";
auto ENDPOINTS = "endpoints";
/** The name of the <code>region-time-to-live</code> element */
auto REGION_TIME_TO_LIVE = "region-time-to-live";
/** The name of the <code>region-idle-time</code> element */
auto REGION_IDLE_TIME = "region-idle-time";
/** The name of the <code>entry-time-to-live</code> element */
auto ENTRY_TIME_TO_LIVE = "entry-time-to-live";
/** The name of the <code>entry-idle-time</code> element */
auto ENTRY_IDLE_TIME = "entry-idle-time";
/** The name of the <code>expiration-attributes</code> element */
auto EXPIRATION_ATTRIBUTES = "expiration-attributes";
/** The name of the <code>cache-loader</code> element */
auto CACHE_LOADER = "cache-loader";
/** The name of the <code>cache-writer</code> element */
auto CACHE_WRITER = "cache-writer";
/** The name of the <code>cache-listener</code> element */
auto CACHE_LISTENER = "cache-listener";
/** The name of the <code>partition-resolver</code> element */
auto PARTITION_RESOLVER = "partition-resolver";
auto LIBRARY_NAME = "library-name";
auto LIBRARY_FUNCTION_NAME = "library-function-name";
auto CACHING_ENABLED = "caching-enabled";
auto INTEREST_LIST_ENABLED = "interest-list-enabled";
auto MAX_DISTRIBUTE_VALUE_LENGTH_WHEN_CREATE =
"max-distribute-value-length-when-create";
/** The name of the <code>scope</code> attribute */
auto SCOPE = "scope";
/** The name of the <code>client-notification</code> attribute */
auto CLIENT_NOTIFICATION_ENABLED = "client-notification";
/** The name of the <code>initial-capacity</code> attribute */
auto INITIAL_CAPACITY = "initial-capacity";
/** The name of the <code>initial-capacity</code> attribute */
auto CONCURRENCY_LEVEL = "concurrency-level";
/** The name of the <code>load-factor</code> attribute */
auto LOAD_FACTOR = "load-factor";
/** The name of the <code>statistics-enabled</code> attribute */
auto STATISTICS_ENABLED = "statistics-enabled";
/** The name of the <code>timeout</code> attribute */
auto TIMEOUT = "timeout";
/** The name of the <code>action</code> attribute */
auto ACTION = "action";
/** The name of the <code>local</code> value */
auto LOCAL = "local";
/** The name of the <code>distributed-no-ack</code> value */
auto DISTRIBUTED_NO_ACK = "distributed-no-ack";
/** The name of the <code>distributed-ack</code> value */
auto DISTRIBUTED_ACK = "distributed-ack";
/** The name of the <code>global</code> value */
auto GLOBAL = "global";
/** The name of the <code>invalidate</code> value */
auto INVALIDATE = "invalidate";
/** The name of the <code>destroy</code> value */
auto DESTROY = "destroy";
/** The name of the <code>overflow</code> value */
auto OVERFLOWS = "overflows";
/** The name of the <code>overflow</code> value */
auto PERSIST = "persist";
/** The name of the <code>none</code> value */
auto NONE = "none";
/** The name of the <code>local-invalidate</code> value */
auto LOCAL_INVALIDATE = "local-invalidate";
/** The name of the <code>local-destroy</code> value */
auto LOCAL_DESTROY = "local-destroy";
/** The name of the <code>persistence-manager</code> value */
auto PERSISTENCE_MANAGER = "persistence-manager";
/** The name of the <code>property</code> value */
auto PROPERTY = "property";
auto CONCURRENCY_CHECKS_ENABLED = "concurrency-checks-enabled";
auto TOMBSTONE_TIMEOUT = "tombstone-timeout";
/** Pool elements and attributes */
auto POOL_NAME = "pool-name";
auto POOL = "pool";
auto NAME = "name";
auto VALUE = "value";
auto LOCATOR = "locator";
auto SERVER = "server";
auto HOST = "host";
auto PORT = "port";
auto IGNORE_UNREAD_FIELDS = "ignore-unread-fields";
auto READ_SERIALIZED = "read-serialized";
auto FREE_CONNECTION_TIMEOUT = "free-connection-timeout";
auto MULTIUSER_SECURE_MODE = "multiuser-authentication";
auto IDLE_TIMEOUT = "idle-timeout";
auto LOAD_CONDITIONING_INTERVAL = "load-conditioning-interval";
auto MAX_CONNECTIONS = "max-connections";
auto MIN_CONNECTIONS = "min-connections";
auto PING_INTERVAL = "ping-interval";
auto UPDATE_LOCATOR_LIST_INTERVAL = "update-locator-list-interval";
auto READ_TIMEOUT = "read-timeout";
auto RETRY_ATTEMPTS = "retry-attempts";
auto SERVER_GROUP = "server-group";
auto SOCKET_BUFFER_SIZE = "socket-buffer-size";
auto STATISTIC_INTERVAL = "statistic-interval";
auto SUBSCRIPTION_ACK_INTERVAL = "subscription-ack-interval";
auto SUBSCRIPTION_ENABLED = "subscription-enabled";
auto SUBSCRIPTION_MTT = "subscription-message-tracking-timeout";
auto SUBSCRIPTION_REDUNDANCY = "subscription-redundancy";
auto THREAD_LOCAL_CONNECTIONS = "thread-local-connections";
auto CLONING_ENABLED = "cloning-enabled";
auto ID = "id";
auto REFID = "refid";
auto PR_SINGLE_HOP_ENABLED = "pr-single-hop-enabled";
std::vector<std::pair<std::string, int>> parseEndPoints(
const std::string &str) {
std::vector<std::pair<std::string, int>> endPoints;
std::string::size_type start = 0;
std::string::size_type pos = str.find_first_of(',');
while (std::string::npos != pos) {
const std::string endPoint(str.substr(start, pos - start));
const std::string::size_type split = endPoint.find_last_of(':');
if (std::string::npos == split) {
endPoints.push_back(std::pair<std::string, int>(endPoint, 0));
} else {
int port = 0;
try {
port = std::stoi(endPoint.substr(split + 1));
} catch (...) {
// NOP
}
endPoints.push_back(
std::pair<std::string, int>(endPoint.substr(0, split), port));
}
start = pos + 1;
pos = str.find_first_of(',', start);
}
return endPoints;
}
} // namespace
/**
* warningDebug:
* @ctxt: An XML parser context
* @msg: the message to display/transmit
* @...: extra parameters for the message display
*
* Display and format a warning messages, gives file, line, position and
* extra parameters.
*/
extern "C" void warningDebug(void *, const char *msg, ...) {
char logmsg[2048];
va_list args;
va_start(args, msg);
vsprintf(logmsg, msg, args);
va_end(args);
LOGWARN("SAX.warning during XML declarative client initialization: %s",
logmsg);
}
/////////////End of XML Parser Cackllback functions///////////////
///////////////static variables of the class////////////////////////
FactoryLoaderFn<CacheLoader> CacheXmlParser::managedCacheLoaderFn_ = nullptr;
FactoryLoaderFn<CacheListener> CacheXmlParser::managedCacheListenerFn_ =
nullptr;
FactoryLoaderFn<PartitionResolver> CacheXmlParser::managedPartitionResolverFn_ =
nullptr;
FactoryLoaderFn<CacheWriter> CacheXmlParser::managedCacheWriterFn_ = nullptr;
FactoryLoaderFn<PersistenceManager>
CacheXmlParser::managedPersistenceManagerFn_ = nullptr;
//////////////////////////////////////////////////////////////////
CacheXmlParser::CacheXmlParser(Cache *cache)
: cacheCreation_(nullptr),
nestedRegions_(0),
config_(nullptr),
parserMessage_(""),
flagCacheXmlException_(false),
flagIllegalStateException_(false),
flagAnyOtherException_(false),
flagExpirationAttribute_(false),
namedRegions_(CacheImpl::getRegionShortcut()),
poolFactory_(nullptr),
cache_(cache) {
start_element_map_.emplace(
std::make_pair(std::string(CACHE), &CacheXmlParser::startCache));
start_element_map_.emplace(
std::make_pair(std::string(CLIENT_CACHE), &CacheXmlParser::startCache));
start_element_map_.emplace(
std::make_pair(std::string(PDX), &CacheXmlParser::startPdx));
start_element_map_.emplace(
std::make_pair(std::string(REGION), &CacheXmlParser::startRegion));
start_element_map_.emplace(
std::make_pair(std::string(ROOT_REGION), &CacheXmlParser::startRegion));
start_element_map_.emplace(std::make_pair(
std::string(REGION_ATTRIBUTES), &CacheXmlParser::startRegionAttributes));
start_element_map_.emplace(
std::make_pair(std::string(EXPIRATION_ATTRIBUTES),
&CacheXmlParser::startExpirationAttributes));
start_element_map_.emplace(std::make_pair(std::string(CACHE_LOADER),
&CacheXmlParser::startCacheLoader));
start_element_map_.emplace(std::make_pair(std::string(CACHE_WRITER),
&CacheXmlParser::startCacheWriter));
start_element_map_.emplace(std::make_pair(
std::string(CACHE_LISTENER), &CacheXmlParser::startCacheListener));
start_element_map_.emplace(
std::make_pair(std::string(PARTITION_RESOLVER),
&CacheXmlParser::startPartitionResolver));
start_element_map_.emplace(
std::make_pair(std::string(PERSISTENCE_MANAGER),
&CacheXmlParser::startPersistenceManager));
start_element_map_.emplace(std::make_pair(
std::string(PROPERTY), &CacheXmlParser::startPersistenceProperty));
start_element_map_.emplace(
std::make_pair(std::string(POOL), &CacheXmlParser::startPool));
start_element_map_.emplace(
std::make_pair(std::string(LOCATOR), &CacheXmlParser::startLocator));
start_element_map_.emplace(
std::make_pair(std::string(SERVER), &CacheXmlParser::startServer));
end_element_map_.emplace(
std::make_pair(std::string(CACHE), &CacheXmlParser::endCache));
end_element_map_.emplace(
std::make_pair(std::string(CLIENT_CACHE), &CacheXmlParser::endCache));
end_element_map_.emplace(
std::make_pair(std::string(REGION), &CacheXmlParser::endRegion));
end_element_map_.emplace(
std::make_pair(std::string(ROOT_REGION), &CacheXmlParser::endRegion));
end_element_map_.emplace(std::make_pair(
std::string(REGION_ATTRIBUTES), &CacheXmlParser::endRegionAttributes));
end_element_map_.emplace(std::make_pair(
std::string(REGION_TIME_TO_LIVE), &CacheXmlParser::endRegionTimeToLive));
end_element_map_.emplace(std::make_pair(std::string(REGION_IDLE_TIME),
&CacheXmlParser::endRegionIdleTime));
end_element_map_.emplace(std::make_pair(std::string(ENTRY_TIME_TO_LIVE),
&CacheXmlParser::endEntryTimeToLive));
end_element_map_.emplace(std::make_pair(std::string(ENTRY_IDLE_TIME),
&CacheXmlParser::endEntryIdleTime));
end_element_map_.emplace(
std::make_pair(std::string(PERSISTENCE_MANAGER),
&CacheXmlParser::endPersistenceManager));
end_element_map_.emplace(
std::make_pair(std::string(POOL), &CacheXmlParser::endPool));
}
void CacheXmlParser::startElement(const XMLCh *const,
const XMLCh *const localname,
const XMLCh *const,
const xercesc::Attributes &attrs) {
auto message = xercesc::XMLString::transcode(localname);
auto name = std::string(message);
auto iter = start_element_map_.find(name);
if (iter != std::end(start_element_map_)) {
iter->second(*this, attrs);
}
xercesc::XMLString::release(&message);
}
void CacheXmlParser::endElement(const XMLCh *const,
const XMLCh *const localname,
const XMLCh *const) {
auto message = xercesc::XMLString::transcode(localname);
auto name = std::string(message);
auto iter = end_element_map_.find(name);
if (iter != std::end(end_element_map_)) {
iter->second(*this);
}
xercesc::XMLString::release(&message);
}
void CacheXmlParser::fatalError(const xercesc::SAXParseException &exception) {
char *message = xercesc::XMLString::transcode(exception.getMessage());
LOGDEBUG("Fatal Error: \"%s\" at line: %" PRIu64, message,
exception.getLineNumber());
auto ex = CacheXmlException(message);
xercesc::XMLString::release(&message);
throw ex;
}
void CacheXmlParser::parseFile(const char *filename) {
try {
xercesc::XMLPlatformUtils::Initialize();
} catch (const xercesc::XMLException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
}
auto parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setFeature(xercesc::XMLUni::fgXercesSchema, false);
parser->setContentHandler(this);
parser->setErrorHandler(this);
try {
parser->parse(filename);
} catch (const xercesc::XMLException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
} catch (const xercesc::SAXParseException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
}
delete parser;
xercesc::XMLPlatformUtils::Terminate();
}
void CacheXmlParser::parseMemory(const char *buffer, int size) {
try {
xercesc::XMLPlatformUtils::Initialize();
} catch (const xercesc::XMLException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
}
auto parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setContentHandler(this);
parser->setErrorHandler(this);
try {
xercesc::MemBufInputSource myxml_buf(
reinterpret_cast<const XMLByte *>(buffer), size,
"CacheXmlParser memory source");
parser->parse(myxml_buf);
} catch (const xercesc::XMLException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
} catch (const xercesc::SAXParseException &toCatch) {
char *message = xercesc::XMLString::transcode(toCatch.getMessage());
auto exceptionMessage = "Error parsing XML file: " + std::string(message);
xercesc::XMLString::release(&message);
throw CacheXmlException(exceptionMessage);
}
delete parser;
xercesc::XMLPlatformUtils::Terminate();
}
////////////////////// Static Methods //////////////////////
/**
* Parses XML data and from it creates an instance of
* <code>CacheXmlParser</code> that can be used to create
* the {@link Cache}, etc.
*
* @param cacheXml
* The xml file
*
* @throws CacheXmlException
* Something went wrong while parsing the XML
* @throws OutOfMemoryException
* @throws CacheXmlException
* If xml file is not well-formed or
* Something went wrong while parsing the XML
* @throws IllegalStateException
* If xml file is well-flrmed but not valid
* @throws UnknownException otherwise
*/
CacheXmlParser *CacheXmlParser::parse(const char *cacheXml, Cache *cache) {
CacheXmlParser *handler;
_GEODE_NEW(handler, CacheXmlParser(cache));
// use RAII to delete the handler object in case of exceptions
DeleteObject<CacheXmlParser> delHandler(handler);
{
handler->parseFile(cacheXml);
delHandler.noDelete();
return handler;
}
}
void CacheXmlParser::setAttributes(Cache *) {}
/**
* Creates cache artifacts ({@link Cache}s, etc.) based upon the XML
* parsed by this parser.
*
* @param cache
* The cachewhcih is to be populated
* @throws OutOfMemoryException if the memory allocation failed
* @throws NotConnectedException if the cache is not connected
* @throws InvalidArgumentException if the attributePtr is nullptr.
* or if RegionAttributes is null or if regionName is null,
* the empty string, or contains a '/'
* @throws RegionExistsException
* @throws CacheClosedException if the cache is closed
* at the time of region creation
* @throws UnknownException otherwise
*
*/
void CacheXmlParser::create(Cache *cache) {
// use DeleteObject class to delete cacheCreation_ in case of exceptions
DeleteObject<CacheXmlCreation> delCacheCreation(cacheCreation_);
if (cache == nullptr) {
throw IllegalArgumentException(
"XML:No cache specified for performing configuration");
}
if (!cacheCreation_) {
throw CacheXmlException("XML: Element <cache> was not provided in the xml");
}
cacheCreation_->create(cache);
delCacheCreation.noDelete();
Log::info("Declarative configuration of cache completed successfully");
}
std::string CacheXmlParser::getOptionalAttribute(
const xercesc::Attributes &attrs, const char *attributeName) {
using unique_xml_char = std::unique_ptr<XMLCh, std::function<void(XMLCh *)>>;
using unique_xerces_char = std::unique_ptr<char, std::function<void(char *)>>;
auto xml_deleter = [](XMLCh *ch) { xercesc::XMLString::release(&ch); };
auto xerces_deleter = [](char *ch) { xercesc::XMLString::release(&ch); };
unique_xml_char translatedName(xercesc::XMLString::transcode(attributeName),
xml_deleter);
auto value = attrs.getValue(translatedName.get());
if (!value) {
return "";
}
unique_xerces_char translatedValue(xercesc::XMLString::transcode(value),
xerces_deleter);
if (!strlen(translatedValue.get())) {
throw CacheXmlException("XML: Empty value provided for attribute: " +
std::string(CACHE) + " or " + CLIENT_CACHE);
}
return {translatedValue.get()};
}
std::string CacheXmlParser::getRequiredAttribute(
const xercesc::Attributes &attrs, const char *attributeName) {
using unique_xml_char = std::unique_ptr<XMLCh, std::function<void(XMLCh *)>>;
auto xml_deleter = [](XMLCh *ch) { xercesc::XMLString::release(&ch); };
unique_xml_char translatedName(xercesc::XMLString::transcode(attributeName),
xml_deleter);
auto value = attrs.getValue(translatedName.get());
if (!value) {
throw CacheXmlException("XML: No value provided for required attribute: " +
std::string(attributeName));
}
return getOptionalAttribute(attrs, attributeName);
}
void CacheXmlParser::startCache(const xercesc::Attributes &attrs) {
auto value = getOptionalAttribute(attrs, ENDPOINTS);
if (!value.empty()) {
if (poolFactory_) {
for (auto &&endPoint : parseEndPoints(value)) {
poolFactory_->addServer(endPoint.first, endPoint.second);
}
}
}
value = getOptionalAttribute(attrs, REDUNDANCY_LEVEL);
if (!value.empty()) {
if (poolFactory_) {
poolFactory_->setSubscriptionRedundancy(std::stoi(value));
}
}
_GEODE_NEW(cacheCreation_, CacheXmlCreation());
}
void CacheXmlParser::startPdx(const xercesc::Attributes &attrs) {
auto ignoreUnreadFields = getOptionalAttribute(attrs, IGNORE_UNREAD_FIELDS);
if (!ignoreUnreadFields.empty()) {
if (equal_ignore_case(ignoreUnreadFields, "true")) {
cacheCreation_->setPdxIgnoreUnreadField(true);
} else {
cacheCreation_->setPdxIgnoreUnreadField(false);
}
}
auto pdxReadSerialized = getOptionalAttribute(attrs, READ_SERIALIZED);
if (!pdxReadSerialized.empty()) {
if (equal_ignore_case(pdxReadSerialized, "true")) {
cacheCreation_->setPdxReadSerialized(true);
} else {
cacheCreation_->setPdxReadSerialized(false);
}
}
}
void CacheXmlParser::startLocator(const xercesc::Attributes &attrs) {
poolFactory_ = std::static_pointer_cast<PoolFactory>(_stack.top());
auto host = getRequiredAttribute(attrs, HOST);
auto port = getRequiredAttribute(attrs, PORT);
poolFactory_->addLocator(host, std::stoi(port));
}
void CacheXmlParser::startServer(const xercesc::Attributes &attrs) {
auto factory = std::static_pointer_cast<PoolFactory>(_stack.top());
auto host = getRequiredAttribute(attrs, HOST);
auto port = getRequiredAttribute(attrs, PORT);
factory->addServer(host, std::stoi(port));
}
void CacheXmlParser::startPool(const xercesc::Attributes &attrs) {
using apache::geode::client::equal_ignore_case;
using apache::geode::internal::chrono::duration::from_string;
auto factory =
std::make_shared<PoolFactory>(cache_->getPoolManager().createFactory());
auto poolName = getRequiredAttribute(attrs, NAME);
auto poolxml = std::make_shared<PoolXmlCreation>(poolName, factory);
auto freeConnectionTimeout =
getOptionalAttribute(attrs, FREE_CONNECTION_TIMEOUT);
if (!freeConnectionTimeout.empty()) {
factory->setFreeConnectionTimeout(
from_string<std::chrono::milliseconds>(freeConnectionTimeout));
}
auto multiUserSecureMode = getOptionalAttribute(attrs, MULTIUSER_SECURE_MODE);
if (!multiUserSecureMode.empty()) {
if (equal_ignore_case(multiUserSecureMode, "true")) {
factory->setMultiuserAuthentication(true);
} else {
factory->setMultiuserAuthentication(false);
}
}
auto idleTimeout = getOptionalAttribute(attrs, IDLE_TIMEOUT);
if (!idleTimeout.empty()) {
factory->setIdleTimeout(
from_string<std::chrono::milliseconds>(idleTimeout));
}
auto loadConditioningInterval =
getOptionalAttribute(attrs, LOAD_CONDITIONING_INTERVAL);
if (!loadConditioningInterval.empty()) {
factory->setLoadConditioningInterval(
from_string<std::chrono::milliseconds>(loadConditioningInterval));
}
auto maxConnections = getOptionalAttribute(attrs, MAX_CONNECTIONS);
if (!maxConnections.empty()) {
factory->setMaxConnections(atoi(maxConnections.c_str()));
}
auto minConnections = getOptionalAttribute(attrs, MIN_CONNECTIONS);
if (!minConnections.empty()) {
factory->setMinConnections(atoi(minConnections.c_str()));
}
auto pingInterval = getOptionalAttribute(attrs, PING_INTERVAL);
if (!pingInterval.empty()) {
factory->setPingInterval(
from_string<std::chrono::milliseconds>(std::string(pingInterval)));
}
auto updateLocatorListInterval =
getOptionalAttribute(attrs, UPDATE_LOCATOR_LIST_INTERVAL);
if (!updateLocatorListInterval.empty()) {
factory->setUpdateLocatorListInterval(
from_string<std::chrono::milliseconds>(updateLocatorListInterval));
}
auto readTimeout = getOptionalAttribute(attrs, READ_TIMEOUT);
if (!readTimeout.empty()) {
factory->setReadTimeout(
from_string<std::chrono::milliseconds>(std::string(readTimeout)));
}
auto retryAttempts = getOptionalAttribute(attrs, RETRY_ATTEMPTS);
if (!retryAttempts.empty()) {
factory->setRetryAttempts(atoi(retryAttempts.c_str()));
}
auto serverGroup = getOptionalAttribute(attrs, SERVER_GROUP);
if (!serverGroup.empty()) {
factory->setServerGroup(serverGroup);
}
auto socketBufferSize = getOptionalAttribute(attrs, SOCKET_BUFFER_SIZE);
if (!socketBufferSize.empty()) {
factory->setSocketBufferSize(atoi(socketBufferSize.c_str()));
}
auto statisticInterval = getOptionalAttribute(attrs, STATISTIC_INTERVAL);
if (!statisticInterval.empty()) {
factory->setStatisticInterval(
from_string<std::chrono::milliseconds>(statisticInterval));
}
auto subscriptionAckInterval =
getOptionalAttribute(attrs, SUBSCRIPTION_ACK_INTERVAL);
if (!subscriptionAckInterval.empty()) {
factory->setSubscriptionAckInterval(
from_string<std::chrono::milliseconds>(subscriptionAckInterval));
}
auto subscriptionEnabled = getOptionalAttribute(attrs, SUBSCRIPTION_ENABLED);
if (!subscriptionEnabled.empty()) {
if (equal_ignore_case(subscriptionEnabled, "true")) {
factory->setSubscriptionEnabled(true);
} else {
factory->setSubscriptionEnabled(false);
}
}
auto subscriptionMessageTrackingTimeout =
getOptionalAttribute(attrs, SUBSCRIPTION_MTT);
if (!subscriptionMessageTrackingTimeout.empty()) {
factory->setSubscriptionMessageTrackingTimeout(
from_string<std::chrono::milliseconds>(
subscriptionMessageTrackingTimeout));
}
auto subscriptionRedundancy =
getOptionalAttribute(attrs, SUBSCRIPTION_REDUNDANCY);
if (!subscriptionRedundancy.empty()) {
factory->setSubscriptionRedundancy(atoi(subscriptionRedundancy.c_str()));
}
auto threadLocalConnections =
getOptionalAttribute(attrs, THREAD_LOCAL_CONNECTIONS);
if (!threadLocalConnections.empty()) {
if (equal_ignore_case(threadLocalConnections, "true")) {
factory->setThreadLocalConnections(true);
} else {
factory->setThreadLocalConnections(false);
}
}
auto prSingleHopEnabled = getOptionalAttribute(attrs, PR_SINGLE_HOP_ENABLED);
if (!prSingleHopEnabled.empty()) {
if (equal_ignore_case(prSingleHopEnabled, "true")) {
factory->setPRSingleHopEnabled(true);
} else {
factory->setPRSingleHopEnabled(false);
}
}
_stack.push(poolxml);
_stack.push(factory);
}
void CacheXmlParser::endPool() {
_stack.pop(); // remove factory
auto poolxml = std::static_pointer_cast<PoolXmlCreation>(_stack.top());
_stack.pop(); // remove pool
cacheCreation_->addPool(poolxml);
}
/**
* When a <code>region</code> element is first encountered, we
* create a {@link RegionCreation} and push it on the _stack.
* An {@link RegionAttributesFactory }is also created and puhed on _stack.
*/
void CacheXmlParser::startRegion(const xercesc::Attributes &attrs) {
incNesting();
auto isRoot = isRootLevel();
auto regionName = getRequiredAttribute(attrs, NAME);
auto region = std::make_shared<RegionXmlCreation>(regionName, isRoot);
if (!region) {
throw UnknownException("CacheXmlParser::startRegion:Out of memory");
}
_stack.push(region);
auto refid = getOptionalAttribute(attrs, REFID);
if (!refid.empty()) {
if (namedRegions_.find(refid) != namedRegions_.end()) {
auto regionAttributesFactory =
RegionAttributesFactory(namedRegions_[refid]);
region->setAttributes(regionAttributesFactory.create());
} else {
throw CacheXmlException("XML:referenced named attribute '" + refid +
"' does not exist.");
}
}
}
void CacheXmlParser::startRegionAttributes(const xercesc::Attributes &attrs) {
bool isDistributed = false;
bool isTCR = false;
std::shared_ptr<RegionAttributesFactory> regionAttributesFactory = nullptr;
if (attrs.getLength() > 24) {
throw CacheXmlException(
"XML:Too many attributes provided for <region-attributes>");
}
if (attrs.getLength() == 0) {
auto region = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
regionAttributesFactory =
std::make_shared<RegionAttributesFactory>(region->getAttributes());
} else {
auto id = getOptionalAttribute(attrs, ID);
if (!id.empty()) {
auto region = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
region->setAttrId(id);
}
auto refid = getOptionalAttribute(attrs, REFID);
if (refid.empty()) {
auto region = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
regionAttributesFactory =
std::make_shared<RegionAttributesFactory>(region->getAttributes());
} else {
if (namedRegions_.find(refid) != namedRegions_.end()) {
regionAttributesFactory =
std::make_shared<RegionAttributesFactory>(namedRegions_[refid]);
} else {
throw CacheXmlException("XML:referenced named attribute '" + refid +
"' does not exist.");
}
}
if (!regionAttributesFactory) {
throw UnknownException(
"CacheXmlParser::startRegionAttributes:Out of memory");
}
auto clientNotificationEnabled =
getOptionalAttribute(attrs, CLIENT_NOTIFICATION_ENABLED);
if (!clientNotificationEnabled.empty()) {
bool flag = false;
std::transform(clientNotificationEnabled.begin(),
clientNotificationEnabled.end(),
clientNotificationEnabled.begin(), ::tolower);
if ("false" == clientNotificationEnabled) {
flag = false;
} else if ("true" == clientNotificationEnabled) {
flag = true;
} else {
throw CacheXmlException(
"XML: " + clientNotificationEnabled +
" is not a valid name for the attribute <client-notification>");
}
if (poolFactory_) {
poolFactory_->setSubscriptionEnabled(flag);
}
}
auto initialCapacity = getOptionalAttribute(attrs, INITIAL_CAPACITY);
if (!initialCapacity.empty()) {
regionAttributesFactory->setInitialCapacity(std::stoi(initialCapacity));
}
auto concurrencyLevel = getOptionalAttribute(attrs, CONCURRENCY_LEVEL);
if (!concurrencyLevel.empty()) {
regionAttributesFactory->setConcurrencyLevel(std::stoi(concurrencyLevel));
}
auto loadFactor = getOptionalAttribute(attrs, LOAD_FACTOR);
if (!loadFactor.empty()) {
regionAttributesFactory->setLoadFactor(std::stof(loadFactor));
}
auto cachingEnabled = getOptionalAttribute(attrs, CACHING_ENABLED);
if (!cachingEnabled.empty()) {
bool flag = false;
std::transform(cachingEnabled.begin(), cachingEnabled.end(),
cachingEnabled.begin(), ::tolower);
if ("false" == cachingEnabled) {
flag = false;
} else if ("true" == cachingEnabled) {
flag = true;
} else {
throw CacheXmlException(
"XML: " + cachingEnabled +
" is not a valid name for the attribute <caching-enabled>");
}
regionAttributesFactory->setCachingEnabled(flag);
}
auto lruEntriesLimit = getOptionalAttribute(attrs, LRU_ENTRIES_LIMIT);
if (!lruEntriesLimit.empty()) {
regionAttributesFactory->setLruEntriesLimit(std::stoi(lruEntriesLimit));
}
auto diskPolicyString = getOptionalAttribute(attrs, DISK_POLICY);
if (!diskPolicyString.empty()) {
auto diskPolicy = apache::geode::client::DiskPolicyType::NONE;
if (OVERFLOWS == diskPolicyString) {
diskPolicy = apache::geode::client::DiskPolicyType::OVERFLOWS;
} else if (PERSIST == diskPolicyString) {
throw IllegalStateException("Persistence feature is not supported");
} else if (NONE == diskPolicyString) {
diskPolicy = apache::geode::client::DiskPolicyType::NONE;
} else {
throw CacheXmlException(
"XML: " + diskPolicyString +
" is not a valid name for the attribute <disk-policy>");
}
regionAttributesFactory->setDiskPolicy(diskPolicy);
}
auto endpoints = getOptionalAttribute(attrs, ENDPOINTS);
if (!endpoints.empty()) {
if (poolFactory_) {
for (auto &&endPoint : parseEndPoints(ENDPOINTS)) {
poolFactory_->addServer(endPoint.first, endPoint.second);
}
}
isTCR = true;
}
auto poolName = getOptionalAttribute(attrs, POOL_NAME);
if (!poolName.empty()) {
regionAttributesFactory->setPoolName(poolName);
isTCR = true;
}
auto cloningEnabled = getOptionalAttribute(attrs, CLONING_ENABLED);
if (!cloningEnabled.empty()) {
bool flag = false;
std::transform(cloningEnabled.begin(), cloningEnabled.end(),
cloningEnabled.begin(), ::tolower);
if ("false" == cloningEnabled) {
flag = false;
} else if ("true" == cloningEnabled) {
flag = true;
} else {
throw CacheXmlException("XML: " + cloningEnabled +
" is not a valid value for the attribute <" +
std::string(CLONING_ENABLED) + ">");
}
regionAttributesFactory->setCloningEnabled(flag);
isTCR = true;
}
auto concurrencyChecksEnabled =
getOptionalAttribute(attrs, CONCURRENCY_CHECKS_ENABLED);
if (!concurrencyChecksEnabled.empty()) {
bool flag = false;
std::transform(concurrencyChecksEnabled.begin(),
concurrencyChecksEnabled.end(),
concurrencyChecksEnabled.begin(), ::tolower);
if ("false" == concurrencyChecksEnabled) {
flag = false;
} else if ("true" == concurrencyChecksEnabled) {
flag = true;
} else {
throw CacheXmlException("XML: " + concurrencyChecksEnabled +
" is not a valid value for the attribute "
"<" +
std::string(CONCURRENCY_CHECKS_ENABLED) + ">");
}
regionAttributesFactory->setConcurrencyChecksEnabled(flag);
}
}
if (isDistributed && isTCR) {
// we don't allow DR+TCR at current stage
throw CacheXmlException(
"XML:endpoints cannot be defined for distributed region.\n");
}
_stack.push(regionAttributesFactory);
}
void CacheXmlParser::endRegionAttributes() {
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
_stack.pop();
if (!regionAttributesFactory) {
throw UnknownException(
"CacheXmlParser::endRegion:RegionAttributesFactory is null");
}
auto regionAttributes = regionAttributesFactory->create();
auto regionPtr = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
if (!regionPtr) {
throw UnknownException("CacheXmlParser::endRegion:Region is null");
}
std::string id = regionPtr->getAttrId();
if (id != "") {
namedRegions_[id] = regionAttributes;
}
regionPtr->setAttributes(regionAttributes);
}
/**
* When a <code>expiration-attributes</code> element is first
* encountered, we create an {@link ExpirationAttibutes} object from
* the element's attributes and push it on the _stack.
*/
void CacheXmlParser::startExpirationAttributes(
const xercesc::Attributes &attrs) {
using apache::geode::internal::chrono::duration::from_string;
flagExpirationAttribute_ = true;
if (attrs.getLength() > 2) {
throw CacheXmlException(
"XML:Incorrect number of attributes provided for "
"<expiration-attributes>");
}
ExpirationAction expire = ExpirationAction::INVALID_ACTION;
auto action = getOptionalAttribute(attrs, ACTION);
if (action.empty()) {
throw CacheXmlException(
"XML:The attribute <action> of <expiration-attributes> cannot be"
"set to empty string. It should either have a action or the "
"attribute should be removed. In the latter case the default action "
"will be set");
} else if (action == INVALIDATE) {
expire = ExpirationAction::INVALIDATE;
} else if (action == DESTROY) {
expire = ExpirationAction::DESTROY;
} else if (action == LOCAL_INVALIDATE) {
expire = ExpirationAction::LOCAL_INVALIDATE;
} else if (action == LOCAL_DESTROY) {
expire = ExpirationAction::LOCAL_DESTROY;
} else {
throw CacheXmlException("XML: " + action +
" is not a valid value for the attribute <action>");
}
auto timeOut = getOptionalAttribute(attrs, TIMEOUT);
if (timeOut.empty()) {
throw CacheXmlException(
"XML:Value for attribute <timeout> needs to be specified");
}
auto timeOutSeconds = from_string<std::chrono::seconds>(timeOut);
auto expireAttr =
std::make_shared<ExpirationAttributes>(timeOutSeconds, expire);
if (!expireAttr) {
throw UnknownException(
"CacheXmlParser::startExpirationAttributes:Out of memory");
}
expireAttr->setAction(expire);
_stack.push(expireAttr);
}
std::string CacheXmlParser::getLibraryName(const xercesc::Attributes &attrs) {
return getRequiredAttribute(attrs, LIBRARY_NAME);
}
std::string CacheXmlParser::getLibraryFunctionName(
const xercesc::Attributes &attrs) {
return getRequiredAttribute(attrs, LIBRARY_FUNCTION_NAME);
}
void CacheXmlParser::startPersistenceManager(const xercesc::Attributes &attrs) {
auto libraryName = getLibraryName(attrs);
auto libraryFunctionName = getLibraryFunctionName(attrs);
verifyFactoryFunction(managedPersistenceManagerFn_, libraryName,
libraryFunctionName);
_stack.emplace(std::make_shared<std::string>(std::move(libraryName)));
_stack.emplace(std::make_shared<std::string>(std::move(libraryFunctionName)));
}
void CacheXmlParser::startPersistenceProperty(
const xercesc::Attributes &attrs) {
auto propertyName = getRequiredAttribute(attrs, NAME);
auto propertyValue = getRequiredAttribute(attrs, VALUE);
if (config_ == nullptr) {
config_ = Properties::create();
}
config_->insert(propertyName, propertyValue);
}
void CacheXmlParser::startCacheLoader(const xercesc::Attributes &attrs) {
auto libraryName = getLibraryName(attrs);
auto libraryFunctionName = getLibraryFunctionName(attrs);
verifyFactoryFunction(managedCacheLoaderFn_, libraryName,
libraryFunctionName);
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setCacheLoader(libraryName, libraryFunctionName);
}
void CacheXmlParser::startCacheListener(const xercesc::Attributes &attrs) {
auto libraryName = getLibraryName(attrs);
auto libraryFunctionName = getLibraryFunctionName(attrs);
verifyFactoryFunction(managedCacheListenerFn_, libraryName,
libraryFunctionName);
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setCacheListener(libraryName, libraryFunctionName);
}
void CacheXmlParser::startPartitionResolver(const xercesc::Attributes &attrs) {
auto libraryName = getLibraryName(attrs);
auto libraryFunctionName = getLibraryFunctionName(attrs);
verifyFactoryFunction(managedPartitionResolverFn_, libraryName,
libraryFunctionName);
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setPartitionResolver(libraryName,
libraryFunctionName);
}
void CacheXmlParser::startCacheWriter(const xercesc::Attributes &attrs) {
auto libraryName = getLibraryName(attrs);
auto libraryFunctionName = getLibraryFunctionName(attrs);
verifyFactoryFunction(managedCacheWriterFn_, libraryName,
libraryFunctionName);
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setCacheWriter(libraryName, libraryFunctionName);
}
/**
* After popping the current <code>RegionXmlCreation</code> off the
* _stack, if the element on top of the _stack is a
* <code>RegionXmlCreation</code>, then it is the parent region.
*/
void CacheXmlParser::endRegion() {
auto isRoot = isRootLevel();
auto regionPtr = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
_stack.pop();
if (isRoot) {
if (!_stack.empty()) {
throw CacheXmlException("Xml file has incorrectly nested region tags");
}
if (!cacheCreation_) {
throw CacheXmlException(
"XML: Element <cache> was not provided in the xml");
}
cacheCreation_->addRootRegion(regionPtr);
} else {
if (_stack.empty()) {
throw CacheXmlException("Xml file has incorrectly nested region tags");
}
auto parent = std::static_pointer_cast<RegionXmlCreation>(_stack.top());
parent->addSubregion(regionPtr);
}
decNesting();
}
/**
* When a <code>cache</code> element is finished
*/
void CacheXmlParser::endCache() {}
/**
* When a <code>region-time-to-live</code> element is finished, the
* {@link ExpirationAttributes} are on top of the _stack followed by
* the {@link RegionAttributesFactory} to which the expiration
* attributes are assigned.
*/
void CacheXmlParser::endRegionTimeToLive() {
if (!flagExpirationAttribute_) {
throw CacheXmlException(
"XML: <region-time-to-live> cannot be without a "
"<expiration-attributes>");
}
auto expireAttr =
std::static_pointer_cast<ExpirationAttributes>(_stack.top());
_stack.pop();
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setRegionTimeToLive(expireAttr->getAction(),
expireAttr->getTimeout());
flagExpirationAttribute_ = false;
}
/**
* When a <code>region-idle-time</code> element is finished, the
* {@link ExpirationAttributes} are on top of the _stack followed by
* the {@link RegionAttributesFactory} to which the expiration
* attributes are assigned.
*/
void CacheXmlParser::endRegionIdleTime() {
if (!flagExpirationAttribute_) {
throw CacheXmlException(
"XML: <region-idle-time> cannot be without <expiration-attributes>");
}
auto expireAttr =
std::static_pointer_cast<ExpirationAttributes>(_stack.top());
_stack.pop();
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setRegionIdleTimeout(expireAttr->getAction(),
expireAttr->getTimeout());
flagExpirationAttribute_ = false;
}
/**
* When a <code>entry-time-to-live</code> element is finished, the
* {@link ExpirationAttributes} are on top of the _stack followed by
* the {@link RegionAttributesFactory} to which the expiration
* attributes are assigned.
*/
void CacheXmlParser::endEntryTimeToLive() {
if (!flagExpirationAttribute_) {
throw CacheXmlException(
"XML: <entry-time-to-live> cannot be without <expiration-attributes>");
}
auto expireAttr =
std::static_pointer_cast<ExpirationAttributes>(_stack.top());
_stack.pop();
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
regionAttributesFactory->setEntryTimeToLive(expireAttr->getAction(),
expireAttr->getTimeout());
flagExpirationAttribute_ = false;
}
/**
* When a <code>entry-idle-time</code> element is finished, the
* {@link ExpirationAttributes} are on top of the _stack followed by
* the {@link RegionAttributesFactory} to which the expiration
* attributes are assigned.
*/
void CacheXmlParser::endEntryIdleTime() {
if (!flagExpirationAttribute_) {
throw CacheXmlException(
"XML: <entry-idle-time> cannot be without <expiration-attributes>");
}
auto expireAttr =
std::static_pointer_cast<ExpirationAttributes>(_stack.top());
_stack.pop();
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
// TODO GEODE-3136: consider string parser here.
regionAttributesFactory->setEntryIdleTimeout(expireAttr->getAction(),
expireAttr->getTimeout());
flagExpirationAttribute_ = false;
}
/**
* When persistence-manager attributes is finished, it will set the attribute
* factory.
*/
void CacheXmlParser::endPersistenceManager() {
std::shared_ptr<std::string> libraryFunctionName =
std::static_pointer_cast<std::string>(_stack.top());
_stack.pop();
std::shared_ptr<std::string> libraryName =
std::static_pointer_cast<std::string>(_stack.top());
_stack.pop();
auto regionAttributesFactory =
std::static_pointer_cast<RegionAttributesFactory>(_stack.top());
if (config_ != nullptr) {
regionAttributesFactory->setPersistenceManager(
libraryName->c_str(), libraryFunctionName->c_str(), config_);
config_ = nullptr;
} else {
regionAttributesFactory->setPersistenceManager(
libraryName->c_str(), libraryFunctionName->c_str());
}
}
CacheXmlParser::~CacheXmlParser() { _GEODE_SAFE_DELETE(cacheCreation_); }
} // namespace client
} // namespace geode
} // namespace apache