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