Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Test/org/spdx/crossref/OsiApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void test() throws InvalidSPDXAnalysisException {
SpdxListedLicense apache20 = new SpdxListedLicense("Apache-2.0");
apache20.setLicenseText("Apache text");
CrossRef osiApacheCrossRef = new CrossRef();
String apache20OsiUrl = "https://opensource.org/licenses/Apache-2.0";
String apache20OsiUrl = "https://opensource.org/licenses/apache-2.0";
osiApacheCrossRef.setUrl(apache20OsiUrl);
OsiApi instance = OsiApi.getInstance();
assertTrue(instance.isApiAvailable());
Expand All @@ -75,7 +75,7 @@ public void test() throws InvalidSPDXAnalysisException {
assertTrue(osiApacheCrossRef.getValid().get());

// not OSI URL
String nonOsiUrl = "https://notopensource.org/licenses/Apache-2.0";
String nonOsiUrl = "https://notopensource.org/licenses/apache-2.0";
assertFalse(OsiApi.isOsiUrl(nonOsiUrl));

// not matching URL
Expand Down
60 changes: 31 additions & 29 deletions src/org/spdx/crossref/OsiApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@
*/
public class OsiApi {
static final Logger logger = LoggerFactory.getLogger(OsiApi.class.getName());
public static final String OSI_PREFIX = "https://opensource.org/licenses";
private static final String API_BASE_URL = "https://api.opensource.org";
private static final String ALL_LICENSES_URL = API_BASE_URL + "/licenses/";
public static final String OSI_PREFIX = "https://opensource.org/license";
private static final String API_BASE_URL = "https://opensource.org/api";
private static final String ALL_LICENSES_URL = API_BASE_URL + "/license";
private static final int READ_TIMEOUT = 5000;
static final List<String> WHITE_LIST = Collections.unmodifiableList(Arrays.asList(
"osi.org")); // currently, we're not allowing any redirects to sites other than OSI

static final List<String> WHITE_LIST = Collections.unmodifiableList(List.of(
"osi.org")); // currently, we're not allowing any redirects to sites other than OSI
private static class InstanceHolder {
private static final OsiApi INSTANCE = new OsiApi();
}
Expand All @@ -71,7 +70,19 @@ public static boolean isOsiUrl(String url) {
}

private boolean apiAvailable = false;
private Map<String, List<String>> urlToSpdxIds = new HashMap<>();
private final Map<String, String> urlToSpdxId = new HashMap<>();

/**
* Normalized an OSI URL taking into account changes and redirects introduced by OSI which breaks
* compatibility with non-normalized URLs
* @param url URL pointing to an OSI license
* @return normalized URL
*/
public static String normalizeOsiUrl(String url) {
return url.toLowerCase() // OSI changed the case on URLs like Apache-2.0 (now apache-2.0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old variant still works. Do you have an idea if this is just for the transition period?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old variants seem to redirect to the new version. In the API, they only store the latest URLs (not the previous variants), so we have to normalize. A bit of historical context - we use to check the URL's directly, but the OSI website would fail due to rate limiting, so we now use their API which is much friendlier to their website infrastructure.

.replace("/licenses/", "/license/") // OSI changed the URLs for licenses removing the 's'
.replaceAll("(\\d)\\.(\\d)$", "$1-$2"); // OSI changed the URL ending in apache-2.0 to apache-2-0
}

private OsiApi() {
try (BufferedReader reader = new BufferedReader(
Expand All @@ -87,22 +98,13 @@ private OsiApi() {
for (OsiLicense osiLicense:osiLicenses) {
if (Objects.nonNull(osiLicense.getLinks()) &&
Objects.nonNull(osiLicense.getId()) &&
Objects.nonNull(osiLicense.getIdentifiers())) {
List<String> spdxIds = new ArrayList<>();
for (OsiLicense.IdentifierType identifier:osiLicense.getIdentifiers()) {
if ("SPDX".equals(identifier.getScheme()) &&
Objects.nonNull(identifier.getIdentifier())) {
spdxIds.add(identifier.getIdentifier());
}
}
if (!spdxIds.isEmpty()) {
for (OsiLicense.Link link:osiLicense.getLinks()) {
if (Objects.nonNull(link.getUrl())) {
urlToSpdxIds.put(link.getUrl(), spdxIds);
}
}
}

Objects.nonNull(osiLicense.getSpdx_id())) {
if (Objects.nonNull(osiLicense.getLinks().getSelf()) && Objects.nonNull(osiLicense.getLinks().getSelf().getHref())) {
urlToSpdxId.put(normalizeOsiUrl(osiLicense.getLinks().getSelf().getHref()), osiLicense.getSpdx_id());
}
if (Objects.nonNull(osiLicense.getLinks().getHtml()) && Objects.nonNull(osiLicense.getLinks().getHtml().getHref())) {
urlToSpdxId.put(normalizeOsiUrl(osiLicense.getLinks().getHtml().getHref()), osiLicense.getSpdx_id());
}
}
}
apiAvailable = true;
Expand All @@ -123,9 +125,8 @@ private InputStream getUrlInputStream(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setReadTimeout(READ_TIMEOUT);
int status = connection.getResponseCode();
if (status != HttpURLConnection.HTTP_OK &&
(status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER)) {
if ((status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER)) {
// redirect
String redirectUrlStr = connection.getHeaderField("Location");
if (Objects.isNull(redirectUrlStr) || redirectUrlStr.isEmpty()) {
Expand Down Expand Up @@ -163,9 +164,10 @@ public boolean isApiAvailable() {
*/
public void setCrossRefDetails(String url, SpdxListedLicense license,
CrossRef crossRef) throws InvalidSPDXAnalysisException {
Boolean isValidUrl = Valid.urlValidator(url);
List<String> spdxIds = urlToSpdxIds.get(url);
Boolean isLiveUrl = Objects.nonNull(spdxIds) && spdxIds.contains(license.getId());
String normalizedUrl = normalizeOsiUrl(url);
Boolean isValidUrl = Valid.urlValidator(normalizedUrl);
String spdxId = urlToSpdxId.get(normalizedUrl);
Boolean isLiveUrl = Objects.equals(spdxId, license.getId());
Boolean isWaybackUrl = false;
String currentDate = Timestamp.getTimestamp();
String matchStatus = "N/A";
Expand Down
78 changes: 36 additions & 42 deletions src/org/spdx/crossref/OsiLicense.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,49 +27,40 @@
*
*/
public class OsiLicense {

public class IdentifierType {
String identifier;
String scheme;
/**
* @return the identifier
*/
public String getIdentifier() {
return identifier;
}
/**
* @return the scheme
*/
public String getScheme() {
return scheme;

public static class LinkType {
String href;

public String getHref() {
return href;
}

}

public class Link {
String note;
String url;
/**
* @return the note
*/
public String getNote() {
return note;

public static class Links {
LinkType self;
LinkType html;
LinkType collection;

public LinkType getSelf() {
return self;
}

public LinkType getHtml() {
return html;
}
/**
* @return the url
*/
public String getUrl() {
return url;

public LinkType getCollection() {
return collection;
}


}

String id;
List<IdentifierType> identifiers;
List<Link> links;
Links _links;
String name;
String spdx_id;
List<String> keywords;
String version;
String submission_date;
/**
* @return the id
*/
Expand All @@ -79,14 +70,8 @@ public String getId() {
/**
* @return the identifiers
*/
public List<IdentifierType> getIdentifiers() {
return identifiers;
}
/**
* @return the links
*/
public List<Link> getLinks() {
return links;
public Links getLinks() {
return _links;
}
/**
* @return the name
Expand All @@ -100,4 +85,13 @@ public String getName() {
public List<String> getKeywords() {
return keywords;
}
public String getSpdx_id() {
return spdx_id;
}
public String getVersion() {
return version;
}
public String getSubmission_date() {
return submission_date;
}
}