001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.databind.model; 007 008import gov.nist.secauto.metaschema.core.metapath.StaticContext; 009import gov.nist.secauto.metaschema.core.model.AbstractModule; 010import gov.nist.secauto.metaschema.core.model.IBoundObject; 011import gov.nist.secauto.metaschema.core.model.ISource; 012import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; 013import gov.nist.secauto.metaschema.core.util.ObjectUtils; 014import gov.nist.secauto.metaschema.databind.IBindingContext; 015import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaModule; 016import gov.nist.secauto.metaschema.databind.model.annotations.NsBinding; 017 018import java.lang.reflect.Array; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.LinkedHashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.function.Function; 026import java.util.stream.Collectors; 027 028import edu.umd.cs.findbugs.annotations.NonNull; 029import nl.talsmasoftware.lazy4j.Lazy; 030 031public abstract class AbstractBoundModule 032 extends AbstractModule< 033 IBoundModule, 034 IBoundDefinitionModelComplex, 035 IBoundDefinitionFlag, 036 IBoundDefinitionModelField<?>, 037 IBoundDefinitionModelAssembly> 038 implements IBoundModule { 039 @NonNull 040 private final IBindingContext bindingContext; 041 @NonNull 042 private final Lazy<Map<Integer, IBoundDefinitionModelAssembly>> assemblyDefinitions; 043 @NonNull 044 private final Lazy<Map<Integer, IBoundDefinitionModelField<?>>> fieldDefinitions; 045 @NonNull 046 private final Lazy<StaticContext> staticContext; 047 @NonNull 048 private final ISource source; 049 050 /** 051 * Construct a new Module instance. 052 * 053 * @param importedModules 054 * Module imports associated with the Metaschema module 055 * @param bindingContext 056 * the Module binding context 057 */ 058 protected AbstractBoundModule( 059 @NonNull List<? extends IBoundModule> importedModules, 060 @NonNull IBindingContext bindingContext) { 061 super(importedModules); 062 this.bindingContext = bindingContext; 063 this.assemblyDefinitions = ObjectUtils.notNull(Lazy.lazy(() -> Arrays.stream(getAssemblyClasses()) 064 .map(clazz -> { 065 assert clazz != null; 066 return (IBoundDefinitionModelAssembly) ObjectUtils 067 .requireNonNull(bindingContext.getBoundDefinitionForClass(clazz)); 068 }) 069 .collect(Collectors.toUnmodifiableMap( 070 def -> def.getDefinitionQName().getIndexPosition(), 071 Function.identity())))); 072 this.fieldDefinitions = ObjectUtils.notNull(Lazy.lazy(() -> Arrays.stream(getFieldClasses()) 073 .map(clazz -> { 074 assert clazz != null; 075 return (IBoundDefinitionModelField<?>) ObjectUtils 076 .requireNonNull(bindingContext.getBoundDefinitionForClass(clazz)); 077 }) 078 .collect(Collectors.toUnmodifiableMap( 079 def -> def.getDefinitionQName().getIndexPosition(), 080 Function.identity())))); 081 this.staticContext = ObjectUtils.notNull(Lazy.lazy(() -> { 082 StaticContext.Builder builder = StaticContext.builder() 083 .defaultModelNamespace(getXmlNamespace()); 084 085 getNamespaceBindings() 086 .forEach( 087 (prefix, ns) -> builder.namespace( 088 ObjectUtils.requireNonNull(prefix), 089 ObjectUtils.requireNonNull(ns))); 090 return builder.build(); 091 })); 092 this.source = ISource.moduleSource(this); 093 } 094 095 @Override 096 public ISource getSource() { 097 return source; 098 } 099 100 @Override 101 public String getLocationHint() { 102 return ObjectUtils.notNull(getClass().getName()); 103 } 104 105 @Override 106 public StaticContext getModuleStaticContext() { 107 return ObjectUtils.notNull(staticContext.get()); 108 } 109 110 @Override 111 @NonNull 112 public IBindingContext getBindingContext() { 113 return bindingContext; 114 } 115 116 @Override 117 public Map<String, String> getNamespaceBindings() { 118 return ObjectUtils.notNull(Arrays.stream(getNsBindings()) 119 .collect(Collectors.toMap( 120 NsBinding::prefix, 121 NsBinding::uri, 122 (v1, v2) -> v2, 123 LinkedHashMap::new))); 124 } 125 126 @SuppressWarnings({ "null" }) 127 @NonNull 128 protected NsBinding[] getNsBindings() { 129 return getClass().isAnnotationPresent(MetaschemaModule.class) 130 ? getClass().getAnnotation(MetaschemaModule.class).nsBindings() 131 : (NsBinding[]) Array.newInstance(NsBinding.class, 0); 132 } 133 134 /** 135 * Get the assembly instance annotations associated with this bound choice 136 * group. 137 * 138 * @return the annotations 139 */ 140 @SuppressWarnings({ "null", "unchecked" }) 141 @NonNull 142 protected Class<? extends IBoundObject>[] getAssemblyClasses() { 143 return getClass().isAnnotationPresent(MetaschemaModule.class) 144 ? getClass().getAnnotation(MetaschemaModule.class).assemblies() 145 : (Class<? extends IBoundObject>[]) Array.newInstance(Class.class, 0); 146 } 147 148 /** 149 * Get the field instance annotations associated with this bound choice group. 150 * 151 * @return the annotations 152 */ 153 @SuppressWarnings({ "null", "unchecked" }) 154 @NonNull 155 protected Class<? extends IBoundObject>[] getFieldClasses() { 156 return getClass().isAnnotationPresent(MetaschemaModule.class) 157 ? getClass().getAnnotation(MetaschemaModule.class).fields() 158 : (Class<? extends IBoundObject>[]) Array.newInstance(Class.class, 0); 159 } 160 161 /** 162 * Get the mapping of assembly definition effective name to definition. 163 * 164 * @return the mapping 165 */ 166 protected Map<Integer, IBoundDefinitionModelAssembly> getAssemblyDefinitionMap() { 167 return assemblyDefinitions.get(); 168 } 169 170 @SuppressWarnings("null") 171 @Override 172 public Collection<IBoundDefinitionModelAssembly> getAssemblyDefinitions() { 173 return getAssemblyDefinitionMap().values(); 174 } 175 176 @Override 177 public IBoundDefinitionModelAssembly getAssemblyDefinitionByName(@NonNull Integer name) { 178 return getAssemblyDefinitionMap().get(name); 179 } 180 181 /** 182 * Get the mapping of field definition effective name to definition. 183 * 184 * @return the mapping 185 */ 186 protected Map<Integer, IBoundDefinitionModelField<?>> getFieldDefinitionMap() { 187 return fieldDefinitions.get(); 188 } 189 190 @SuppressWarnings("null") 191 @Override 192 public Collection<IBoundDefinitionModelField<?>> getFieldDefinitions() { 193 return getFieldDefinitionMap().values(); 194 } 195 196 @Override 197 public IBoundDefinitionModelField<?> getFieldDefinitionByName(@NonNull Integer name) { 198 return getFieldDefinitionMap().get(name); 199 } 200 201 @SuppressWarnings("null") 202 @Override 203 public Collection<IBoundDefinitionFlag> getFlagDefinitions() { 204 // Flags are always inline, so they do not have separate definitions 205 return Collections.emptyList(); 206 } 207 208 @Override 209 public IBoundDefinitionFlag getFlagDefinitionByName(@NonNull IEnhancedQName name) { 210 // Flags are always inline, so they do not have separate definitions 211 return null; 212 } 213}