All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
bt.bencoding.model.JUMModelBuilder Maven / Gradle / Ivy
Go to download
Library for parsing, encoding and validating bencoded documents in Java
package bt.bencoding.model;
import bt.bencoding.model.rule.ExclusiveRule;
import bt.bencoding.model.rule.RequiredRule;
import bt.bencoding.model.rule.Rule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static bt.bencoding.model.ClassUtil.cast;
import static bt.bencoding.model.ClassUtil.castList;
import static bt.bencoding.model.ClassUtil.read;
import static bt.bencoding.model.ClassUtil.readNotNull;
/**
* Builds an object model from a {@link java.util.Map}-based definition.
*
* @since 1.0
*/
public class JUMModelBuilder implements BEObjectModelBuilder {
private static final String TYPE_KEY = "type";
private static final String REQUIRED_KEY = "required";
private static final String EXCLUSIVES_KEY = "exclusives";
private static final String MAP_ENTRIES_KEY = "entries";
private static final String MAP_ENTRY_KEY_KEY = "key";
private static final String LIST_ELEMENTS_KEY = "elements";
// TODO: allow defining custom types in separate files and re-use
@Override
public BEObjectModel buildModel(Map map) {
// try reading custom object type and if it's not there resort to default types
return readObjectModel(map).orElseGet(() -> {
try {
String sourceType = readType(map);
switch (sourceType) {
case "dictionary": {
return buildMap(map);
}
case "list": {
return buildList(map);
}
case "binary": {
return new BEStringModel(true, Collections.emptyList());
}
case "string": {
return new BEStringModel(false, Collections.emptyList());
}
case "integer": {
return new BEIntegerModel(Collections.emptyList());
}
default: {
throw new IllegalArgumentException("Unsupported BE type: " + sourceType);
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to build BE model", e);
}
});
}
private Optional readObjectModel(Map map) {
try {
Object objectModel = read(map, Object.class, TYPE_KEY);
if (objectModel == null || !Map.class.isAssignableFrom(objectModel.getClass())) {
return Optional.empty();
} else {
return Optional.of(buildModel((Map) objectModel));
}
} catch (Exception e) {
throw new RuntimeException("Failed to read type", e);
}
}
private String readType(Map map) {
try {
return readNotNull(map, String.class, TYPE_KEY).toLowerCase();
} catch (Exception e) {
throw new RuntimeException("Failed to read type", e);
}
}
private BEObjectModel buildMap(Map map) throws Exception {
List entries = castList(Map.class, readNotNull(map, List.class, MAP_ENTRIES_KEY));
Map entriesModel = new HashMap<>(entries.size() + 1);
for (Map entry : entries) {
String key = readNotNull(entry, String.class, MAP_ENTRY_KEY_KEY);
entriesModel.put(key, buildModel(entry));
}
return new BEMapModel(entriesModel, buildMapValidation(map, entries));
}
private List buildMapValidation(Map map, List entries) throws Exception {
List rules = new ArrayList<>(2);
List required = entries.stream()
.filter(this::isRequired)
.map(entry -> {
try {
return readNotNull(entry, String.class, MAP_ENTRY_KEY_KEY);
} catch (Exception e) {
throw new RuntimeException("Unexpected error", e);
}
})
.collect(Collectors.toList());
@SuppressWarnings("unchecked")
List exclusives = (List) cast(List.class, EXCLUSIVES_KEY, map.get(EXCLUSIVES_KEY));
if (exclusives != null) {
Collection> exclusiveSets = exclusives.stream()
.map(item -> {
if (item instanceof String) {
return Collections.singleton((String) item);
} else {
try {
List strings = castList(String.class, cast(List.class, null, item));
return new HashSet<>(strings);
} catch (Exception e) {
throw new RuntimeException("Unexpected error", e);
}
}
})
.collect(Collectors.toList());
rules.add(new ExclusiveRule(exclusiveSets, required));
} else {
rules.add(new RequiredRule(required));
}
return rules.isEmpty()? Collections.emptyList() : rules;
}
private boolean isRequired(Map map) {
try {
return (map.get(REQUIRED_KEY) == null) ?
true : cast(Boolean.class, REQUIRED_KEY, map.get(REQUIRED_KEY));
} catch (Exception e) {
throw new RuntimeException("Failed to check if object is required", e);
}
}
private BEListModel buildList(Map map) throws Exception {
Map elements = readNotNull(map, Map.class, LIST_ELEMENTS_KEY);
BEObjectModel elementModel = buildModel(elements);
return new BEListModel(elementModel, Collections.emptyList());
}
@Override
public Class getSourceType() {
return Map.class;
}
}