1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.databind.model.impl;
7   
8   import gov.nist.secauto.metaschema.core.model.IBoundObject;
9   import gov.nist.secauto.metaschema.core.model.ISource;
10  import gov.nist.secauto.metaschema.core.model.util.ModuleUtils;
11  import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
12  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
13  import gov.nist.secauto.metaschema.databind.IBindingContext;
14  import gov.nist.secauto.metaschema.databind.io.BindingException;
15  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
16  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceFlag;
17  import gov.nist.secauto.metaschema.databind.model.IBoundModule;
18  
19  import java.lang.annotation.Annotation;
20  import java.lang.reflect.Method;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  import edu.umd.cs.findbugs.annotations.Nullable;
24  import nl.talsmasoftware.lazy4j.Lazy;
25  
26  public abstract class AbstractBoundDefinitionModelComplex<A extends Annotation>
27      implements IBoundDefinitionModelComplex {
28    @NonNull
29    private final Class<? extends IBoundObject> clazz;
30    @NonNull
31    private final A annotation;
32    @NonNull
33    private final IBindingContext bindingContext;
34    @NonNull
35    private final IBoundModule module;
36    @NonNull
37    private final Lazy<IEnhancedQName> qname;
38    @NonNull
39    private final Lazy<IEnhancedQName> definitionQName;
40    @Nullable
41    private final Method beforeDeserializeMethod;
42    @Nullable
43    private final Method afterDeserializeMethod;
44  
45    protected AbstractBoundDefinitionModelComplex(
46        @NonNull Class<? extends IBoundObject> clazz,
47        @NonNull A annotation,
48        @NonNull IBoundModule module,
49        @NonNull IBindingContext bindingContext) {
50      this.clazz = clazz;
51      this.annotation = annotation;
52      this.bindingContext = bindingContext;
53      this.module = module;
54      this.qname = ObjectUtils.notNull(Lazy.lazy(() -> ModuleUtils.parseModelName(
55          getContainingModule(),
56          getEffectiveName())));
57      this.definitionQName = ObjectUtils.notNull(Lazy.lazy(() -> ModuleUtils.parseModelName(
58          getContainingModule(),
59          getName())));
60      this.beforeDeserializeMethod = ClassIntrospector.getMatchingMethod(
61          clazz,
62          "beforeDeserialize",
63          Object.class);
64      this.afterDeserializeMethod = ClassIntrospector.getMatchingMethod(
65          clazz,
66          "afterDeserialize",
67          Object.class);
68    }
69  
70    @Override
71    public Class<? extends IBoundObject> getBoundClass() {
72      return clazz;
73    }
74  
75    @NonNull
76    public A getAnnotation() {
77      return annotation;
78    }
79  
80    @Override
81    @NonNull
82    public IBoundModule getContainingModule() {
83      return module;
84    }
85  
86    @Override
87    public ISource getSource() {
88      return getContainingModule().getSource();
89    }
90  
91    @Override
92    @NonNull
93    public IBindingContext getBindingContext() {
94      return bindingContext;
95    }
96  
97    @SuppressWarnings("null")
98    @Override
99    public final IEnhancedQName getQName() {
100     return qname.get();
101   }
102 
103   @SuppressWarnings("null")
104   @Override
105   public final IEnhancedQName getDefinitionQName() {
106     return definitionQName.get();
107   }
108 
109   @Override
110   public Method getBeforeDeserializeMethod() {
111     return beforeDeserializeMethod;
112   }
113 
114   @Override
115   public Method getAfterDeserializeMethod() {
116     return afterDeserializeMethod;
117   }
118 
119   // @Override
120   // public String getJsonKeyFlagName() {
121   // // definition items never have a JSON key
122   // return null;
123   // }
124 
125   @Override
126   public IBoundObject deepCopyItem(IBoundObject item, IBoundObject parentInstance) throws BindingException {
127     IBoundObject instance = newInstance(item::getMetaschemaData);
128 
129     callBeforeDeserialize(instance, parentInstance);
130 
131     deepCopyItemInternal(item, instance);
132 
133     callAfterDeserialize(instance, parentInstance);
134 
135     return instance;
136   }
137 
138   protected void deepCopyItemInternal(@NonNull IBoundObject fromObject, @NonNull IBoundObject toObject)
139       throws BindingException {
140     for (IBoundInstanceFlag instance : getFlagInstances()) {
141       assert instance != null;
142 
143       instance.deepCopy(fromObject, toObject);
144     }
145   }
146 }