/*
* RESTHeart - the Web API for MongoDB
* Copyright (C) SoftInstigate Srl
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.restheart.metadata.transformers;
import org.restheart.metadata.transformers.Transformer;
import io.undertow.server.HttpServerExchange;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonObjectId;
import org.bson.BsonValue;
import org.bson.types.ObjectId;
import org.restheart.handlers.RequestContext;
/**
*
* @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
*
* On REQUEST phase This transformer replaces strings that are valid ObjectIds
* with ObjectIds.
*
* <br>Example:
* <br>POST( { "_id": "553f59d2e4b041ceaac64e33", a:2 } -> { "_id": {"$oid":
* "553f59d2e4b041ceaac64e33" }, a: 1 }
*
*/
public class ValidOidsStringsAsOidsTransformer implements Transformer {
/**
*
* @param exchange
* @param context
* @param contentToTransform
* @param args names of properties to transform eventually (if value is valid
ObjectId) as an array of strings (["_id", "prop2"]
*/
@Override
public void transform(
final HttpServerExchange exchange,
final RequestContext context,
BsonValue contentToTransform,
final BsonValue args) {
if (contentToTransform == null) {
// nothing to do
return;
}
if (!contentToTransform.isDocument()) {
throw new IllegalStateException(
"content to transform is not a document");
}
BsonDocument _contentToTransform = contentToTransform.asDocument();
// this set contains the names of the properties to transform eventually
Set<String> propertiesToTransform = new HashSet<>();
if (args.isArray()) {
BsonArray _ids = args.asArray();
_ids.forEach(propertyName -> {
if (propertyName.isString()) {
propertiesToTransform.add(
propertyName
.asString()
.getValue());
} else {
context.addWarning("element in the args "
+ "list is not a string: " + propertyName);
}
});
} else {
context.addWarning("transformer wrong definition: "
+ "args property must be an arrary "
+ "of string (properties names).");
}
_transform(_contentToTransform, propertiesToTransform);
}
private void _transform(BsonDocument data, Set<String> propertiesNames) {
data.keySet().stream().forEach(key -> {
BsonValue value = data.get(key);
if (shouldTransform(key, propertiesNames)) {
if (value.isString()
&& ObjectId.isValid(value
.asString()
.getValue())) {
data.put(key,
new BsonObjectId(
new ObjectId(value
.asString()
.getValue())));
}
}
if (value instanceof BsonDocument) {
_transform(value.asDocument(), propertiesNames);
}
});
}
/**
* @param key the name of the property to transform (in case of patch can
* also use the dot notation)
* @param propertiesToTransform the set of properties names to transform if
their value is a valid ObjectId
* @return true if the property should be transformed
*/
private boolean shouldTransform(String key,
Set<String> propertiesToTransform) {
if (key.contains(".")) {
String keyTokens[] = key.split(Pattern.quote("."));
key = keyTokens[keyTokens.length - 1];
}
return propertiesToTransform.contains(key);
}
}