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 }