use of com.linkedin.restli.restspec.ServiceErrorSchema in project rest.li by linkedin.
the class ServiceErrorGatheringVisitor method checkServiceErrors.
/**
* Given a record which includes {@link ServiceErrorsSchema}, collects all the defined service errors and returns
* true if any service errors are encountered.
*
* @param record record which includes {@link ServiceErrorsSchema}
* @param isResourceLevel true if checking from the context of a resource
* @return true if any service error is encountered
*/
private boolean checkServiceErrors(RecordTemplate record, boolean isResourceLevel) {
final ServiceErrorsSchema serviceErrorsSchema = new ServiceErrorsSchema(record.data());
if (serviceErrorsSchema.hasServiceErrors()) {
final Map<String, ServiceErrorSchema> serviceErrorMap = serviceErrorsSchema.getServiceErrors().stream().collect(Collectors.toMap(ServiceErrorSchema::getCode, Function.identity()));
_serviceErrors.putAll(serviceErrorMap);
if (isResourceLevel) {
_resourceLevelServiceErrors.putAll(serviceErrorMap);
}
return true;
}
return false;
}
use of com.linkedin.restli.restspec.ServiceErrorSchema in project rest.li by linkedin.
the class ResourceModelEncoder method buildServiceErrors.
/**
* Given a list of service errors, returns a service error schema array record.
*
* @param serviceErrors list of service errors to build, assumed to be non-null and non-empty
* @return service error schema array
*/
private ServiceErrorSchemaArray buildServiceErrors(final List<ServiceError> serviceErrors) {
final ServiceErrorSchemaArray serviceErrorSchemaArray = new ServiceErrorSchemaArray();
// For each service error, build a service error schema and append it to the service error schema array
for (ServiceError serviceError : serviceErrors) {
ServiceErrorSchema serviceErrorSchema = new ServiceErrorSchema().setStatus(serviceError.httpStatus().getCode()).setCode(serviceError.code());
final String message = serviceError.message();
if (message != null) {
serviceErrorSchema.setMessage(message);
}
final Class<?> errorDetailType = serviceError.errorDetailType();
if (errorDetailType != null) {
serviceErrorSchema.setErrorDetailType(errorDetailType.getCanonicalName());
}
if (serviceError instanceof ParametersServiceError) {
final String[] parameterNames = ((ParametersServiceError) serviceError).parameterNames();
if (parameterNames != null && parameterNames.length != 0) {
serviceErrorSchema.setParameters(new StringArray(Arrays.asList(parameterNames)));
}
}
serviceErrorSchemaArray.add(serviceErrorSchema);
}
return serviceErrorSchemaArray;
}
use of com.linkedin.restli.restspec.ServiceErrorSchema in project rest.li by linkedin.
the class SnapshotGenerator method findErrorDetailTypeModels.
/**
* For a given record that includes the {@link ServiceErrorsSchema} record, keep track of all referenced
* error detail type models.
*
* @param schema record that includes the {@link ServiceErrorsSchema}
* @param foundTypes running mapping of found data schemas
* @param typeOrder running, ordered list of found data schemas
*/
private void findErrorDetailTypeModels(RecordTemplate schema, Map<String, NamedDataSchema> foundTypes, List<NamedDataSchema> typeOrder) {
// Wrap the underlying data map in the shared schema interface
final ServiceErrorsSchema serviceErrorsSchema = new ServiceErrorsSchema(schema.data());
// For each service error, inspect its error detail type field and keep track of all referenced types
final ServiceErrorSchemaArray serviceErrorSchemaArray = serviceErrorsSchema.getServiceErrors();
if (serviceErrorSchemaArray != null) {
for (ServiceErrorSchema serviceErrorSchema : serviceErrorSchemaArray) {
if (serviceErrorSchema.hasErrorDetailType()) {
recordType(serviceErrorSchema.getErrorDetailType(), foundTypes, typeOrder);
}
}
}
}
use of com.linkedin.restli.restspec.ServiceErrorSchema in project rest.li by linkedin.
the class ResourceCompatibilityChecker method checkMethodServiceErrors.
/**
* Checks the compatibility of method-level service errors. All service error compatibility logic is checked
* semantically at the method level, so this method takes the union of the resource-level errors (from the context)
* and the method-level errors to compute the compatibility.
*
* @param prevMethodServiceErrors previous method-level service errors
* @param currMethodServiceErrors current method-level service errors
*/
private void checkMethodServiceErrors(RecordDataSchema.Field field, ServiceErrorSchemaArray prevMethodServiceErrors, ServiceErrorSchemaArray currMethodServiceErrors) {
assert field != null;
_infoPath.push(field.getName());
// Compute the union of resource and method service errors separately for previous and current
TreeResourceContext state = _resourceContexts.peek();
Map<String, ServiceErrorSchema> prevServiceErrorUnion = getServiceErrorUnion(state._prevResourceLevelErrors, prevMethodServiceErrors);
Map<String, ServiceErrorSchema> currServiceErrorUnion = getServiceErrorUnion(state._currResourceLevelErrors, currMethodServiceErrors);
// Compute the union of resource and method service errors for both previous and current together
Set<String> serviceErrorCodeUnion = new HashSet<>();
serviceErrorCodeUnion.addAll(prevServiceErrorUnion.keySet());
serviceErrorCodeUnion.addAll(currServiceErrorUnion.keySet());
// Compute the intersection and both complementary subsets of previous and current service error codes
Set<String> serviceErrorCodeIntersection = new HashSet<>();
Set<String> removedServiceErrorCodes = new HashSet<>();
Set<String> newServiceErrorCodes = new HashSet<>();
for (String code : serviceErrorCodeUnion) {
if (prevServiceErrorUnion.containsKey(code) && currServiceErrorUnion.containsKey(code)) {
serviceErrorCodeIntersection.add(code);
} else if (prevServiceErrorUnion.containsKey(code)) {
removedServiceErrorCodes.add(code);
} else {
newServiceErrorCodes.add(code);
}
}
// Check to ensure that retained service errors are compatible
for (String code : serviceErrorCodeIntersection) {
ServiceErrorSchema prevServiceErrorSchema = prevServiceErrorUnion.get(code);
ServiceErrorSchema currServiceErrorSchema = currServiceErrorUnion.get(code);
_infoPath.push(code);
checkServiceErrorSchema(prevServiceErrorSchema, currServiceErrorSchema);
_infoPath.pop();
}
// Add info about removed service errors
for (String code : removedServiceErrorCodes) {
_infoMap.addRestSpecInfo(CompatibilityInfo.Type.SERVICE_ERROR_REMOVED, _infoPath, code);
}
// Add info about new service errors
for (String code : newServiceErrorCodes) {
_infoMap.addRestSpecInfo(CompatibilityInfo.Type.SERVICE_ERROR_ADDED, _infoPath, code);
}
_infoPath.pop();
}
use of com.linkedin.restli.restspec.ServiceErrorSchema in project rest.li by linkedin.
the class RestLiResourceRelationship method findDataModels.
private void findDataModels() {
final ResourceSchemaVisitior visitor = new BaseResourceSchemaVisitor() {
@Override
public void visitResourceSchema(VisitContext visitContext, ResourceSchema resourceSchema) {
final String schema = resourceSchema.getSchema();
// ActionSet resources do not have a schema
if (schema != null) {
final NamedDataSchema schemaSchema = extractSchema(schema);
if (schemaSchema != null) {
connectSchemaToResource(visitContext, schemaSchema);
}
}
}
@Override
public void visitCollectionResource(VisitContext visitContext, CollectionSchema collectionSchema) {
connectErrorDetailTypeToResource(visitContext, collectionSchema);
final IdentifierSchema id = collectionSchema.getIdentifier();
final NamedDataSchema typeSchema = extractSchema(id.getType());
if (typeSchema != null) {
connectSchemaToResource(visitContext, typeSchema);
}
final String params = id.getParams();
if (params != null) {
final NamedDataSchema paramsSchema = extractSchema(params);
if (paramsSchema != null) {
connectSchemaToResource(visitContext, paramsSchema);
}
}
}
@Override
public void visitAssociationResource(VisitContext visitContext, AssociationSchema associationSchema) {
connectErrorDetailTypeToResource(visitContext, associationSchema);
for (AssocKeySchema key : associationSchema.getAssocKeys()) {
final NamedDataSchema keyTypeSchema = extractSchema(key.getType());
if (keyTypeSchema != null) {
connectSchemaToResource(visitContext, keyTypeSchema);
}
}
}
@Override
public void visitSimpleResource(VisitContext visitContext, SimpleSchema simpleSchema) {
connectErrorDetailTypeToResource(visitContext, simpleSchema);
}
@Override
public void visitActionSetResource(VisitContext visitContext, ActionsSetSchema actionSetSchema) {
connectErrorDetailTypeToResource(visitContext, actionSetSchema);
}
@Override
public void visitParameter(VisitContext visitContext, RecordTemplate parentResource, Object parentMethodSchema, ParameterSchema parameterSchema) {
String parameterTypeString = parameterSchema.getType();
if (// the parameter type field contains a inline schema, so we traverse into it
isInlineSchema(parameterTypeString)) {
visitInlineSchema(visitContext, parameterTypeString);
} else {
final NamedDataSchema schema;
// grab the schema name from it
if (parameterSchema.hasItems()) {
schema = extractSchema(parameterSchema.getItems());
} else // the only remaining possibility is that the type field contains the name of a data schema
{
schema = extractSchema(parameterTypeString);
}
if (schema != null) {
connectSchemaToResource(visitContext, schema);
}
}
}
@Override
public void visitRestMethod(VisitContext visitContext, RecordTemplate parentResource, RestMethodSchema restMethodSchema) {
connectErrorDetailTypeToResource(visitContext, restMethodSchema);
}
@Override
public void visitFinder(VisitContext visitContext, RecordTemplate parentResource, FinderSchema finderSchema) {
connectErrorDetailTypeToResource(visitContext, finderSchema);
final MetadataSchema metadata = finderSchema.getMetadata();
if (metadata != null) {
final NamedDataSchema metadataTypeSchema = extractSchema(metadata.getType());
if (metadataTypeSchema != null) {
connectSchemaToResource(visitContext, metadataTypeSchema);
}
}
}
@Override
public void visitBatchFinder(VisitContext visitContext, RecordTemplate parentResource, BatchFinderSchema batchFinderSchema) {
connectErrorDetailTypeToResource(visitContext, batchFinderSchema);
final MetadataSchema metadata = batchFinderSchema.getMetadata();
if (metadata != null) {
final NamedDataSchema metadataTypeSchema = extractSchema(metadata.getType());
if (metadataTypeSchema != null) {
connectSchemaToResource(visitContext, metadataTypeSchema);
}
}
}
@Override
public void visitAction(VisitContext visitContext, RecordTemplate parentResource, ResourceLevel resourceLevel, ActionSchema actionSchema) {
connectErrorDetailTypeToResource(visitContext, actionSchema);
final String returns = actionSchema.getReturns();
if (returns != null) {
if (// the parameter type field contains a inline schema, so we traverse into it
isInlineSchema(returns)) {
visitInlineSchema(visitContext, returns);
} else // otherwise the type field contains the name of a data schema
{
final NamedDataSchema returnsSchema = extractSchema(returns);
if (returnsSchema != null) {
connectSchemaToResource(visitContext, returnsSchema);
}
}
}
final StringArray throwsArray = actionSchema.getThrows();
if (throwsArray != null) {
for (String errorName : throwsArray) {
final NamedDataSchema errorSchema = extractSchema(errorName);
if (errorSchema != null) {
connectSchemaToResource(visitContext, errorSchema);
}
}
}
}
private boolean isInlineSchema(String schemaString) {
return schemaString.startsWith("{");
}
private void visitInlineSchema(VisitContext visitContext, String schemaString) {
DataSchema schema = DataTemplateUtil.parseSchema(schemaString, _schemaResolver, SchemaFormatType.PDSC);
if (schema instanceof ArrayDataSchema) {
DataSchema itemSchema = ((ArrayDataSchema) schema).getItems();
if (itemSchema instanceof NamedDataSchema) {
connectSchemaToResource(visitContext, (NamedDataSchema) itemSchema);
}
}
if (schema instanceof MapDataSchema) {
DataSchema valueSchema = ((MapDataSchema) schema).getValues();
if (valueSchema instanceof NamedDataSchema) {
connectSchemaToResource(visitContext, (NamedDataSchema) valueSchema);
}
}
}
private void connectSchemaToResource(VisitContext visitContext, final NamedDataSchema schema) {
final Node<NamedDataSchema> schemaNode = _relationships.get(schema);
_dataModels.put(schema.getFullName(), schema);
final DataSchemaTraverse traveler = new DataSchemaTraverse();
traveler.traverse(schema, (path, nestedSchema) -> {
if (nestedSchema instanceof RecordDataSchema && nestedSchema != schema) {
final RecordDataSchema nestedRecordSchema = (RecordDataSchema) nestedSchema;
_dataModels.put(nestedRecordSchema.getFullName(), nestedRecordSchema);
final Node<RecordDataSchema> node = _relationships.get(nestedRecordSchema);
schemaNode.addAdjacentNode(node);
}
});
final Node<ResourceSchema> resourceNode = _relationships.get(visitContext.getParentSchema());
resourceNode.addAdjacentNode(schemaNode);
schemaNode.addAdjacentNode(resourceNode);
}
/**
* Given a record which includes {@link ServiceErrorsSchema}, scans for service errors and connects the error
* detail type field (if any) to the resource.
*
* @param visitContext visit context
* @param record record which includes {@link ServiceErrorsSchema}
*/
private void connectErrorDetailTypeToResource(VisitContext visitContext, RecordTemplate record) {
final ServiceErrorsSchema serviceErrorsSchema = new ServiceErrorsSchema(record.data());
if (serviceErrorsSchema.getServiceErrors() != null) {
for (ServiceErrorSchema serviceErrorSchema : serviceErrorsSchema.getServiceErrors()) {
if (serviceErrorSchema.hasErrorDetailType()) {
final NamedDataSchema errorDetailTypeSchema = extractSchema(serviceErrorSchema.getErrorDetailType());
if (errorDetailTypeSchema != null) {
connectSchemaToResource(visitContext, errorDetailTypeSchema);
}
}
}
}
}
};
ResourceSchemaCollection.visitResources(_resourceSchemas.getResources().values(), visitor);
}
Aggregations