diff --git a/.github/testForLicenseHeaders.sh b/.github/testForLicenseHeaders.sh
index 58a4c8136b..cbaa3ec278 100755
--- a/.github/testForLicenseHeaders.sh
+++ b/.github/testForLicenseHeaders.sh
@@ -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/*')" \
diff --git a/README.md b/README.md
index eac76af259..7f98cf686c 100644
--- a/README.md
+++ b/README.md
@@ -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
@@ -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
diff --git a/backend/src-common/pom.xml b/backend/src-common/pom.xml
index 5462fd0509..bae6c27950 100644
--- a/backend/src-common/pom.xml
+++ b/backend/src-common/pom.xml
@@ -63,5 +63,16 @@
com.github.package-url
packageurl-java
+
+ org.eclipse.sw360
+ nouveau-handler
+ ${project.version}
+ compile
+
+
+ com.ibm.cloud
+ cloudant
+ ${cloudantsdk.version}
+
diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/common/utils/SearchUtils.java b/backend/src-common/src/main/java/org/eclipse/sw360/common/utils/SearchUtils.java
new file mode 100644
index 0000000000..619af56566
--- /dev/null
+++ b/backend/src-common/src/main/java/org/eclipse/sw360/common/utils/SearchUtils.java
@@ -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});" +
+ " }" +
+ " }";
+}
diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentAwareDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentAwareDatabaseHandler.java
index 34c50559a9..793887ce5d 100644
--- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentAwareDatabaseHandler.java
+++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentAwareDatabaseHandler.java
@@ -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;
@@ -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;
@@ -43,8 +42,8 @@ protected AttachmentAwareDatabaseHandler(AttachmentDatabaseHandler attachmentDat
this.attachmentDatabaseHandler = attachmentDatabaseHandler;
}
- protected AttachmentAwareDatabaseHandler(Supplier 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){
diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentContentRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentContentRepository.java
index 35ae1db878..b077f14e1e 100644
--- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentContentRepository.java
+++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentContentRepository.java
@@ -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;
@@ -44,15 +42,17 @@ public class AttachmentContentRepository extends DatabaseRepositoryCloudantClien
public AttachmentContentRepository(DatabaseConnectorCloudant db) {
super(db, AttachmentContent.class);
- Map views = new HashMap();
+ Map views = new HashMap<>();
views.put("onlyRemotes", createMapReduce(ONLYREMOTES, null));
views.put("all", createMapReduce(ALL, null));
initStandardDesignDocument(views, db);
}
public List 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);
}
@@ -69,10 +69,14 @@ public RequestSummary vacuumAttachmentDB(User user, final Set usedIds) {
requestSummary.setTotalElements(allAttachmentContents.size());
requestSummary.setTotalAffectedElements(unusedAttachmentContents.size());
- final List documentOperationResults = getConnector().deleteBulk(unusedAttachmentContents);
+ final List 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;
diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentDatabaseHandler.java
index 7bd083d5c2..43c02e551a 100644
--- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentDatabaseHandler.java
+++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentDatabaseHandler.java
@@ -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;
@@ -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;
@@ -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;
@@ -56,13 +54,13 @@ public class AttachmentDatabaseHandler {
private static final Logger log = LogManager.getLogger(AttachmentDatabaseHandler.class);
- public AttachmentDatabaseHandler(Supplier 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(){
@@ -74,7 +72,7 @@ public AttachmentContent add(AttachmentContent attachmentContent){
return attachmentContent;
}
public List makeAttachmentContents(List attachmentContents) throws TException {
- final List documentOperationResults = attachmentContentRepository.executeBulk(attachmentContents);
+ final List documentOperationResults = attachmentContentRepository.executeBulk(attachmentContents);
if (documentOperationResults.isEmpty())
log.error("Failed Attachment store results " + documentOperationResults);
@@ -91,7 +89,7 @@ public void updateAttachmentContent(AttachmentContent attachment) throws TExcept
attachmentConnector.updateAttachmentContent(attachment);
}
public RequestSummary bulkDelete(List ids) {
- final List documentOperationResults = attachmentContentRepository.deleteIds(ids);
+ final List documentOperationResults = attachmentContentRepository.deleteIds(ids);
return CommonUtils.getRequestSummary(ids, documentOperationResults);
}
public RequestStatus deleteAttachmentContent(String attachmentId) throws TException {
@@ -147,9 +145,9 @@ public AttachmentUsage makeAttachmentUsage(AttachmentUsage attachmentUsage) {
public void makeAttachmentUsages(List attachmentUsages) throws TException {
List sanitizedUsages = distinctAttachmentUsages(attachmentUsages);
- List results = attachmentUsageRepository.executeBulk(sanitizedUsages);
- results = results.stream().filter(res -> res.getError() != null || res.getStatusCode() != HttpStatus.SC_CREATED)
- .collect(Collectors.toList());
+ List 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);
}
@@ -187,9 +185,9 @@ public AttachmentUsage updateAttachmentUsage(AttachmentUsage attachmentUsage) {
}
public void updateAttachmentUsages(List attachmentUsages) throws TException {
- List results = attachmentUsageRepository.executeBulk(attachmentUsages);
- results = results.stream().filter(res -> res.getError() != null || res.getStatusCode() != HttpStatus.SC_CREATED)
- .collect(Collectors.toList());
+ List 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);
}
@@ -200,10 +198,10 @@ public void deleteAttachmentUsage(AttachmentUsage attachmentUsage) throws SW360E
}
public void deleteAttachmentUsages(List attachmentUsages) throws SW360Exception {
- List results = attachmentUsageRepository.deleteIds(
+ List 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);
}
diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentOwnerRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentOwnerRepository.java
index 5717b5ab76..5c7f8aa0d5 100644
--- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentOwnerRepository.java
+++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/AttachmentOwnerRepository.java
@@ -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;
@@ -31,13 +32,17 @@ public class AttachmentOwnerRepository extends DatabaseRepositoryCloudantClient<
public AttachmentOwnerRepository(DatabaseConnectorCloudant db) {
super(db, Source.class);
- Map views = new HashMap();
+ Map views = new HashMap<>();
views.put("attachmentOwner", createMapReduce(ATTACHMENTOWNER_VIEW_NAME, null));
initStandardDesignDocument(views, db);
}
- public List