Skip to content

Commit

Permalink
Merged in task/dspace-cris-2023_02_x/DSC-1997 (pull request DSpace#2962)
Browse files Browse the repository at this point in the history
Task/dspace cris 2023 02 x/DSC-1997

Approved-by: Vincenzo Mecca
  • Loading branch information
AdamF42 authored and vins01-4science committed Nov 13, 2024
2 parents 4c666a3 + e29a193 commit 2eb6108
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;

import org.dspace.authorize.AuthorizeException;
Expand Down Expand Up @@ -59,6 +60,11 @@ public Site findSite(Context context) throws SQLException {
return siteDAO.findSite(context);
}

@Override
public List<Site> findAll(Context context) throws SQLException {
return siteDAO.findAll(context);
}

@Override
public Site find(Context context, UUID id) throws SQLException {
return siteDAO.findByID(context, Site.class, id);
Expand Down
10 changes: 10 additions & 0 deletions dspace-api/src/main/java/org/dspace/content/dao/SiteDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.dspace.content.dao;

import java.sql.SQLException;
import java.util.List;

import org.dspace.content.Site;
import org.dspace.core.Context;
Expand All @@ -22,4 +23,13 @@
public interface SiteDAO extends DSpaceObjectDAO<Site> {

public Site findSite(Context context) throws SQLException;

/**
* Fetches all Site objects from the database.
*
* @param context The relevant DSpace Context.
* @return A List of all Site objects in the database.
* @throws SQLException If a database access error occurs.
*/
List<Site> findAll(Context context) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.dspace.content.dao.impl;

import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
Expand Down Expand Up @@ -37,4 +38,20 @@ public Site findSite(Context context) throws SQLException {
criteriaQuery.select(siteRoot);
return uniqueResult(context, criteriaQuery, true, Site.class);
}


/**
* {@inheritDoc}
*
* @see SiteDAO#findAll(Context)
*
*/
@Override
public List<Site> findAll(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery<Site> criteriaQuery = getCriteriaQuery(criteriaBuilder, Site.class);
Root<Site> siteRoot = criteriaQuery.from(Site.class);
criteriaQuery.select(siteRoot);
return list(context, criteriaQuery, false, Site.class, -1,-1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.dspace.content.service;

import java.sql.SQLException;
import java.util.List;

import org.dspace.content.Site;
import org.dspace.core.Context;
Expand All @@ -24,4 +25,13 @@ public interface SiteService extends DSpaceObjectService<Site> {
public Site createSite(Context context) throws SQLException;

public Site findSite(Context context) throws SQLException;

/**
* Retrieve a list of all sites in the system.
*
* @param context The relevant DSpace Context.
* @return A List of all Site objects in the system.
* @throws SQLException If a database access error occurs.
*/
List<Site> findAll(Context context) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

import org.apache.solr.client.solrj.SolrServerException;
import org.dspace.app.rest.DiscoverableEndpointsService;
import org.dspace.app.rest.health.EPersonGroupHealthIndicator;
import org.dspace.app.rest.health.GeoIpHealthIndicator;
import org.dspace.app.rest.health.SiteHealthIndicator;
import org.dspace.authority.AuthoritySolrServiceImpl;
import org.dspace.discovery.SolrSearchCore;
import org.dspace.statistics.SolrStatisticsCore;
Expand Down Expand Up @@ -88,6 +90,18 @@ public GeoIpHealthIndicator geoIpHealthIndicator() {
return new GeoIpHealthIndicator();
}

@Bean
@ConditionalOnEnabledHealthIndicator("site")
public SiteHealthIndicator siteHealthIndicator() {
return new SiteHealthIndicator();
}

@Bean
@ConditionalOnEnabledHealthIndicator("ePersonGroup")
public EPersonGroupHealthIndicator ePersonGroupHealthIndicator() {
return new EPersonGroupHealthIndicator();
}

public String getActuatorBasePath() {
return actuatorBasePath;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.health;

import java.sql.SQLException;
import java.util.Map;

import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.web.ContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;

/**
* Implementation of {@link HealthIndicator} to verify the presence of essential
* groups in the system, specifically "Anonymous" and "Administrators" in the
* `epersongroups` table.
* Marks the status as "UP" if both groups are present, otherwise "DOWN" with
* details about the missing group(s).
*
* @author Adamo Fapohunda (adamo.fapohunda at 4science.com)
*/
public class EPersonGroupHealthIndicator extends AbstractHealthIndicator {

private static final Map<Map<Boolean, Boolean>, String> ERROR_MESSAGES = Map.of(
Map.of(false, false), "Both 'Anonymous' and 'Administrators' groups are missing",
Map.of(true, false), "The 'Administrators' group is missing",
Map.of(false, true), "The 'Anonymous' group is missing"
);
@Autowired
private GroupService groupService;

@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Context context = ContextUtil.obtainCurrentRequestContext();
try {
boolean hasAnonymous = groupService.findByName(context, Group.ANONYMOUS) != null;
boolean hasAdministrators = groupService.findByName(context, Group.ADMIN) != null;

if (hasAnonymous && hasAdministrators) {
builder.up();
} else {
builder.down()
.withDetail("error", ERROR_MESSAGES.get(Map.of(hasAnonymous, hasAdministrators)));
}
} catch (SQLException e) {
builder.down(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest.health;

import java.sql.SQLException;
import java.util.List;

import org.dspace.content.Site;
import org.dspace.content.service.SiteService;
import org.dspace.core.Context;
import org.dspace.web.ContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;


/**
* Implementation of {@link HealthIndicator} that verifies if the table sites
* has exactly one row.
*
* @author Adamo Fapohunda (adamo.fapohunda at 4science.com)
*/
public class SiteHealthIndicator extends AbstractHealthIndicator {

@Autowired
private SiteService siteService;

@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Context context = ContextUtil.obtainCurrentRequestContext();
try {
List<Site> sites = siteService.findAll(context);
if (sites != null && sites.size() != 1) {
builder.down().withDetail("error", "`sites` table must contain exactly one row");
} else {
builder.up();
}
} catch (SQLException e) {
builder.down(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import static org.dspace.app.rest.configuration.ActuatorConfiguration.UP_WITH_ISSUES_STATUS;
import static org.dspace.app.rest.link.search.HealthIndicatorMatcher.match;
import static org.dspace.app.rest.link.search.HealthIndicatorMatcher.matchDatabase;
import static org.dspace.app.rest.link.search.HealthIndicatorMatcher.matchEPersonGroup;
import static org.dspace.app.rest.link.search.HealthIndicatorMatcher.matchSite;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
Expand All @@ -26,7 +28,6 @@
* Integration tests to verify the health indicators configuration.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class HealthIndicatorsIT extends AbstractControllerIntegrationTest {

Expand All @@ -36,9 +37,9 @@ public class HealthIndicatorsIT extends AbstractControllerIntegrationTest {
public void testWithAnonymousUser() throws Exception {

getClient().perform(get(HEALTH_PATH))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components").doesNotExist());
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components").doesNotExist());

}

Expand All @@ -48,9 +49,9 @@ public void testWithNotAdminUser() throws Exception {
String token = getAuthToken(eperson.getEmail(), password);

getClient(token).perform(get(HEALTH_PATH))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components").doesNotExist());
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components").doesNotExist());

}

Expand All @@ -60,15 +61,18 @@ public void testWithAdminUser() throws Exception {
String token = getAuthToken(admin.getEmail(), password);

getClient(token).perform(get(HEALTH_PATH))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components", allOf(
matchDatabase(Status.UP),
match("solrSearchCore", Status.UP, Map.of("status", 0, "detectedPathType", "root")),
match("solrStatisticsCore", Status.UP, Map.of("status", 0, "detectedPathType", "root")),
match("geoIp", UP_WITH_ISSUES_STATUS,
Map.of("reason", "The required 'dbfile' configuration is missing in usage-statistics.cfg!"))
)));
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is(UP_WITH_ISSUES_STATUS.getCode())))
.andExpect(jsonPath("$.components", allOf(
matchDatabase(Status.UP),
match("solrSearchCore", Status.UP, Map.of("status", 0, "detectedPathType", "root")),
match("solrStatisticsCore", Status.UP, Map.of("status", 0, "detectedPathType", "root")),
matchSite(Status.UP),
matchEPersonGroup(Status.UP),
match("geoIp", UP_WITH_ISSUES_STATUS,
Map.of("reason",
"The required 'dbfile' configuration is missing in usage-statistics.cfg!"))
)));

}
}
Loading

0 comments on commit 2eb6108

Please sign in to comment.