summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-23 00:34:18 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-23 00:34:18 +0100
commit748a44fba54acb936249d13f69231c85f07a1069 (patch)
tree7f0dfb438aea1e7daf6911cbb49441472fee0f57 /src
parentc7aab61b7cf2b824f168507d9a693b375df0515b (diff)
Implemented most functions in ResourceManager
Diffstat (limited to 'src')
-rw-r--r--src/core/resource/ResourceManager.cpp294
-rw-r--r--src/core/resource/ResourceManager.hpp146
2 files changed, 275 insertions, 165 deletions
diff --git a/src/core/resource/ResourceManager.cpp b/src/core/resource/ResourceManager.cpp
index 563fc12..4a42609 100644
--- a/src/core/resource/ResourceManager.cpp
+++ b/src/core/resource/ResourceManager.cpp
@@ -16,6 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <vector>
+
+#include <core/common/Exceptions.hpp>
#include <core/common/Logger.hpp>
#include <core/common/Rtti.hpp>
#include <core/common/Utils.hpp>
@@ -23,128 +26,182 @@
#include <core/parser/ParserContext.hpp>
#include <core/Registry.hpp>
-#include "Resource.hpp"
#include "ResourceManager.hpp"
+#include "ResourceUtils.hpp"
namespace ousia {
-/* Deduction of the ResourceType */
-
-namespace RttiTypes {
-extern const Rtti Document;
-extern const Rtti Domain;
-extern const Rtti Node;
-extern const Rtti Typesystem;
-}
-
-/**
- * Map mapping from relations (the "rel" attribute in includes) to the
- * corresponding ResourceType.
- */
-static const std::unordered_map<std::string, ResourceType> RelResourceTypeMap{
- {"document", ResourceType::DOCUMENT},
- {"domain", ResourceType::DOMAIN_DESC},
- {"typesystem", ResourceType::TYPESYSTEM}};
-
-/**
- * Map mapping from Rtti pointers to the corresponding ResourceType.
- */
-static const std::unordered_map<Rtti *, ResourceType> RttiResourceTypeMap{
- {&RttiTypes::Document, ResourceType::DOCUMENT},
- {&RttiTypes::Domain, ResourceType::DOMAIN_DESC},
- {&RttiTypes::Typesystem, ResourceType::TYPESYSTEM}};
-
-static ResourceType relToResourceType(const std::string &rel, Logger &logger)
+/* Static helper functions */
+
+static bool typeSetsIntersect(const RttiSet &s1, const RttiSet &s2)
{
- std::string s = Utils::toLowercase(rel);
- if (!s.empty()) {
- auto it = RelResourceTypeMap.find(s);
- if (it != RelResourceTypeMap.end()) {
- return it->second;
- } else {
- logger.error(std::string("Unknown relation \"") + rel +
- std::string("\""));
+ for (const Rtti *t1 : s1) {
+ if (t1->isOneOf(s2)) {
+ return true;
}
}
- return ResourceType::UNKNOWN;
+ return false;
}
-static ResourceType supportedTypesToResourceType(const RttiSet &supportedTypes)
+static void logUnsopportedType(Logger &logger, const RttiSet &supportedTypes)
{
- if (supportedTypes.size() == 1U) {
- auto it = RttiResourceTypeMap.find(supportedTypes[0]);
- if (it != RelResourceTypeMap.end()) {
- return it->second;
- }
+ // Build a list containing the expected type names
+ std::vector<std::string> expected;
+ for (const Rtti *supportedType : supportedTypes) {
+ expected.push_back(supportedType->name);
}
- return ResourceType::UNKNOWN;
+
+ // Log the actual error message
+ ctx.logger.error(
+ std::string("Expected the file \"") + resource.location +
+ std::string("\" to define one of the following internal types ") +
+ Utils::join(expected, ", ", "{", "}"));
}
-static ResourceType deduceResourceType(const std::string &rel,
- const RttiSet &supportedTypes,
- Logger &logger)
+/* Class ResourceManager */
+
+SourceId ResourceManager::allocateSourceId(const Resource &resource)
{
- ResourceType res;
+ // Increment the source id and make sure the values don't overflow
+ SourceId sourceId = nextSourceId++;
+ if (sourceId == InvalidSourceId) {
+ nextSourceId = InvalidSourceId;
+ throw OusiaException{"Internal resource handles depleted!"};
+ }
+
+ // Register the node and the resource with this id
+ locations[resource.getLocation()] = sourceId;
+ resources[sourceId] = resource;
+
+ return sourceId;
+}
- // Try to deduce the ResourceType from the "rel" attribute
- res = relToResourceType(rel, logger);
+void ResourceManager::storeNode(SourceId sourceId, Handle<Node> node)
+{
+ nodes[sourceId] = node->getUid();
+}
- // If this did not work, try to deduce the ResourceType from the
- // supportedTypes supplied by the Parser instance.
- if (res == ResourceType::UNKNOWN) {
- res = supportedTypesToResourceType(supportedTypes);
+void ResourceManager::purgeResource(SourceId sourceId)
+{
+ Resource res = getResource(sourceId);
+ if (res.isValid()) {
+ locations.erase(res.getLocation());
}
- if (res == ResourceType::UNKNOWN) {
- logger.note(
- "Ambigous resource type, consider specifying the \"rel\" "
- "attribute");
+ resources.erase(sourceId);
+ nodes.erase(sourceId);
+ lineNumberCache.erase(sourceId);
+}
+
+Rooted<Node> ResourceManager::parse(ParserContext &ctx, Resource &resource,
+ const std::string &mimetype,
+ const RttiSet &supportedTypes)
+{
+ // Try to deduce the mimetype of no mimetype was given
+ std::string mime = mimetype;
+ if (mime.empty()) {
+ mime = ctx.registry.getMimetypeForFilename(resource.getLocation());
+ if (mime.empty()) {
+ ctx.logger.error(std::string("Filename \"") + path +
+ std::string(
+ "\" has an unknown file extension. Explicitly "
+ "specify a mimetype."));
+ return nullptr;
+ }
}
- return res;
+
+ // Fetch a parser for the mimetype
+ const std::pair<Parser *, RttiSet> &parserDescr =
+ ctx.registry.getParserForMimetype(mime);
+ Parser *parser = parserDescr.first;
+
+ // Make sure a parser was found
+ if (!parser) {
+ ctx.logger.error(std::string("Cannot parse files of type \"") + mime +
+ std::string("\""));
+ return nullptr;
+ }
+
+ // Make sure the parser returns at least one of the supported types
+ if (!typeSetsIntersect(parserDescr.second, supportedTypes)) {
+ logUnsopportedType(ctx.logger, supportedTypes);
+ return nullptr;
+ }
+
+ // Allocate a new SourceId handle for this Resource
+ SourceId sourceId = allocateSourceId(resource);
+
+ // We can now try to parse the given file
+ Rooted<Node> node;
+ try {
+ CharReader reader(resource.stream(), sourceId);
+ node = parser->parse(reader, ctx);
+ if (node == nullptr) {
+ throw LoggableException{"Internal error: Parser returned null."};
+ }
+ } catch (LoggableException ex) {
+ // Remove all data associated with the allocated source id
+ purgeResource(sourceId);
+
+ // Log the exception and return nullptr
+ ctx.logger.log(ex);
+ return nullptr;
+ }
+
+ // Store the parsed node along with the sourceId
+ storeNode(sourceId, node);
+
+ // Return the parsed node
+ return node;
}
-/* Functions for reducing the set of supported types */
+SourceId ResourceManager::getSourceId(const std::string &location)
+{
+ auto it = locations.find(location);
+ if (it != locations.end()) {
+ return it->second;
+ }
+ return InvalidSourceId;
+}
-/**
- * Map mapping from relations (the "rel" attribute in includes) to the
- * corresponding RttiType
- */
-static const std::unordered_map<std::string, Rtti *> RelRttiTypeMap{
- {"document", &RttiTypes::DOCUMENT},
- {"domain", &RttiTypes::DOMAIN},
- {"typesystem", &RttiTypes::TYPESYSTEM}};
+SourceId ResourceManager::getSourceId(const Resource &resource)
+{
+ if (resource.isValid()) {
+ return getSourceId(resource.getLocation());
+ }
+ return InvalidSourceId;
+}
-static Rtti *relToRttiType(const std::string &rel)
+const Resource &ResourceManager::getResource(SourceId sourceId) const
{
- std::string s = Utils::toLowercase(rel);
- if (!s.empty()) {
- auto it = RelRttiTypeMap.find(s);
- if (it != RelRttiTypeMap.end()) {
- return it->second;
- }
+ auto it = resources.find(sourceId);
+ if (it != resourced.end()) {
+ return it->second;
}
- return &ResourceType::Node;
+ return NullResource;
}
-static RttiType shrinkSupportedTypes(const RttiSet &supportedTypes,
- const std::string &rel)
+Rooted<Node> ResourceManager::getNode(Manager &mgr, SourceId sourceId)
{
- RttiSet types;
- RttiType *type = relToRttiType(rel);
- for (RttiType *supportedType : supportedTypes) {
- if (supportedType->isa(type)) {
- types.insert(supportedType);
+ auto it = nodes.find(sourceId);
+ if (it != nodes.end()) {
+ Managed *managed = mgr.getManaged(sourceId);
+ if (managed != nullptr) {
+ return dynamic_cast<Node *>(managed);
+ } else {
+ purgeResource(sourceId);
}
}
- return types;
+ return nullptr;
}
-/* Class ResourceManager */
+Rooted<Node> ResourceManager::getNode(Manager &mgr, const std::string &location)
+{
+ return getNode(mgr, getSourceId(location));
+}
-Rooted<Node> ResourceManager::link(ParserContext &ctx, Resource &resource,
- const std::string &mimetype,
- const RttiSet &supportedTypes)
+Rooted<Node> ResourceManager::getNode(Manager &mgr, const Resource &resource)
{
-
+ return getNode(mgr, getSourceId(resource));
}
Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path,
@@ -155,7 +212,7 @@ Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path,
{
// Try to deduce the ResourceType
ResourceType resourceType =
- deduceResourceType(rel, supportedTypes, ctx.logger);
+ ResourceUtils::deduceResourceType(rel, supportedTypes, ctx.logger);
// Lookup the resource for given path and resource type
Resource resource;
@@ -166,50 +223,27 @@ Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path,
}
// Try to shrink the set of supportedTypes
- RttiSet types = shrinkSupportedTypes(supportedTypes, rel);
+ RttiSet types = ResourceUtils::limitRttiTypes(supportedTypes, rel);
// Check whether the resource has already been parsed
- Rooted<Node> node = nullptr;
- auto it = locations.find(res.getLocation());
- if (it != locations.end()) {
- node =
- }
- = link(ctx, resource, mimetype, types);
+ Rooted<Node> node = getNode(ctx.manager, resource);
+ if (node == nullptr) {
+ // Node has not already been parsed, parse it now
+ node = parse(ctx, resource, mimetype, supportedTypes);
- // Try to deduce the mimetype
- std::string mime = mimetype;
- if (mime.empty()) {
- // Fetch the file extension
- std::string ext = Utils::extractFileExtension(path);
- if (ext.empty()) {
- ctx.logger.error(
- std::string("Specified filename \"") + path +
- std::string(
- "\" has no extension and no mimetype (\"type\" "
- "attribute) was given instead."));
- return nullptr;
- }
-
- // Fetch the mimetype for the extension
- mime = ctx.registry.getMimetypeForExtension(ext);
- if (mime.empty()) {
- ctx.logger.error(std::string("Unknown file extension \"") + ext +
- std::string("\""));
+ // Abort if parsing failed
+ if (node == nullptr) {
return nullptr;
}
}
- // Fetch a parser for the mimetype
- const std::pair<Parser *, RttiSet> parser =
- ctx.registry.getParserForMimetype(mime);
-
- // Make sure a parser was found
- if (!parser->first) {
- ctx.logger.error(std::string("Cannot parse files of type \"") + mime +
- std::string("\""));
+ // Make sure the node has one of the supported types
+ if (!node->type().isOneOf(supportedTypes)) {
+ logUnsopportedType(ctx.logger, supportedTypes);
+ return nullptr;
}
- // Make sure the parser returns one of the supported types
+ return node;
}
Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path,
@@ -229,14 +263,6 @@ Rooted<Node> ResourceManager::link(ParserContext &ctx, const std::string &path,
return include(ctx, path, mimetype, rel, supportedTypes, relativeResource);
}
-const Resource &getResource(SourceId sourceId) const
-{
- if (sourceId < resources.size()) {
- return resources[sourceId];
- }
- return NullResource;
-}
-
SourceContext ResourceManager::buildContext(const SourceLocation &location)
{
SourceContext res;
@@ -245,7 +271,7 @@ SourceContext ResourceManager::buildContext(const SourceLocation &location)
return res;
}
-};
+
}
#endif /* _OUSIA_RESOURCE_MANAGER_HPP_ */
diff --git a/src/core/resource/ResourceManager.hpp b/src/core/resource/ResourceManager.hpp
index 809fd55..05dcc8e 100644
--- a/src/core/resource/ResourceManager.hpp
+++ b/src/core/resource/ResourceManager.hpp
@@ -35,12 +35,13 @@
#include <core/common/Location.hpp>
#include <core/managed/Managed.hpp>
+#include "Resource.hpp"
+
namespace ousia {
// Forward declarations
class Node;
class ParserContext;
-class Resource;
class RttiSet;
extern const Resource NullResource;
@@ -52,19 +53,19 @@ extern const Resource NullResource;
class ResourceManager {
private:
/**
- * Vector used for mapping SourceId instances to the underlying resource.
+ * Next SourceId to be used.
*/
- std::vector<Resource> resources;
+ SourceId nextSourceId = 0;
/**
- * Index pointing at the next free entry in the resources list.
+ * Map between Resource locations and the corresponding SourceId.
*/
- SourceId nextFreeSourceId = 0;
+ std::unordered_map<std::string, SourceId> locations;
/**
- * Map between Resource locations and the corresponding SourceId.
+ * Map used for mapping SourceId instances to the underlying resource.
*/
- std::unordered_map<std::string, SourceId> locations;
+ std::unordered_map<SourceId, Resource> resources;
/**
* Map between a SourceId and the corresponding (if available) parsed node
@@ -79,22 +80,115 @@ private:
*/
std::unordered_map<SourceId, std::vector<SourceOffset>> lineNumberCache;
+ /**
+ * Allocates a new SourceId for the given resource.
+ *
+ * @param resource is the Resource that should be associated with the newly
+ * allocated SourceId.
+ * @return a new SourceId describing the given resource.
+ */
+ SourceId allocateSourceId(const Resource &resource);
- Rooted<Node> getCachedNode(SourceId id);
+ /**
+ * Registers the parsed node for this node id.
+ *
+ * @param sourceId is SourceId instance of the resource.
+ * @param node is the node that was parsed from that resource.
+ */
+ void storeNode(SourceId sourceId, Handle<Node> node);
- Rooted<Node> getCachedNode(const std::string &location);
+ /**
+ * Removes a resource from the internal stores.
+ *
+ * @param sourceId is the id of the file that should be removed.
+ */
+ void purgeResource(SourceId sourceId);
+ /**
+ * Used internally to parse the given resource.
+ *
+ * @param ctx is the context from the Registry and the Logger instance will
+ * be looked up.
+ * @param resource is the resource from which the input stream should be
+ * obtained.
+ * @param mimetype is the mimetype of the resource that should be parsed
+ * (may be empty, in which case the mimetype is deduced from the file
+ * extension)
+ * @param supportedTypes contains the types of the returned Node the caller
+ * can deal with. Note that only the types the parser claims to return are
+ * checked, not the actual result.
+ * @return the parsed node or nullptr if something goes wrong.
+ */
+ Rooted<Node> parse(ParserContext &ctx, Resource &resource,
+ const std::string &mimetype,
+ const RttiSet &supportedTypes);
+
+public:
+ /**
+ * Returns the sourceId for the given location string.
+ *
+ * @param location is the location string for which the resource id should
+ * be returned.
+ * @return the SourceId that can be used to identify the Resource, or
+ * InvalidSourceId if the specified location is not loaded.
+ */
SourceId getSourceId(const std::string &location);
/**
- * Used internally to either parse a resource or retrieve it from the
- * internal cache of already parsed resources.
+ * Returns the sourceId for the given Resource.
+ *
+ * @param resource is the Resource for which the sourceId should be
+ * returned.
+ * @return the SourceId that can be used to identify the Resource, or
+ * InvalidSourceId if the specified resource is not loaded or invalid.
*/
- Rooted<Node> link(ParserContext &ctx, Resource &resource, const std::string &mimetype,
- const RttiSet &supportedTypes);
+ SourceId getSourceId(const Resource &resource);
+ /**
+ * Returns a Resource instance for the given SourceId.
+ *
+ * @param sourceId is the id of the Resource instance that should be
+ * returned.
+ * @return the Resource instance corresponding to the given sourceId. If the
+ * sourceId is invalid, the returned Resource will be invalid (a reference
+ * at NullResource).
+ */
+ const Resource &getResource(SourceId sourceId) const;
+
+ /**
+ * Returns the node that is associated with the given SourceId or nullptr if
+ * the Node no longer exists or the supplied SourceId is invalid.
+ *
+ * @param mgr is the Manager instance that should be used to resolve the
+ * internal weak reference to the Node instance.
+ * @param sourceId is the id of the resource for which the parsed Node
+ * instance should be returned.
+ * @return the Node instance corresponding to the given sourceId.
+ */
+ Rooted<Node> getNode(Manager &mgr, SourceId sourceId);
+
+ /**
+ * Returns the node that is associated with the given location or nullptr if
+ * the Node no longer exists or the supplied location was never parsed.
+ *
+ * @param mgr is the Manager instance that should be used to resolve the
+ * internal weak reference to the Node instance.
+ * @param location is the location from which the node was parsed.
+ * @return the Node instance corresponding to the given location.
+ */
+ Rooted<Node> getNode(Manager &mgr, const std::string &location);
+
+ /**
+ * Returns the node that is associated with the given resource or nullptr if
+ * the Node no longer exists or the supplied resource was never parsed.
+ *
+ * @param mgr is the Manager instance that should be used to resolve the
+ * internal weak reference to the Node instance.
+ * @param resource is the resource from which the node was parsed.
+ * @return the Node instance corresponding to the given resource.
+ */
+ Rooted<Node> getNode(Manager &mgr, const Resource &resource);
-public:
/**
* Resolves the reference to the file specified by the given path and -- if
* this has not already happened -- parses the file. Logs any problem in
@@ -107,10 +201,10 @@ public:
* mimetype is given, the path must have an extension that is known by
*/
Rooted<Node> link(ParserContext &ctx, const std::string &path,
- const std::string &mimetype = "",
- const std::string &rel = "",
- const RttiSet &supportedTypes = RttiSet{},
- const Resource &relativeTo = NullResource);
+ const std::string &mimetype = "",
+ const std::string &rel = "",
+ const RttiSet &supportedTypes = RttiSet{},
+ const Resource &relativeTo = NullResource);
/**
* Resolves the reference to the file specified by the given path and -- if
@@ -118,19 +212,8 @@ public:
* the logger instance of the given ParserContext.
*/
Rooted<Node> link(ParserContext &ctx, const std::string &path,
- const std::string &mimetype, const std::string &rel,
- const RttiSet &supportedTypes, SourceId relativeTo);
-
- /**
- * Returns a Resource instance for the given SourceId.
- *
- * @param sourceId is the id of the Resource instance that should be
- * returned.
- * @return the Resource instance corresponding to the given sourceId. If the
- * sourceId is invalid, the returned Resource will be invalid (a reference
- * at NullResource).
- */
- const Resource &getResource(SourceId sourceId) const;
+ const std::string &mimetype, const std::string &rel,
+ const RttiSet &supportedTypes, SourceId relativeTo);
/**
* Creates and returns a SourceContext structure containing information
@@ -145,6 +228,7 @@ public:
* invalid SourceContext if the location is invalid.
*/
SourceContext buildContext(const SourceLocation &location);
+
};
}