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