View Javadoc
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 }