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 package example.localservice; 16 17 import org.fourthline.cling.binding.annotations.*; 18 19 /** 20 * Mapping state variables 21 * <p> 22 * The following example only has a single field named <code>power</code>, 23 * however, the UPnP service requires two state variables. In this case 24 * you declare the UPnP state variables with annotations on the class: 25 * </p> 26 * <a class="citation" href="javacode://this" style="include:INC1"/> 27 * <p> 28 * The <code>power</code> field is not mapped to the state variables and 29 * you are free to design your service internals as you like. Did you 30 * notice that you never declared the datatype of your state variables? 31 * Also, how can Cling read the "current state" of your service for GENA 32 * subscribers or when a "query state variable" action is received? 33 * Both questions have the same answer. 34 * </p> 35 * <p> 36 * Let's consider GENA eventing first. This example has an evented 37 * state variable called <code>Status</code>, and if a control point 38 * subscribes to the service to be notified of changes, how 39 * will Cling obtain the current status? If you'd have used 40 * <code>@UpnpStateVariable</code> on your fields, Cling would then 41 * directly access field values through Java Reflection. On the other 42 * hand if you declare state variables not on fields but on your service 43 * class, Cling will during binding detect any JavaBean-style getter 44 * method that matches the derived property name of the state variable. 45 * </p> 46 * <p> 47 * In other words, Cling will discover that your class has a 48 * <code>getStatus()</code> method. It doesn't matter if that method 49 * is also an action-mapped method, the important thing is that it 50 * matches JavaBean property naming conventions. The <code>Status</code> 51 * UPnP state variable maps to the <code>status</code> property, which 52 * is expected to have a <code>getStatus()</code> accessor method. 53 * Cling will use this method to read the current state of your 54 * service for GENA subscribers and when the state variable is 55 * manually queried. 56 * </p> 57 * <p> 58 * If you do not provide a UPnP datatype name in your 59 * <code>@UpnpStateVariable</code> annotation, Cling will use the type 60 * of the annotated field or discovered JavaBean getter method to 61 * figure out the type. The supported default mappings between Java types 62 * and UPnP datatypes are shown in the following table: 63 * </p> 64 * <table class="infotable halfwidth" border="1"> 65 * <thead><tr> 66 * <th>Java Type</th> 67 * <th class="halfwidth">UPnP Datatype</th> 68 * </tr></thead> 69 * <tbody> 70 * <tr><td><code>java.lang.Boolean</code></td><td><code>boolean</code></td></tr> 71 * <tr><td><code>boolean</code></td><td><code>boolean</code></td></tr> 72 * <tr><td><code>java.lang.Short</code></td><td><code>i2</code></td></tr> 73 * <tr><td><code>short</code></td><td><code>i2</code></td></tr> 74 * <tr><td><code>java.lang.Integer</code></td><td><code>i4</code></td></tr> 75 * <tr><td><code>int</code></td><td><code>i4</code></td></tr> 76 * <tr><td><code>org.fourthline.cling.model.types.UnsignedIntegerOneByte</code></td><td><code>ui1</code></td></tr> 77 * <tr><td><code>org.fourthline.cling.model.types.UnsignedIntegerTwoBytes</code></td><td><code>ui2</code></td></tr> 78 * <tr><td><code>org.fourthline.cling.model.types.UnsignedIntegerFourBytes</code></td><td><code>ui4</code></td></tr> 79 * <tr><td><code>java.lang.Float</code></td><td><code>r4</code></td></tr> 80 * <tr><td><code>float</code></td><td><code>r4</code></td></tr> 81 * <tr><td><code>java.lang.Double</code></td><td><code>float</code></td></tr> 82 * <tr><td><code>double</code></td><td><code>float</code></td></tr> 83 * <tr><td><code>java.lang.Character</code></td><td><code>char</code></td></tr> 84 * <tr><td><code>char</code></td><td><code>char</code></td></tr> 85 * <tr><td><code>java.lang.String</code></td><td><code>string</code></td></tr> 86 * <tr><td><code>java.util.Calendar</code></td><td><code>datetime</code></td></tr> 87 * <tr><td><code>byte[]</code></td><td><code>bin.base64</code></td></tr> 88 * <tr><td><code>java.net.URI</code></td><td><code>uri</code></td></tr> 89 * </tbody> 90 * </table> 91 * 92 */ 93 @UpnpService( // DOC:INC1 94 serviceId = @UpnpServiceId("SwitchPower"), 95 serviceType = @UpnpServiceType(value = "SwitchPower", version = 1) 96 97 ) 98 @UpnpStateVariables( 99 { 100 @UpnpStateVariable( 101 name = "Target", 102 defaultValue = "0", 103 sendEvents = false 104 ), 105 @UpnpStateVariable( 106 name = "Status", 107 defaultValue = "0" 108 ) 109 } 110 ) 111 public class SwitchPowerAnnotatedClass { 112 113 private boolean power; 114 115 @UpnpAction 116 public void setTarget(@UpnpInputArgument(name = "NewTargetValue") 117 boolean newTargetValue) { 118 power = newTargetValue; 119 System.out.println("Switch is: " + power); 120 } 121 122 @UpnpAction(out = @UpnpOutputArgument(name = "RetTargetValue")) 123 public boolean getTarget() { 124 return power; 125 } 126 127 @UpnpAction(out = @UpnpOutputArgument(name = "ResultStatus")) 128 public boolean getStatus() { 129 return power; 130 } 131 } // DOC:INC1