事件
对于订阅事件,首先先需要进行事件订阅,在协议中的订阅Request的Method为SUBSCRIBE;
我们看一下事件订阅的逻辑触发;
SubscriptionCallback
我们首先先看一下SubscriptionCallback定义:
SubscriptionCallback callback = new SubscriptionCallback(service, 600) {
@Override
public void established(GENASubscription sub) {
}
@Override
protected void failed(GENASubscription subscription,
UpnpResponse responseStatus,
Exception exception,
String defaultMsg) {
}
@Override
public void ended(GENASubscription sub,
CancelReason reason,
UpnpResponse response) {
}
@Override
public void eventReceived(GENASubscription sub) {
}
@Override
public void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
}
@Override
protected void invalidMessage(RemoteGENASubscription sub,
UnsupportedDataException ex) {
}
};
事件订阅
ControlPoint Request
我们可以先看一下ControlPoint的能力:
public interface ControlPoint {
public UpnpServiceConfiguration getConfiguration();
public ProtocolFactory getProtocolFactory();
public Registry getRegistry();
public void search();
public void search(UpnpHeader searchType);
public void search(int mxSeconds);
public void search(UpnpHeader searchType, int mxSeconds);
public Future execute(ActionCallback callback);
public void execute(SubscriptionCallback callback);
}
在interface定义中,search、execute(ActionCallback callback)、execute(SubscriptionCallback callback);
- search:用于搜索可见、可用的UPnP设备,有多种搜索形式;
- execute(ActionCallback callback):用于执行action指令Runnable;
- execute(SubscriptionCallback callback):用于执行subscribe的Runnable;
订阅事件的执行方法为:
this.upnpService.getControlPoint().execute(
new SubscriptionCallback(localService));
直接调用ControlPoint中的execute(SubscriptionCallback callback)方法即可,其中传入了SubscriptionCallback对象或者是SubscriptionCallback的扩展类(自定义子类);
调用了ControlPoint中的execute()方法之后,我们就需要看一下SubscriptionCallback的run()方法:
synchronized public void run() {
if (getControlPoint() == null) {
throw new IllegalStateException("Callback must be executed through ControlPoint");
}
if (getService() instanceof LocalService) {
establishLocalSubscription((LocalService) service);
} else if (getService() instanceof RemoteService) {
establishRemoteSubscription((RemoteService) service);
}
}
需要确认Service的类型,LocalService和RemoteService,因为我们在扫描阶段的时候,就得知从UPnP设备获取到的Service就是RemoteService,相对于UPnP设备,它是属于LocalService,所以会执行到establishRemoteSubscription()方法:
private void establishRemoteSubscription(RemoteService service) {
RemoteGENASubscription remoteSubscription =
new RemoteGENASubscription(service, requestedDurationSeconds) {
public void failed(UpnpResponse responseStatus) {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.setSubscription(null);
SubscriptionCallback.this.failed(this, responseStatus, null);
}
}
public void established() {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.setSubscription(this);
SubscriptionCallback.this.established(this);
}
}
public void ended(CancelReason reason, UpnpResponse responseStatus) {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.setSubscription(null);
SubscriptionCallback.this.ended(this, reason, responseStatus);
}
}
public void eventReceived() {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.eventReceived(this);
}
}
public void eventsMissed(int numberOfMissedEvents) {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.eventsMissed(this, numberOfMissedEvents);
}
}
public void invalidMessage(UnsupportedDataException ex) {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.invalidMessage(this, ex);
}
}
};
SendingSubscribe protocol;
try {
protocol = getControlPoint().getProtocolFactory().createSendingSubscribe(remoteSubscription);
} catch (ProtocolCreationException ex) {
failed(subscription, null, ex);
return;
}
protocol.run();
}
创建了RemoteGENASubscription对象,然后根据创建的RemoteGENASubscription对象创建SendingSubscribe对象protocol,然后调用了protocol.run()方法;
createSendingSubscribe
我们首先先看一下createSendingSubscribe(remoteSubscription)方法:
public SendingSubscribe createSendingSubscribe(RemoteGENASubscription subscription) throws ProtocolCreationException {
try {
List<NetworkAddress> activeStreamServers =
getUpnpService().getRouter().getActiveStreamServers(
subscription.getService().getDevice().getIdentity().getDiscoveredOnLocalAddress()
);
return new SendingSubscribe(getUpnpService(), subscription, activeStreamServers);
} catch (RouterException ex) {
throw new ProtocolCreationException(
"Failed to obtain local stream servers (for event callback URL creation) from router",
ex
);
}
}
方法返回了创建的SendingSubscribe对象,其中包含了UpnpService、RemoteGENASubscription对象以及RemoteDevice中存活的StreamServer,这里需要区别一下StreamServer,AVTransportService和RendingControlService属于StreamServer,ConnectionManagerService属于连接Service;
public SendingSubscribe(UpnpService upnpService,
RemoteGENASubscription subscription,
List<NetworkAddress> activeStreamServers) {
super(
upnpService,
new OutgoingSubscribeRequestMessage(
subscription,
subscription.getEventCallbackURLs(
activeStreamServers,
upnpService.getConfiguration().getNamespace()
),
upnpService.getConfiguration().getEventSubscriptionHeaders(subscription.getService())
)
);
this.subscription = subscription;
}
在SendingSubscribe的构造方法中,执行了super(),其中传入了new OutgoingSubscribeRequestMessage:
public OutgoingSubscribeRequestMessage(RemoteGENASubscription subscription,
List<URL> callbackURLs,
UpnpHeaders extraHeaders) {
super(UpnpRequest.Method.SUBSCRIBE, subscription.getEventSubscriptionURL());
getHeaders().add(
UpnpHeader.Type.CALLBACK,
new CallbackHeader(callbackURLs)
);
getHeaders().add(
UpnpHeader.Type.NT,
new NTEventHeader()
);
getHeaders().add(
UpnpHeader.Type.TIMEOUT,
new TimeoutHeader(subscription.getRequestedDurationSeconds())
);
if (extraHeaders != null)
getHeaders().putAll(extraHeaders);
}
其中又调用了super(),传入了UpnpRequest.Method.SUBSCRIBE,表明了该类请求命令Method为SUBSCRIBE:
public StreamRequestMessage(UpnpRequest.Method method, URL url) {
super(new UpnpRequest(method, url));
}
至此,subscribe的请求message就创建成功了;
protocol.run()
SendingSubscribe protocol;
try {
protocol = getControlPoint().getProtocolFactory().createSendingSubscribe(remoteSubscription);
} catch (ProtocolCreationException ex) {
failed(subscription, null, ex);
return;
}
protocol.run();
SendingSubscribe对象创建成功之后,就紧接着执行了run()方法,该方法在SendingAsync中:
public void run() {
try {
execute();
} catch (Exception ex) {
Throwable cause = Exceptions.unwrap(ex);
if (cause instanceof InterruptedException) {
log.log(Level.INFO, "Interrupted protocol '" + getClass().getSimpleName() + "': " + ex, cause);
} else {
throw new RuntimeException(
"Fatal error while executing protocol '" + getClass().getSimpleName() + "': " + ex, ex
);
}
}
}
其中调用了execute()方法,其中SendingSubscribe继承自SendingSync<IN extends StreamRequestMessage, OUT extends StreamResponseMessage>,SendingSync继承自SendingAsync,execute()方法在SendingSync定义:
final protected void execute() throws RouterException {
outputMessage = executeSync();
}
protected abstract OUT executeSync() throws RouterException;
execute()方法调用了executeSync()方法,executeSync()方法为抽象方法,在SendingSubscribe中实现:
protected IncomingSubscribeResponseMessage executeSync() throws RouterException {
if (!getInputMessage().hasCallbackURLs()) {
log.fine("Subscription failed, no active local callback URLs available (network disabled?)");
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
subscription.fail(null);
}
}
);
return null;
}
log.fine("Sending subscription request: " + getInputMessage());
try {
// register this pending Subscription to bloc if the notification is received before the
// registration result.
getUpnpService().getRegistry().registerPendingRemoteSubscription(subscription);
StreamResponseMessage response = null;
try {
response = getUpnpService().getRouter().send(getInputMessage());
} catch (RouterException ex) {
onSubscriptionFailure();
return null;
}
if (response == null) {
onSubscriptionFailure();
return null;
}
final IncomingSubscribeResponseMessage responseMessage = new IncomingSubscribeResponseMessage(response);
if (response.getOperation().isFailed()) {
log.fine("Subscription failed, response was: " + responseMessage);
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
subscription.fail(responseMessage.getOperation());
}
}
);
} else if (!responseMessage.isValidHeaders()) {
log.severe("Subscription failed, invalid or missing (SID, Timeout) response headers");
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
subscription.fail(responseMessage.getOperation());
}
}
);
} else {
log.fine("Subscription established, adding to registry, response was: " + response);
subscription.setSubscriptionId(responseMessage.getSubscriptionId());
subscription.setActualSubscriptionDurationSeconds(responseMessage.getSubscriptionDurationSeconds());
getUpnpService().getRegistry().addRemoteSubscription(subscription);
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
subscription.establish();
}
}
);
}
return responseMessage;
} finally {
getUpnpService().getRegistry().unregisterPendingRemoteSubscription(subscription);
}
}
getInputMessage()就是在创建SendingSubscribe的时候创建的OutgoingSubscribeRequestMessage对象,这个message就是在client端封装成的需要发送的message;
然后和扫描阶段的请求和响应类似了,使用了StreamRequestMessage和StreamResponseMessage的方式请求和接收响应;
然后将订阅事件添加到Registry中,保存到AndroidUpnpService中。然后getUpnpService().getConfiguration().getRegistryListenerExecutor().execute()方法,其中执行了subscription.establish()方法,我们需要知道,subscription对象就是我们之前创建的RemoteGENASubscription对象,其中所有的方法都是重写的,作用是为了告知连接成功;
UPnP设备 Response
这一块的逻辑,又回到了AsyncServletStreamServerImpl的HttpServlet中了;
响应逻辑的定义在AsyncServletStreamServerImpl中:
protected Servlet createServlet(final Router router) {
return new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
final long startTime = System.currentTimeMillis();
final int counter = mCounter++;
if (log.isLoggable(Level.FINE))
log.fine(String.format("HttpServlet.service(): id: %3d, request URI: %s", counter, req.getRequestURI()));
AsyncContext async = req.startAsync();
async.setTimeout(getConfiguration().getAsyncTimeoutSeconds()*1000);
……………………
AsyncServletUpnpStream stream =
new AsyncServletUpnpStream(router.getProtocolFactory(), async, req) {
@Override
protected Connection createConnection() {
return new AsyncServletConnection(getRequest());
}
};
router.received(stream);
}
};
}
在该方法中调用了received()方法,用于处理接收到请求或者是响应;
public void received(UpnpStream stream) {
if (!enabled) {
log.fine("Router disabled, ignoring incoming: " + stream);
return;
}
log.fine("Received synchronous stream: " + stream);
getConfiguration().getSyncProtocolExecutorService().execute(stream);
}
调用了execute()方法,执行了Runnable,即UpnpStream;
不再过多的赘述中间的过程了,大致说一下调用流程:
-
AsyncServletUpnpStream.run()
-
UpnpStream.process()
- ProtocolFactory.createReceivingSync():其中在该方法中创建了对应的ReceivingSubscribe对象,用于之后的使用;
-
ReceivingSync.run()
-
ReceivingSync.execute()
-
ReceivingSubscribe.executeSync():该处的ReceivingSubscribe对象就是上述通过createReceivingSync()方法创建的对象;
protected OutgoingSubscribeResponseMessage executeSync() throws RouterException {
ServiceEventSubscriptionResource resource =
getUpnpService().getRegistry().getResource(
ServiceEventSubscriptionResource.class,
getInputMessage().getUri()
);
if (resource == null) {
log.fine("No local resource found: " + getInputMessage());
return null;
}
log.fine("Found local event subscription matching relative request URI: " + getInputMessage().getUri());
IncomingSubscribeRequestMessage requestMessage =
new IncomingSubscribeRequestMessage(getInputMessage(), resource.getModel());
// Error conditions UDA 1.0 section 4.1.1 and 4.1.2
if (requestMessage.getSubscriptionId() != null &&
(requestMessage.hasNotificationHeader() || requestMessage.getCallbackURLs() != null)) {
log.fine("Subscription ID and NT or Callback in subscribe request: " + getInputMessage());
return new OutgoingSubscribeResponseMessage(UpnpResponse.Status.BAD_REQUEST);
}
if (requestMessage.getSubscriptionId() != null) {
return processRenewal(resource.getModel(), requestMessage);
} else if (requestMessage.hasNotificationHeader() && requestMessage.getCallbackURLs() != null){
return processNewSubscription(resource.getModel(), requestMessage);
} else {
log.fine("No subscription ID, no NT or Callback, neither subscription or renewal: " + getInputMessage());
return new OutgoingSubscribeResponseMessage(UpnpResponse.Status.PRECONDITION_FAILED);
}
}
在executeSync()方法中根据client端传入的requestMessage,封装成一个IncomingSubscribeRequestMessage对象requestMessage;
然后通过判断requestMessage的一系列判断,创建对应的processXxx()方法,在第一次订阅事件时,会执行processNewSubscription()方法:
protected OutgoingSubscribeResponseMessage processNewSubscription(LocalService service,
IncomingSubscribeRequestMessage requestMessage) {
List<URL> callbackURLs = requestMessage.getCallbackURLs();
// Error conditions UDA 1.0 section 4.1.1 and 4.1.2
if (callbackURLs == null || callbackURLs.size() == 0) {
log.fine("Missing or invalid Callback URLs in subscribe request: " + getInputMessage());
return new OutgoingSubscribeResponseMessage(UpnpResponse.Status.PRECONDITION_FAILED);
}
if (!requestMessage.hasNotificationHeader()) {
log.fine("Missing or invalid NT header in subscribe request: " + getInputMessage());
return new OutgoingSubscribeResponseMessage(UpnpResponse.Status.PRECONDITION_FAILED);
}
Integer timeoutSeconds;
if(getUpnpService().getConfiguration().isReceivedSubscriptionTimeoutIgnored()) {
timeoutSeconds = null; // Use default value
} else {
timeoutSeconds = requestMessage.getRequestedTimeoutSeconds();
}
try {
subscription = new LocalGENASubscription(service, timeoutSeconds, callbackURLs) {
public void established() {
}
public void ended(CancelReason reason) {
}
public void eventReceived() {
// The only thing we are interested in, sending an event when the state changes
getUpnpService().getConfiguration().getSyncProtocolExecutorService().execute(
getUpnpService().getProtocolFactory().createSendingEvent(this)
);
}
};
} catch (Exception ex) {
log.warning("Couldn't create local subscription to service: " + Exceptions.unwrap(ex));
return new OutgoingSubscribeResponseMessage(UpnpResponse.Status.INTERNAL_SERVER_ERROR);
}
log.fine("Adding subscription to registry: " + subscription);
getUpnpService().getRegistry().addLocalSubscription(subscription);
log.fine("Returning subscription response, waiting to send initial event");
return new OutgoingSubscribeResponseMessage(subscription);
}
在该方法中主要是用于创建响应使用的OutgoingSubscribeResponseMessage,在这之前创建了LocalGENASubscription类型的subscription,然后将创建成功的
subscription添加到registry中保存,之后就是等待发送初始事件;
final protected void execute() throws RouterException {
outputMessage = executeSync();
if (outputMessage != null && getRemoteClientInfo().getExtraResponseHeaders().size() > 0) {
log.fine("Setting extra headers on response message: " + getRemoteClientInfo().getExtraResponseHeaders().size());
outputMessage.getHeaders().putAll(getRemoteClientInfo().getExtraResponseHeaders());
}
}
最后在execute()方法中将封装好的ResponseMessage添加到outputMessage中;
然后一直返回封装好的message,直到返回到AsyncServletUpnpStream中的run()方法中:
@Override
public void run() {
try {
……………………
} catch (Throwable t) {
……………………
} finally {
complete();
}
}
在该方法的finally代码块中执行了complete()方法:
protected void complete() {
try {
asyncContext.complete();
} catch (IllegalStateException ex) {
// If Jetty's connection, for whatever reason, is in an illegal state, this will be thrown
// and we can "probably" ignore it. The request is complete, no matter how it ended.
log.info("Error calling servlet container's AsyncContext#complete() method: " + ex);
}
}
complete执行完成之后,会调用onComplete()方法:
@Override
public void onComplete(AsyncEvent event) throws IOException {
if (log.isLoggable(Level.FINER))
log.finer("Completed asynchronous processing of HTTP request: " + event.getSuppliedRequest());
responseSent(responseMessage);
}
其中调用网络responseSent()方法:
protected void responseSent(StreamResponseMessage responseMessage) {
if (syncProtocol != null)
syncProtocol.responseSent(responseMessage);
}
调用了responseSent()方法,将ResponseMessage发送;
状态变化事件响应
事件订阅分为订阅者和消息提供者,client端属于订阅者,用于监听UPnP设备的状态信息变化,UPnP设备作为消息提供者,向订阅者发送消息广播;
这个阶段,我们以start play为例,看一下是如何触发的事件回调以及该过程中有哪些执行逻辑;
LocalGENASubscription
订阅逻辑初始化成功之后,即创建了LocalGENASubscription对象之后,就将该对象添加到了Registry中,之后就等待事件的发送;
protected void responseSent(StreamResponseMessage responseMessage) {
if (syncProtocol != null)
syncProtocol.responseSent(responseMessage);
}
LocalGENASubscription对象创建成功之后,最后执行了responseSent()方法,在该方法中调用了syncProtocol.responseSent(responseMessage)方法:
@Override
public void responseSent(StreamResponseMessage responseMessage) {
if (subscription == null) return; // Preconditions failed very early on
if (responseMessage != null
&& !responseMessage.getOperation().isFailed()
&& subscription.getCurrentSequence().getValue() == 0) { // Note that renewals should not have 0
// This is a minor concurrency issue: If we now register on the service and henceforth send a new
// event message whenever the state of the service changes, there is still a chance that the initial
// event message arrives later than the first on-change event message. Shouldn't be a problem as the
// subscriber is supposed to figure out what to do with out-of-sequence messages. I would be
// surprised though if actual implementations won't crash!
log.fine("Establishing subscription");
subscription.registerOnService();
subscription.establish();
log.fine("Response to subscription sent successfully, now sending initial event asynchronously");
getUpnpService().getConfiguration().getAsyncProtocolExecutor().execute(
getUpnpService().getProtocolFactory().createSendingEvent(subscription)
);
} else if (subscription.getCurrentSequence().getValue() == 0) {
log.fine("Subscription request's response aborted, not sending initial event");
if (responseMessage == null) {
log.fine("Reason: No response at all from subscriber");
} else {
log.fine("Reason: " + responseMessage.getOperation());
}
log.fine("Removing subscription from registry: " + subscription);
getUpnpService().getRegistry().removeLocalSubscription(subscription);
}
}
在该方法中首先会对subscription变量进行判断,subscription变量其实就是刚刚创建的LocalGENASubscription对象,然后在该方法调用了registerOnService()方法:
synchronized public void registerOnService() {
getService().getManager().getPropertyChangeSupport().addPropertyChangeListener(this);
}
在该方法中调用了getPropertyChangeSupport().addPropertyChangeListener(this)方法,getPropertyChangeSupport()即为在DefaultServiceManager中创建的propertyChangeSupport对象,调用了addPropertyChangeListener()方法,入参为LocalGENASubscription对象本身:
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (listener == null) {
return;
}
if (listener instanceof PropertyChangeListenerProxy) {
PropertyChangeListenerProxy proxy =
(PropertyChangeListenerProxy)listener;
// Call two argument add method.
addPropertyChangeListener(proxy.getPropertyName(),
proxy.getListener());
} else {
this.map.add(null, listener);
}
}
在该方法中会将LocalGENASubscription对象保存到一个map集合中,至此,LocalGENASubscription对象的存储逻辑就执行完成了;
LastChange
因为start play的操作属于AVTransport Service支持的action,所以我们看一下AVTransport Service在创建的时候,到底执行了哪些逻辑:
mAvTransportLastChange = new LastChange(new AVTransportLastChangeParser());
LocalService<NoboAVTransportService> avTransportService
= mLocalServiceBinder.read(NoboAVTransportService.class);
mAVTransport
= new LastChangeAwareServiceManager<NoboAVTransportService>(avTransportService,
new AVTransportLastChangeParser()) {
@Override
protected NoboAVTransportService createServiceInstance() throws Exception {
return new NoboAVTransportService(mAvTransportLastChange, mMediaPlayers);
}
};
avTransportService.setManager(mAVTransport);
在创建NoboAVTransportService对象的时候,其中传入了两个参数,一个为mAvTransportLastChange,该变量的类型为LastChange,LastChange用于收集每个逻辑实例的所有状态更改;一个变量是mMediaPlayers,类型为Map,用于保存Player集合的。我们主要关注mAvTransportLastChange变量的流转逻辑;
我们紧接着看一下NoboAVTransportService对象的构造方法:
public NoboAVTransportService(LastChange lastChange,
Map<UnsignedIntegerFourBytes, NoboMediaPlayer> players) {
super(lastChange);
mPlayers = players;
}
NoboAVTransportService构造方法接收到mAvTransportLastChange对象之后,将mAvTransportLastChange对象传入到了父类中,NoboAVTransportService继承自AbstractAVTransportService,所以我们看一下AbstractAVTransportService的逻辑:
protected AbstractAVTransportService(LastChange lastChange) {
this.propertyChangeSupport = new PropertyChangeSupport(this);
this.lastChange = lastChange;
}
在该构造方法中将lastChange对象赋值给了AbstractAVTransportService的lastChange,用于保存;
至此,LastChange对象就基本上创建完成了,我们需要看一下之后的调用逻辑了;
事件Event信息保存
当UPnP设备端触发了start Play逻辑之后,就需要将start Play的状态结果告知client,它的调用逻辑被封装成了一个方法:
public synchronized void transportStateChanged(TransportState newState) {
mCurrentTransportInfo = new TransportInfo(newState);
getAvTransportLastChange().setEventedValue(
getInstanceId(),
new AVTransportVariable.TransportState(newState),
new AVTransportVariable.CurrentTransportActions(getCurrentTransportActions())
);
}
在这个方法中,涉及到了2个逻辑:
- 通过new TransportInfo创建新的状态值,并赋值给mCurrentTransportInfo变量作为最新状态值;
- 调用setEventedValue()方法将状态值变化消息事件发送出去;
创建最新状态值
mCurrentTransportInfo = new TransportInfo(newState);
首先,我们先看一下TransportInfo类的定义:
public TransportInfo(TransportState currentTransportState) {
this.currentTransportState = currentTransportState;
}
在该类中保存了Transport的状态值:
public enum TransportState {
STOPPED,
PLAYING,
TRANSITIONING,
PAUSED_PLAYBACK,
PAUSED_RECORDING,
RECORDING,
NO_MEDIA_PRESENT,
CUSTOM;
String value;
TransportState() {
this.value = name();
}
public String getValue() {
return value;
}
public TransportState setValue(String value) {
this.value = value;
return this;
}
public static TransportState valueOrCustomOf(String s) {
try {
return TransportState.valueOf(s);
} catch (IllegalArgumentException ex) {
return TransportState.CUSTOM.setValue(s);
}
}
}
TransportState中定义了多种状态值,通过setter/getter的方法获取;
最新的状态创建成功之后,赋值给赋值给mCurrentTransportInfo变量作为最新状态值,然后就调用getAvTransportLastChange().setEventedValue()方法,getAvTransportLastChange()方法返回的就是我们之前刚刚分析过得LastChange对象:
getAvTransportLastChange().setEventedValue(
getInstanceId(),
new AVTransportVariable.TransportState(newState),
new AVTransportVariable.CurrentTransportActions(getCurrentTransportActions())
);
其中传入了三个参数,我们首先对这3个参数进行分析:
getInstanceId():
其实就是对应的UPnP设备的唯一标识Id;
new AVTransportVariable.TransportState(newState):
public static class TransportState extends EventedValueEnum<org.fourthline.cling.support.model.TransportState> {
public TransportState(org.fourthline.cling.support.model.TransportState avTransportState) {
super(avTransportState);
}
public TransportState(Map.Entry<String, String>[] attributes) {
super(attributes);
}
@Override
protected org.fourthline.cling.support.model.TransportState enumValueOf(String s) {
return org.fourthline.cling.support.model.TransportState.valueOf(s);
}
}
根据最新的状态值创建AVTransportVariable.TransportState对象,AVTransportVariable.TransportState继承自EventedValueEnum,EventedValueEnum又继承自EventedValue;
new AVTransportVariable.CurrentTransportActions(getCurrentTransportActions()):
public static class CurrentTransportActions extends EventedValueEnumArray<TransportAction>{
public CurrentTransportActions(TransportAction[] e) {
super(e);
}
public CurrentTransportActions(Map.Entry<String, String>[] attributes) {
super(attributes);
}
@Override
protected TransportAction[] enumValueOf(String[] names) {
if (names == null) return new TransportAction[0];
List<TransportAction> list = new ArrayList<>();
for (String s : names) {
list.add(TransportAction.valueOf(s));
}
return list.toArray(new TransportAction[list.size()]);
}
}
顾名思义,这个就是用于获取保存当前状态下支持的Actions集合,通过getCurrentTransportActions()方法获取当前状态下支持的Actions集合;
public synchronized TransportAction[] getCurrentTransportActions() {
TransportState state = mCurrentTransportInfo.getCurrentTransportState();
TransportAction[] actions;
switch (state) {
case STOPPED:
actions = new TransportAction[] {
TransportAction.Play
};
break;
case PLAYING:
actions = new TransportAction[] {
TransportAction.Stop,
TransportAction.Pause,
TransportAction.Seek,
TransportAction.Next,
TransportAction.Previous
};
break;
case PAUSED_PLAYBACK:
actions = new TransportAction[] {
TransportAction.Stop,
TransportAction.Play,
TransportAction.Pause,
TransportAction.Seek,
TransportAction.Next,
TransportAction.Previous
};
break;
default:
actions = null;
}
return actions;
}
在该方法定义了一些状态下支持的一些状态集合,类型为TransportAction[];
保存Event事件信息
CurrentTransportActions继承自EventedValueEnumArray,将传入的TransportAction[]传入到了EventedValueEnumArray,EventedValueEnumArray又继承自EventedValue,同样也获取到了TransportAction[],和new AVTransportVariable.TransportState中的逻辑相似,两者都是最终都是继承自EventedValue;
3个参数描述完成之后,紧接着我们看一下setEventedValue()方法的逻辑:
synchronized public void setEventedValue(UnsignedIntegerFourBytes instanceID, EventedValue... ev) {
for (EventedValue eventedValue : ev) {
if (eventedValue != null)
event.setEventedValue(instanceID, eventedValue);
}
}
在该方法中,调用event.setEventedValue()方法将传入的EventedValue绑定UPnP设备的instanceId传入到了setEventedValue()方法中。event的类型为Event;
public void setEventedValue(UnsignedIntegerFourBytes id, EventedValue ev) {
InstanceID instanceID = null;
for (InstanceID i : getInstanceIDs()) {
if (i.getId().equals(id)) {
instanceID = i;
}
}
if (instanceID == null) {
instanceID = new InstanceID(id);
getInstanceIDs().add(instanceID);
}
Iterator<EventedValue> it = instanceID.getValues().iterator();
while (it.hasNext()) {
EventedValue existingEv = it.next();
if (existingEv.getClass().equals(ev.getClass())) {
it.remove();
}
}
instanceID.getValues().add(ev);
}
在该方法中,首先先创建了一个InstanceID对象,InstanceID的定义:
public class InstanceID {
protected UnsignedIntegerFourBytes id;
protected List<EventedValue> values = new ArrayList<>();
public InstanceID(UnsignedIntegerFourBytes id) {
this(id, new ArrayList<EventedValue>());
}
public InstanceID(UnsignedIntegerFourBytes id, List<EventedValue> values) {
this.id = id;
this.values = values;
}
public UnsignedIntegerFourBytes getId() {
return id;
}
public List<EventedValue> getValues() {
return values;
}
}
主要是用于保存相同ID下的所有的EventedValue信息;
至此,数据就保存到Event对象中了;
Event事件发送
我们需要回顾一下,在创建AVTransport Service的时候,执行了哪些操作;
LocalService<NoboAVTransportService> avTransportService
= mLocalServiceBinder.read(NoboAVTransportService.class);
mAVTransport
= new LastChangeAwareServiceManager<NoboAVTransportService>(avTransportService,
new AVTransportLastChangeParser()) {
@Override
protected NoboAVTransportService createServiceInstance() throws Exception {
return new NoboAVTransportService(mAvTransportLastChange, mMediaPlayers);
}
};
avTransportService.setManager(mAVTransport);
在创建LastChangeAwareServiceManager对象的时候,在其中重写了createServiceInstance()方法,但是不会立即执行该方法;
public NoboAVTransportService(LastChange lastChange,
Map<UnsignedIntegerFourBytes, NoboMediaPlayer> players) {
super(lastChange);
mPlayers = players;
}
我们看一下NoboAVTransportService的父类AbstractAVTransportService的构造方法:
final private LastChange lastChange;
final protected PropertyChangeSupport propertyChangeSupport;
protected AbstractAVTransportService(LastChange lastChange) {
this.propertyChangeSupport = new PropertyChangeSupport(this);
this.lastChange = lastChange;
}
在该构造方法中,创建了PropertyChangeSupport对象,这个不属于cling开源库中的代码,属于Android SDK中的,PropertyChangeSupport与PropertyChangeListener配合使用能够实现,绑定属性会在属性值发生变化时,通知所有相关的监听器;
LastChangeAwareServiceManager对象创建成功之后,紧接着调用了mAVTransport.fireLastChange():
private void runLastChangePushThread() {
new Thread() {
@Override
public void run() {
try {
while(true) {
mAVTransport.fireLastChange();
mRenderingControl.fireLastChange();
Thread.sleep(500);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}.start();
}
执行了LastChangeAwareServiceManager.fireLastChange()方法,而且使用while(true)使之一直处于无线循环过程中:
public void fireLastChange() {
// We need to obtain locks in the right order to avoid deadlocks:
// 1. The lock() of the DefaultServiceManager
// 2. The monitor/synchronized of the LastChange.fire() method
lock();
try {
getImplementation().getLastChange().fire(getPropertyChangeSupport());
} finally {
unlock();
}
}
在该方法中通过getLastChange()方法获取到了对应AVTransport Service的LastChange对象,通然后调用了fire()方法,其中传入了getPropertyChangeSupport(),该方法在DefaultServiceManager中定义;
getPropertyChangeSupport()
我们看一下getPropertyChangeSupport()返回的是什么:
public PropertyChangeSupport getPropertyChangeSupport() {
lock();
try {
if (propertyChangeSupport == null) {
init();
}
return propertyChangeSupport;
} finally {
unlock();
}
}
首先会判断propertyChangeSupport这个变量是否为空,如果为空的话,会调用init()方法,正常来说,我们现在还没有初始化propertyChangeSupport这个变量,所以会执行到init()方法:
protected void init() {
log.fine("No service implementation instance available, initializing...");
try {
// The actual instance we ware going to use and hold a reference to (1:1 instance for manager)
serviceImpl = createServiceInstance();
// How the implementation instance will tell us about property changes
propertyChangeSupport = createPropertyChangeSupport(serviceImpl);
propertyChangeSupport.addPropertyChangeListener(createPropertyChangeListener(serviceImpl));
} catch (Exception ex) {
throw new RuntimeException("Could not initialize implementation: " + ex, ex);
}
}
在该方法中首先就是调用了createServiceInstance()方法,我们通过分析上下文,得知createServiceInstance()方法就是我们在创建LastChangeAwareServiceManager对象时重写的方法,之后在该方法中创建了propertyChangeSupport对象;
然后调用了createPropertyChangeSupport(serviceImpl)方法:
protected PropertyChangeSupport createPropertyChangeSupport(T serviceImpl) throws Exception {
Method m;
if ((m = Reflections.getGetterMethod(serviceImpl.getClass(), "propertyChangeSupport")) != null &&
PropertyChangeSupport.class.isAssignableFrom(m.getReturnType())) {
log.fine("Service implementation instance offers PropertyChangeSupport, using that: " + serviceImpl.getClass().getName());
return (PropertyChangeSupport) m.invoke(serviceImpl);
}
log.fine("Creating new PropertyChangeSupport for service implementation: " + serviceImpl.getClass().getName());
return new PropertyChangeSupport(serviceImpl);
}
在该方法中通过反射的方式,获取到了createServiceInstance()方法中创建的propertyChangeSupport对象并赋值给DefaultServiceManager中的propertyChangeSupport变量;
然后调用了propertyChangeSupport.addPropertyChangeListener(),通过注册指定Listener的监听,我们向其中注册的listener为createPropertyChangeListener(serviceImpl):
protected PropertyChangeListener createPropertyChangeListener(T serviceImpl) throws Exception {
return new DefaultPropertyChangeListener();
}
protected class DefaultPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
log.finer("Property change event on local service: " + e.getPropertyName());
// Prevent recursion
if (e.getPropertyName().equals(EVENTED_STATE_VARIABLES)) return;
String[] variableNames = ModelUtil.fromCommaSeparatedList(e.getPropertyName());
log.fine("Changed variable names: " + Arrays.toString(variableNames));
try {
Collection<StateVariableValue> currentValues = getCurrentState(variableNames);
if (!currentValues.isEmpty()) {
getPropertyChangeSupport().firePropertyChange(
EVENTED_STATE_VARIABLES,
null,
currentValues
);
}
} catch (Exception ex) {
// TODO: Is it OK to only log this error? It means we keep running although we couldn't send events?
log.log(
Level.SEVERE,
"Error reading state of service after state variable update event: " + Exceptions.unwrap(ex),
ex
);
}
}
}
在该listener中存在一个方法:propertyChange(PropertyChangeEvent e),当状态值发生变化时,该方法会被调用,并回调了PropertyChangeEvent对象:
public PropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue) {
super(source);
this.propertyName = propertyName;
this.newValue = newValue;
this.oldValue = oldValue;
}
该类中定义了3个变量,propertyName为属性名,newValue为该属性的新值,oldValue为该属性的旧值,client端就可以根据回调的PropertyEvent来对client的控制状态进行更新;
fire()
getPropertyChangeSupport()方法执行完成之后,propertyChangeSupport对象就创建并初始化成功了;
紧接着我们还是回到fire()方法中,在fire()方法中传入了propertyChangeSupport对象:
synchronized public void fire(PropertyChangeSupport propertyChangeSupport) {
String lastChanges = toString();
if (lastChanges != null && lastChanges.length() > 0) {
propertyChangeSupport.firePropertyChange("LastChange", previousValue, lastChanges);
reset();
}
}
首先会调用toString()方法:
@Override
synchronized public String toString() {
if (!event.hasChanges()) return "";
try {
return parser.generate(event);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
toString()方法会判断event对象是否有可用数据,如果没有,返回空字符串,否则调用parser.generate(event)返回对应的XML的描述字符串;
lastChanges获取到对应Event的XML描述字符串,紧接着判断lastChanges的有效性,如果有效,则执行propertyChangeSupport.firePropertyChange()方法:
public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
}
}
该方法中调用了firePropertyChange()方法,其中创建了PropertyChangeEvent对象,包含了propertyName、oldValue、newValue3个值:
public void firePropertyChange(PropertyChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
String name = event.getPropertyName();
PropertyChangeListener[] common = this.map.get(null);
PropertyChangeListener[] named = (name != null)
? this.map.get(name)
: null;
fire(common, event);
fire(named, event);
}
}
从this.map中获取到所有的listeners,然后在最后调用了fire()方法,将listeners传入其中:
private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
if (listeners != null) {
for (PropertyChangeListener listener : listeners) {
listener.propertyChange(event);
}
}
}
调用网络listener.propertyChange(),其中就包括上述过程中描述过的LocalGENASubscription对象:
synchronized public void propertyChange(PropertyChangeEvent e) {
if (!e.getPropertyName().equals(ServiceManager.EVENTED_STATE_VARIABLES)) return;
log.fine("Eventing triggered, getting state for subscription: " + getSubscriptionId());
long currentTime = new Date().getTime();
Collection<StateVariableValue> newValues = (Collection) e.getNewValue();
Set<String> excludedVariables = moderateStateVariables(currentTime, newValues);
currentValues.clear();
for (StateVariableValue newValue : newValues) {
String name = newValue.getStateVariable().getName();
if (!excludedVariables.contains(name)) {
log.fine("Adding state variable value to current values of event: " + newValue.getStateVariable() + " = " + newValue);
currentValues.put(newValue.getStateVariable().getName(), newValue);
// Preserve "last sent" state for future moderation
lastSentTimestamp.put(name, currentTime);
if (newValue.getStateVariable().isModeratedNumericType()) {
lastSentNumericValue.put(name, Long.valueOf(newValue.toString()));
}
}
}
if (currentValues.size() > 0) {
log.fine("Propagating new state variable values to subscription: " + this);
// TODO: I'm not happy with this design, this dispatches to a separate thread which _then_
// is supposed to lock and read the values off this instance. That obviously doesn't work
// so it's currently a hack in SendingEvent.java
eventReceived();
} else {
log.fine("No state variable values for event (all moderated out?), not triggering event");
}
}
在该方法的最后调用了eventReceived()方法,eventReceived()方法为抽象方法,在创建LocalGENASubscription实例的时候实现了该方法:
public void eventReceived() {
// The only thing we are interested in, sending an event when the state changes
getUpnpService().getConfiguration().getSyncProtocolExecutorService().execute(
getUpnpService().getProtocolFactory().createSendingEvent(this)
);
}
在该方法中创建了SendingEvent对象,并执行了其中的run()方法:
public SendingEvent createSendingEvent(LocalGENASubscription subscription) {
return new SendingEvent(getUpnpService(), subscription);
}
public SendingEvent(UpnpService upnpService, LocalGENASubscription subscription) {
super(upnpService, null); // Special case, we actually need to send several messages to each callback URL
// TODO: Ugly design! It is critical (concurrency) that we prepare the event messages here, in the constructor thread!
subscriptionId = subscription.getSubscriptionId();
requestMessages = new OutgoingEventRequestMessage[subscription.getCallbackURLs().size()];
int i = 0;
for (URL url : subscription.getCallbackURLs()) {
requestMessages[i] = new OutgoingEventRequestMessage(subscription, url);
getUpnpService().getConfiguration().getGenaEventProcessor().writeBody(requestMessages[i]);
i++;
}
currentSequence = subscription.getCurrentSequence();
// Always increment sequence now, as (its value) has already been set on the headers and the
// next event will use the incremented value
subscription.incrementSequence();
}
在SendingEvent的构造方法中,直接将需要发送的Event事件信息封装成了OutgoingEventRequestMessage对象;
SendingEvent对象创建成功之后,执行run()方法,该方法在SendingAsync中定义:
public void run() {
try {
execute();
} catch (Exception ex) {
……………………
}
}
protected abstract void execute() throws RouterException;
execute()为抽象方法,在SendingAsync的子类SendingSync中实现:
final protected void execute() throws RouterException {
outputMessage = executeSync();
}
protected abstract OUT executeSync() throws RouterException;
再向上追溯到SendingEvent中:
protected StreamResponseMessage executeSync() throws RouterException {
log.fine("Sending event for subscription: " + subscriptionId);
StreamResponseMessage lastResponse = null;
for (OutgoingEventRequestMessage requestMessage : requestMessages) {
if (currentSequence.getValue() == 0) {
log.fine("Sending initial event message to callback URL: " + requestMessage.getUri());
} else {
log.fine("Sending event message '"+currentSequence+"' to callback URL: " + requestMessage.getUri());
}
// Send request
lastResponse = getUpnpService().getRouter().send(requestMessage);
log.fine("Received event callback response: " + lastResponse);
}
// It's not really used, so just return the last one - we have only one callback URL most of the
// time anyway
return lastResponse;
}
将上述刚刚创建好的OutgoingEventRequestMessage对象通过调用RouterImpl.send()方法发送到网络中;
至此,整个监听链路就串通了;
最后调用reset()方法:
synchronized public void reset() {
previousValue = toString();
event.clear();
}
保存已发送的Event事件为previous Event Value,然后将event对象清空,表明event事件已全部发送;
Event事件监听
同理,client端也是通过HttpServlet接收响应:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
……………………
AsyncServletUpnpStream stream =
new AsyncServletUpnpStream(router.getProtocolFactory(), async, req) {
@Override
protected Connection createConnection() {
return new AsyncServletConnection(getRequest());
}
};
router.received(stream);
}
public void received(UpnpStream stream) {
if (!enabled) {
log.fine("Router disabled, ignoring incoming: " + stream);
return;
}
log.fine("Received synchronous stream: " + stream);
getConfiguration().getSyncProtocolExecutorService().execute(stream);
}
我们直接看一下AsyncServletUpnpStream.run()方法;
我们看一下stream中的run()方法(stream的类型为AsyncServletUpnpStream,是Runable):
@Override
public void run() {
try {
StreamRequestMessage requestMessage = readRequestMessage();
if (log.isLoggable(Level.FINER))
log.finer("Processing new request message: " + requestMessage);
responseMessage = process(requestMessage);
……………………
} catch (Throwable t) {
……………………
} finally {
complete();
}
}
在该方法中调用了process()方法:
public StreamResponseMessage process(StreamRequestMessage requestMsg) {
log.fine("Processing stream request message: " + requestMsg);
try {
// Try to get a protocol implementation that matches the request message
syncProtocol = getProtocolFactory().createReceivingSync(requestMsg);
} catch (ProtocolCreationException ex) {
log.warning("Processing stream request failed - " + Exceptions.unwrap(ex).toString());
return new StreamResponseMessage(UpnpResponse.Status.NOT_IMPLEMENTED);
}
// Run it
log.fine("Running protocol for synchronous message processing: " + syncProtocol);
syncProtocol.run();
// ... then grab the response
StreamResponseMessage responseMsg = syncProtocol.getOutputMessage();
if (responseMsg == null) {
// That's ok, the caller is supposed to handle this properly (e.g. convert it to HTTP 404)
log.finer("Protocol did not return any response message");
return null;
}
log.finer("Protocol returned response: " + responseMsg);
return responseMsg;
}
在该方法中,调用了getProtocolFactory().createReceivingSync()方法,尝试获得与请求消息匹配的协议实现:
public ReceivingSync createReceivingSync(StreamRequestMessage message) throws ProtocolCreationException {
log.fine("Creating protocol for incoming synchronous: " + message);
if (message.getOperation().getMethod().equals(UpnpRequest.Method.GET)) {
……………………
} else if (getUpnpService().getConfiguration().getNamespace().isControlPath(message.getUri())) {
……………………
} else if (getUpnpService().getConfiguration().getNamespace().isEventSubscriptionPath(message.getUri())) {
……………………
} else if (getUpnpService().getConfiguration().getNamespace().isEventCallbackPath(message.getUri())) {
if (message.getOperation().getMethod().equals(UpnpRequest.Method.NOTIFY))
return createReceivingEvent(message);
} else {
……………………
}
throw new ProtocolCreationException("Protocol for message type not found: " + message);
}
因为对应的是SendingEvent的sendRequestMessage,所以这里会调用对应的createReceivingEvent()方法:
protected ReceivingEvent createReceivingEvent(StreamRequestMessage message) {
return new ReceivingEvent(getUpnpService(), message);
}
public ReceivingEvent(UpnpService upnpService, StreamRequestMessage inputMessage) {
super(upnpService, inputMessage);
}
然后就是执行run()方法,在ReceivingEvent中定义:
public void run() {
boolean proceed;
try {
proceed = waitBeforeExecution();
} catch (InterruptedException ex) {
log.info("Protocol wait before execution interrupted (on shutdown?): " + getClass().getSimpleName());
proceed = false;
}
if (proceed) {
try {
execute();
} catch (Exception ex) {
……………………
}
}
}
其中调用了ReceivingAsync.execute()方法,然后又调用了ReceivingSync.executeSync()方法,executeSync()方法在ReceivingEvent中实现:
protected OutgoingEventResponseMessage executeSync() throws RouterException{
if (!getInputMessage().isContentTypeTextUDA()) {
log.warning("Received without or with invalid Content-Type: " + getInputMessage());
// We continue despite the invalid UPnP message because we can still hope to convert the content
// return new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.UNSUPPORTED_MEDIA_TYPE));
}
ServiceEventCallbackResource resource =
getUpnpService().getRegistry().getResource(
ServiceEventCallbackResource.class,
getInputMessage().getUri()
);
if (resource == null) {
log.fine("No local resource found: " + getInputMessage());
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.NOT_FOUND));
}
final IncomingEventRequestMessage requestMessage =
new IncomingEventRequestMessage(getInputMessage(), resource.getModel());
// Error conditions UDA 1.0 section 4.2.1
if (requestMessage.getSubscrptionId() == null) {
log.fine("Subscription ID missing in event request: " + getInputMessage());
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.PRECONDITION_FAILED));
}
if (!requestMessage.hasValidNotificationHeaders()) {
log.fine("Missing NT and/or NTS headers in event request: " + getInputMessage());
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.BAD_REQUEST));
}
if (!requestMessage.hasValidNotificationHeaders()) {
log.fine("Invalid NT and/or NTS headers in event request: " + getInputMessage());
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.PRECONDITION_FAILED));
}
if (requestMessage.getSequence() == null) {
log.fine("Sequence missing in event request: " + getInputMessage());
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.PRECONDITION_FAILED));
}
try {
getUpnpService().getConfiguration().getGenaEventProcessor().readBody(requestMessage);
} catch (final UnsupportedDataException ex) {
log.fine("Can't read event message request body, " + ex);
// Pass the parsing failure on to any listeners, so they can take action if necessary
final RemoteGENASubscription subscription =
getUpnpService().getRegistry().getRemoteSubscription(requestMessage.getSubscrptionId());
if (subscription != null) {
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
subscription.invalidMessage(ex);
}
}
);
}
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.INTERNAL_SERVER_ERROR));
}
// get the remove subscription, if the subscription can't be found, wait for pending subscription
// requests to finish
final RemoteGENASubscription subscription =
getUpnpService().getRegistry().getWaitRemoteSubscription(requestMessage.getSubscrptionId());
if (subscription == null) {
log.severe("Invalid subscription ID, no active subscription: " + requestMessage);
return new OutgoingEventResponseMessage(new UpnpResponse(UpnpResponse.Status.PRECONDITION_FAILED));
}
getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
new Runnable() {
public void run() {
log.fine("Calling active subscription with event state variable values");
subscription.receive(
requestMessage.getSequence(),
requestMessage.getStateVariableValues()
);
}
}
);
return new OutgoingEventResponseMessage();
}
最终在这个方法中调用了subscription.receive()方法,subscription的类型为RemoteGENASubscription,就是我们在调用SubscriptionCallback时创建的RemoteGENASubscription对象:
synchronized public void receive(UnsignedIntegerFourBytes sequence, Collection<StateVariableValue> newValues) {
if (this.currentSequence != null) {
// TODO: Handle rollover to 1!
if (this.currentSequence.getValue().equals(this.currentSequence.getBits().getMaxValue()) && sequence.getValue() == 1) {
System.err.println("TODO: HANDLE ROLLOVER");
return;
}
if (this.currentSequence.getValue() >= sequence.getValue()) {
return;
}
int difference;
long expectedValue = currentSequence.getValue() + 1;
if ((difference = (int) (sequence.getValue() - expectedValue)) != 0) {
eventsMissed(difference);
}
}
this.currentSequence = sequence;
for (StateVariableValue newValue : newValues) {
currentValues.put(newValue.getStateVariable().getName(), newValue);
}
eventReceived();
}
其中调用了eventReceived()方法,eventReceived()方法为抽象方法,所以我们看一下创建RemoteGENASubscription对象时重写的方法:
public void eventReceived() {
synchronized (SubscriptionCallback.this) {
SubscriptionCallback.this.eventReceived(this);
}
}
在该方法中调用了SubscriptionCallback.this.eventReceived(this),SubscriptionCallback为cling开源库提供的原生、抽象的callback,一般在使用的时候,我们会自定义一个SubscriptionCallback对象,用于实现原生的SubscriptionCallback,同时实现其中的一些抽象方法;
至此,event事件就传递到了client应用层了;