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.
com.memority.citadel.shared.api.im.ApiObject Maven / Gradle / Ivy
Go to download
This artifact provides the API classes that are necessary to implement general configuration Rules on the Memority IM platform.
/*
* Copyright (c) 2016-2023 Memority. All Rights Reserved.
*
* This file is part of Memority Citadel API , a Memority project.
*
* This file is released under the Memority Public Artifacts End-User License Agreement,
* see
* Unauthorized copying of this file, via any medium is strictly prohibited.
*/
package com.memority.citadel.shared.api.im;
import org.apache.commons.lang3.Validate;
import com.memority.toolkit.core.api.groovy.ReadWriteMapLikeGroovyObject;
import com.memority.toolkit.core.api.changetracking.ChangeTracking;
import com.memority.toolkit.core.api.changetracking.ChangeTrackingList;
import com.memority.toolkit.core.api.changetracking.ChangeTrackingMap;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Collections.emptyList;
/**
* Managed object representation suitable for Groovy scripts (rules, actions,...).
* All managed objects exposed in Groovy scripts are represented as ApiObjects.
*/
public class ApiObject implements ReadWriteMapLikeGroovyObject, ChangeTracking, HasMutableValues {
private final String KEY_KIND = BuiltinAttributeIds.KIND;
private final String KEY_TYPE = BuiltinAttributeIds.TYPE;
private final String KEY_ID = BuiltinAttributeIds.ID;
private final ChangeTrackingMap map;
public ApiObject() {
this.map = new ChangeTrackingMap<>();
}
public ApiObject(List> attributeValues) {
this.map = new ChangeTrackingMap<>();
this.init(attributeValues);
}
private ApiObject(ChangeTrackingMap map) {
this.map = map;
}
@Override
public boolean hasChanged() {
return Stream.concat(Stream.of(this.map), this.map.values().stream())
.filter(o -> o instanceof ChangeTracking)
.anyMatch(o -> ((ChangeTracking) o).hasChanged());
}
@Override
public void resetChanged() {
Stream.concat(Stream.of(this.map), Stream.of(this.map.values()))
.filter(o -> o instanceof ChangeTracking)
.forEach(o -> ((ChangeTracking) o).resetChanged());
}
public ApiObject(ObjectKind objectKind, String objectType, List> attributeValues) {
this(attributeValues);
this.setKind(objectKind);
this.setType(objectType);
}
public ApiObject(ObjectKind objectKind, String objectType) {
this(objectKind, objectType, emptyList());
}
private void init(List> attributeValues) {
for (AttributeValue> attributeValue:attributeValues) {
if (attributeValue.isMultiValued()) {
this.map.put(attributeValue.getId(), new AttributeChangeTrackingList(attributeValue.getValues(), attributeValue.getOrigin()));
} else {
if (attributeValue.hasValue()) {
this.map.put(attributeValue.getId(), new AttributeChangeTrackingValue(attributeValue.getValue(), attributeValue.getOrigin()));
} else {
this.map.put(attributeValue.getId(), new AttributeChangeTrackingValue(null, attributeValue.getOrigin()));
}
}
}
this.resetChanged();
}
public List> attributeValues() {
return this.map.entrySet().stream()
.map(e -> this.attributeValue(e.getKey(), e.getValue()))
.collect(Collectors.toList());
}
public AttributeValue> attributeValue(String id) {
return attributeValue(id, this.map.get(id));
}
public Map> attributeValueMap() {
return map.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> this.attributeValue(e.getKey(), e.getValue())));
}
private AttributeValue> attributeValue(String id, AttributeWrapper wrapper) {
if (wrapper == null) {
return AttributeValue.from(id, null);
}
AttributeValue> val = AttributeValue.from(id, wrapper.unwrap());
val.setOrigin(wrapper.getAttributeOrigin());
return val;
}
public ObjectKind getKind() {
return (ObjectKind) getProperty(KEY_KIND);
}
public ApiObject setKind(ObjectKind kind) {
this.map.put(KEY_KIND, new AttributeChangeTrackingValue(kind, AttributeOrigin.SYSTEM));
return this;
}
public String getId() {
//noinspection RedundantClassCall
return String.class.cast(getProperty(KEY_ID));
}
public ApiObject setId(String id) {
this.map.put(KEY_ID, new AttributeChangeTrackingValue(id, AttributeOrigin.SYSTEM));
return this;
}
public String getType() {
//noinspection RedundantClassCall
return String.class.cast(getProperty(KEY_TYPE));
}
public ApiObject setType(String type) {
this.map.put(KEY_TYPE, new AttributeChangeTrackingValue(type, AttributeOrigin.SYSTEM));
return this;
}
@Override
public Object getProperty(String propertyName) {
AttributeWrapper wrapped = this.map.get(propertyName);
return wrapped == null ? null : wrapped.unwrap();
}
@Override
public void setProperty(String propertyName, Object newValue) {
if (newValue instanceof Iterable) {
AttributeChangeTrackingList values = new AttributeChangeTrackingList(AttributeOrigin.RULE);
((Iterable>) newValue).forEach(values::add); // will mark list as changed
this.map.put(propertyName, values);
} else {
this.map.put(propertyName, new AttributeChangeTrackingValue(newValue, AttributeOrigin.RULE));
}
}
/**
* Deprecated since {@link ApiObject} does not implement {@code Map} anymore,
* kept for backward compatibility.
*
* @param propertyName the attribute id
* @return the attribute value
*/
@Deprecated
public Object get(String propertyName) {
return getProperty(propertyName);
}
/**
* Deprecated since {@link ApiObject} does not implement {@code Map} anymore,
* kept for backward compatibility.
*
* @param propertyName the id of the attribute to set
* @param newValue the value to set
* @return the old attribute value
*/
@Deprecated
public Object put(String propertyName, Object newValue) {
Object oldValue = getProperty(propertyName);
setProperty(propertyName, newValue);
return oldValue;
}
@Override
public ApiObject immutable() {
return new ApiObject(this.map.immutable());
}
@Override
public List> values(String attributeId) {
if (! this.has(attributeId)) {
// No property by that name, initialize an empty list
setProperty(attributeId, Collections.emptyList());
}
Object value = getProperty(attributeId);
if (value instanceof List) {
return (List>) value;
} else {
// As per the HasValue interface, we should return a list anyway. However, this
// should not be expected to be mutable to change the attribute value
// so we return an unmodifiable list.
return Collections.singletonList(value);
}
}
@Override
public Object value(String attributeId) {
Object value = getProperty(attributeId);
if (value == null) {
return null;
} else if (value instanceof List) {
return ((List>) value).isEmpty() ? null : ((List>) value).get(0);
} else {
return value;
}
}
@Override
public boolean hasValue(String attributeId) {
return ! values(attributeId).isEmpty();
}
@Override
public boolean has(String attributeId) {
return this.map.containsKey(attributeId);
}
@Override
public Set names() {
return this.map.keySet();
}
@Override
public void setValue(String name, T newValue) {
setProperty(name, newValue);
}
@Override
public void setValues(String name, List newValues) {
Validate.notNull(newValues);
setProperty(name, newValues);
}
@Override
public boolean addValue(String name, T additionalValue, boolean distinct, boolean sorted) {
return addValues(name, Collections.singletonList(additionalValue), distinct, sorted);
}
@Override
@SuppressWarnings("unchecked")
public boolean addValues(String name, List additionalValues, boolean distinct, boolean sorted) {
List values = (List) values(name);
boolean changed = false;
for (T additionalValue:additionalValues) {
if (distinct && values.contains(additionalValue)) {
continue;
}
changed |= values.add(additionalValue);
}
if (sorted) {
values.sort((Comparator)Comparator.naturalOrder());
changed = true;
}
return changed;
}
@Override
public boolean removeValue(String name, T valueToRemove) {
return removeValues(name, Collections.singletonList(valueToRemove));
}
@Override
public boolean removeValues(String name, List valuesToRemove) {
Object val = getProperty(name);
if (val == null) {
return false;
} else if (val instanceof AttributeChangeTrackingList) {
return ((AttributeChangeTrackingList) val).removeAll(valuesToRemove);
} else {
if (valuesToRemove.contains(val)) {
setProperty(name, null);
return true;
} else {
return false;
}
}
}
@Override
public boolean remove(String name) {
// If no value, nothing to do
if (!this.map.containsKey(name)) {
return false;
}
// Get value and...
Object value = this.map.get(name);
// Value is null, won't do much with that
if (value == null) {
return false;
}
if (value instanceof List) {
@SuppressWarnings("rawtypes")
List list = (List) value;
boolean changed = !list.isEmpty();
list.clear();
return changed;
} else {
this.map.put(name, null);
return true;
}
}
@Override
public boolean delete(String name) {
return this.map.remove(name) != null;
}
interface AttributeWrapper {
AttributeOrigin getAttributeOrigin();
Object unwrap();
}
static class AttributeChangeTrackingList extends ChangeTrackingList implements AttributeWrapper {
private AttributeOrigin origin;
public AttributeChangeTrackingList(List> values, AttributeOrigin origin) {
this.origin = origin;
this.addAll(values);
this.resetChanged();
}
public AttributeChangeTrackingList(AttributeOrigin origin) {
this.origin = origin;
}
protected AttributeChangeTrackingList(List delegate) {
super(delegate);
}
@Override
public AttributeOrigin getAttributeOrigin() {
return hasChanged() ? AttributeOrigin.RULE : origin;
}
@Override
public Object unwrap() {
return this;
}
@Override
public ChangeTrackingList immutable() {
AttributeChangeTrackingList immutable = new AttributeChangeTrackingList(Collections.unmodifiableList(this.delegate));
immutable.origin = this.origin;
return immutable;
}
}
static class AttributeChangeTrackingValue implements AttributeWrapper {
private final AttributeOrigin origin;
private final Object value;
public AttributeChangeTrackingValue(Object value, AttributeOrigin origin) {
this.origin = origin;
this.value = value;
}
@Override
public AttributeOrigin getAttributeOrigin() {
return this.origin;
}
@Override
public Object unwrap() {
return this.value;
}
}
}