From 47b0e6d6c48fca569163f52d0e7a16e26e45f9e2 Mon Sep 17 00:00:00 2001 From: ialbert Date: Tue, 1 Nov 2022 18:24:36 +0300 Subject: [PATCH] meta parsing --- clearing-parent/backend-api/pom.xml | 5 + .../backendapi/meta/ActionElement.java | 49 +++++ .../clearing/backendapi/meta/ActionField.java | 118 +++++++++++ ...ClearingMetaServerValidationException.java | 21 ++ .../backendapi/meta/FieldExtracted.java | 100 +++++++++ .../clearing/backendapi/meta/MetaBase.java | 49 +++++ .../meta/MetaDataTypeDeserializer.java | 20 ++ .../meta/MetaDataTypeSerializer.java | 15 ++ .../backendapi/meta/MetaDataTypes.java | 52 +++++ .../clearing/backendapi/meta/MetaServer.java | 191 ++++++++++++++++++ .../backendapi/meta/ObjectElement.java | 79 ++++++++ .../backendapi/meta/ObjectEnumElement.java | 63 ++++++ .../backendapi/meta/ObjectExtracted.java | 61 ++++++ .../OtcMetaServerGetterNotFoundException.java | 18 ++ .../clearing/backendapi/meta/RfHelper.java | 58 ++++++ .../backendapi/meta/Subscription.java | 38 ++++ 16 files changed, 937 insertions(+) create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionElement.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionField.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ClearingMetaServerValidationException.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/FieldExtracted.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaBase.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeDeserializer.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeSerializer.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypes.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaServer.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectElement.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectEnumElement.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectExtracted.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/OtcMetaServerGetterNotFoundException.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/RfHelper.java create mode 100644 clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/Subscription.java diff --git a/clearing-parent/backend-api/pom.xml b/clearing-parent/backend-api/pom.xml index ad0714978..974f8f46f 100644 --- a/clearing-parent/backend-api/pom.xml +++ b/clearing-parent/backend-api/pom.xml @@ -82,6 +82,11 @@ assertj-core test + + org.reflections + reflections + 0.9.11 + diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionElement.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionElement.java new file mode 100644 index 000000000..8fa0523be --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionElement.java @@ -0,0 +1,49 @@ +package ru.spcex.clearing.backendapi.meta; + + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings({"DefaultAnnotationParam", "unused"}) +public class ActionElement { + @JsonProperty(value = "class") + private String clazz = null; + + @JsonProperty(value = "name", required = true) + private String name = null; + + @JsonProperty(value = "destination", required = false) + private String destination = null; + + @JsonProperty(value = "array", required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Boolean isArray = null; + + // @JsonProperty(value = "fields", required = true) +// private List> fields = new LinkedList<>(); + @JsonProperty(value = "fields", required = true) + private List fields = new LinkedList<>(); + + public String getName() { + return name; + } + + public List getFields() { + return fields; + } + + public String getDestination() { + return destination; + } + + public String getClazz() { + return clazz; + } + + public Boolean getArray() { + return isArray; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionField.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionField.java new file mode 100644 index 000000000..b672c14cd --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ActionField.java @@ -0,0 +1,118 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import java.util.HashMap; +import java.util.Map; + +public class ActionField { + @JsonProperty(value = "code") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String code; + + @JsonProperty(value = "name") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String name; + + @JsonProperty(value = "shortname") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String shortname; + + @JsonProperty(value = "linkCode") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String linkcode; + + @JsonProperty(value = "link") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String link; + + @JsonProperty(value = "field") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String field; + + @JsonProperty(value = "length") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private Integer length; + + @JsonProperty(value = "required") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private Boolean required; + + @JsonProperty(value = "table") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private String table; + + @JsonProperty(value = "type") + @JsonDeserialize(using = MetaDataTypeDeserializer.class) + @JsonSerialize(using = MetaDataTypeSerializer.class, include = JsonSerialize.Inclusion.NON_EMPTY) + private MetaDataTypes type; + + @JsonProperty(value = "virtual") + @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY) + private Boolean virtual; + + @JsonIgnore + private Map additionalProperties = new HashMap<>(); + + public String getCode() { + return code; + } + + public String getField() { + return field; + } + + public Integer getLength() { + return length; + } + + public Boolean isRequired() { + return required; + } + + public MetaDataTypes getType() { + return type; + } + + public String getName() { + return name; + } + + public String getLink() { + return link; + } + + public String getShortname() { + return shortname; + } + + public String getLinkcode() { + return linkcode; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + public Boolean isVirtual(){ + return virtual; + } + public Boolean getVirtual() { + return virtual; + } + + public void setVirtual(Boolean virtual) { + this.virtual = virtual; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ClearingMetaServerValidationException.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ClearingMetaServerValidationException.java new file mode 100644 index 000000000..d55f219b3 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ClearingMetaServerValidationException.java @@ -0,0 +1,21 @@ +package ru.spcex.clearing.backendapi.meta; + + +import ru.clearing.classes.ConstSerializable; + +public class ClearingMetaServerValidationException extends RuntimeException { + private static final long serialVersionUID = ConstSerializable.serialVersionUID; + + public ClearingMetaServerValidationException(String s) { + super(s); + } + + public ClearingMetaServerValidationException(String s, Throwable throwable) { + super(s, throwable); + } + + public ClearingMetaServerValidationException(Throwable throwable) { + super(throwable); + } + +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/FieldExtracted.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/FieldExtracted.java new file mode 100644 index 000000000..033cded57 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/FieldExtracted.java @@ -0,0 +1,100 @@ +package ru.spcex.clearing.backendapi.meta; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public abstract class FieldExtracted { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private ActionField field; + private String memberName; + private Collection getterNames; + + public FieldExtracted(ActionField field) { + this.field = field; + this.memberName = field.getField() != null ? field.getField() : field.getCode(); + this.getterNames = gettersForField(this.memberName); + } + + public static Collection gettersForField(String fieldName) { + String[] fieldParts = fieldName.split("\\."); + List getters = new LinkedList<>(); + for (String partName : fieldParts) { + getters.add(String.format("%s%s%s", + RfHelper.GETTER_NAME_PREFIX, + partName.substring(0, 1).toUpperCase(), + partName.substring(1, partName.length()) + )); + } + return getters; + } + + @Override + public String toString() { + return String.format("%s (%s) (getters=%d)", field.getCode(), memberName, getterNames.size()); + } + + public abstract Object getObjectRef(Object o); + + public Object extractValue(Object from) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Object result = from; + for (String getterName : getGetterNames()) { + if (RfHelper.BUSINESS_OBJECT_REF.equals(result.getClass().getSimpleName()) && !RfHelper.GETTER_NAME_ID.equals(getterName)) { + Object resultNew = getObjectRef(result); + if (resultNew == null) { + log.warn("BusinessObject by referenceId does not exists!"); + break; + } + result = resultNew; + } + Method m = result.getClass().getMethod(getterName); + result = m.invoke(result); + if (result == null) + break; + } + + // тут нужно вернуть список id объектов а не список самих объектов для случая + // - add(r, "addresseeId", o.getAddressee() == null ? null : o.getAddressee().stream().map(OtcObjectBase::getId).collect(Collectors.toSet()), fieldFilter); + if (result instanceof Set && ((Set) result).size() > 0) { + try { + Set t = new HashSet(); + Class citem = (((Set) result).iterator().next()).getClass(); + for (Object item : (Set) result) { + t.add(citem.getMethod(RfHelper.GETTER_NAME_ID).invoke(item)); + } + result = t; + } catch (Throwable ignored) {// вернем сами объекты + } + } + return result; + } + + public ActionField getField() { + return field; + } + + public void setField(ActionField field) { + this.field = field; + } + + public void setMemberName(String memberName) { + this.memberName = memberName; + } + + public void setGetterNames(Collection getterNames) { + this.getterNames = getterNames; + } + + public String getMemberName() { + return memberName; + } + + public Collection getGetterNames() { + return getterNames; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaBase.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaBase.java new file mode 100644 index 000000000..641856800 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaBase.java @@ -0,0 +1,49 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.*; + +public class MetaBase { + + @JsonProperty(required = true, defaultValue = "unknown") + private String version = null; + + public String getVersion() { + return version; + } + + @JsonProperty(required = true) + private Map enums = new LinkedHashMap<>(); + + @JsonProperty(required = true) + private Map objects = new LinkedHashMap<>(); + + @JsonProperty(required = true) + private List> types = new LinkedList<>(); + + @JsonProperty + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map views = new HashMap<>(); + + public Map getEnums() { + return enums; + } + + public Map getObjects() { + return objects; + } + + public List> getTypes() { + return types; + } + + public Map getViews() { + return views; + } + + public void setViews(Map views) { + this.views = views; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeDeserializer.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeDeserializer.java new file mode 100644 index 000000000..8e2672f99 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeDeserializer.java @@ -0,0 +1,20 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import ru.spcex.platform.utils.enumeration.IEnumId; + +import java.io.IOException; + +public class MetaDataTypeDeserializer extends JsonDeserializer { + @Override + public MetaDataTypes deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + if (p.getText() != null && p.getText().length() > 0) { + if (!"0".equals(p.getText()) && !p.getText().matches("[1-9]+[0-9]*")) return null; + Long metaDataType = new Long(p.getText()); + return IEnumId.getEnumById(MetaDataTypes.class, metaDataType); + } else return null; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeSerializer.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeSerializer.java new file mode 100644 index 000000000..1115c8dce --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypeSerializer.java @@ -0,0 +1,15 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +public class MetaDataTypeSerializer extends JsonSerializer { + @Override + public void serialize(MetaDataTypes metaDataTypes, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeNumber(metaDataTypes.getId()); + } + +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypes.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypes.java new file mode 100644 index 000000000..2e8f6c5db --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaDataTypes.java @@ -0,0 +1,52 @@ +package ru.spcex.clearing.backendapi.meta; + +import ru.spcex.platform.utils.enumeration.IEnumId; + +public enum MetaDataTypes implements IEnumId { + Identity(1L), + String(2L), + Long(3L), + DateTime(4L), + Time(5L), + Date(6L), + Array(7L), + Object(8L), + Boolean(9L), + Double(10L), + UID(11L); + + private final Long id; + + MetaDataTypes(Long id) { + this.id = id; + } + + @Override + public java.lang.Long getId() { + return this.id; + } + + public int getTypeSize() { + switch (this) { + case Long: + return java.lang.String.valueOf(java.lang.Long.MAX_VALUE).length(); + case Identity: + return java.lang.String.valueOf(java.lang.Long.MAX_VALUE).length(); + case DateTime: + return 25; + case Time: + return 25; + case Date: + return 25; + case Array: + return java.lang.String.valueOf(java.lang.Long.MAX_VALUE).length() * 400; + case Boolean: + return java.lang.Boolean.TRUE.toString().length(); + case Double: + return 18; + case UID: + return 36; + } + return 0; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaServer.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaServer.java new file mode 100644 index 000000000..9dfb63789 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/MetaServer.java @@ -0,0 +1,191 @@ +package ru.spcex.clearing.backendapi.meta; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public abstract class MetaServer extends MetaBase { + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + private Collection objectsExtracted; + private Map objectsExtractedByClazz; + private Map objectsExtractedByDestination; + private Map actionObjectsExtracted; + private Map objectElementByDestination; + + protected abstract ObjectExtracted getImplInstanceObjectExtracted(String clazz, List actionFields); + + @SuppressWarnings("Duplicates") + public void initAndValidate() throws ClearingMetaServerValidationException, OtcMetaServerGetterNotFoundException { + if (objectsExtracted == null) { + objectsExtracted = new LinkedList<>(); + actionObjectsExtracted = new ConcurrentHashMap<>(); + objectsExtractedByClazz = new ConcurrentHashMap<>(); + objectsExtractedByDestination = new ConcurrentHashMap<>(); + objectElementByDestination = new ConcurrentHashMap<>(); + try { + Map objects = getObjects(); + log.info("Meta objects:\n{}", + objects.values() + .stream() + .map(ObjectElement::getName) + .collect(Collectors.joining(";", "[", "]"))); + for (String key : objects.keySet()) { + ObjectExtracted oe; + ObjectElement objectElement = objects.get(key); + if (objectElement.getSubscription() != null) { + objectElementByDestination.put(objectElement.getSubscription().destination, objectElement); + if (objectElement.getSubscriptionHistory() != null) { + objectElementByDestination.put(objectElement.getSubscriptionHistory().destination, objectElement); + } + } + try { + oe = getImplInstanceObjectExtracted(objectElement.getClazz(), objectElement.getFields()); + } catch (Throwable e) { + log.warn("META SERVER >>> Класс {} не найден!", objects.get(key).getClazz()); + continue; + } + objectsExtracted.add(oe); + objectsExtractedByClazz.put(oe.getClassName(), oe); + if (objectElement.getSubscription() != null && objectElement.getSubscription().destination != null) { + objectsExtractedByDestination.put(objectElement.getSubscription().destination, oe); + } + for (ActionElement actionElement : objectElement.getActions()) { + if (actionElement.getClazz() == null) { + continue; + } + + try { + oe = getImplInstanceObjectExtracted(actionElement.getClazz(), actionElement.getFields()); + if (actionElement.getArray() != null) { + oe.setArray(actionElement.getArray()); + } + } catch (Throwable e) { + log.warn("META SERVER >>> {}", e.getLocalizedMessage()); + continue; + } + actionObjectsExtracted.put(actionElement.getDestination(), oe); + } + } + } catch (Throwable e) { + throw new ClearingMetaServerValidationException(e.getLocalizedMessage()); + } + } + for (ObjectExtracted o : this.objectsExtracted) { + try { + if (!RfHelper.isAbstract(o.getClazz())) { + try { + Object instance = newInstance(o.getClassName()); + // создается успешно. + } catch (Throwable e) { + log.warn("META SERVER >>> Не удается создать класс {} !", o.getClassName()); + } + } + validateGetterForObject(o); + } catch (OtcMetaServerGetterNotFoundException e) { + throw e; + } catch (Throwable e) { + throw new ClearingMetaServerValidationException(e.getLocalizedMessage()); + } + } + + for (ObjectExtracted o : this.actionObjectsExtracted.values()) { + try { + if (!RfHelper.isAbstract(o.getClazz())) { + try { + Object instance = newInstance(o.getClassName()); + // создается успешно. + } catch (Throwable e) { + log.warn("META SERVER ACTION >>> Не удается создать класс {} !", o.getClassName()); + } + } + validateGetterForObject(o); + } catch (OtcMetaServerGetterNotFoundException e) { + throw e; + } catch (Throwable e) { + throw new ClearingMetaServerValidationException(e.getLocalizedMessage()); + } + } + + } + + /** + * проверим наличие геттеров к полям + * + * @param o + * @throws ClassNotFoundException + */ + private void validateGetterForObject(ObjectExtracted o) throws ClassNotFoundException { + for (FieldExtracted field : o.getFields()) { + Class c = o.getClazz(); + for (String getterName : field.getGetterNames()) { + try { + Method m = RfHelper.searchGetter(c, getterName); + if (m == null) { + for (Class sub : RfHelper.getSubclasses(c)) { + m = RfHelper.searchGetter(sub, getterName); + if (m != null) + break; + } + if (m == null) { + throw new OtcMetaServerGetterNotFoundException(c, getterName); + } + } + c = RfHelper.getMetodReturnClazz(m); + } catch (OtcMetaServerGetterNotFoundException e) { + log.warn("META SERVER >>> Геттер {}.{} не найден!", o.getClassName(), getterName); + } + } + } + } + + public Object newInstance(String className, Object... args) throws Exception { + Class clazz = Class.forName(className); + if (args == null || args.length == 0) { + return clazz.newInstance(); + } + + List> argTypes = new ArrayList>(); + for (Object object : args) { + argTypes.add(object.getClass()); + } + Constructor explicitConstructor = clazz.getConstructor(argTypes.toArray(new Class[argTypes.size()])); + return explicitConstructor.newInstance(args); + } + + public Collection getObjectsExtracted() { + return objectsExtracted; + } + + public Map getActionObjectsExtracted() { + return actionObjectsExtracted; + } + + public Map getObjectsExtractedByClazz() { + return objectsExtractedByClazz; + } + + public Map getObjectElementByDestination() { + return objectElementByDestination; + } + + public Map getObjectsExtractedByDestination() { + return objectsExtractedByDestination; + } + + public Integer getPartSizeValueByDestination(String destination) { + ObjectElement objectElementByDestination = getObjectElementByDestination().get(destination); + Integer partSize = null; + if (objectElementByDestination == null) { + log.warn("Null objectElement for destination: {}", destination); + } else { + partSize = objectElementByDestination.getSubscription().getPartSize(); + } + return partSize; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectElement.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectElement.java new file mode 100644 index 000000000..c554c5d29 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectElement.java @@ -0,0 +1,79 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.*; + +@SuppressWarnings({"DefaultAnnotationParam", "unused"}) +public class ObjectElement { + @JsonProperty(required = true) + private String name = null; + + @JsonProperty(value = "class", required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private String clazz = null; + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private String table = null; + + @JsonProperty(value = "fields", required = true) + private List fields = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map query = new LinkedHashMap<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Subscription subscription; + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Subscription subscriptionHistory; + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List actions = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List> values = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map views = new HashMap<>(); + + public String getName() { + return name; + } + + public String getClazz() { + return clazz; + } + + public Map getQuery() { + return query; + } + + public Subscription getSubscription() { + return subscription; + } + + public List getActions() { + return actions; + } + + public List> getValues() { + return values; + } + + public List getFields() { + return fields; + } + + public Subscription getSubscriptionHistory() { + return subscriptionHistory; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectEnumElement.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectEnumElement.java new file mode 100644 index 000000000..6132e39bb --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectEnumElement.java @@ -0,0 +1,63 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.*; + +@SuppressWarnings({"DefaultAnnotationParam", "unused"}) +public class ObjectEnumElement { + @JsonProperty(required = true) + private String name = null; + + @JsonProperty(value = "class", required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private String clazz = null; + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private String table = null; + + @JsonProperty(value = "fields", required = true) + private List fields = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map query = new LinkedHashMap<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List actions = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List> values = new LinkedList<>(); + + @JsonProperty(required = false) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map views = new HashMap<>(); + + public String getName() { + return name; + } + + public String getClazz() { + return clazz; + } + + public Map getQuery() { + return query; + } + + public List getActions() { + return actions; + } + + public List> getValues() { + return values; + } + + public List getFields() { + return fields; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectExtracted.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectExtracted.java new file mode 100644 index 000000000..5f75b9de5 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/ObjectExtracted.java @@ -0,0 +1,61 @@ +package ru.spcex.clearing.backendapi.meta; + + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class ObjectExtracted { + private String className; + private Class clazz; + private List fields = new LinkedList<>(); + private Map fieldByCode = new ConcurrentHashMap<>(); + private boolean isArray = false; + + + public ObjectExtracted(String clazz, List actionFields) { + this.className = clazz; + try { + this.clazz = Class.forName(this.className); + } catch (ClassNotFoundException e) { + throw new ClearingMetaServerValidationException(String.format("Class not found [%s]", this.className)); + } + for (ActionField field : actionFields) { + if (field.getVirtual() != null && field.isVirtual()){ + continue; + } + FieldExtracted fe = getImplFieldExtracted(field); + fields.add(fe); + fieldByCode.put(field.getCode(), fe); + } + } + + public abstract FieldExtracted getImplFieldExtracted(ActionField field); + @Override + public String toString() { + return String.format("%s (fields=%d)", className, fields.size()); + } + + public String getClassName() { + return className; + } + + public Class getClazz() { + return clazz; + } + + public List getFields() { + return new ArrayList<>(fields); + } + + public Map getFieldByCode() { + return new HashMap<>(fieldByCode); + } + + public boolean isArray() { + return isArray; + } + + public void setArray(boolean array) { + isArray = array; + } +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/OtcMetaServerGetterNotFoundException.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/OtcMetaServerGetterNotFoundException.java new file mode 100644 index 000000000..177f15db2 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/OtcMetaServerGetterNotFoundException.java @@ -0,0 +1,18 @@ +package ru.spcex.clearing.backendapi.meta; + + +import ru.clearing.classes.ConstSerializable; + +public class OtcMetaServerGetterNotFoundException extends RuntimeException { + private static final long serialVersionUID = ConstSerializable.serialVersionUID; + + public OtcMetaServerGetterNotFoundException(Class clazz, String getterName) { + super( + String.format( + "Method %s() not found for class %s and subclasses!", + getterName, clazz + ) + ); + } + +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/RfHelper.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/RfHelper.java new file mode 100644 index 000000000..099057f05 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/RfHelper.java @@ -0,0 +1,58 @@ +package ru.spcex.clearing.backendapi.meta; + +import org.reflections.Reflections; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class RfHelper { + + private static Map REFLECTION_CACHE = new HashMap<>(); + public static final String BUSINESS_OBJECT_REF = "BusinessObjectRef"; + public static final String OTC_CLASSES_PACKAGE = "com.moex.otc.classes"; + public static final String GETTER_NAME_PREFIX = "get"; + public static final String GETTER_NAME_ID = GETTER_NAME_PREFIX + "Id"; + + public static Method searchGetter(Class methodOwner, String name) { + for (Method m : methodOwner.getMethods()) { + if (m.getName().equals(name)) { + return m; + } + } + return null; + } + + public static Class[] getSubclasses(Class clazz) { + return getSubclasses(clazz, OTC_CLASSES_PACKAGE); + } + + public static Class[] getSubclasses(Class clazz, String packageName) { + Reflections reflections = REFLECTION_CACHE.computeIfAbsent(packageName, k -> new Reflections(packageName)); + Set> classes = reflections.getSubTypesOf(clazz); + return classes.toArray(new Class[]{}); + } + + public static boolean isAbstract(Class clazz) { + return Modifier.isAbstract(clazz.getModifiers()); + } + + public static Class getMetodReturnClazz(Method m) throws ClassNotFoundException { + Type t = m.getAnnotatedReturnType().getType(); + if (t instanceof ParameterizedType) { + Class raw = Class.forName(((ParameterizedType) t).getRawType().getTypeName()); + if (BUSINESS_OBJECT_REF.equals(raw.getSimpleName())) { + return Class.forName(((ParameterizedType) t).getActualTypeArguments()[0].getTypeName()); + } else if ("Set".equals(raw.getSimpleName())) { // множества пока не распаковываем + return Class.forName(raw.getName()); + } + } + return Class.forName(t.getTypeName()); + } + + +} diff --git a/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/Subscription.java b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/Subscription.java new file mode 100644 index 000000000..53f364041 --- /dev/null +++ b/clearing-parent/backend-api/src/main/java/ru/spcex/clearing/backendapi/meta/Subscription.java @@ -0,0 +1,38 @@ +package ru.spcex.clearing.backendapi.meta; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Subscription { + @JsonProperty + public String destination; + + @JsonProperty + public boolean enabled; + + @JsonProperty(value = "partSize") + private Integer partSize; + + public String getDestination() { + return destination; + } + + public void setDestination(String destination) { + this.destination = destination; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Integer getPartSize() { + return partSize; + } + + public void setPartSize(Integer partSize) { + this.partSize = partSize; + } +}