2 * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.common;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableMap;
14 import javax.ws.rs.core.Response.Status;
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.opendaylight.yangtools.yang.common.ErrorTag;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
21 * {@link ErrorTag} mapping to HTTP errors. Aside from the mappings defined by
22 * <a href="https://datatracker.ietf.org/doc/html/rfc8040#section-7">RFC8040 section 7</a>, we also define tags which
23 * map to useful {@link Status} codes.
27 public final class ErrorTags {
29 * Error reported when the request is valid, but the resource cannot be accessed. This tag typically maps to
30 * {@link Status#SERVICE_UNAVAILABLE}.
32 // FIXME: redefine as SERVICE_UNAVAILABLE? It would be more obvious
33 public static final ErrorTag RESOURCE_DENIED_TRANSPORT = new ErrorTag("resource-denied-transport");
35 private static final Logger LOG = LoggerFactory.getLogger(ErrorTags.class);
36 private static final ImmutableMap<ErrorTag, Status> WELL_KNOWN_ERROR_TAGS = ImmutableMap.<ErrorTag, Status>builder()
37 .put(ErrorTag.IN_USE, Status.CONFLICT)
38 .put(ErrorTag.INVALID_VALUE, Status.BAD_REQUEST)
39 .put(ErrorTag.TOO_BIG, Status.REQUEST_ENTITY_TOO_LARGE)
40 .put(ErrorTag.MISSING_ATTRIBUTE, Status.BAD_REQUEST)
41 .put(ErrorTag.BAD_ATTRIBUTE, Status.BAD_REQUEST)
42 .put(ErrorTag.UNKNOWN_ATTRIBUTE, Status.BAD_REQUEST)
43 .put(ErrorTag.MISSING_ELEMENT, Status.BAD_REQUEST)
44 .put(ErrorTag.BAD_ELEMENT, Status.BAD_REQUEST)
45 .put(ErrorTag.UNKNOWN_ELEMENT, Status.BAD_REQUEST)
46 .put(ErrorTag.UNKNOWN_NAMESPACE, Status.BAD_REQUEST)
48 .put(ErrorTag.ACCESS_DENIED, Status.FORBIDDEN)
49 .put(ErrorTag.LOCK_DENIED, Status.CONFLICT)
50 .put(ErrorTag.RESOURCE_DENIED, Status.CONFLICT)
51 .put(ErrorTag.ROLLBACK_FAILED, Status.INTERNAL_SERVER_ERROR)
52 .put(ErrorTag.DATA_EXISTS, Status.CONFLICT)
53 .put(ErrorTag.DATA_MISSING, dataMissingHttpStatus())
55 .put(ErrorTag.OPERATION_NOT_SUPPORTED, Status.NOT_IMPLEMENTED)
56 .put(ErrorTag.OPERATION_FAILED, Status.INTERNAL_SERVER_ERROR)
57 .put(ErrorTag.PARTIAL_OPERATION, Status.INTERNAL_SERVER_ERROR)
58 .put(ErrorTag.MALFORMED_MESSAGE, Status.BAD_REQUEST)
59 .put(ErrorTags.RESOURCE_DENIED_TRANSPORT, Status.SERVICE_UNAVAILABLE)
67 * Return the HTTP {@link Status} corresponding to specified {@link ErrorTag}.
69 * @param tag Error tag to map
71 * @throws NullPointerException if {@code tag} is null
73 public static Status statusOf(final ErrorTag tag) {
74 final Status known = WELL_KNOWN_ERROR_TAGS.get(requireNonNull(tag));
75 return known != null ? known : Status.INTERNAL_SERVER_ERROR;
78 private static Status dataMissingHttpStatus() {
79 // Control over the HTTP status reported on "data-missing" conditions. This defaults to disabled,
80 // HTTP status 409 as specified by RFC8040 (and all previous drafts). See the discussion in:
81 // https://www.rfc-editor.org/errata/eid5565
82 // https://mailarchive.ietf.org/arch/msg/netconf/hkVDdHK4xA74NgvXzWP0zObMiyY/
83 final String propName = "org.opendaylight.restconf.eid5565";
84 final String propValue = System.getProperty(propName, "disabled");
87 // RFC7231 interpretation: 404 Not Found
88 LOG.info("RESTCONF data-missing condition is reported as HTTP status 404 (Errata 5565)");
89 return Status.NOT_FOUND;
93 LOG.warn("Unhandled {} value \"{}\", assuming disabled", propName, propValue);
96 // RFC8040 specification: 409 Conflict
97 return Status.CONFLICT;