001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.core.metapath.item.node; 028 029import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; 030import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; 031import gov.nist.secauto.metaschema.core.model.IChoiceInstance; 032import gov.nist.secauto.metaschema.core.model.IFieldDefinition; 033import gov.nist.secauto.metaschema.core.model.IFieldInstance; 034import gov.nist.secauto.metaschema.core.model.IModelContainer; 035import gov.nist.secauto.metaschema.core.model.IModule; 036import gov.nist.secauto.metaschema.core.model.INamedModelInstance; 037import gov.nist.secauto.metaschema.core.util.ObjectUtils; 038 039import java.net.URI; 040import java.util.stream.Stream; 041 042import edu.umd.cs.findbugs.annotations.NonNull; 043import edu.umd.cs.findbugs.annotations.Nullable; 044 045public abstract class AbstractNodeItemFactory implements INodeItemFactory, INodeItemGenerator { 046 @Override 047 public IDocumentNodeItem newDocumentNodeItem( 048 IAssemblyDefinition definition, 049 URI documentUri, 050 Object value) { 051 return new DocumentNodeItemImpl( 052 definition, 053 value, 054 documentUri, 055 this); 056 } 057 058 @Override 059 public IModuleNodeItem newModuleNodeItem( 060 IModule module) { 061 return new ModuleNodeItemImpl( 062 module, 063 this); 064 } 065 066 @Override 067 public IFieldNodeItem newFieldNodeItem( 068 IFieldDefinition definition, 069 IModuleNodeItem module) { 070 return new FieldGlobalDefinitionNodeItemImpl( 071 definition, 072 module, 073 this); 074 } 075 076 @Override 077 public IFieldNodeItem newFieldNodeItem( 078 IFieldDefinition definition, 079 URI baseUri) { 080 return new FieldOrphanedDefinitionNodeItemImpl( 081 definition, 082 baseUri, 083 this); 084 } 085 086 @Override 087 public IFieldNodeItem newFieldNodeItem( 088 IFieldInstance instance, 089 IAssemblyNodeItem parent) { 090 return new FieldInstanceNoValueNodeItemImpl(instance, parent, this); 091 } 092 093 @Override 094 public IFieldNodeItem newFieldNodeItem( 095 IFieldInstance instance, 096 IAssemblyNodeItem parent, 097 int position, 098 Object value) { 099 return new FieldInstanceNodeItemImpl(instance, parent, position, value, this); 100 } 101 102 @Override 103 public IAssemblyNodeItem newAssemblyNodeItem( 104 IAssemblyDefinition definition, 105 IModuleNodeItem module) { 106 return new AssemblyGlobalDefinitionNodeItemImpl( 107 definition, 108 module, 109 this); 110 } 111 112 @Override 113 public IAssemblyNodeItem newAssemblyNodeItem( 114 IAssemblyDefinition definition, 115 URI baseUri) { 116 return new AssemblyOrphanedDefinitionNodeItemImpl( 117 definition, 118 baseUri, 119 this); 120 } 121 122 @Override 123 public IAssemblyNodeItem newAssemblyNodeItem( 124 IAssemblyDefinition definition, 125 URI baseUri, 126 Object value) { 127 return new AssemblyOrphanedDefinitionDataNodeItemImpl( 128 definition, 129 baseUri, 130 value, 131 this); 132 } 133 134 @Override 135 public IAssemblyNodeItem newAssemblyNodeItem( 136 IAssemblyInstance instance, 137 IAssemblyNodeItem parent) { 138 IAssemblyNodeItem retval = null; 139 if (!instance.getDefinition().isInline()) { 140 // if not inline, need to check for a cycle 141 IAssemblyNodeItem cycle = getCycledInstance(instance.getEffectiveName(), instance.getDefinition(), parent); 142 if (cycle != null) { 143 // generate a cycle wrapper of the original node item 144 retval = new CycledAssemblyInstanceNodeItemImpl(instance, parent, cycle); 145 } 146 } 147 148 if (retval == null) { 149 retval = new AssemblyInstanceNoValueNodeItemImpl(instance, parent, this); 150 } 151 return retval; 152 } 153 154 @Override 155 public IAssemblyNodeItem newAssemblyNodeItem( 156 IAssemblyInstance instance, 157 IAssemblyNodeItem parent, 158 int position, 159 Object value) { 160 return new AssemblyInstanceNodeItemImpl(instance, parent, position, value, this); 161 } 162 163 @Nullable 164 private IAssemblyNodeItem getCycledInstance( 165 @NonNull String effectiveName, 166 @NonNull IAssemblyDefinition definition, 167 @NonNull IAssemblyNodeItem parent) { 168 IAssemblyNodeItem retval = null; 169 170 IAssemblyDefinition parentDefinition = parent.getDefinition(); 171 if (parent.getName().equals(effectiveName) && parentDefinition.equals(definition)) { 172 retval = parent; 173 } else { 174 IAssemblyNodeItem ancestor = parent.getParentContentNodeItem(); 175 if (ancestor != null) { 176 retval = getCycledInstance(effectiveName, definition, ancestor); 177 } 178 } 179 return retval; 180 } 181 182 /** 183 * Create a new {@link IModelNodeItem} based on the provided {@code instance} 184 * that is a child of the provided {@code parent}. This new item will have the 185 * provided {@code value}. 186 * 187 * @param instance 188 * the model instance to create the node for 189 * @param parent 190 * the item to use as the parent item for the created node item 191 * @param position 192 * the data item's position in the sequence of data items for the 193 * instance 194 * @param value 195 * the data item's value 196 * @return the created node item 197 */ 198 @NonNull 199 protected IModelNodeItem<?, ?> newModelItem( 200 @NonNull INamedModelInstance instance, 201 @NonNull IAssemblyNodeItem parent, 202 int position, 203 @NonNull Object value) { 204 @NonNull IModelNodeItem<?, ?> item; 205 if (instance instanceof IAssemblyInstance) { 206 item = newAssemblyNodeItem((IAssemblyInstance) instance, parent, position, value); 207 } else if (instance instanceof IFieldInstance) { 208 item = newFieldNodeItem((IFieldInstance) instance, parent, position, value); 209 } else { 210 throw new UnsupportedOperationException("unsupported instance type: " + instance.getClass().getName()); 211 } 212 return item; 213 } 214 215 /** 216 * Create a new {@link IModelNodeItem} based on the provided {@code instance} 217 * that is a child of the provided {@code parent}. This new item will have no 218 * associated value. 219 * 220 * @param instance 221 * the model instance to create the node for 222 * @param parent 223 * the item to use as the parent item for the created node item 224 * @return the created node item 225 */ 226 @NonNull 227 protected IModelNodeItem<?, ?> newModelItem( 228 @NonNull INamedModelInstance instance, 229 @NonNull IAssemblyNodeItem parent) { 230 @NonNull IModelNodeItem<?, ?> item; 231 if (instance instanceof IAssemblyInstance) { 232 item = newAssemblyNodeItem((IAssemblyInstance) instance, parent); 233 } else if (instance instanceof IFieldInstance) { 234 item = newFieldNodeItem((IFieldInstance) instance, parent); 235 } else { 236 throw new UnsupportedOperationException("unsupported instance type: " + instance.getClass().getName()); 237 } 238 return item; 239 } 240 241 /** 242 * Get the descendant model instances of the provided {@code container}. 243 * 244 * @param container 245 * the container to get descendant instances for 246 * @return the stream of descendant instances 247 */ 248 @NonNull 249 protected Stream<INamedModelInstance> getNamedModelInstances(@NonNull IModelContainer container) { 250 return ObjectUtils.notNull(container.getModelInstances().stream() 251 .flatMap(instance -> { 252 Stream<INamedModelInstance> retval; 253 if (instance instanceof IAssemblyInstance || instance instanceof IFieldInstance) { 254 retval = Stream.of((INamedModelInstance) instance); 255 } else if (instance instanceof IChoiceInstance) { 256 // descend into the choice 257 retval = getNamedModelInstances((IChoiceInstance) instance); 258 } else { 259 throw new UnsupportedOperationException("unsupported instance type: " + instance.getClass().getName()); 260 } 261 return retval; 262 })); 263 } 264}