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

translate ModelValidationException to 4XX #489

Merged
merged 1 commit into from
Jan 2, 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
@@ -1,5 +1,9 @@
package com.linkedin.metadata.dao.exception;

/**
* Exception thrown when the requested aspect is not defined in the asset model / there is invalid aspect present
* in the database that is not defined in the asset model.
*/
public class ModelValidationException extends RuntimeException {

public ModelValidationException(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.linkedin.data.template.StringArray;
import com.linkedin.data.template.UnionTemplate;
import com.linkedin.metadata.dao.AspectKey;
import com.linkedin.metadata.dao.exception.ModelValidationException;
import com.linkedin.metadata.dao.ingestion.AspectCallbackRegistry;
import com.linkedin.metadata.dao.ingestion.AspectCallbackResponse;
import com.linkedin.metadata.dao.ingestion.AspectCallbackRoutingClient;
Expand Down Expand Up @@ -143,8 +144,12 @@ protected Task<VALUE> get(@Nonnull KEY id, @QueryParam(PARAM_ASPECTS) @Optional
public Task<SNAPSHOT> getSnapshot(@ActionParam(PARAM_URN) @Nonnull String urnString,
@ActionParam(PARAM_ASPECTS) @Optional @Nullable String[] aspectNames) {
final URN urn = parseUrnParam(urnString);
return getSnapshot(urnString, aspectNames,
getResourceLix().testGetSnapshot(String.valueOf(urn), ModelUtils.getEntityType(urn)));
try {
return getSnapshot(urnString, aspectNames,
getResourceLix().testGetSnapshot(String.valueOf(urn), ModelUtils.getEntityType(urn)));
} catch (ModelValidationException e) {
throw RestliUtils.invalidArgumentsException(e.getMessage());
}
}

@Nonnull
Expand Down Expand Up @@ -202,27 +207,31 @@ protected Task<SNAPSHOT> getSnapshot(@ActionParam(PARAM_URN) @Nonnull String urn
@Override
public Task<ASSET> getAsset(@ActionParam(PARAM_URN) @Nonnull String urnString,
@ActionParam(PARAM_ASPECTS) @Optional @Nullable String[] aspectNames) {
try {
return RestliUtils.toTask(() -> {
final URN urn = parseUrnParam(urnString);
final Set<Class<? extends RecordTemplate>> aspectClasses = parseAspectsParam(aspectNames, true);

return RestliUtils.toTask(() -> {
final URN urn = parseUrnParam(urnString);
final Set<Class<? extends RecordTemplate>> aspectClasses = parseAspectsParam(aspectNames, true);

if (!containsRoutingAspect(aspectClasses)) {
// Get snapshot from Local DAO.
final List<INTERNAL_ASPECT_UNION> aspectUnions = getInternalAspectsFromLocalDao(urn, aspectClasses);
return ModelUtils.newAsset(_assetClass, urn, aspectUnions);
} else {
final Set<Class<? extends RecordTemplate>> nonRoutingAspects = getNonRoutingAspects(aspectClasses);
final List<INTERNAL_ASPECT_UNION> aspectsFromLocalDao = getInternalAspectsFromLocalDao(urn, nonRoutingAspects);
final Set<Class<? extends RecordTemplate>> routingAspects = getRoutingAspects(aspectClasses);
final List<INTERNAL_ASPECT_UNION> aspectsFromGms = routingAspects.stream()
.map(routingAspect -> getInternalAspectsFromGms(urn, routingAspect))
.flatMap(List::stream)
.collect(Collectors.toList());
return ModelUtils.newAsset(_assetClass, urn,
Stream.concat(aspectsFromGms.stream(), aspectsFromLocalDao.stream()).collect(Collectors.toList()));
}
});
if (!containsRoutingAspect(aspectClasses)) {
// Get snapshot from Local DAO.
final List<INTERNAL_ASPECT_UNION> aspectUnions = getInternalAspectsFromLocalDao(urn, aspectClasses);
return ModelUtils.newAsset(_assetClass, urn, aspectUnions);
} else {
final Set<Class<? extends RecordTemplate>> nonRoutingAspects = getNonRoutingAspects(aspectClasses);
final List<INTERNAL_ASPECT_UNION> aspectsFromLocalDao =
getInternalAspectsFromLocalDao(urn, nonRoutingAspects);
final Set<Class<? extends RecordTemplate>> routingAspects = getRoutingAspects(aspectClasses);
final List<INTERNAL_ASPECT_UNION> aspectsFromGms = routingAspects.stream()
.map(routingAspect -> getInternalAspectsFromGms(urn, routingAspect))
.flatMap(List::stream)
.collect(Collectors.toList());
return ModelUtils.newAsset(_assetClass, urn,
Stream.concat(aspectsFromGms.stream(), aspectsFromLocalDao.stream()).collect(Collectors.toList()));
}
});
} catch (ModelValidationException e) {
throw RestliUtils.invalidArgumentsException(e.getMessage());
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.linkedin.metadata.dao.BaseLocalDAO;
import com.linkedin.metadata.dao.ListResult;
import com.linkedin.metadata.dao.UrnAspectEntry;
import com.linkedin.metadata.dao.exception.ModelValidationException;
import com.linkedin.metadata.dao.tracking.BaseTrackingManager;
import com.linkedin.metadata.dao.utils.ModelUtils;
import com.linkedin.metadata.events.IngestionMode;
Expand Down Expand Up @@ -477,9 +478,13 @@ protected Task<Void> rawIngestAssetInternal(@Nonnull ASSET asset,
@Nonnull
public Task<SNAPSHOT> getSnapshot(@ActionParam(PARAM_URN) @Nonnull String urnString,
@ActionParam(PARAM_ASPECTS) @Optional @Nullable String[] aspectNames) {
final URN urn = parseUrnParam(urnString);
return getSnapshot(urnString, aspectNames,
getResourceLix().testGetSnapshot(String.valueOf(urn), ModelUtils.getEntityType(urn)));
try {
final URN urn = parseUrnParam(urnString);
return getSnapshot(urnString, aspectNames,
getResourceLix().testGetSnapshot(String.valueOf(urn), ModelUtils.getEntityType(urn)));
} catch (ModelValidationException e) {
throw RestliUtils.invalidArgumentsException(e.getMessage());
}
}

@Deprecated
Expand Down Expand Up @@ -525,27 +530,30 @@ protected Task<SNAPSHOT> getSnapshot(@ActionParam(PARAM_URN) @Nonnull String urn
@Nonnull
public Task<ASSET> getAsset(@ActionParam(PARAM_URN) @Nonnull String urnString,
@ActionParam(PARAM_ASPECTS) @Optional @Nullable String[] aspectNames) {
try {
return RestliUtils.toTask(() -> {
final URN urn = parseUrnParam(urnString);

return RestliUtils.toTask(() -> {
final URN urn = parseUrnParam(urnString);

if (!getLocalDAO().exists(urn)) {
throw RestliUtils.resourceNotFoundException();
}
if (!getLocalDAO().exists(urn)) {
throw RestliUtils.resourceNotFoundException();
}

final Set<AspectKey<URN, ? extends RecordTemplate>> keys = parseAspectsParam(aspectNames, true).stream()
.map(aspectClass -> new AspectKey<>(aspectClass, urn, LATEST_VERSION))
.collect(Collectors.toSet());
final Set<AspectKey<URN, ? extends RecordTemplate>> keys = parseAspectsParam(aspectNames, true).stream()
.map(aspectClass -> new AspectKey<>(aspectClass, urn, LATEST_VERSION))
.collect(Collectors.toSet());

final List<UnionTemplate> aspects = getLocalDAO().get(keys)
.values()
.stream()
.filter(java.util.Optional::isPresent)
.map(aspect -> ModelUtils.newAspectUnion(_internalAspectUnionClass, aspect.get()))
.collect(Collectors.toList());
final List<UnionTemplate> aspects = getLocalDAO().get(keys)
.values()
.stream()
.filter(java.util.Optional::isPresent)
.map(aspect -> ModelUtils.newAspectUnion(_internalAspectUnionClass, aspect.get()))
.collect(Collectors.toList());

return ModelUtils.newAsset(_assetClass, urn, aspects);
});
return ModelUtils.newAsset(_assetClass, urn, aspects);
});
} catch (ModelValidationException e) {
throw RestliUtils.invalidArgumentsException(e.getMessage());
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.linkedin.metadata.dao.ListResult;
import com.linkedin.metadata.dao.UrnAspectEntry;
import com.linkedin.metadata.dao.builder.BaseLocalRelationshipBuilder.LocalRelationshipUpdates;
import com.linkedin.metadata.dao.exception.ModelValidationException;
import com.linkedin.metadata.dao.internal.BaseGraphWriterDAO;
import com.linkedin.metadata.dao.utils.ModelUtils;
import com.linkedin.metadata.dao.utils.RecordUtils;
Expand Down Expand Up @@ -713,6 +714,18 @@ public void testGetSnapshotWithOneAspect() {
assertEquals(snapshot.getAspects().get(0).getAspectFoo(), foo);
}

@Test
public void testGetSnapshotWithModelValidationException() {
FooUrn urn = makeFooUrn(1);
AspectFoo foo = new AspectFoo().setValue("foo");
AspectKey<FooUrn, ? extends RecordTemplate> fooKey = new AspectKey<>(AspectFoo.class, urn, LATEST_VERSION);
Set<AspectKey<FooUrn, ? extends RecordTemplate>> aspectKeys = ImmutableSet.of(fooKey);
when(_mockLocalDAO.get(aspectKeys)).thenThrow(new ModelValidationException("model validation exception"));
String[] aspectNames = new String[]{ModelUtils.getAspectName(AspectFoo.class)};

assertThrows(RestLiServiceException.class, () -> runAndWait(_resource.getSnapshot(urn.toString(), aspectNames)));
}

@Test
public void testGetSnapshotWithAllAspects() {
FooUrn urn = makeFooUrn(1);
Expand Down Expand Up @@ -1487,6 +1500,20 @@ public void testGetAsset() {
assertEquals(asset.getAspectAttributes(), attributes);
}

@Test
public void testGetAssetWithModelValidationException() {
FooUrn urn = makeFooUrn(1);

AspectKey<FooUrn, ? extends RecordTemplate> fooKey = new AspectKey<>(AspectFoo.class, urn, LATEST_VERSION);

Set<AspectKey<FooUrn, ? extends RecordTemplate>> aspectKeys =
ImmutableSet.of(fooKey);
when(_mockLocalDAO.get(aspectKeys)).thenThrow(new ModelValidationException("model validation exception"));

assertThrows(RestLiServiceException.class,
() -> runAndWait(_resource.getAsset(urn.toString(), new String[] { "com.linkedin.testing.AspectFoo" })));
}

@Test
public void testGetNonExistAsset() {
// Test get non existing assets
Expand Down
Loading