1 /*
2 * Copyright (C) 2013 4th Line GmbH, Switzerland
3 *
4 * The contents of this file are subject to the terms of either the GNU
5 * Lesser General Public License Version 2 or later ("LGPL") or the
6 * Common Development and Distribution License Version 1 or later
7 * ("CDDL") (collectively, the "License"). You may not use this file
8 * except in compliance with the License. See LICENSE.txt for more
9 * information.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 */
15
16 package org.fourthline.cling.model;
17
18 import java.util.logging.Logger;
19
20 import org.fourthline.cling.model.types.Datatype;
21 import org.fourthline.cling.model.types.InvalidValueException;
22
23 /**
24 * Encapsulates a variable or argument value, validates and transforms it from/to a string representaion.
25 *
26 * @author Christian Bauer
27 */
28 public class VariableValue {
29
30 final private static Logger log = Logger.getLogger(VariableValue.class.getName());
31
32 final private Datatype datatype;
33 final private Object value;
34
35 /**
36 * Creates and validates a variable value.
37 * <p>
38 * If the given value is a <code>String</code>, it will be converted
39 * with {@link org.fourthline.cling.model.types.Datatype#valueOf(String)}. Any
40 * other value will be checked, whether it matches the datatype and if its
41 * string representation is valid in XML documents (unicode character test).
42 * </p>
43 * <p>
44 * Note that for performance reasons, validation of a non-string value
45 * argument is skipped if executed on an Android runtime!
46 * </p>
47 *
48 * @param datatype The type of the variable.
49 * @param value The value of the variable.
50 * @throws InvalidValueException If the value is invalid for the given datatype, or if
51 * its string representation is invalid in XML.
52 */
53 public VariableValue(Datatype datatype, Object value) throws InvalidValueException {
54 this.datatype = datatype;
55 this.value = value instanceof String ? datatype.valueOf((String) value) : value;
56
57 if (ModelUtil.ANDROID_RUNTIME) return; // Skipping validation on Android
58
59 // We can skip this validation because we can catch invalid values
60 // of any remote service (action invocation, event value) before, they are
61 // strings. The datatype's valueOf() will take care of that. The validations
62 // are really only used when a developer prepares input arguments for an action
63 // invocation or when a local service returns a wrong value.
64
65 // In the first case the developer will get an exception when executing the
66 // action, if his action input argument value was of the wrong type. Or,
67 // an XML processing error will occur as soon as the SOAP message is handled,
68 // if the value contained invalid characters.
69
70 // The second case indicates a bug in the local service, either metadata (state
71 // variable type) or implementation (action method return value). This will
72 // most likely be caught by the metadata/annotation binder when the service is
73 // created.
74
75 if (!getDatatype().isValid(getValue()))
76 throw new InvalidValueException("Invalid value for " + getDatatype() +": " + getValue());
77
78 logInvalidXML(toString());
79 }
80
81 public Datatype getDatatype() {
82 return datatype;
83 }
84
85 public Object getValue() {
86 return value;
87 }
88
89 protected void logInvalidXML(String s) {
90 // Just display warnings. PS3 Media server sends null char in DIDL-Lite
91 // http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
92 int cp;
93 int i = 0;
94 while (i < s.length()) {
95 cp = s.codePointAt(i);
96 if (!(cp == 0x9 || cp == 0xA || cp == 0xD ||
97 (cp >= 0x20 && cp <= 0xD7FF) ||
98 (cp >= 0xE000 && cp <= 0xFFFD) ||
99 (cp >= 0x10000 && cp <= 0x10FFFF))) {
100 log.warning("Found invalid XML char code: " + cp);
101 }
102 i += Character.charCount(cp);
103 }
104 }
105
106 @Override
107 public String toString() {
108 return getDatatype().getString(getValue());
109 }
110
111 }