Skip to content

Commit 4210d72

Browse files
authored
Merge pull request #52 from spdx/sonarfixes
General maintenance - bug fixes and cleanup
2 parents a943db3 + f85328b commit 4210d72

34 files changed

+490
-284
lines changed

.github/workflows/build.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# This workflow will build a Java project with Maven
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3+
4+
name: Java CI with Maven
5+
6+
on:
7+
push:
8+
branches: [ master ]
9+
pull_request:
10+
branches: [ master ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
with:
20+
fetch-depth: 0
21+
- name: Set up JDK 11
22+
uses: actions/setup-java@v1
23+
with:
24+
java-version: 11
25+
- name: Cache SonarCloud packages
26+
uses: actions/cache@v1
27+
with:
28+
path: ~/.sonar/cache
29+
key: ${{ runner.os }}-sonar
30+
restore-keys: ${{ runner.os }}-sonar
31+
- name: Cache Maven packages
32+
uses: actions/cache@v1
33+
with:
34+
path: ~/.m2
35+
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
36+
restore-keys: ${{ runner.os }}-m2
37+
- name: Build and analyze
38+
env:
39+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
41+
run: mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar

.github/workflows/maven.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
Java library which implements the Java object model for SPDX and provides useful helper functions.
55

6+
# Code quality badges
7+
8+
| [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=java-spdx-library&metric=bugs)](https://sonarcloud.io/dashboard?id=java-spdx-library) | [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=java-spdx-library&metric=security_rating)](https://sonarcloud.io/dashboard?id=java-spdx-library) | [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=java-spdx-library&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=java-spdx-library) | [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=java-spdx-library&metric=sqale_index)](https://sonarcloud.io/dashboard?id=java-spdx-library) |
9+
610
## Storage Interface
711
The Spdx-Java-Library allows for different implementations of SPDX object storage. The storage facility implements the org.spdx.storage.IModelStore interface. This is a low level Service Provider Interface (SPI). The ISerializableModelStore extends the IModelStore and supports serializing and de-serializing the store to an I/O Stream. This interface is currently used to implement JSON, XML, YAML, and RDF/XML formats. The default storage interface is an in-memory Map which should be sufficient for light weight usage of the library.
812

pom.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>org.spdx</groupId>
66
<artifactId>java-spdx-library</artifactId>
7-
<version>1.0.5-SNAPSHOT</version>
7+
<version>1.0.6</version>
88
<packaging>jar</packaging>
99

1010
<name>java-spdx-library</name>
@@ -43,6 +43,9 @@
4343
</distributionManagement>
4444
<properties>
4545
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
46+
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
47+
<sonar.organization>spdx</sonar.organization>
48+
<sonar.projectKey>java-spdx-library</sonar.projectKey>
4649
</properties>
4750
<profiles>
4851
<profile>

src/main/java/org/spdx/library/ModelCopyManager.java

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class ModelCopyManager {
5858
* Create a ModelCopyManager with default options
5959
*/
6060
public ModelCopyManager() {
61-
61+
// Required empty constructor
6262
}
6363

6464
/**
@@ -153,48 +153,86 @@ public void copy(IModelStore toStore, String toDocumentUri, String toId, IModelS
153153
List<String> propertyNames = fromStore.getPropertyValueNames(fromDocumentUri, fromId);
154154
for (String propName:propertyNames) {
155155
if (fromStore.isCollectionProperty(fromDocumentUri, fromId, propName)) {
156-
Iterator<Object> fromListIter = fromStore.listValues(fromDocumentUri, fromId, propName);
157-
while (fromListIter.hasNext()) {
158-
Object listItem = fromListIter.next();
159-
Object toStoreItem;
160-
if (listItem instanceof IndividualUriValue) {
161-
toStoreItem = new SimpleUriValue((IndividualUriValue)listItem);
162-
} else if (listItem instanceof TypedValue) {
163-
TypedValue listItemTv = (TypedValue)listItem;
164-
if (toStore.equals(fromStore) && toDocumentUri.equals(fromDocumentUri)) {
165-
toStoreItem = listItemTv;
166-
} else {
167-
toStoreItem = copy(toStore, toDocumentUri, fromStore, fromDocumentUri,
168-
listItemTv.getId(), listItemTv.getType());
169-
}
170-
} else {
171-
toStoreItem = listItem;
172-
}
173-
toStore.addValueToCollection(toDocumentUri, toId, propName, toStoreItem);
174-
}
156+
copyCollectionProperty(toStore, toDocumentUri, toId, fromStore, fromDocumentUri, fromId, propName);
175157
} else {
176-
Optional<Object> result = fromStore.getValue(fromDocumentUri, fromId, propName);
177-
if (result.isPresent()) {
178-
if (result.get() instanceof IndividualUriValue) {
179-
toStore.setValue(toDocumentUri, toId, propName, new SimpleUriValue((IndividualUriValue)result.get()));
180-
} else if (result.get() instanceof TypedValue) {
181-
TypedValue tv = (TypedValue)result.get();
182-
if (fromStore.equals(toStore) && fromDocumentUri.equals(toDocumentUri)) {
183-
toStore.setValue(toDocumentUri, toId, propName, tv);
184-
} else {
185-
toStore.setValue(toDocumentUri, toId, propName,
186-
copy(toStore, toDocumentUri, fromStore, fromDocumentUri,
187-
tv.getId(), tv.getType()));
188-
}
189-
} else {
190-
toStore.setValue(toDocumentUri, toId, propName, result.get());
191-
}
192-
}
158+
copyIndividualProperty(toStore, toDocumentUri, toId, fromStore, fromDocumentUri, fromId, propName);
193159
}
194160
}
195161
}
196162

197163
/**
164+
* Copies an individual property value (non-collection property value)
165+
* @param toStore Model Store to copy to
166+
* @param toId Id to use in the copy
167+
* @param toDocumentUri Target document URI
168+
* @param fromStore Model Store containing the source item
169+
* @param fromDocumentUri Document URI for the source item
170+
* @param fromId ID source ID
171+
* @param propName Name of the property
172+
* @throws InvalidSPDXAnalysisException
173+
*/
174+
private void copyIndividualProperty(IModelStore toStore, String toDocumentUri, String toId, IModelStore fromStore,
175+
String fromDocumentUri, String fromId, String propName) throws InvalidSPDXAnalysisException {
176+
if (fromStore.isCollectionProperty(fromDocumentUri, fromId, propName)) {
177+
throw new InvalidSPDXAnalysisException("Property "+propName+" is a collection type");
178+
}
179+
Optional<Object> result = fromStore.getValue(fromDocumentUri, fromId, propName);
180+
if (result.isPresent()) {
181+
if (result.get() instanceof IndividualUriValue) {
182+
toStore.setValue(toDocumentUri, toId, propName, new SimpleUriValue((IndividualUriValue)result.get()));
183+
} else if (result.get() instanceof TypedValue) {
184+
TypedValue tv = (TypedValue)result.get();
185+
if (fromStore.equals(toStore) && fromDocumentUri.equals(toDocumentUri)) {
186+
toStore.setValue(toDocumentUri, toId, propName, tv);
187+
} else {
188+
toStore.setValue(toDocumentUri, toId, propName,
189+
copy(toStore, toDocumentUri, fromStore, fromDocumentUri,
190+
tv.getId(), tv.getType()));
191+
}
192+
} else {
193+
toStore.setValue(toDocumentUri, toId, propName, result.get());
194+
}
195+
}
196+
}
197+
198+
/**
199+
* Copies a property which is is a collection
200+
* @param toStore Model Store to copy to
201+
* @param toId Id to use in the copy
202+
* @param toDocumentUri Target document URI
203+
* @param fromStore Model Store containing the source item
204+
* @param fromDocumentUri Document URI for the source item
205+
* @param fromId ID source ID
206+
* @param propName Name of the property
207+
* @throws InvalidSPDXAnalysisException
208+
*/
209+
private void copyCollectionProperty(IModelStore toStore, String toDocumentUri, String toId, IModelStore fromStore,
210+
String fromDocumentUri, String fromId, String propName) throws InvalidSPDXAnalysisException {
211+
if (!fromStore.isCollectionProperty(fromDocumentUri, fromId, propName)) {
212+
throw new InvalidSPDXAnalysisException("Property "+propName+" is not a collection type");
213+
}
214+
Iterator<Object> fromListIter = fromStore.listValues(fromDocumentUri, fromId, propName);
215+
while (fromListIter.hasNext()) {
216+
Object listItem = fromListIter.next();
217+
Object toStoreItem;
218+
if (listItem instanceof IndividualUriValue) {
219+
toStoreItem = new SimpleUriValue((IndividualUriValue)listItem);
220+
} else if (listItem instanceof TypedValue) {
221+
TypedValue listItemTv = (TypedValue)listItem;
222+
if (toStore.equals(fromStore) && toDocumentUri.equals(fromDocumentUri)) {
223+
toStoreItem = listItemTv;
224+
} else {
225+
toStoreItem = copy(toStore, toDocumentUri, fromStore, fromDocumentUri,
226+
listItemTv.getId(), listItemTv.getType());
227+
}
228+
} else {
229+
toStoreItem = listItem;
230+
}
231+
toStore.addValueToCollection(toDocumentUri, toId, propName, toStoreItem);
232+
}
233+
}
234+
235+
/**
198236
* Copy an item from one Model Object Store to another using the source ID for the target unless it is anonymous
199237
* @param toStore Model Store to copy to
200238
* @param toDocumentUri Target document URI

src/main/java/org/spdx/library/SpdxConstants.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,14 @@ public class SpdxConstants {
360360

361361
// Download Location Format
362362
private static final String SUPPORTED_DOWNLOAD_REPOS = "(git|hg|svn|bzr)";
363-
private static final String URL_PATTERN = "(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/|ssh:\\/\\/|git:\\/\\/|svn:\\/\\/|sftp:\\/\\/|ftp:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)";
363+
private static final String URL_PATTERN = "(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/|ssh:\\/\\/|git:\\/\\/|svn:\\/\\/|sftp:\\/\\/|ftp:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+){0,100}\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)";
364364
private static final String GIT_PATTERN = "(git\\+git@[a-zA-Z0-9\\.]+:[a-zA-Z0-9]+)";
365365
private static final String BAZAAR_PATTERN = "(bzr\\+lp:[a-zA-Z0-9\\.]+)";
366366
public static final Pattern DOWNLOAD_LOCATION_PATTERN = Pattern.compile("^(NONE|NOASSERTION|(("+SUPPORTED_DOWNLOAD_REPOS+"\\+)?"+URL_PATTERN+")|"+GIT_PATTERN+"|"+BAZAAR_PATTERN+")$", Pattern.CASE_INSENSITIVE);
367367

368+
// License list version Format
369+
370+
public static final Pattern LICENSE_LIST_VERSION_PATTERN = Pattern.compile("^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+");
368371
// Standard value strings
369372
public static String NONE_VALUE = "NONE";
370373
public static String NOASSERTION_VALUE = "NOASSERTION";

src/main/java/org/spdx/library/model/ModelObject.java

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -711,56 +711,17 @@ public boolean equivalent(ModelObject compare, boolean ignoreRelatedElements) th
711711
continue;
712712
}
713713
if (comparePropertyValueNames.contains(propertyName)) {
714-
Optional<Object> myValue = this.getObjectPropertyValue(propertyName);
715-
Optional<Object> compareValue = compare.getObjectPropertyValue(propertyName);
716-
if (!myValue.isPresent()) {
717-
if (compareValue.isPresent()) {
718-
if (compareValue.get() instanceof ModelCollection) {
719-
if (((ModelCollection<?>)compareValue.get()).size() > 0) {
720-
return false;
721-
}
722-
} else {
723-
return false;
724-
}
725-
}
726-
} else if (!compareValue.isPresent()) {
727-
if (myValue.get() instanceof ModelCollection) {
728-
if (((ModelCollection<?>)myValue.get()).size() > 0) {
729-
return false;
730-
}
731-
} else {
732-
return false;
733-
}
734-
} else if (myValue.get() instanceof ModelCollection && compareValue.get() instanceof ModelCollection) {
735-
List<?> myList = ((ModelCollection<?>)myValue.get()).toImmutableList();
736-
List<?> compareList = ((ModelCollection<?>)compareValue.get()).toImmutableList();
737-
if (!listsEquivalent(myList, compareList, ignoreRelatedElements)) {
738-
return false;
739-
}
740-
} else if (myValue.get() instanceof List && compareValue.get() instanceof List) {
741-
if (!listsEquivalent((List<?>)myValue.get(), (List<?>)compareValue.get(), ignoreRelatedElements)) {
742-
return false;
743-
}
744-
} else if (myValue.get() instanceof IndividualUriValue && compareValue.get() instanceof IndividualUriValue) {
745-
if (!Objects.equals(((IndividualUriValue)myValue.get()).getIndividualURI(), ((IndividualUriValue)compareValue.get()).getIndividualURI())) {
746-
return false;
747-
}
748-
// Note: we must check the IndividualValue before the ModelObject types since the IndividualValue takes precedence
749-
} else if (myValue.get() instanceof ModelObject && compareValue.get() instanceof ModelObject) {
750-
if (!((ModelObject)myValue.get()).equivalent(((ModelObject)compareValue.get()),
751-
SpdxConstants.PROP_RELATED_SPDX_ELEMENT.equals(propertyName) ? true : ignoreRelatedElements)) {
752-
return false;
753-
}
754-
755-
} else if (!OptionalObjectsEquivalent(myValue, compareValue)) { // Present, not a list, and not a TypedValue
756-
return false;
714+
if (!propertyValuesEquivalent(propertyName, this.getObjectPropertyValue(propertyName),
715+
compare.getObjectPropertyValue(propertyName), ignoreRelatedElements)) {
716+
return false;
757717
}
758718
comparePropertyValueNames.remove(propertyName);
759719
} else {
760720
// No property value
761-
if (this.getObjectPropertyValue(propertyName).isPresent()) {
762-
if (this.getObjectPropertyValue(propertyName).get() instanceof ModelCollection) {
763-
if (((ModelCollection<?>)(this.getObjectPropertyValue(propertyName).get())).size() > 0) {
721+
Optional<Object> propertyValue = this.getObjectPropertyValue(propertyName);
722+
if (propertyValue.isPresent()) {
723+
if (propertyValue.get() instanceof ModelCollection) {
724+
if (((ModelCollection<?>)(propertyValue.get())).size() > 0) {
764725
return false;
765726
}
766727
} else {
@@ -778,6 +739,61 @@ public boolean equivalent(ModelObject compare, boolean ignoreRelatedElements) th
778739
}
779740

780741
/**
742+
* @param propertyName Name of the property
743+
* @param valueA value to compare
744+
* @param valueB value to compare
745+
* @param ignoreRelatedElements if true, do not compare properties relatedSpdxElement - used to prevent infinite recursion
746+
* @return true if the property values are equivalent
747+
* @throws InvalidSPDXAnalysisException
748+
*/
749+
private boolean propertyValuesEquivalent(String propertyName, Optional<Object> valueA,
750+
Optional<Object> valueB, boolean ignoreRelatedElements) throws InvalidSPDXAnalysisException {
751+
if (!valueA.isPresent()) {
752+
if (valueB.isPresent()) {
753+
if (valueB.get() instanceof ModelCollection) {
754+
if (((ModelCollection<?>)valueB.get()).size() > 0) {
755+
return false;
756+
}
757+
} else {
758+
return false;
759+
}
760+
}
761+
} else if (!valueB.isPresent()) {
762+
if (valueA.get() instanceof ModelCollection) {
763+
if (((ModelCollection<?>)valueA.get()).size() > 0) {
764+
return false;
765+
}
766+
} else {
767+
return false;
768+
}
769+
} else if (valueA.get() instanceof ModelCollection && valueB.get() instanceof ModelCollection) {
770+
List<?> myList = ((ModelCollection<?>)valueA.get()).toImmutableList();
771+
List<?> compareList = ((ModelCollection<?>)valueB.get()).toImmutableList();
772+
if (!listsEquivalent(myList, compareList, ignoreRelatedElements)) {
773+
return false;
774+
}
775+
} else if (valueA.get() instanceof List && valueB.get() instanceof List) {
776+
if (!listsEquivalent((List<?>)valueA.get(), (List<?>)valueB.get(), ignoreRelatedElements)) {
777+
return false;
778+
}
779+
} else if (valueA.get() instanceof IndividualUriValue && valueB.get() instanceof IndividualUriValue) {
780+
if (!Objects.equals(((IndividualUriValue)valueA.get()).getIndividualURI(), ((IndividualUriValue)valueB.get()).getIndividualURI())) {
781+
return false;
782+
}
783+
// Note: we must check the IndividualValue before the ModelObject types since the IndividualValue takes precedence
784+
} else if (valueA.get() instanceof ModelObject && valueB.get() instanceof ModelObject) {
785+
if (!((ModelObject)valueA.get()).equivalent(((ModelObject)valueB.get()),
786+
SpdxConstants.PROP_RELATED_SPDX_ELEMENT.equals(propertyName) ? true : ignoreRelatedElements)) {
787+
return false;
788+
}
789+
790+
} else if (!OptionalObjectsEquivalent(valueA, valueB)) { // Present, not a list, and not a TypedValue
791+
return false;
792+
}
793+
return true;
794+
}
795+
796+
/**
781797
* Compares 2 simple optional objects considering NONE and NOASSERTION values which are equivalent to their strings
782798
* @param valueA
783799
* @param valueB

src/main/java/org/spdx/library/model/RelatedElementCollection.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ public boolean remove(Object o) {
177177
if (rel instanceof Relationship) {
178178
Relationship relationship = (Relationship)rel;
179179
try {
180-
if (relationship.getRelatedSpdxElement().isPresent() &&
181-
relationship.getRelatedSpdxElement().get().equals(o) &&
180+
Optional<SpdxElement> relatedElement = relationship.getRelatedSpdxElement();
181+
if (relatedElement.isPresent() &&
182+
relatedElement.get().equals(o) &&
182183
relationship.getRelationshipType().equals(relationshipTypeFilter)) {
183184
return relationshipCollection.remove(relationship);
184185
}

0 commit comments

Comments
 (0)