blob: 95f498289c89878d8adb21951238e6bc7afe3458 [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.
*/
#pragma once
#include "minifi-cpp/Exception.h"
#include "utils/file/AssetManager.h"
namespace org::apache::nifi::minifi::core {
using IdResolver = std::function<std::optional<std::string>(std::string_view /* category */, std::string_view /* value */)>;
class MalformedReferenceException : public Exception {
public:
explicit MalformedReferenceException(const std::string &message) : Exception(ExceptionType::FLOW_EXCEPTION, message) {}
explicit MalformedReferenceException(const char *message) : Exception(ExceptionType::FLOW_EXCEPTION, message) {}
};
class UnknownCategoryException : public Exception {
public:
explicit UnknownCategoryException(const std::string &message) : Exception(ExceptionType::FLOW_EXCEPTION, message) {}
explicit UnknownCategoryException(const char *message) : Exception(ExceptionType::FLOW_EXCEPTION, message) {}
};
std::string resolveIdentifier(std::string_view str, std::vector<IdResolver> resolvers) {
std::string result;
enum class ParseState {
OutsideToken,
InAtMark,
InToken,
InId
} state{ParseState::OutsideToken};
std::string category;
std::string id;
for (size_t offset = 0; offset < str.length(); ++offset) {
if (state == ParseState::OutsideToken) {
if (str[offset] == '@') {
state = ParseState::InAtMark;
continue;
}
result += str[offset];
} else if (state == ParseState::InAtMark) {
if (str[offset] == '@') {
result += '@';
state = ParseState::OutsideToken;
continue;
}
if (str[offset] == '{') {
state = ParseState::InToken;
category.clear();
id.clear();
continue;
}
throw MalformedReferenceException(fmt::format("Malformed reference at {} in '{}'", offset, str));
} else if (state == ParseState::InToken) {
if (str[offset] == ':') {
state = ParseState::InId;
continue;
}
category += str[offset];
} else if (state == ParseState::InId) {
if (str[offset] == '}') {
std::optional <std::string> replacement;
for (auto &resolver: resolvers) {
replacement = resolver(category, id);
if (replacement) {
break;
}
}
if (!replacement) {
throw UnknownCategoryException(fmt::format("Could not resolve '{}' in category '{}'", id, category));
}
result += replacement.value();
state = ParseState::OutsideToken;
continue;
}
id += str[offset];
}
}
if (state != ParseState::OutsideToken) {
throw MalformedReferenceException(fmt::format("Found invalid asset reference expression in '{}'", str));
}
return result;
}
class AssetException : public Exception {
public:
explicit AssetException(const std::string &message) : Exception(ExceptionType::ASSET_EXCEPTION, message) {}
explicit AssetException(const char *message) : Exception(ExceptionType::ASSET_EXCEPTION, message) {}
};
IdResolver getAssetResolver(std::function<std::optional<std::filesystem::path>(std::string_view)> find_asset) {
return [find_asset] (std::string_view category, std::string_view id) -> std::optional<std::string> {
if (category != "asset-id") {
return std::nullopt;
}
if (!find_asset) {
throw AssetException(fmt::format("Asset manager is not available, asset path resolution of '{}' is not supported", id));
}
auto path = find_asset(id);
if (!path) {
throw AssetException(fmt::format("Failed to find asset @{{asset-id:{}}}", id));
}
return path.value().string();
};
}
IdResolver getAssetResolver(utils::file::AssetManager* asset_manager) {
if (!asset_manager) {
return getAssetResolver(std::function<std::optional<std::filesystem::path>(std::string_view)>{nullptr});
}
return getAssetResolver([asset_manager] (std::string_view id) {
return asset_manager->findAssetById(id);
});
}
} // namespace org::apache::nifi::minifi::core