Skip to content

NMS-17749: Zenith Connect UI, connect with Registration Rest API #7718

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

Merged
merged 2 commits into from
May 7, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,27 @@
package org.opennms.features.zenithconnect.persistence.api;

public class ZenithConnectPersistenceException extends Exception {
private boolean attemptedToAddDuplicate;

public ZenithConnectPersistenceException() {
super();
}

public ZenithConnectPersistenceException(boolean attemptedToAddDuplicate) {
super();

this.attemptedToAddDuplicate = attemptedToAddDuplicate;
}

public ZenithConnectPersistenceException(String message) {
super(message);
}

public ZenithConnectPersistenceException(String message, Throwable e) {
super(message, e);
}

public boolean isAttemptedToAddDuplicate() {
return attemptedToAddDuplicate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,22 @@ public interface ZenithConnectPersistenceService {

/**
* Add a new registration.
* Currently we only support a single registration.
* Currently we only support a single registration, so this will replace any registration that
* already exists.
* Returns the added registration, including an id and createTimeMs.
* @param preventDuplicates If true, will check to see if the given registration appears to be
* a duplicate of an existing registration (same systemId and same accessToken or refreshToken).
* If so, will throw an exception. This is to prevent e.g. the UI from sending multiple
* duplicate add requests.
*/
ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration) throws ZenithConnectPersistenceException;
ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration, boolean preventDuplicates)
throws ZenithConnectPersistenceException;

/**
* Add a new registration, ignoring preventDuplicates.
*/
ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration)
throws ZenithConnectPersistenceException;

/**
* Update an existing registration. The given id and registration.id must match an existing registration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ public ZenithConnectRegistrations getRegistrations() throws ZenithConnectPersist
}

/** {@inheritDoc} */
public ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration) throws ZenithConnectPersistenceException {
public ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration, boolean preventDuplicates)
throws ZenithConnectPersistenceException {
if (preventDuplicates && isDuplicateRegistration(registration)) {
throw new ZenithConnectPersistenceException(true);
}

registration.id = UUID.randomUUID().toString();
registration.createTimeMs = Instant.now().toEpochMilli();

Expand All @@ -69,6 +74,11 @@ public ZenithConnectRegistration addRegistration(ZenithConnectRegistration regis
return registration;
}

public ZenithConnectRegistration addRegistration(ZenithConnectRegistration registration)
throws ZenithConnectPersistenceException {
return addRegistration(registration, false);
}

/** {@inheritDoc} */
public void updateRegistration(String id, ZenithConnectRegistration registration) throws ZenithConnectPersistenceException {
if (Strings.isNullOrEmpty(id) ||
Expand Down Expand Up @@ -136,4 +146,31 @@ private void setRegistrations(ZenithConnectRegistrations registrations) throws Z
throw new ZenithConnectPersistenceException("Could not serialize Zenith Connect registrations", e);
}
}

private boolean isDuplicateRegistration(ZenithConnectRegistration registration)
throws ZenithConnectPersistenceException {
ZenithConnectRegistrations existingRegistrations = getRegistrationsImpl();
ZenithConnectRegistration existingRegistration = existingRegistrations.first();

if (existingRegistration == null) {
return false;
}

boolean systemIdsMatch = registration.systemId != null && existingRegistration.systemId != null &&
registration.systemId.equals(existingRegistration.systemId);

if (systemIdsMatch) {
boolean accessTokenMatches = registration.accessToken != null &&
existingRegistration.accessToken != null &&
registration.accessToken.equals(existingRegistration.accessToken);

boolean refreshTokenMatches = registration.refreshToken != null &&
existingRegistration.refreshToken != null &&
registration.refreshToken.equals(existingRegistration.refreshToken);

return accessTokenMatches || refreshTokenMatches;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,38 @@ public void testAddAndGetRegistrations() throws ZenithConnectPersistenceExceptio
assertThat(createdRegistration.createTimeMs, greaterThanOrEqualTo(currentTime));
}

@Test
public void testAddDuplicateRegistrations() throws ZenithConnectPersistenceException {
// add a registration
var registration = createDefaultRegistration();
long currentTime = Instant.now().toEpochMilli();
persistenceService.addRegistration(registration);

// make sure it was added correctly
ZenithConnectRegistrations registrations = persistenceService.getRegistrations();
assertNotNull(registrations);

ZenithConnectRegistration createdRegistration = registrations.first();
assertRegistrationFieldsEqual(registration, createdRegistration);

assertThat(createdRegistration.id, not(emptyString()));
assertThat(createdRegistration.id, matchesPattern(UUID_REGEX));
assertThat(createdRegistration.createTimeMs, greaterThanOrEqualTo(currentTime));

// Now add it again, should fail with specific exception and flag
var duplicate = createDefaultRegistration();
ZenithConnectPersistenceException exception = null;

try {
persistenceService.addRegistration(duplicate, true);
} catch (ZenithConnectPersistenceException e) {
exception = e;
}

assertNotNull("Adding duplicate to persistenceService.addRegistration should throw a ZenithConnectPersistenceException.", exception);
assertTrue("Adding duplicate to persistenceService.addRegistration should set attemptedToAddDuplicate.", exception.isAttemptedToAddDuplicate());
}

@Test
public void testUpdateRegistration() throws ZenithConnectPersistenceException {
// add a registration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ public DefaultZenithConnectRestService(ZenithConnectPersistenceService persisten
this.persistenceService = persistenceService;
}

/** {@inheritDoc} */
/**
* Get all registrations.
* Currently, there is only one registration at a time, so this will return a
* ZenithConnectRegistrations object with a single object in the registrations list.
*/
@Override
public Response getRegistrations() {
try {
Expand All @@ -58,19 +62,31 @@ public Response getRegistrations() {
}
}

/** {@inheritDoc} */
/**
* Add the given registration.
* This will throw a 400 Bad Request if the request is a duplicate of an existing registration.
* Throws a 500 Server Error if the request is malformed, or there was an error updating the database.
*/
@Override
public Response addRegistration(ZenithConnectRegistration registration) {
try {
var newRegistration = persistenceService.addRegistration(registration);
var newRegistration = persistenceService.addRegistration(registration, true);
return Response.status(Response.Status.CREATED).entity(newRegistration).build();
} catch (ZenithConnectPersistenceException e) {
LOG.error("Could not add registration: {}.", e.getMessage(), e);
LOG.error("Could not add registration: {}. Attempted to add duplicate: {}",
e.getMessage(), e.isAttemptedToAddDuplicate(), e);

if (e.isAttemptedToAddDuplicate()) {
return Response.status(Response.Status.BAD_REQUEST).build();
}

return Response.serverError().build();
}
}

/** {@inheritDoc} */
/**
* Update an existing registration. The id and registration.id must match an existing registration.
*/
@Override
public Response updateRegistration(String id, ZenithConnectRegistration registration) {
try {
Expand Down
Loading