blob: ce4c5cd9a41144d4701785987caba41ddd0fb56b [file] [log] [blame]
Henry Yu830b5dc2017-11-16 10:44:45 -05001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.restconf.restconfmanager;
18
19import org.onosproject.net.DeviceId;
20import org.onosproject.yang.model.ResourceId;
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
24import javax.ws.rs.core.UriBuilder;
25import java.io.UnsupportedEncodingException;
26import java.net.URI;
27import java.net.URLDecoder;
28
29import static org.onosproject.d.config.DeviceResourceIds.toResourceId;
30import static org.onosproject.d.config.ResourceIds.concat;
31import static org.onosproject.d.config.ResourceIds.removeRootNode;
32import static org.onosproject.restconf.utils.RestconfUtils.convertUriToRid;
33
34/**
35 * Representation of the data resource identifiers used by the RESTCONF manager.
36 * <p>
37 * For a data resource under the device hierarchy, the restconf manager needs
38 * to maintain 2 separate resource IDs, one used by the
39 * the Dynamic Config, and the other by the Yang
40 * Runtime. (i.e., The resource IDs used by the dyn-config contain the
41 * "/devices/device" prefix, whereas the ones used by Yang Runtime do not.)
42 * This class provides the interface for the RESTCONF manager to use these
43 * 2 resource IDs.
44 */
45public final class DataResourceLocator {
46
47 private static final Logger log = LoggerFactory.getLogger(DataResourceLocator.class);
48
49 private static final String DATA_ROOT_DIR = "/onos/restconf/data";
50 private static final String DEVICE_REGEX = "/devices/device=[^/]+";
51 private static final String DEVICE_URI_PREFIX = DATA_ROOT_DIR + "/devices/device=";
52
53 /**
54 * The resource ID used by Yang Runtime to refer to
55 * a data node.
56 */
57 private ResourceId yrtResourceId;
58
59 /**
60 * The resource ID used by the Dynamic Config to refer
61 * to a data node.
62 */
63 private ResourceId dcsResourceId;
64
65 /**
66 * URI used by RESTCONF to refer to a data node.
67 */
68 private URI uriForRestconf;
69
70 /**
71 * URI used by Yang Runtime to refer to a data node.
72 */
73 private URI uriForYangRuntime;
74
75 // Suppresses default constructor, ensuring non-instantiability.
76 private DataResourceLocator() {
77 }
78
79 private DataResourceLocator(ResourceId yrtResourceId,
80 ResourceId dcsResourceId,
81 URI uriForRestconf,
82 URI uriForYangRuntime) {
83 this.yrtResourceId = yrtResourceId;
84 this.dcsResourceId = dcsResourceId;
85 this.uriForRestconf = uriForRestconf;
86 this.uriForYangRuntime = uriForYangRuntime;
87 }
88
89 public ResourceId ridForDynConfig() {
90 return dcsResourceId;
91 }
92
93 public ResourceId ridForYangRuntime() {
94 return yrtResourceId;
95 }
96
97 public URI uriForRestconf() {
98 return uriForRestconf;
99 }
100
101 public URI uriForYangRuntime() {
102 return uriForYangRuntime;
103 }
104
105 /**
106 * Creates a DataResourceLocator object based on a given URI.
107 *
108 * @param uri given URI
109 * @return instantiated DataResourceLocator object
110 */
111 public static DataResourceLocator newInstance(URI uri) {
112 URI uriForYangRuntime = uriForYangRuntime(uri);
113 ResourceId yrtResourceId = ridForYangRuntime(uriForYangRuntime);
114 /*
115 * If the given URI starts with "devices/device" prefix, then form the
116 * resource ID used by dyn-config by adding the prefix to the resource ID
117 * used by YANG runtime. Otherwise the two resource IDs are the same.
118 */
119 ResourceId dcsResourceId = isDeviceResource(uri) ?
120 addDevicePrefix(yrtResourceId, getDeviceId(uri)) : yrtResourceId;
121
122 return new DataResourceLocator(yrtResourceId, dcsResourceId,
123 uri, uriForYangRuntime);
124 }
125
126 private static URI uriForYangRuntime(URI uriForRestconf) {
127 return isDeviceResource(uriForRestconf) ?
128 removeDeviceProxyPrefix(uriForRestconf) : uriForRestconf;
129 }
130
131 private static ResourceId ridForYangRuntime(URI uriForYangRuntime) {
132 ResourceId yrtResourceId = convertUriToRid(uriForYangRuntime);
133 if (yrtResourceId == null) {
134 yrtResourceId = ResourceId.builder().addBranchPointSchema("/", null).build();
135 }
136
137 return yrtResourceId;
138 }
139
140 private static URI removeDeviceProxyPrefix(URI uri) {
141 if (uri == null) {
142 return null;
143 }
144 UriBuilder builder = UriBuilder.fromUri(uri);
145 String newPath = rmDeviceStr(uri.getRawPath());
146 builder.replacePath(newPath);
147
148 return builder.build();
149 }
150
151 private static String rmDeviceStr(String uriStr) {
152 if (uriStr == null) {
153 return null;
154
155 }
156 return uriStr.replaceFirst(DEVICE_REGEX, "");
157 }
158
159 private static DeviceId getDeviceId(URI uri) {
160 return DeviceId.deviceId(deviceIdStr(uri.getRawPath()));
161 }
162
163 private static String deviceIdStr(String rawPath) {
164 String[] segments = rawPath.split("/");
165 try {
166 for (String s : segments) {
167 if (s.startsWith("device=")) {
168 return URLDecoder.decode(s.substring("device=".length()), "utf-8");
169 }
170 }
171 } catch (UnsupportedEncodingException e) {
172 log.error("deviceIdStr: caught UnsupportedEncodingException");
173 log.debug("deviceIdStr: ", e);
174 }
175 return null;
176 }
177
178 private static ResourceId addDevicePrefix(ResourceId rid, DeviceId did) {
179 return concat(toResourceId(did), removeRootNode(rid));
180 }
181
182 private static boolean isDeviceResource(URI uri) {
183 if (uri == null) {
184 return false;
185 }
186 return uri.getRawPath().startsWith(DEVICE_URI_PREFIX);
187 }
188}