1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.binding.xml;
17
18 import org.fourthline.cling.binding.staging.MutableAction;
19 import org.fourthline.cling.binding.staging.MutableActionArgument;
20 import org.fourthline.cling.binding.staging.MutableAllowedValueRange;
21 import org.fourthline.cling.binding.staging.MutableService;
22 import org.fourthline.cling.binding.staging.MutableStateVariable;
23 import org.fourthline.cling.model.ValidationException;
24 import org.fourthline.cling.model.meta.ActionArgument;
25 import org.fourthline.cling.model.meta.Service;
26 import org.fourthline.cling.model.meta.StateVariableEventDetails;
27 import org.fourthline.cling.model.types.CustomDatatype;
28 import org.fourthline.cling.model.types.Datatype;
29 import org.seamless.xml.SAXParser;
30 import org.xml.sax.Attributes;
31 import org.xml.sax.InputSource;
32 import org.xml.sax.SAXException;
33
34 import java.io.StringReader;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.logging.Logger;
39
40 import static org.fourthline.cling.binding.xml.Descriptor.Service.ATTRIBUTE;
41 import static org.fourthline.cling.binding.xml.Descriptor.Service.ELEMENT;
42
43
44
45
46
47
48 public class UDA10ServiceDescriptorBinderSAXImpl extends UDA10ServiceDescriptorBinderImpl {
49
50 private static Logger log = Logger.getLogger(ServiceDescriptorBinder.class.getName());
51
52 @Override
53 public <S extends Service> S describe(S undescribedService, String descriptorXml) throws DescriptorBindingException, ValidationException {
54
55 if (descriptorXml == null || descriptorXml.length() == 0) {
56 throw new DescriptorBindingException("Null or empty descriptor");
57 }
58
59 try {
60 log.fine("Reading service from XML descriptor");
61
62 SAXParser parser = new SAXParser();
63
64 MutableService descriptor = new MutableService();
65
66 hydrateBasic(descriptor, undescribedService);
67
68 new RootHandler(descriptor, parser);
69
70 parser.parse(
71 new InputSource(
72
73 new StringReader(descriptorXml.trim())
74 )
75 );
76
77
78 return (S)descriptor.build(undescribedService.getDevice());
79
80 } catch (ValidationException ex) {
81 throw ex;
82 } catch (Exception ex) {
83 throw new DescriptorBindingException("Could not parse service descriptor: " + ex.toString(), ex);
84 }
85 }
86
87 protected static class RootHandler extends ServiceDescriptorHandler<MutableService> {
88
89 public RootHandler(MutableService instance, SAXParser parser) {
90 super(instance, parser);
91 }
92
93 @Override
94 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
95
96
97
98
99
100
101
102
103
104 if (element.equals(ActionListHandler.EL)) {
105 List<MutableAction> actions = new ArrayList<>();
106 getInstance().actions = actions;
107 new ActionListHandler(actions, this);
108 }
109
110 if (element.equals(StateVariableListHandler.EL)) {
111 List<MutableStateVariable> stateVariables = new ArrayList<>();
112 getInstance().stateVariables = stateVariables;
113 new StateVariableListHandler(stateVariables, this);
114 }
115
116 }
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 protected static class ActionListHandler extends ServiceDescriptorHandler<List<MutableAction>> {
148
149 public static final ELEMENT EL = ELEMENT.actionList;
150
151 public ActionListHandler(List<MutableAction> instance, ServiceDescriptorHandler parent) {
152 super(instance, parent);
153 }
154
155 @Override
156 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
157 if (element.equals(ActionHandler.EL)) {
158 MutableAction action = new MutableAction();
159 getInstance().add(action);
160 new ActionHandler(action, this);
161 }
162 }
163
164 @Override
165 public boolean isLastElement(ELEMENT element) {
166 return element.equals(EL);
167 }
168 }
169
170 protected static class ActionHandler extends ServiceDescriptorHandler<MutableAction> {
171
172 public static final ELEMENT EL = ELEMENT.action;
173
174 public ActionHandler(MutableAction instance, ServiceDescriptorHandler parent) {
175 super(instance, parent);
176 }
177
178 @Override
179 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
180 if (element.equals(ActionArgumentListHandler.EL)) {
181 List<MutableActionArgument> arguments = new ArrayList<>();
182 getInstance().arguments = arguments;
183 new ActionArgumentListHandler(arguments, this);
184 }
185 }
186
187 @Override
188 public void endElement(ELEMENT element) throws SAXException {
189 switch (element) {
190 case name:
191 getInstance().name = getCharacters();
192 break;
193 }
194 }
195
196 @Override
197 public boolean isLastElement(ELEMENT element) {
198 return element.equals(EL);
199 }
200 }
201
202 protected static class ActionArgumentListHandler extends ServiceDescriptorHandler<List<MutableActionArgument>> {
203
204 public static final ELEMENT EL = ELEMENT.argumentList;
205
206 public ActionArgumentListHandler(List<MutableActionArgument> instance, ServiceDescriptorHandler parent) {
207 super(instance, parent);
208 }
209
210 @Override
211 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
212 if (element.equals(ActionArgumentHandler.EL)) {
213 MutableActionArgument argument = new MutableActionArgument();
214 getInstance().add(argument);
215 new ActionArgumentHandler(argument, this);
216 }
217 }
218
219 @Override
220 public boolean isLastElement(ELEMENT element) {
221 return element.equals(EL);
222 }
223 }
224
225 protected static class ActionArgumentHandler extends ServiceDescriptorHandler<MutableActionArgument> {
226
227 public static final ELEMENT EL = ELEMENT.argument;
228
229 public ActionArgumentHandler(MutableActionArgument instance, ServiceDescriptorHandler parent) {
230 super(instance, parent);
231 }
232
233 @Override
234 public void endElement(ELEMENT element) throws SAXException {
235 switch (element) {
236 case name:
237 getInstance().name = getCharacters();
238 break;
239 case direction:
240 String directionString = getCharacters();
241 try {
242 getInstance().direction = ActionArgument.Direction.valueOf(directionString.toUpperCase(Locale.ROOT));
243 } catch (IllegalArgumentException ex) {
244
245 log.warning("UPnP specification violation: Invalid action argument direction, assuming 'IN': " + directionString);
246 getInstance().direction = ActionArgument.Direction.IN;
247 }
248 break;
249 case relatedStateVariable:
250 getInstance().relatedStateVariable = getCharacters();
251 break;
252 case retval:
253 getInstance().retval = true;
254 break;
255 }
256 }
257
258 @Override
259 public boolean isLastElement(ELEMENT element) {
260 return element.equals(EL);
261 }
262 }
263
264 protected static class StateVariableListHandler extends ServiceDescriptorHandler<List<MutableStateVariable>> {
265
266 public static final ELEMENT EL = ELEMENT.serviceStateTable;
267
268 public StateVariableListHandler(List<MutableStateVariable> instance, ServiceDescriptorHandler parent) {
269 super(instance, parent);
270 }
271
272 @Override
273 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
274 if (element.equals(StateVariableHandler.EL)) {
275 MutableStateVariable stateVariable = new MutableStateVariable();
276
277 String sendEventsAttributeValue = attributes.getValue(ATTRIBUTE.sendEvents.toString());
278 stateVariable.eventDetails = new StateVariableEventDetails(
279 sendEventsAttributeValue != null && sendEventsAttributeValue.toUpperCase(Locale.ROOT).equals("YES")
280 );
281
282 getInstance().add(stateVariable);
283 new StateVariableHandler(stateVariable, this);
284 }
285 }
286
287 @Override
288 public boolean isLastElement(ELEMENT element) {
289 return element.equals(EL);
290 }
291 }
292
293 protected static class StateVariableHandler extends ServiceDescriptorHandler<MutableStateVariable> {
294
295 public static final ELEMENT EL = ELEMENT.stateVariable;
296
297 public StateVariableHandler(MutableStateVariable instance, ServiceDescriptorHandler parent) {
298 super(instance, parent);
299 }
300
301 @Override
302 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
303 if (element.equals(AllowedValueListHandler.EL)) {
304 List<String> allowedValues = new ArrayList<>();
305 getInstance().allowedValues = allowedValues;
306 new AllowedValueListHandler(allowedValues, this);
307 }
308
309 if (element.equals(AllowedValueRangeHandler.EL)) {
310 MutableAllowedValueRange allowedValueRange = new MutableAllowedValueRange();
311 getInstance().allowedValueRange = allowedValueRange;
312 new AllowedValueRangeHandler(allowedValueRange, this);
313 }
314 }
315
316 @Override
317 public void endElement(ELEMENT element) throws SAXException {
318 switch (element) {
319 case name:
320 getInstance().name = getCharacters();
321 break;
322 case dataType:
323 String dtName = getCharacters();
324 Datatype.Builtin builtin = Datatype.Builtin.getByDescriptorName(dtName);
325 getInstance().dataType = builtin != null ? builtin.getDatatype() : new CustomDatatype(dtName);
326 break;
327 case defaultValue:
328 getInstance().defaultValue = getCharacters();
329 break;
330 }
331 }
332
333 @Override
334 public boolean isLastElement(ELEMENT element) {
335 return element.equals(EL);
336 }
337 }
338
339 protected static class AllowedValueListHandler extends ServiceDescriptorHandler<List<String>> {
340
341 public static final ELEMENT EL = ELEMENT.allowedValueList;
342
343 public AllowedValueListHandler(List<String> instance, ServiceDescriptorHandler parent) {
344 super(instance, parent);
345 }
346
347 @Override
348 public void endElement(ELEMENT element) throws SAXException {
349 switch (element) {
350 case allowedValue:
351 getInstance().add(getCharacters());
352 break;
353 }
354 }
355
356 @Override
357 public boolean isLastElement(ELEMENT element) {
358 return element.equals(EL);
359 }
360 }
361
362 protected static class AllowedValueRangeHandler extends ServiceDescriptorHandler<MutableAllowedValueRange> {
363
364 public static final ELEMENT EL = ELEMENT.allowedValueRange;
365
366 public AllowedValueRangeHandler(MutableAllowedValueRange instance, ServiceDescriptorHandler parent) {
367 super(instance, parent);
368 }
369
370 @Override
371 public void endElement(ELEMENT element) throws SAXException {
372 try {
373 switch (element) {
374 case minimum:
375 getInstance().minimum = Long.valueOf(getCharacters());
376 break;
377 case maximum:
378 getInstance().maximum = Long.valueOf(getCharacters());
379 break;
380 case step:
381 getInstance().step = Long.valueOf(getCharacters());
382 break;
383 }
384 } catch (Exception ex) {
385
386 }
387 }
388
389 @Override
390 public boolean isLastElement(ELEMENT element) {
391 return element.equals(EL);
392 }
393 }
394
395 protected static class ServiceDescriptorHandler<I> extends SAXParser.Handler<I> {
396
397 public ServiceDescriptorHandler(I instance) {
398 super(instance);
399 }
400
401 public ServiceDescriptorHandler(I instance, SAXParser parser) {
402 super(instance, parser);
403 }
404
405 public ServiceDescriptorHandler(I instance, ServiceDescriptorHandler parent) {
406 super(instance, parent);
407 }
408
409 public ServiceDescriptorHandler(I instance, SAXParser parser, ServiceDescriptorHandler parent) {
410 super(instance, parser, parent);
411 }
412
413 @Override
414 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
415 super.startElement(uri, localName, qName, attributes);
416 ELEMENT el = ELEMENT.valueOrNullOf(localName);
417 if (el == null) return;
418 startElement(el, attributes);
419 }
420
421 @Override
422 public void endElement(String uri, String localName, String qName) throws SAXException {
423 super.endElement(uri, localName, qName);
424 ELEMENT el = ELEMENT.valueOrNullOf(localName);
425 if (el == null) return;
426 endElement(el);
427 }
428
429 @Override
430 protected boolean isLastElement(String uri, String localName, String qName) {
431 ELEMENT el = ELEMENT.valueOrNullOf(localName);
432 return el != null && isLastElement(el);
433 }
434
435 public void startElement(ELEMENT element, Attributes attributes) throws SAXException {
436
437 }
438
439 public void endElement(ELEMENT element) throws SAXException {
440
441 }
442
443 public boolean isLastElement(ELEMENT element) {
444 return false;
445 }
446 }
447
448 }