1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.support.connectionmanager;
17
18 import org.fourthline.cling.binding.annotations.UpnpAction;
19 import org.fourthline.cling.binding.annotations.UpnpInputArgument;
20 import org.fourthline.cling.binding.annotations.UpnpOutputArgument;
21 import org.fourthline.cling.controlpoint.ControlPoint;
22 import org.fourthline.cling.model.ServiceReference;
23 import org.fourthline.cling.model.action.ActionException;
24 import org.fourthline.cling.model.action.ActionInvocation;
25 import org.fourthline.cling.model.message.UpnpResponse;
26 import org.fourthline.cling.model.meta.Service;
27 import org.fourthline.cling.model.types.ErrorCode;
28 import org.fourthline.cling.model.types.UnsignedIntegerFourBytes;
29 import org.fourthline.cling.model.types.csv.CSV;
30 import org.fourthline.cling.support.connectionmanager.callback.ConnectionComplete;
31 import org.fourthline.cling.support.connectionmanager.callback.PrepareForConnection;
32 import org.fourthline.cling.support.model.ConnectionInfo;
33 import org.fourthline.cling.support.model.ProtocolInfo;
34 import org.fourthline.cling.support.model.ProtocolInfos;
35
36 import java.beans.PropertyChangeSupport;
37 import java.util.logging.Logger;
38
39
40
41
42
43
44
45 public abstract class AbstractPeeringConnectionManagerService extends ConnectionManagerService {
46
47 final private static Logger log = Logger.getLogger(AbstractPeeringConnectionManagerService.class.getName());
48
49 protected AbstractPeeringConnectionManagerService(ConnectionInfo... activeConnections) {
50 super(activeConnections);
51 }
52
53 protected AbstractPeeringConnectionManagerService(ProtocolInfos sourceProtocolInfo, ProtocolInfos sinkProtocolInfo,
54 ConnectionInfo... activeConnections) {
55 super(sourceProtocolInfo, sinkProtocolInfo, activeConnections);
56 }
57
58 protected AbstractPeeringConnectionManagerService(PropertyChangeSupport propertyChangeSupport,
59 ProtocolInfos sourceProtocolInfo, ProtocolInfos sinkProtocolInfo,
60 ConnectionInfo... activeConnections) {
61 super(propertyChangeSupport, sourceProtocolInfo, sinkProtocolInfo, activeConnections);
62 }
63
64 synchronized protected int getNewConnectionId() {
65 int currentHighestID = -1;
66 for (Integer key : activeConnections.keySet()) {
67 if (key > currentHighestID) currentHighestID = key;
68 }
69 return ++currentHighestID;
70 }
71
72 synchronized protected void storeConnection(ConnectionInfo info) {
73 CSV<UnsignedIntegerFourBytes> oldConnectionIDs = getCurrentConnectionIDs();
74 activeConnections.put(info.getConnectionID(), info);
75 log.fine("Connection stored, firing event: " + info.getConnectionID());
76 CSV<UnsignedIntegerFourBytes> newConnectionIDs = getCurrentConnectionIDs();
77 getPropertyChangeSupport().firePropertyChange("CurrentConnectionIDs", oldConnectionIDs, newConnectionIDs);
78 }
79
80 synchronized protected void removeConnection(int connectionID) {
81 CSV<UnsignedIntegerFourBytes> oldConnectionIDs = getCurrentConnectionIDs();
82 activeConnections.remove(connectionID);
83 log.fine("Connection removed, firing event: " + connectionID);
84 CSV<UnsignedIntegerFourBytes> newConnectionIDs = getCurrentConnectionIDs();
85 getPropertyChangeSupport().firePropertyChange("CurrentConnectionIDs", oldConnectionIDs, newConnectionIDs);
86 }
87
88 @UpnpAction(out = {
89 @UpnpOutputArgument(name = "ConnectionID", stateVariable = "A_ARG_TYPE_ConnectionID", getterName = "getConnectionID"),
90 @UpnpOutputArgument(name = "AVTransportID", stateVariable = "A_ARG_TYPE_AVTransportID", getterName = "getAvTransportID"),
91 @UpnpOutputArgument(name = "RcsID", stateVariable = "A_ARG_TYPE_RcsID", getterName = "getRcsID")
92 })
93 synchronized public ConnectionInfo prepareForConnection(
94 @UpnpInputArgument(name = "RemoteProtocolInfo", stateVariable = "A_ARG_TYPE_ProtocolInfo") ProtocolInfo remoteProtocolInfo,
95 @UpnpInputArgument(name = "PeerConnectionManager", stateVariable = "A_ARG_TYPE_ConnectionManager") ServiceReference peerConnectionManager,
96 @UpnpInputArgument(name = "PeerConnectionID", stateVariable = "A_ARG_TYPE_ConnectionID") int peerConnectionId,
97 @UpnpInputArgument(name = "Direction", stateVariable = "A_ARG_TYPE_Direction") String direction)
98 throws ActionException {
99
100 int connectionId = getNewConnectionId();
101
102 ConnectionInfo.Direction dir;
103 try {
104 dir = ConnectionInfo.Direction.valueOf(direction);
105 } catch (Exception ex) {
106 throw new ConnectionManagerException(ErrorCode.ARGUMENT_VALUE_INVALID, "Unsupported direction: " + direction);
107 }
108
109 log.fine("Preparing for connection with local new ID " + connectionId + " and peer connection ID: " + peerConnectionId);
110
111 ConnectionInfo newConnectionInfo = createConnection(
112 connectionId,
113 peerConnectionId,
114 peerConnectionManager,
115 dir,
116 remoteProtocolInfo
117 );
118
119 storeConnection(newConnectionInfo);
120
121 return newConnectionInfo;
122 }
123
124 @UpnpAction
125 synchronized public void connectionComplete(@UpnpInputArgument(name = "ConnectionID", stateVariable = "A_ARG_TYPE_ConnectionID") int connectionID)
126 throws ActionException {
127 ConnectionInfo info = getCurrentConnectionInfo(connectionID);
128 log.fine("Closing connection ID " + connectionID);
129 closeConnection(info);
130 removeConnection(connectionID);
131 }
132
133
134
135
136
137
138
139 synchronized public int createConnectionWithPeer(final ServiceReference localServiceReference,
140 final ControlPoint controlPoint,
141 final Service peerService,
142 final ProtocolInfo protInfo,
143 final ConnectionInfo.Direction direction) {
144
145
146
147
148 final int localConnectionID = getNewConnectionId();
149
150 log.fine("Creating new connection ID " + localConnectionID + " with peer: " + peerService);
151 final boolean[] failed = new boolean[1];
152 new PrepareForConnection(
153 peerService,
154 controlPoint,
155 protInfo,
156 localServiceReference,
157 localConnectionID,
158 direction
159 ) {
160 @Override
161 public void received(ActionInvocation invocation, int peerConnectionID, int rcsID, int avTransportID) {
162 ConnectionInfo info = new ConnectionInfo(
163 localConnectionID,
164 rcsID,
165 avTransportID,
166 protInfo,
167 peerService.getReference(),
168 peerConnectionID,
169 direction.getOpposite(),
170 ConnectionInfo.Status.OK
171 );
172 storeConnection(info);
173 }
174
175 @Override
176 public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
177 AbstractPeeringConnectionManagerService.this.peerFailure(
178 invocation, operation, defaultMsg
179 );
180 failed[0] = true;
181 }
182 }.run();
183
184 return failed[0] ? -1 : localConnectionID;
185 }
186
187
188
189
190 synchronized public void closeConnectionWithPeer(ControlPoint controlPoint,
191 Service peerService,
192 int connectionID) throws ActionException {
193 closeConnectionWithPeer(controlPoint, peerService, getCurrentConnectionInfo(connectionID));
194 }
195
196
197
198
199 synchronized public void closeConnectionWithPeer(final ControlPoint controlPoint,
200 final Service peerService,
201 final ConnectionInfo connectionInfo) throws ActionException {
202
203
204 log.fine("Closing connection ID " + connectionInfo.getConnectionID() + " with peer: " + peerService);
205 new ConnectionComplete(
206 peerService,
207 controlPoint,
208 connectionInfo.getPeerConnectionID()
209 ) {
210
211 @Override
212 public void success(ActionInvocation invocation) {
213 removeConnection(connectionInfo.getConnectionID());
214 }
215
216 @Override
217 public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
218 AbstractPeeringConnectionManagerService.this.peerFailure(
219 invocation, operation, defaultMsg
220 );
221 }
222 }.run();
223 }
224
225 protected abstract ConnectionInfo createConnection(int connectionID,
226 int peerConnectionId, ServiceReference peerConnectionManager,
227 ConnectionInfo.Direction direction, ProtocolInfo protocolInfo) throws ActionException;
228
229 protected abstract void closeConnection(ConnectionInfo connectionInfo);
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 protected abstract void peerFailure(ActionInvocation invocation, UpnpResponse operation, String defaultFailureMessage);
245
246 }