
org.hcjf.layers.query.JoinableMap Maven / Gradle / Ivy
package org.hcjf.layers.query;
import com.google.gson.internal.LinkedTreeMap;
import org.hcjf.bson.BsonArray;
import org.hcjf.bson.BsonDocument;
import org.hcjf.utils.Strings;
import org.hcjf.utils.bson.BsonParcelable;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* This is a wrapper of map implementation wit the joinable implementation.
* @author javaito
*
*/
public class JoinableMap implements Joinable, Groupable, Enlarged, BsonParcelable, Map {
private static final String RESOURCES_FIELD = "__resources__";
private static final String MAP_INSTANCE_FIELD = "__map_instance__";
private static final String RESOURCE_FIELD_PATTERN = "%s.%s";
private final Set resources;
private final Map mapInstance;
private final Map> mapInstanceByResource;
private Set staticFields;
private boolean purged = false;
private Map staticFieldsMap;
public JoinableMap() {
this.resources = new TreeSet<>();
this.mapInstance = new LinkedTreeMap<>();
this.mapInstanceByResource = new LinkedHashMap<>();
this.staticFields = new LinkedHashSet<>();
this.staticFieldsMap = new HashMap<>();
}
public JoinableMap(String resourceName) {
this.resources = new TreeSet<>();
this.resources.add(resourceName);
this.mapInstance = new LinkedHashMap<>();
this.mapInstanceByResource = new LinkedHashMap<>();
this.mapInstanceByResource.put(resourceName, new HashMap<>());
}
public JoinableMap(Map mapInstance, String... fields) {
this.resources = new TreeSet<>();
this.mapInstance = new LinkedHashMap<>();
this.mapInstanceByResource = new LinkedHashMap<>();
if(fields != null && fields.length > 0) {
staticFields = new LinkedHashSet<>();
for(String field : fields) {
staticFields.add(field);
}
staticFieldsMap = new HashMap<>();
}
for(String key : mapInstance.keySet()) {
if(key.contains(Strings.CLASS_SEPARATOR)) {
resources.add(key.substring(0, key.lastIndexOf(Strings.CLASS_SEPARATOR)));
}
this.put(key, mapInstance.get(key));
}
}
/**
* Creates a bson document from the JoinableMap instance.
* @return Bson document instance.
*/
@Override
public BsonDocument toBson() {
purge();
BsonDocument bsonDocument = BsonParcelable.super.toBson();
bsonDocument.put(BsonParcelable.super.toBson(MAP_INSTANCE_FIELD, mapInstance));
bsonDocument.put(BsonParcelable.super.toBson(RESOURCES_FIELD, resources));
return bsonDocument;
}
/**
* This method populate the joinable map with the information into the bson document.
* @param document Bson document to populate the parcelable.
* @param Expected BsonParcelable data type.
* @return Returns the bson parcelable instance.
*/
@Override
public
P populate(BsonDocument document) {
BsonParcelable.super.populate(document);
BsonDocument bsonDocument = document.get(MAP_INSTANCE_FIELD).getAsDocument();
this.mapInstance.putAll(fromBson(String.class, Object.class, bsonDocument));
BsonArray bsonArray = document.get(RESOURCES_FIELD).getAsArray();
this.resources.addAll(fromBson(Object.class, bsonArray));
return (P) this;
}
/**
* This method remove all the fields that it's not static
*/
@Override
public void purge() {
if(staticFieldsMap != null) {
mapInstance.clear();
mapInstance.putAll(staticFieldsMap);
staticFieldsMap = null;
purged = true;
}
}
/**
* Clone the joinable map instance.
* @return Joinalbe map clone.
*/
@Override
public Enlarged clone(String... fields) {
JoinableMap result = new JoinableMap(new HashMap<>(), fields);
result.resources.addAll(resources);
result.mapInstance.putAll(mapInstance);
result.mapInstanceByResource.putAll(mapInstanceByResource);
return result;
}
/**
* Clone the joinable map without domain information.
* @return Joinable map clone.
*/
@Override
public Enlarged cloneEmpty() {
JoinableMap clone = new JoinableMap(this);
clone.clear();
return clone;
}
/**
* Return the value of the field name.
* @param fieldName Field name.
* @return Value of the field.
*/
@Override
public Object get(String fieldName) {
Object result = null;
if(!fieldName.contains(Strings.CLASS_SEPARATOR)) {
for(String resource : resources) {
result = mapInstance.get(String.join(Strings.CLASS_SEPARATOR, resource, fieldName));
if(result != null) {
break;
}
}
if(result == null) {
result = mapInstance.get(fieldName);
}
} else {
result = mapInstance.get(fieldName);
}
return result;
}
public void setResource(String resourceName) {
if(!containsResource(resourceName)) {
resources.add(resourceName);
mapInstanceByResource.put(resourceName, mapInstance);
}
}
/**
* Join the information stored into this instance of the joinable with the
* informacion stored into the joinable parameter.
* @param leftResource Name of the left resource of the join.
* @param rightResource Name of the right resource of the join.
* @param joinable Joinable parameter.
* @return Return this instance of the joinable.
* @throws IllegalArgumentException if the joinable parameter is not a JoinableMap instance.
* @throws NullPointerException if the joinable parameter is null.
*/
@Override
public Joinable join(String leftResource, String rightResource, Joinable joinable) {
if(joinable == null) {
throw new NullPointerException("Try to join with null joinable.");
}
if(!(joinable instanceof JoinableMap)) {
throw new IllegalArgumentException("Only support JoinableMap instance.");
}
JoinableMap result;
if(mapInstanceByResource.containsKey(leftResource)) {
result = new JoinableMap();
result.resources.addAll(resources);
result.mapInstance.putAll(mapInstance);
if(mapInstanceByResource.size() > 1) {
result.mapInstanceByResource.putAll(mapInstanceByResource);
} else {
result.mapInstanceByResource.put(leftResource, mapInstance);
}
} else {
result = new JoinableMap(leftResource);
result.mapInstance.putAll(mapInstance);
result.mapInstanceByResource.get(leftResource).putAll(mapInstance);
}
result.resources.add(rightResource);
result.mapInstanceByResource.put(rightResource, new HashMap<>());
result.mapInstanceByResource.get(rightResource).putAll(((JoinableMap)joinable));
for(Entry entry : ((JoinableMap)joinable).entrySet()) {
if(result.mapInstance.containsKey(entry.getKey())) {
result.mapInstance.put(String.format(RESOURCE_FIELD_PATTERN, rightResource, entry.getKey()), entry.getValue());
} else {
result.mapInstance.put(entry.getKey(), entry.getValue());
}
}
return result;
}
/**
* Verify if the joinable map instance contains a specific resource.
* @param resourceName Resource name
* @return Return true of the resource is present into the instance nad false in the otherwise.
*/
public boolean containsResource(String resourceName) {
return mapInstanceByResource.containsKey(resourceName);
}
/**
* Returns a part of the model that represents a specific resource.
* @param resourceName Resource name.
* @return Part of the model.
*/
public Map getResourceModel(String resourceName) {
return Collections.unmodifiableMap(mapInstanceByResource.get(resourceName));
}
/**
* Returns the set of resources.
* @return Set of resources.
*/
public Set getResources() {
return Collections.unmodifiableSet(resources);
}
@Override
public Groupable group(Groupable groupable) {
Object instanceValue;
Object groupableValue;
GroupableSet groupSet;
for(String key : groupable.keySet()) {
if(containsKey(key)) {
instanceValue = get(key);
groupableValue = groupable.get(key);
if(instanceValue instanceof GroupableSet) {
((GroupableSet)instanceValue).add(groupableValue);
} else if(!get(key).equals(groupable.get(key))) {
groupSet = new GroupableSet();
groupSet.add(instanceValue);
groupSet.add(groupableValue);
put(key, groupSet);
}
} else {
put(key, groupable.get(key));
}
}
return this;
}
/**
* Write all the elements of the map.
* @return Map print.
*/
@Override
public final String toString() {
Strings.Builder builder = new Strings.Builder();
builder.append(Strings.START_SUB_GROUP);
for(String key : mapInstance.keySet()) {
builder.append(key).append(Strings.ASSIGNATION);
builder.append(mapInstance.get(key), Strings.ARGUMENT_SEPARATOR, Strings.WHITE_SPACE);
}
return super.toString();
}
@Override
public int size() {
return mapInstance.size();
}
@Override
public boolean isEmpty() {
return mapInstance.isEmpty();
}
@Override
public boolean containsKey(Object key) {
boolean result = false;
String fieldName = (String) key;
if(!fieldName.contains(Strings.CLASS_SEPARATOR)) {
for(String resource : resources) {
result = mapInstance.containsKey(resource + Strings.CLASS_SEPARATOR + fieldName);
if(result) {
break;
}
}
if(!result) {
result = mapInstance.containsKey(fieldName);
}
} else {
result = mapInstance.containsKey(fieldName);
}
return result;
}
@Override
public boolean containsValue(Object value) {
return mapInstance.containsValue(value);
}
@Override
public Object get(Object key) {
return get(key.toString());
}
@Override
public Object put(String key, Object value) {
if(key.contains(Strings.CLASS_SEPARATOR)) {
resources.add(key.substring(0, key.lastIndexOf(Strings.CLASS_SEPARATOR)));
}
if(staticFields != null && staticFields.contains(key)) {
staticFieldsMap.put(key, value);
}
return mapInstance.put(key, value);
}
@Override
public Object remove(Object key) {
return mapInstance.remove(key);
}
@Override
public void putAll(Map extends String, ?> m) {
mapInstance.putAll(m);
}
@Override
public void clear() {
mapInstance.clear();
}
@Override
public Set keySet() {
return purged ? staticFields : mapInstance.keySet();
}
@Override
public Collection