55 */
66package org .spdx .core ;
77
8+ import java .lang .reflect .Constructor ;
9+ import java .lang .reflect .InvocationTargetException ;
810import java .util .ArrayList ;
911import java .util .Collections ;
1012import java .util .HashMap ;
@@ -38,6 +40,7 @@ public class ModelRegistry {
3840 private static final ReadWriteLock lock = new ReentrantReadWriteLock ();
3941
4042 private final Map <String , ISpdxModelInfo > registeredModels = new HashMap <>();
43+ private final Map <String , Class <? extends CoreModelObject >> extensions = new HashMap <>();
4144
4245 /**
4346 * Private constructor - singleton class
@@ -184,13 +187,43 @@ public CoreModelObject inflateModelObject(IModelStore modelStore, String objectU
184187 if (!containsSpecVersion (specVersion )) {
185188 throw new ModelRegistryException (specVersion + DOES_NOT_EXIST_MSG );
186189 }
187- return registeredModels .get (specVersion ).createModelObject (modelStore , objectUri ,
188- type , copyManager , specVersion , create , idPrefix );
190+ if (extensions .containsKey (type )) {
191+ return inflateExtension (modelStore , objectUri , type , copyManager , specVersion , create , idPrefix );
192+ } else {
193+ return registeredModels .get (specVersion ).createModelObject (modelStore , objectUri ,
194+ type , copyManager , specVersion , create , idPrefix );
195+ }
189196 } finally {
190197 lock .readLock ().unlock ();
191198 }
192199 }
193200
201+ private CoreModelObject inflateExtension (IModelStore modelStore , String objectUri , String type ,
202+ IModelCopyManager copyManager , String specVersion ,
203+ boolean create , String idPrefix ) throws InvalidSPDXAnalysisException {
204+ try {
205+ Constructor <?> con = extensions .get (type ).getDeclaredConstructor (IModelStore .class , String .class ,
206+ IModelCopyManager .class , boolean .class , String .class , String .class );
207+ return (CoreModelObject )con .newInstance (modelStore , objectUri , copyManager , create , specVersion , idPrefix );
208+ } catch (NoSuchMethodException e ) {
209+ throw new InvalidSPDXAnalysisException ("Could not create the extension type: " +type );
210+ } catch (SecurityException e ) {
211+ throw new InvalidSPDXAnalysisException ("Unexpected security exception for extension type: " +type , e );
212+ } catch (InstantiationException e ) {
213+ throw new InvalidSPDXAnalysisException ("Unexpected instantiation exception for extension type: " +type , e );
214+ } catch (IllegalAccessException e ) {
215+ throw new InvalidSPDXAnalysisException ("Unexpected illegal access exception for extension type: " +type , e );
216+ } catch (IllegalArgumentException e ) {
217+ throw new InvalidSPDXAnalysisException ("Unexpected illegal argument exception for extension type: " +type , e );
218+ } catch (InvocationTargetException e ) {
219+ if (e .getTargetException () instanceof InvalidSPDXAnalysisException ) {
220+ throw (InvalidSPDXAnalysisException )e .getTargetException ();
221+ } else {
222+ throw new InvalidSPDXAnalysisException ("Unexpected invocation target exception for extension type: " +type , e );
223+ }
224+ }
225+ }
226+
194227 /**
195228 * @param type String representation of the SPDX type
196229 * @param specVersion version of the SPDX spec
@@ -205,7 +238,7 @@ public CoreModelObject inflateModelObject(IModelStore modelStore, String objectU
205238 if (!registeredModels .containsKey (specVersion )) {
206239 throw new ModelRegistryException ("No implementation found for SPDX spec version " +specVersion );
207240 }
208- return registeredModels .get (specVersion ).getTypeToClassMap ().get (type );
241+ return registeredModels .get (specVersion ).getTypeToClassMap ().getOrDefault ( type , extensions . get (type ) );
209242 } finally {
210243 lock .readLock ().unlock ();
211244 }
@@ -218,6 +251,7 @@ public void clearAll() {
218251 lock .writeLock ().lock ();
219252 try {
220253 registeredModels .clear ();
254+ extensions .clear ();;
221255 } finally {
222256 lock .writeLock ().unlock ();
223257 }
@@ -252,9 +286,30 @@ public boolean canBeExternal(Class<?> clazz, String specVersion) throws ModelReg
252286 if (!containsSpecVersion (specVersion )) {
253287 throw new ModelRegistryException (specVersion + DOES_NOT_EXIST_MSG );
254288 }
289+ if (extensions .containsValue (clazz )) {
290+ return false ;
291+ }
255292 return registeredModels .get (specVersion ).canBeExternal (clazz );
256293 } finally {
257294 lock .readLock ().unlock ();
258295 }
259296 }
297+
298+ /**
299+ * Registers an extension class that can be used to extend an SPDX model
300+ * @param type type to be used
301+ * @param clazz class which must be a subclass of ModelObject
302+ * @return the class which was added to the registry
303+ * @throws ModelRegistryException on missing model registry for the provided specVersion
304+ */
305+ public Class <?> registerExtensionType (String type , Class <? extends CoreModelObject > clazz ) throws ModelRegistryException {
306+ Objects .requireNonNull (clazz , "Class can not be null to register extension type" );
307+ Objects .requireNonNull (type , "Type can not be null to register extension type" );
308+ lock .writeLock ().lock ();
309+ try {
310+ return extensions .put (type , clazz );
311+ } finally {
312+ lock .writeLock ().unlock ();
313+ }
314+ }
260315}
0 commit comments