1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.model.action;
17
18 import org.fourthline.cling.model.Command;
19 import org.fourthline.cling.model.ServiceManager;
20 import org.fourthline.cling.model.meta.Action;
21 import org.fourthline.cling.model.meta.ActionArgument;
22 import org.fourthline.cling.model.meta.LocalService;
23 import org.fourthline.cling.model.state.StateVariableAccessor;
24 import org.fourthline.cling.model.types.ErrorCode;
25 import org.fourthline.cling.model.types.InvalidValueException;
26 import org.seamless.util.Exceptions;
27
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32
33
34
35
36
37
38 public abstract class AbstractActionExecutor implements ActionExecutor {
39
40 private static Logger log = Logger.getLogger(AbstractActionExecutor.class.getName());
41
42 protected Map<ActionArgument<LocalService>, StateVariableAccessor> outputArgumentAccessors =
43 new HashMap<>();
44
45 protected AbstractActionExecutor() {
46 }
47
48 protected AbstractActionExecutor(Map<ActionArgument<LocalService>, StateVariableAccessor> outputArgumentAccessors) {
49 this.outputArgumentAccessors = outputArgumentAccessors;
50 }
51
52 public Map<ActionArgument<LocalService>, StateVariableAccessor> getOutputArgumentAccessors() {
53 return outputArgumentAccessors;
54 }
55
56
57
58
59 public void execute(final ActionInvocation<LocalService> actionInvocation) {
60
61 log.fine("Invoking on local service: " + actionInvocation);
62
63 final LocalService service = actionInvocation.getAction().getService();
64
65 try {
66
67 if (service.getManager() == null) {
68 throw new IllegalStateException("Service has no implementation factory, can't get service instance");
69 }
70
71 service.getManager().execute(new Command() {
72 public void execute(ServiceManager serviceManager) throws Exception {
73 AbstractActionExecutor.this.execute(
74 actionInvocation,
75 serviceManager.getImplementation()
76 );
77 }
78
79 @Override
80 public String toString() {
81 return "Action invocation: " + actionInvocation.getAction();
82 }
83 });
84
85 } catch (ActionException ex) {
86 if (log.isLoggable(Level.FINE)) {
87 log.fine("ActionException thrown by service, wrapping in invocation and returning: " + ex);
88 log.log(Level.FINE, "Exception root cause: ", Exceptions.unwrap(ex));
89 }
90 actionInvocation.setFailure(ex);
91 } catch (InterruptedException ex) {
92 if (log.isLoggable(Level.FINE)) {
93 log.fine("InterruptedException thrown by service, wrapping in invocation and returning: " + ex);
94 log.log(Level.FINE, "Exception root cause: ", Exceptions.unwrap(ex));
95 }
96 actionInvocation.setFailure(new ActionCancelledException(ex));
97 } catch (Throwable t) {
98 Throwable rootCause = Exceptions.unwrap(t);
99 if (log.isLoggable(Level.FINE)) {
100 log.fine("Execution has thrown, wrapping root cause in ActionException and returning: " + t);
101 log.log(Level.FINE, "Exception root cause: ", rootCause);
102 }
103 actionInvocation.setFailure(
104 new ActionException(
105 ErrorCode.ACTION_FAILED,
106 (rootCause.getMessage() != null ? rootCause.getMessage() : rootCause.toString()),
107 rootCause
108 )
109 );
110 }
111 }
112
113 protected abstract void execute(ActionInvocation<LocalService> actionInvocation, Object serviceImpl) throws Exception;
114
115
116
117
118
119
120
121
122
123
124 protected Object readOutputArgumentValues(Action<LocalService> action, Object instance) throws Exception {
125 Object[] results = new Object[action.getOutputArguments().length];
126 log.fine("Attempting to retrieve output argument values using accessor: " + results.length);
127
128 int i = 0;
129 for (ActionArgument outputArgument : action.getOutputArguments()) {
130 log.finer("Calling acccessor method for: " + outputArgument);
131
132 StateVariableAccessor accessor = getOutputArgumentAccessors().get(outputArgument);
133 if (accessor != null) {
134 log.fine("Calling accessor to read output argument value: " + accessor);
135 results[i++] = accessor.read(instance);
136 } else {
137 throw new IllegalStateException("No accessor bound for: " + outputArgument);
138 }
139 }
140
141 if (results.length == 1) {
142 return results[0];
143 }
144 return results.length > 0 ? results : null;
145 }
146
147
148
149
150 protected void setOutputArgumentValue(ActionInvocation<LocalService> actionInvocation, ActionArgument<LocalService> argument, Object result)
151 throws ActionException {
152
153 LocalService service = actionInvocation.getAction().getService();
154
155 if (result != null) {
156 try {
157 if (service.isStringConvertibleType(result)) {
158 log.fine("Result of invocation matches convertible type, setting toString() single output argument value");
159 actionInvocation.setOutput(new ActionArgumentValue(argument, result.toString()));
160 } else {
161 log.fine("Result of invocation is Object, setting single output argument value");
162 actionInvocation.setOutput(new ActionArgumentValue(argument, result));
163 }
164 } catch (InvalidValueException ex) {
165 throw new ActionException(
166 ErrorCode.ARGUMENT_VALUE_INVALID,
167 "Wrong type or invalid value for '" + argument.getName() + "': " + ex.getMessage(),
168 ex
169 );
170 }
171 } else {
172
173 log.fine("Result of invocation is null, not setting any output argument value(s)");
174 }
175
176 }
177
178 }