基于cling的函数接口
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
import java.io.IOException;
import org.fourthline.cling.UpnpServiceImpl;
import org.fourthline.cling.binding.LocalServiceBindingException;
import org.fourthline.cling.binding.annotations.*;
import org.fourthline.cling.controlpoint.ActionCallback;
import org.fourthline.cling.model.DefaultServiceManager;
import org.fourthline.cling.model.ValidationException;
import org.fourthline.cling.model.action.ActionInvocation;
import org.fourthline.cling.model.message.UpnpResponse;
import org.fourthline.cling.model.meta.DeviceDetails;
import org.fourthline.cling.model.meta.DeviceIdentity;
import org.fourthline.cling.model.meta.Icon;
import org.fourthline.cling.model.meta.LocalDevice;
import org.fourthline.cling.model.meta.LocalService;
import org.fourthline.cling.model.meta.ManufacturerDetails;
import org.fourthline.cling.model.meta.ModelDetails;
import org.fourthline.cling.model.meta.RemoteDevice;
import org.fourthline.cling.model.types.DeviceType;
import org.fourthline.cling.model.types.InvalidValueException;
import org.fourthline.cling.model.types.ServiceId;
import org.fourthline.cling.model.types.UDADeviceType;
import org.fourthline.cling.model.types.UDAServiceId;
import org.fourthline.cling.model.types.UDN;
import org.fourthline.cling.registry.DefaultRegistryListener;
import org.fourthline.cling.registry.Registry;
import org.fourthline.cling.registry.RegistryListener;
import android.app.Service;
//The SwitchPower service implementation
//电源状态车切换服务的实现
@UpnpService(
serviceId = @UpnpServiceId("SwitchPower"), //本服务id
serviceType = @UpnpServiceType(value = "SwitchPower", version = 1))//本服务类型
public class upnuserver{
@UpnpStateVariable(defaultValue = "0", sendEvents = false) //缺省值为0,状态为false
private boolean target = false;
@UpnpStateVariable(defaultValue = "0")
private boolean status = false;
@UpnpAction
public void setTarget(@UpnpInputArgument(name = "NewTargetValue") //设置当前状态值,目标值
boolean newTargetValue) { //
target = newTargetValue;
status = newTargetValue;
System.out.println("Switch is: " + status);
}
@UpnpAction(out = @UpnpOutputArgument(name = "RetTargetValue"))//
public boolean getTarget() { //获取目标
return target;
}
@UpnpAction(out = @UpnpOutputArgument(name = "ResultStatus"))
public boolean getStatus() { //获取状态
return status;
}
}
//创建设备
LocalDevice createDevice()
throws ValidationException, LocalServiceBindingException, IOException {
DeviceIdentity identity =new DeviceIdentity( //创建设备Identity(UDN)
UDN.uniqueSystemIdentifier("Demo Binary Light")
);
DeviceType type =new UDADeviceType("BinaryLight", 1); //设备类型
DeviceDetails details =new DeviceDetails( //设备的具体信息
"Friendly Binary Light",
new ManufacturerDetails("ACME"),
new ModelDetails(
"BinLight2000",
"A demo light with on/off switch.",
"v1"
)
);
Icon icon = new Icon("image/png", 48, 48, 8, getClass().getResource("icon.png") );//设备的图标
LocalService
switchPowerService.setManager(new DefaultServiceManager(switchPowerService, SwitchPower.class)); //setManager
//一个服务只是一些元数据描述,必须使用ServiceManager来完成实际的动作
//ServiceManager是元数据和服务之间的连接
//服务的动作一旦被执行,DefaultServiceManager 会实例化一个SwitchPower类
//一旦一个服务注册了upnp栈,新建的DefaultServiceManager 会保持并重用实例化的SwitchPower类
//the service manager is the factory that instantiates your actual implementation of a UPnP service.
//service manager 是一个实际执行upnp服务的工厂
return new LocalDevice(identity, type, details, icon, switchPowerService);
/* Several services can be bound to the same device:
return new LocalDevice(identity, type, details, icon,
new LocalService[] {switchPowerService, myOtherService}
);
*/
}
//启动服务
//一旦UPnPServiceImpl被构造,栈就被挂起并跑起来了。无论你是写服务端还是客户端,你都要创建一个UpnpService
//UpnpService维持着已经注册的远程设备和已经绑定的设备之间的联系,
//UpnpService负责呈现发现的设备和后台事件的挂起
//应用程序离开之前必须关闭UPnP service,如果不关闭,控制点会认为它还可用
public class BinaryLightServer implements Runnable {
public static void main(String[] args) throws Exception {
// Start a user thread that runs the UPnP stack
Thread serverThread = new Thread(new BinaryLightServer()); // 创建一个线程
serverThread.setDaemon(false); //普通线程
serverThread.start(); //开启线程
}
public void run() { //线程执行的代码
try {
final UpnpService upnpService = new UpnpServiceImpl();
//注册一个不能继承的UpnpService
Runtime.getRuntime().addShutdownHook(new Thread() {
//这个方法的含义说明:
// 这个方法的意思就是在jvm中增加一个关闭的钩子,
//当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,
//当系统执行完这些钩子后,jvm才会关闭。
//所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。
@Override
public void run() {
upnpService.shutdown();
}
}
);
// Add the bound local device to the registry
//添
加绑定的设备在注册表里面
upnpService.getRegistry().addDevice(
createDevice()
);
} catch (Exception ex) {
System.err.println("Exception occured: " + ex);
ex.printStackTrace(System.err);
System.exit(1);
}
}
}
//Creating a control point创建一个控制点
//客户端和服务器端拥有一样的架构,客户端也使用一个独立的共享的UpnpService实例对象
//一般来说,一个控制点在网络里面没有出现新的设备的时候一直处于休眠状态,
//当远端设备被发现或者设备自动广播时,RegistryListener 会被Cling叫醒
//一般来说,控制点不会等设备自动广播,所以会自动搜索全部设备,
//这会触发这些设备的匹配询问
//控制点里面有一个search()方法,这是你写一个Cling的UPnP客户端时交互的主要接口之一
//由前面的代码可知,应用退出的时候我们没有关闭UpnpService ,但在这里不是个问题
//因为这个应用没有任何本地设备和事件监听器绑定或者注册
public class BinaryLightClient implements Runnable {
public static void main(String[] args) throws Exception {
// Start a user thread that runs the UPnP stack
Thread clientThread = new Thread(new BinaryLightClient()
);
clientThread.setDaemon(false);
clientThread.start();
}
public void run() {
try {
UpnpService upnpService = new UpnpServiceImpl();
// Add a listener for device registration events
upnpService.getRegistry().addListener(createRegistryListener(upnpService)
);
// Broadcast a search message for all devices
upnpService.getControlPoint().search(new STAllHeader());
} catch (Exception ex) {
System.err.println("Exception occured: " + ex);
System.exit(1);
}
}
}
//现在服务和我们创建的控制点之间的交互仅限于都继承了 SwitchPower
//由于每个服务都有自己的标识符,所以我们要验证我们找到的设备是否提供这样的服务
RegistryListener createRegistryListener(final UpnpService upnpService) {
return new DefaultRegistryListener() {
ServiceId serviceId = new UDAServiceId("SwitchPower");
@Override
public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
Service switchPower;
if ((switchPower = device.findService(serviceId)) != null) {
System.out.println("Service discovered: " + switchPower);
executeAction(upnpService, switchPower);
}
}
@Override
public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
Service switchPower;
if ((switchPower = device.findService(serviceId)) != null) {
System.out.println("Service disappeared: " + switchPower);
}
}
}
;
}
//
//一旦服务可以使用,我们立刻就使用它,
// 一个 SwitchPower 设备 在消失前会打印信息
//Remember that this is a very trivial control point,
//it executes a single a fire-and-forget operation when a service becomes available:
//The Action (metadata) and the ActionInvocation (actual call data) APIs
//allow very fine-grained control of how an invocation is prepared,
//how input values are set, how the action is executed,
//and how the output and outcome is handled.
//Action和ActionInvocation的api定义了一些琐碎的为访问做准备的事
//如何设置输入值
//如何执行动作
//输出如何处理
//UPnP 天生异步,所以API接口都是回调的
// 推荐在ActionInvocation的子类中放入特殊服务,
//
//
//
void executeAction(UpnpService upnpService, Service switchPowerService) {
ActionInvocation setTargetInvocation =new SetTargetActionInvocation(switchPowerService);
// Executes asynchronous in the background
upnpService.getControlPoint().execute(
new ActionCallback(setTargetInvocation) {
@Override
public void success(ActionInvocation invocation) {
assert invocation.getOutput().length == 0;
System.out.println("Successfully called action!");
}
@Override
public void failure(ActionInvocation invocation,
UpnpResponse operation,
String defaultMsg) {
System.err.println(defaultMsg);
} } );
}
class SetTargetActionInvocation extends ActionInvocation {
SetTargetActionInvocation(Service service) {
super(service.getAction("SetTarget"));
try { // Throws InvalidValueException if the value is of wrong type
setInput("NewTargetValue", true);
} catch (InvalidValueException ex) {
System.err.println(ex.getMessage());
System.exit(1);
}
}}
}
}
//
//
}