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