Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cloudant): upgrade to ibm cloudant sdk #2607

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 0 additions & 1 deletion .github/testForLicenseHeaders.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ done <<< "$(git ls-files \
| grep -v 'sw360.code-workspace' \
| grep -v 'default_secrets' \
| grep -v 'requirements.txt' \
| grep -Ev 'third-party/couchdb-lucene/*' \
| grep -Ev '*/asciidoc/*' \
| grep -Ev '.vscode/*' \
| grep -Ev 'config/*')" \
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ This is a multi module maven file. please consider that we have the following mo
### Issues

If you run in any issues with documentation or software, please be kind and report to our
[Github issues area](https://github.com/eclipse/sw360/issues).
[GitHub issues area](https://github.com/eclipse/sw360/issues).

### Deployment

Is recommended using the docker based setup,
[described here](https://github.com/eclipse/sw360/blob/main/README_DOCKER.md).

If you intend to install in a bare metal machine or use in your own virtualizaed system, [bare metal instructions are provided here](https://www.eclipse.org/sw360/docs/deployment/baremetal/deploy-natively/).
If you intend to install in a bare metal machine or use in your own virtualized system, [bare metal instructions are provided here](https://www.eclipse.org/sw360/docs/deployment/baremetal/deploy-natively/).

### Development

Expand Down Expand Up @@ -89,7 +89,7 @@ mvn package -P deploy \
-Dbackend.deploy.dir=webapps
```

If you want run the the tests, we need start a local couchdb server and Docker is required:
If you want to run the tests, we need start a local couchdb server and Docker is required:

### License

Expand Down
11 changes: 11 additions & 0 deletions backend/src-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,16 @@
<groupId>com.github.package-url</groupId>
<artifactId>packageurl-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.sw360</groupId>
<artifactId>nouveau-handler</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.ibm.cloud</groupId>
<artifactId>cloudant</artifactId>
<version>${cloudantsdk.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright Siemens AG, 2024. Part of the SW360 Portal Project.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/

package org.eclipse.sw360.common.utils;

public class SearchUtils {
/*
* This function returns the entire document as a string which can then be
* indexed as a text field for 'default' index in Nouveau.
* Possible values for `typeof` are documented at
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#description
* We entertain only following types:
* - number, bigint, string -> Directly converted to string with `+`
* - boolean -> Converted to string using `toString()`
* - object -> Recursively converted to string.
* - function & others -> skip
*/
public static final String OBJ_TO_DEFAULT_INDEX = " function getObjAsString(obj) {" +
" let result = '';" +
" for (var key in obj) {" +
" if (key == '_rev' || key == 'type') continue;" +
" switch (typeof(obj[key])) {" +
" case 'object':" +
" if (obj[key] !== null) {" +
" result += ' ' + getObjAsString(obj[key]);" +
" }" +
" break;" +
" case 'number':" +
" case 'bigint':" +
" case 'string':" +
" result += ' ' + obj[key];" +
" break;" +
" case 'boolean':" +
" result += ' ' + obj[key].toString();" +
" break;" +
" case 'function':" +
" default:" +
" break;" +
" }" +
" }" +
" return result.trim();" +
" };";

/*
* This function takes an array (or object) and traverse through it. Get all
* the values and index them as a text index.
*/
public static final String OBJ_ARRAY_TO_STRING_INDEX = " function arrayToStringIndex(arr, indexName) {" +
" let result = '';" +
" for (let i in arr) {" +
" if (arr[i] && typeof(arr[i]) == 'string' && arr[i].length > 0) {" +
" result += ' ' + arr[i];" +
" }" +
" }" +
" if (result.trim().length > 0) {" +
" index('text', indexName, result.trim(), {'store': true});" +
" }" +
" }";
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import com.ibm.cloud.cloudant.v1.Cloudant;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import org.eclipse.sw360.datahandler.common.SW360Utils;
Expand All @@ -31,7 +31,6 @@
import org.eclipse.sw360.datahandler.thrift.packages.Package;
import org.eclipse.sw360.datahandler.thrift.projects.Project;

import com.cloudant.client.api.CloudantClient;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;

Expand All @@ -43,8 +42,8 @@ protected AttachmentAwareDatabaseHandler(AttachmentDatabaseHandler attachmentDat
this.attachmentDatabaseHandler = attachmentDatabaseHandler;
}

protected AttachmentAwareDatabaseHandler(Supplier<CloudantClient> httpClient, String dbName, String attachmentDbName) throws MalformedURLException {
this(new AttachmentDatabaseHandler(httpClient, dbName, attachmentDbName));
protected AttachmentAwareDatabaseHandler(Cloudant client, String dbName, String attachmentDbName) throws MalformedURLException {
this(new AttachmentDatabaseHandler(client, dbName, attachmentDbName));
}

protected Source toSource(Release release){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentContent;
import org.eclipse.sw360.datahandler.thrift.users.User;

import com.cloudant.client.api.model.Response;
import com.cloudant.client.api.model.DesignDocument.MapReduce;
import com.cloudant.client.api.views.Key;
import com.cloudant.client.api.views.UnpaginatedRequestBuilder;
import com.cloudant.client.api.views.ViewRequestBuilder;
import com.ibm.cloud.cloudant.v1.model.DocumentResult;
import com.ibm.cloud.cloudant.v1.model.DesignDocumentViewsMapReduce;
import com.ibm.cloud.cloudant.v1.model.PostViewOptions;

import java.util.HashMap;
import java.util.List;
Expand All @@ -44,15 +42,17 @@ public class AttachmentContentRepository extends DatabaseRepositoryCloudantClien

public AttachmentContentRepository(DatabaseConnectorCloudant db) {
super(db, AttachmentContent.class);
Map<String, MapReduce> views = new HashMap<String, MapReduce>();
Map<String, DesignDocumentViewsMapReduce> views = new HashMap<>();
views.put("onlyRemotes", createMapReduce(ONLYREMOTES, null));
views.put("all", createMapReduce(ALL, null));
initStandardDesignDocument(views, db);
}

public List<AttachmentContent> getOnlyRemoteAttachments() {
ViewRequestBuilder query = getConnector().createQuery(AttachmentContent.class, "onlyRemotes");
UnpaginatedRequestBuilder req = query.newRequest(Key.Type.STRING, Object.class).includeDocs(true);
PostViewOptions req = getConnector()
.getPostViewQueryBuilder(AttachmentContent.class, "onlyRemotes")
.includeDocs(true)
.build();
return queryView(req);
}

Expand All @@ -69,10 +69,14 @@ public RequestSummary vacuumAttachmentDB(User user, final Set<String> usedIds) {
requestSummary.setTotalElements(allAttachmentContents.size());
requestSummary.setTotalAffectedElements(unusedAttachmentContents.size());

final List<Response> documentOperationResults = getConnector().deleteBulk(unusedAttachmentContents);
final List<DocumentResult> documentOperationResults = getConnector().deleteIds(
unusedAttachmentContents
.stream()
.map(AttachmentContent::getId).collect(Collectors.toSet())
);
if (unusedAttachmentContents.isEmpty() || !documentOperationResults.isEmpty()) {
requestSummary.setRequestStatus(RequestStatus.SUCCESS);
}else{
} else {
requestSummary.setRequestStatus(RequestStatus.FAILURE);
}
return requestSummary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
*/
package org.eclipse.sw360.datahandler.db;

import com.cloudant.client.api.CloudantClient;
import com.cloudant.client.api.model.Response;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DocumentResult;
import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant;
import org.eclipse.sw360.datahandler.common.CommonUtils;
import org.eclipse.sw360.datahandler.couchdb.AttachmentConnector;
Expand All @@ -24,7 +24,6 @@
import org.eclipse.sw360.datahandler.thrift.users.User;

import org.apache.logging.log4j.Logger;
import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.thrift.TException;

Expand All @@ -33,7 +32,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static org.eclipse.sw360.datahandler.common.Duration.durationOf;
Expand All @@ -56,13 +54,13 @@ public class AttachmentDatabaseHandler {

private static final Logger log = LogManager.getLogger(AttachmentDatabaseHandler.class);

public AttachmentDatabaseHandler(Supplier<CloudantClient> httpClient, String dbName, String attachmentDbName) throws MalformedURLException {
db = new DatabaseConnectorCloudant(httpClient, attachmentDbName);
attachmentConnector = new AttachmentConnector(httpClient, attachmentDbName, durationOf(30, TimeUnit.SECONDS));
public AttachmentDatabaseHandler(Cloudant client, String dbName, String attachmentDbName) throws MalformedURLException {
db = new DatabaseConnectorCloudant(client, attachmentDbName);
attachmentConnector = new AttachmentConnector(client, attachmentDbName, durationOf(30, TimeUnit.SECONDS));
attachmentContentRepository = new AttachmentContentRepository(db);
attachmentUsageRepository = new AttachmentUsageRepository(new DatabaseConnectorCloudant(httpClient, dbName));
attachmentRepository = new AttachmentRepository(new DatabaseConnectorCloudant(httpClient, dbName));
attachmentOwnerRepository = new AttachmentOwnerRepository(new DatabaseConnectorCloudant(httpClient, dbName));
attachmentUsageRepository = new AttachmentUsageRepository(new DatabaseConnectorCloudant(client, dbName));
attachmentRepository = new AttachmentRepository(new DatabaseConnectorCloudant(client, dbName));
attachmentOwnerRepository = new AttachmentOwnerRepository(new DatabaseConnectorCloudant(client, dbName));
}

public AttachmentConnector getAttachmentConnector(){
Expand All @@ -74,7 +72,7 @@ public AttachmentContent add(AttachmentContent attachmentContent){
return attachmentContent;
}
public List<AttachmentContent> makeAttachmentContents(List<AttachmentContent> attachmentContents) throws TException {
final List<Response> documentOperationResults = attachmentContentRepository.executeBulk(attachmentContents);
final List<DocumentResult> documentOperationResults = attachmentContentRepository.executeBulk(attachmentContents);
if (documentOperationResults.isEmpty())
log.error("Failed Attachment store results " + documentOperationResults);

Expand All @@ -91,7 +89,7 @@ public void updateAttachmentContent(AttachmentContent attachment) throws TExcept
attachmentConnector.updateAttachmentContent(attachment);
}
public RequestSummary bulkDelete(List<String> ids) {
final List<Response> documentOperationResults = attachmentContentRepository.deleteIds(ids);
final List<DocumentResult> documentOperationResults = attachmentContentRepository.deleteIds(ids);
return CommonUtils.getRequestSummary(ids, documentOperationResults);
}
public RequestStatus deleteAttachmentContent(String attachmentId) throws TException {
Expand Down Expand Up @@ -147,9 +145,9 @@ public AttachmentUsage makeAttachmentUsage(AttachmentUsage attachmentUsage) {

public void makeAttachmentUsages(List<AttachmentUsage> attachmentUsages) throws TException {
List<AttachmentUsage> sanitizedUsages = distinctAttachmentUsages(attachmentUsages);
List<Response> results = attachmentUsageRepository.executeBulk(sanitizedUsages);
results = results.stream().filter(res -> res.getError() != null || res.getStatusCode() != HttpStatus.SC_CREATED)
.collect(Collectors.toList());
List<DocumentResult> results = attachmentUsageRepository.executeBulk(sanitizedUsages);
results = results.stream().filter(res -> res.getError() != null || !res.isOk())
.toList();
if (!results.isEmpty()) {
throw new SW360Exception("Some of the usage documents could not be created: " + results);
}
Expand Down Expand Up @@ -187,9 +185,9 @@ public AttachmentUsage updateAttachmentUsage(AttachmentUsage attachmentUsage) {
}

public void updateAttachmentUsages(List<AttachmentUsage> attachmentUsages) throws TException {
List<Response> results = attachmentUsageRepository.executeBulk(attachmentUsages);
results = results.stream().filter(res -> res.getError() != null || res.getStatusCode() != HttpStatus.SC_CREATED)
.collect(Collectors.toList());
List<DocumentResult> results = attachmentUsageRepository.executeBulk(attachmentUsages);
results = results.stream().filter(res -> res.getError() != null || !res.isOk())
.toList();
if (!results.isEmpty()) {
throw new SW360Exception("Some of the usage documents could not be updated: " + results);
}
Expand All @@ -200,10 +198,10 @@ public void deleteAttachmentUsage(AttachmentUsage attachmentUsage) throws SW360E
}

public void deleteAttachmentUsages(List<AttachmentUsage> attachmentUsages) throws SW360Exception {
List<Response> results = attachmentUsageRepository.deleteIds(
List<DocumentResult> results = attachmentUsageRepository.deleteIds(
attachmentUsages.stream().map(AttachmentUsage::getId).collect(Collectors.toList()));
results = results.stream().filter(res -> res.getError() != null || res.getStatusCode() != HttpStatus.SC_OK)
.collect(Collectors.toList());
results = results.stream().filter(res -> res.getError() != null || !res.isOk())
.toList();
if (!results.isEmpty()) {
throw new SW360Exception("Some of the usage documents could not be deleted: " + results);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
import org.eclipse.sw360.datahandler.cloudantclient.DatabaseRepositoryCloudantClient;
import org.eclipse.sw360.datahandler.thrift.Source;

import com.cloudant.client.api.model.DesignDocument.MapReduce;
import com.cloudant.client.api.views.ViewRequestBuilder;
import com.ibm.cloud.cloudant.v1.model.DesignDocumentViewsMapReduce;
import com.ibm.cloud.cloudant.v1.model.PostViewOptions;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.List;
Expand All @@ -31,13 +32,17 @@ public class AttachmentOwnerRepository extends DatabaseRepositoryCloudantClient<

public AttachmentOwnerRepository(DatabaseConnectorCloudant db) {
super(db, Source.class);
Map<String, MapReduce> views = new HashMap<String, MapReduce>();
Map<String, DesignDocumentViewsMapReduce> views = new HashMap<>();
views.put("attachmentOwner", createMapReduce(ATTACHMENTOWNER_VIEW_NAME, null));
initStandardDesignDocument(views, db);
}

public List<Source> getOwnersByIds(Set<String> ids) {
ViewRequestBuilder viewQuery = getConnector().createQuery(Source.class, "attachmentOwner");
return queryViewForSource(buildRequest(viewQuery, ids));
public List<Source> getOwnersByIds(@NotNull Set<String> ids) {
PostViewOptions viewQuery = getConnector()
.getPostViewQueryBuilder(Source.class, "attachmentOwner")
.includeDocs(false)
.keys(ids.stream().map(r -> (Object)r).toList())
.build();
return queryViewForSource(viewQuery);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
import org.eclipse.sw360.datahandler.cloudantclient.DatabaseRepositoryCloudantClient;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;

import com.cloudant.client.api.model.DesignDocument.MapReduce;
import com.cloudant.client.api.views.ViewRequestBuilder;
import com.ibm.cloud.cloudant.v1.model.DesignDocumentViewsMapReduce;
import com.ibm.cloud.cloudant.v1.model.PostViewOptions;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.List;
Expand All @@ -32,19 +33,27 @@ public class AttachmentRepository extends DatabaseRepositoryCloudantClient<Attac

public AttachmentRepository(DatabaseConnectorCloudant db) {
super(db, Attachment.class);
Map<String, MapReduce> views = new HashMap<String, MapReduce>();
Map<String, DesignDocumentViewsMapReduce> views = new HashMap<>();
views.put("byid", createMapReduce(BYID_VIEW_NAME, null));
views.put("bysha1", createMapReduce(BYSHA1_VIEW_NAME, null));
initStandardDesignDocument(views, db);
}

public List<Attachment> getAttachmentsByIds(Set<String> ids) {
ViewRequestBuilder viewQuery = getConnector().createQuery(Attachment.class, "byid");
return queryViewForAttchmnt(buildRequest(viewQuery, ids));
public List<Attachment> getAttachmentsByIds(@NotNull Set<String> ids) {
PostViewOptions viewQuery = getConnector()
.getPostViewQueryBuilder(Attachment.class, "byid")
.includeDocs(false)
.keys(ids.stream().map(r -> (Object)r).toList())
.build();
return queryViewForAttachment(viewQuery);
}

public List<Attachment> getAttachmentsBySha1s(Set<String> sha1s) {
ViewRequestBuilder viewQuery = getConnector().createQuery(Attachment.class, "bysha1");
return queryViewForAttchmnt(buildRequest(viewQuery, sha1s));
public List<Attachment> getAttachmentsBySha1s(@NotNull Set<String> sha1s) {
PostViewOptions viewQuery = getConnector()
.getPostViewQueryBuilder(Attachment.class, "bysha1")
.includeDocs(false)
.keys(sha1s.stream().map(r -> (Object)r).toList())
.build();
return queryViewForAttachment(viewQuery);
}
}
Loading