2525import  java .util .HashMap ;
2626import  java .util .HashSet ;
2727import  java .util .Map ;
28- import  java .util .Optional ;
2928import  java .util .Set ;
30- import  java .util .function .Predicate ;
3129import  java .util .stream .Collectors ;
3230
3331import  org .slf4j .Logger ;
3432import  org .slf4j .LoggerFactory ;
3533import  org .spdx .jacksonstore .MultiFormatStore ;
3634import  org .spdx .jacksonstore .MultiFormatStore .Format ;
3735import  org .spdx .library .InvalidSPDXAnalysisException ;
38- import  org .spdx .library .model .Relationship ;
3936import  org .spdx .library .model .SpdxPackage ;
37+ import  org .spdx .library .model .enumerations .RelationshipType ;
4038import  org .spdx .storage .simple .InMemSpdxStore ;
4139
4240import  com .redhat .exhort .api .PackageRef ;
43- import  com .redhat .exhort .integration .Constants ;
4441import  com .redhat .exhort .integration .backend .sbom .SbomParser ;
4542import  com .redhat .exhort .model .DependencyTree ;
4643import  com .redhat .exhort .model .DirectDependency ;
@@ -57,16 +54,7 @@ protected DependencyTree buildTree(InputStream input) {
5754    try  {
5855      MultiFormatStore  inputStore  = new  MultiFormatStore (new  InMemSpdxStore (), Format .JSON_PRETTY );
5956      SpdxWrapper  wrapper  = new  SpdxWrapper (inputStore , input );
60-       PackageRef  root  = wrapper .getRootRef ();
6157      Map <PackageRef , DirectDependency > deps  = buildDeps (wrapper );
62-       if  (root  == null ) {
63-         Optional <PackageRef > first  = deps .keySet ().stream ().findFirst ();
64-         if  (first .isEmpty ()) {
65-           root  = DependencyTree .getDefaultRoot (Constants .MAVEN_PKG_MANAGER );
66-         } else  {
67-           root  = DependencyTree .getDefaultRoot (first .get ().purl ().getType ());
68-         }
69-       }
7058      DependencyTree  tree  = new  DependencyTree (deps );
7159      return  tree ;
7260    } catch  (SpdxProcessingException  | InvalidSPDXAnalysisException  | IOException  e ) {
@@ -80,21 +68,8 @@ protected DependencyTree buildTree(InputStream input) {
8068  private  Map <PackageRef , DirectDependency > buildDeps (SpdxWrapper  wrapper ) {
8169    Collection <SpdxPackage > packages  = wrapper .getPackages ();
8270    Map <String , Set <String >> links  = new  HashMap <>();
83-     packages .stream ()
84-         .filter (Predicate .not (wrapper ::hasRootName ))
85-         .forEach (
86-             p  -> {
87-               try  {
88-                 String  id  = p .getId ();
89-                 Set <String > rels  =
90-                     p .getRelationships ().stream ()
91-                         .map (this ::getRelationshipId )
92-                         .collect (Collectors .toSet ());
93-                 links .put (id , rels );
94-               } catch  (InvalidSPDXAnalysisException  e ) {
95-                 throw  new  SpdxProcessingException ("Unable to retrieve relationsips" , e );
96-               }
97-             });
71+     packages .stream ().forEach (p  -> createPackageLinks (p , packages , links ));
72+ 
9873    Set <String > directDeps  =
9974        links .keySet ().stream ()
10075            .filter (
@@ -131,6 +106,94 @@ private Map<PackageRef, DirectDependency> buildDeps(SpdxWrapper wrapper) {
131106    return  deps ;
132107  }
133108
109+   private  void  createPackageLinks (
110+       SpdxPackage  p , Collection <SpdxPackage > packages , Map <String , Set <String >> links ) {
111+     try  {
112+       String  pkgId  = p .getId ();
113+       if  (packages .stream ().noneMatch (pkg  -> pkg .getId ().equals (pkgId ))) {
114+         return ;
115+       }
116+       if  (p .getRelationships () == null  || p .getRelationships ().isEmpty ()) {
117+         addLink (links , pkgId , null );
118+       }
119+       p .getRelationships ().stream ()
120+           .forEach (
121+               rel  -> {
122+                 try  {
123+                   String  relatedId ;
124+                   if  (rel .getRelatedSpdxElement ().isPresent ()) {
125+                     relatedId  = rel .getRelatedSpdxElement ().get ().getId ();
126+                   } else  {
127+                     relatedId  = null ;
128+                   }
129+                   boolean  shouldIndexRelated  =
130+                       packages .stream ().anyMatch (pkg  -> pkg .getId ().equals (relatedId ));
131+ 
132+                   switch  (RelationshipDirection .fromRelationshipType (rel .getRelationshipType ())) {
133+                     case  FORWARD :
134+                       if  (shouldIndexRelated ) {
135+                         addLink (links , pkgId , relatedId );
136+                       } else  {
137+                         addLink (links , pkgId , null );
138+                       }
139+                       break ;
140+                     case  BACKWARDS :
141+                       if  (shouldIndexRelated ) {
142+                         addLink (links , relatedId , pkgId );
143+                       }
144+                       break ;
145+                     case  IGNORED :
146+                   }
147+                 } catch  (InvalidSPDXAnalysisException  e ) {
148+                   throw  new  SpdxProcessingException (
149+                       "Unable to determine relationship for "  + p .getId (), e );
150+                 }
151+               });
152+     } catch  (InvalidSPDXAnalysisException  e ) {
153+       throw  new  SpdxProcessingException ("Unable to build package relationships" , e );
154+     }
155+   }
156+ 
157+   private  enum  RelationshipDirection  {
158+     FORWARD ,
159+     BACKWARDS ,
160+     IGNORED ;
161+ 
162+     static  RelationshipDirection  fromRelationshipType (RelationshipType  type ) {
163+       switch  (type ) {
164+         case  DEPENDS_ON :
165+         case  CONTAINS :
166+         case  BUILD_DEPENDENCY_OF :
167+         case  OPTIONAL_COMPONENT_OF :
168+         case  OPTIONAL_DEPENDENCY_OF :
169+         case  PROVIDED_DEPENDENCY_OF :
170+         case  TEST_DEPENDENCY_OF :
171+         case  RUNTIME_DEPENDENCY_OF :
172+         case  DEV_DEPENDENCY_OF :
173+         case  ANCESTOR_OF :
174+           return  FORWARD ;
175+         case  DEPENDENCY_OF :
176+         case  DESCENDANT_OF :
177+         case  PACKAGE_OF :
178+         case  CONTAINED_BY :
179+           return  BACKWARDS ;
180+         default :
181+           return  IGNORED ;
182+       }
183+     }
184+   }
185+ 
186+   private  void  addLink (Map <String , Set <String >> links , String  fromId , String  toId ) {
187+     Set <String > toRefs  = links .get (fromId );
188+     if  (toRefs  == null ) {
189+       toRefs  = new  HashSet <>();
190+       links .put (fromId , toRefs );
191+     }
192+     if  (toId  != null ) {
193+       toRefs .add (toId );
194+     }
195+   }
196+ 
134197  private  Set <String > addAllTransitive (String  depKey , Map <String , Set <String >> links ) {
135198    Set <String > deps  = links .get (depKey );
136199    if  (deps  == null ) {
@@ -144,12 +207,4 @@ private Set<String> addAllTransitive(String depKey, Map<String, Set<String>> lin
144207            });
145208    return  result ;
146209  }
147- 
148-   private  String  getRelationshipId (Relationship  r ) {
149-     try  {
150-       return  r .getRelatedSpdxElement ().get ().getId ();
151-     } catch  (InvalidSPDXAnalysisException  e ) {
152-       throw  new  SpdxProcessingException ("Unable to retrieve related Spdx element" , e );
153-     }
154-   }
155210}
0 commit comments