1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.model;
17
18 import java.net.URI;
19 import java.net.URISyntaxException;
20 import java.util.ArrayList;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.logging.Logger;
25
26 import org.fourthline.cling.model.meta.Device;
27 import org.fourthline.cling.model.meta.Icon;
28 import org.fourthline.cling.model.meta.Service;
29 import org.fourthline.cling.model.resource.Resource;
30 import org.seamless.util.URIUtil;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class Namespace {
60
61 final private static Logger log = Logger.getLogger(Namespace.class.getName());
62
63 public static final String DEVICE = "/dev";
64 public static final String SERVICE = "/svc";
65 public static final String CONTROL = "/action";
66 public static final String EVENTS = "/event";
67 public static final String DESCRIPTOR_FILE = "/desc";
68 public static final String CALLBACK_FILE = "/cb";
69
70 final protected URI basePath;
71 final protected String decodedPath;
72
73 public Namespace() {
74 this("");
75 }
76
77 public Namespace(String basePath) {
78 this(URI.create(basePath));
79 }
80
81 public Namespace(URI basePath) {
82 this.basePath = basePath;
83 this.decodedPath = basePath.getPath();
84 }
85
86 public URI getBasePath() {
87 return basePath;
88 }
89
90 public URI getPath(Device device) {
91 return appendPathToBaseURI(getDevicePath(device));
92 }
93
94 public URI getPath(Service service) {
95 return appendPathToBaseURI(getServicePath(service));
96 }
97
98 public URI getDescriptorPath(Device device) {
99 return appendPathToBaseURI(getDevicePath(device.getRoot()) + DESCRIPTOR_FILE);
100 }
101
102
103
104
105 public String getDescriptorPathString(Device device) {
106 return decodedPath + getDevicePath(device.getRoot()) + DESCRIPTOR_FILE;
107 }
108
109 public URI getDescriptorPath(Service service) {
110 return appendPathToBaseURI(getServicePath(service) + DESCRIPTOR_FILE);
111 }
112
113 public URI getControlPath(Service service) {
114 return appendPathToBaseURI(getServicePath(service) + CONTROL);
115 }
116
117 public URI getIconPath(Icon icon) {
118 return appendPathToBaseURI(getDevicePath(icon.getDevice()) + "/" + icon.getUri().toString());
119 }
120
121 public URI getEventSubscriptionPath(Service service) {
122 return appendPathToBaseURI(getServicePath(service) + EVENTS);
123 }
124
125 public URI getEventCallbackPath(Service service) {
126 return appendPathToBaseURI(getServicePath(service) + EVENTS + CALLBACK_FILE);
127 }
128
129
130
131
132 public String getEventCallbackPathString(Service service) {
133 return decodedPath + getServicePath(service) + EVENTS + CALLBACK_FILE;
134 }
135
136 public URI prefixIfRelative(Device device, URI uri) {
137 if (!uri.isAbsolute() && !uri.getPath().startsWith("/")) {
138 return appendPathToBaseURI(getDevicePath(device) + "/" + uri);
139 }
140 return uri;
141 }
142
143 public boolean isControlPath(URI uri) {
144 return uri.toString().endsWith(Namespace.CONTROL);
145 }
146
147 public boolean isEventSubscriptionPath(URI uri) {
148 return uri.toString().endsWith(Namespace.EVENTS);
149 }
150
151 public boolean isEventCallbackPath(URI uri) {
152 return uri.toString().endsWith(Namespace.CALLBACK_FILE);
153 }
154
155 public Resource[] getResources(Device device) throws ValidationException {
156 if (!device.isRoot()) return null;
157
158 Set<Resource> resources = new HashSet<>();
159 List<ValidationError> errors = new ArrayList<>();
160
161 log.fine("Discovering local resources of device graph");
162 Resource[] discoveredResources = device.discoverResources(this);
163 for (Resource resource : discoveredResources) {
164 log.finer("Discovered: " + resource);
165 if (!resources.add(resource)) {
166 log.finer("Local resource already exists, queueing validation error");
167 errors.add(new ValidationError(
168 getClass(),
169 "resources",
170 "Local URI namespace conflict between resources of device: " + resource
171 ));
172 }
173 }
174 if (errors.size() > 0) {
175 throw new ValidationException("Validation of device graph failed, call getErrors() on exception", errors);
176 }
177 return resources.toArray(new Resource[resources.size()]);
178 }
179
180 protected URI appendPathToBaseURI(String path) {
181 try {
182
183 return
184 new URI(
185 basePath.getScheme(),
186 null,
187 basePath.getHost(),
188 basePath.getPort(),
189 decodedPath + path,
190 null,
191 null
192 );
193 } catch (URISyntaxException e) {
194 return URI.create(basePath + path);
195 }
196 }
197
198 protected String getDevicePath(Device device) {
199 if (device.getIdentity().getUdn() == null) {
200 throw new IllegalStateException("Can't generate local URI prefix without UDN");
201 }
202 StringBuilder s = new StringBuilder();
203 s.append(DEVICE).append("/");
204
205 s.append(URIUtil.encodePathSegment(device.getIdentity().getUdn().getIdentifierString()));
206 return s.toString();
207 }
208
209 protected String getServicePath(Service service) {
210 if (service.getServiceId() == null) {
211 throw new IllegalStateException("Can't generate local URI prefix without service ID");
212 }
213 StringBuilder s = new StringBuilder();
214 s.append(SERVICE);
215 s.append("/");
216 s.append(service.getServiceId().getNamespace());
217 s.append("/");
218 s.append(service.getServiceId().getId());
219 return getDevicePath(service.getDevice()) + s.toString();
220 }
221 }