1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.model.meta;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.logging.Logger;
23
24 import org.fourthline.cling.model.ServiceReference;
25 import org.fourthline.cling.model.ValidationError;
26 import org.fourthline.cling.model.ValidationException;
27 import org.fourthline.cling.model.types.Datatype;
28 import org.fourthline.cling.model.types.ServiceId;
29 import org.fourthline.cling.model.types.ServiceType;
30
31
32
33
34
35
36 public abstract class Service<D extends Device, S extends Service> {
37
38 final private static Logger log = Logger.getLogger(Service.class.getName());
39
40 final private ServiceType serviceType;
41 final private ServiceId serviceId;
42
43
44 final private Map<String, Action> actions = new HashMap<>();
45 final private Map<String, StateVariable> stateVariables = new HashMap<>();
46
47
48 private D device;
49
50 public Service(ServiceType serviceType, ServiceId serviceId) throws ValidationException {
51 this(serviceType, serviceId, null, null);
52 }
53
54 public Service(ServiceType serviceType, ServiceId serviceId,
55 Action<S>[] actions, StateVariable<S>[] stateVariables) throws ValidationException {
56
57 this.serviceType = serviceType;
58 this.serviceId = serviceId;
59
60 if (actions != null) {
61 for (Action action : actions) {
62 this.actions.put(action.getName(), action);
63 action.setService(this);
64 }
65 }
66
67 if (stateVariables != null) {
68 for (StateVariable stateVariable : stateVariables) {
69 this.stateVariables.put(stateVariable.getName(), stateVariable);
70 stateVariable.setService(this);
71 }
72 }
73
74 }
75
76 public ServiceType getServiceType() {
77 return serviceType;
78 }
79
80 public ServiceId getServiceId() {
81 return serviceId;
82 }
83
84 public boolean hasActions() {
85 return getActions() != null && getActions().length > 0;
86 }
87
88 public Action<S>[] getActions() {
89 return actions == null ? null : actions.values().toArray(new Action[actions.values().size()]);
90 }
91
92 public boolean hasStateVariables() {
93
94 return getStateVariables() != null && getStateVariables().length > 0;
95 }
96
97 public StateVariable<S>[] getStateVariables() {
98 return stateVariables == null ? null : stateVariables.values().toArray(new StateVariable[stateVariables.values().size()]);
99 }
100
101 public D getDevice() {
102 return device;
103 }
104
105 void setDevice(D device) {
106 if (this.device != null)
107 throw new IllegalStateException("Final value has been set already, model is immutable");
108 this.device = device;
109 }
110
111 public Action<S> getAction(String name) {
112 return actions == null ? null : actions.get(name);
113 }
114
115 public StateVariable<S> getStateVariable(String name) {
116
117 if (QueryStateVariableAction.VIRTUAL_STATEVARIABLE_INPUT.equals(name)) {
118 return new StateVariable(
119 QueryStateVariableAction.VIRTUAL_STATEVARIABLE_INPUT,
120 new StateVariableTypeDetails(Datatype.Builtin.STRING.getDatatype())
121 );
122 }
123 if (QueryStateVariableAction.VIRTUAL_STATEVARIABLE_OUTPUT.equals(name)) {
124 return new StateVariable(
125 QueryStateVariableAction.VIRTUAL_STATEVARIABLE_OUTPUT,
126 new StateVariableTypeDetails(Datatype.Builtin.STRING.getDatatype())
127 );
128 }
129 return stateVariables == null ? null : stateVariables.get(name);
130 }
131
132 public StateVariable<S> getRelatedStateVariable(ActionArgument argument) {
133 return getStateVariable(argument.getRelatedStateVariableName());
134 }
135
136 public Datatype<S> getDatatype(ActionArgument argument) {
137 return getRelatedStateVariable(argument).getTypeDetails().getDatatype();
138 }
139
140 public ServiceReference getReference() {
141 return new ServiceReference(getDevice().getIdentity().getUdn(), getServiceId());
142 }
143
144 public List<ValidationError> validate() {
145 List<ValidationError> errors = new ArrayList<>();
146
147 if (getServiceType() == null) {
148 errors.add(new ValidationError(
149 getClass(),
150 "serviceType",
151 "Service type/info is required"
152 ));
153 }
154
155 if (getServiceId() == null) {
156 errors.add(new ValidationError(
157 getClass(),
158 "serviceId",
159 "Service ID is required"
160 ));
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 if (hasStateVariables()) {
177 for (StateVariable stateVariable : getStateVariables()) {
178 errors.addAll(stateVariable.validate());
179 }
180 }
181
182 if (hasActions()) {
183 for (Action action : getActions()) {
184
185
186
187
188 List<ValidationError> actionErrors = action.validate();
189 if(actionErrors.size() > 0) {
190 actions.remove(action.getName());
191 log.warning("Discarding invalid action of service '" + getServiceId() + "': " + action.getName());
192 for (ValidationError actionError : actionErrors) {
193 log.warning("Invalid action '" + action.getName() + "': " + actionError);
194 }
195 }
196 }
197 }
198
199 return errors;
200 }
201
202 public abstract Action getQueryStateVariableAction();
203
204 @Override
205 public String toString() {
206 return "(" + getClass().getSimpleName() + ") ServiceId: " + getServiceId();
207 }
208 }