blob: afc0628f7b476e5952b715213eb8c75ad0430b99 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.upnp.basedriver.export;
import org.cybergarage.upnp.Action;
import org.cybergarage.upnp.AllowedValueList;
import org.cybergarage.upnp.AllowedValueRange;
import org.cybergarage.upnp.Argument;
import org.cybergarage.upnp.ArgumentList;
import org.cybergarage.upnp.Device;
import org.cybergarage.upnp.RootDescription;
import org.cybergarage.upnp.Service;
import org.cybergarage.upnp.StateVariable;
import org.cybergarage.upnp.xml.DeviceData;
import org.cybergarage.xml.Node;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.upnp.UPnPAction;
import org.osgi.service.upnp.UPnPDevice;
import org.osgi.service.upnp.UPnPService;
import org.osgi.service.upnp.UPnPStateVariable;
import org.apache.felix.upnp.basedriver.Activator;
import org.apache.felix.upnp.basedriver.util.Converter;
/*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class BuildDevice {
private static Node buildRootNode(){
Node root = new Node(RootDescription.ROOT_ELEMENT);
root.setAttribute("xmlns",RootDescription.ROOT_ELEMENT_NAMESPACE);
Node spec = new Node(RootDescription.SPECVERSION_ELEMENT);
Node maj =new Node(RootDescription.MAJOR_ELEMENT);
maj.setValue("1");
Node min =new Node(RootDescription.MINOR_ELEMENT);
min.setValue("0");
spec.addNode(maj);
spec.addNode(min);
root.addNode(spec);
return root;
}
private static String extractDeviceType(ServiceReference sr) {
Object aux = sr.getProperty(UPnPDevice.TYPE);
if(aux instanceof String){
return (String) aux;
}else if(aux instanceof String[]){
//The property key UPnP.device.type should be a String
String[] v = (String[]) aux;
int maxindex=0;
int max=Integer.parseInt(v[0].substring(v[0].lastIndexOf(":")+1));
int tmp;
for (int i = 1; i < v.length; i++) {
tmp=Integer.parseInt(v[i].substring(v[i].lastIndexOf(":")+1));
if(max<tmp){
max=tmp;
maxindex=i;
}
}
return v[maxindex];
}else{
return "";
}
}
private static Device buildRootDeviceNode(Node root, ServiceReference sr){
Node dev = new Node(Device.ELEM_NAME);
root.addNode(dev);
DeviceData dd = new DeviceData();
dd.setDescriptionURI("/gen-desc.xml");
dev.setUserData(dd);
Device devUPnP = new Device(root,dev);
devUPnP.setDeviceType(extractDeviceType(sr));
devUPnP.setFriendlyName((String) sr.getProperty(UPnPDevice.FRIENDLY_NAME));
devUPnP.setManufacture((String) sr.getProperty(UPnPDevice.MANUFACTURER));
devUPnP.setManufactureURL((String) sr.getProperty(UPnPDevice.MANUFACTURER_URL));
devUPnP.setModelDescription((String) sr.getProperty(UPnPDevice.MODEL_DESCRIPTION));
devUPnP.setModelName((String) sr.getProperty(UPnPDevice.MODEL_NAME));
devUPnP.setModelNumber((String) sr.getProperty(UPnPDevice.MODEL_NUMBER));
devUPnP.setModelURL((String) sr.getProperty(UPnPDevice.MODEL_URL));
devUPnP.setSerialNumber((String) sr.getProperty(UPnPDevice.SERIAL_NUMBER));
devUPnP.setUDN((String) sr.getProperty(UPnPDevice.UDN));
devUPnP.setUPC((String) sr.getProperty(UPnPDevice.UPC));
devUPnP.setLocation("/gen-desc.xml");
addServices("",devUPnP,sr);
addDevices("",devUPnP,sr);
devUPnP.setPresentationURL((String) sr.getProperty(UPnPDevice.PRESENTATION_URL));
return devUPnP;
}
private static void addDevices(String id,Device devUPnP, ServiceReference sr) {
String[] udns=(String[]) sr.getProperty(UPnPDevice.CHILDREN_UDN);
if(udns==null) {
return;
}
for (int i = 0; i < udns.length; i++) {
try {
ServiceReference[] aux = Activator.bc.getServiceReferences(
UPnPDevice.class.getName(),"("+UPnPDevice.UDN+"="+udns[i]+")"
);
if(aux==null || aux.length == 0)
continue;
//id=+"/device/"+i; // twa: wrong in recursion
//buildDevice(id,devUPnP,aux[0]); // twa: wrong in recursion
String localId = new StringBuffer(id).append("/device/").append(i).toString();
buildDevice(localId,devUPnP,aux[0]); // twa: better
} catch (InvalidSyntaxException ignored) {}
}
}
private static void buildDevice(String id,Device parent, ServiceReference sr) {
Node dev = new Node(Device.ELEM_NAME);
DeviceData dd = new DeviceData();
dd.setDescriptionURI(id+"/gen-desc.xml");
dev.setUserData(dd);
Device devUPnP = new Device(dev);
devUPnP.setDeviceType(extractDeviceType(sr));
devUPnP.setFriendlyName((String) sr.getProperty(UPnPDevice.FRIENDLY_NAME));
devUPnP.setManufacture((String) sr.getProperty(UPnPDevice.MANUFACTURER));
devUPnP.setManufactureURL((String) sr.getProperty(UPnPDevice.MANUFACTURER_URL));
devUPnP.setModelDescription((String) sr.getProperty(UPnPDevice.MODEL_DESCRIPTION));
devUPnP.setModelName((String) sr.getProperty(UPnPDevice.MODEL_NAME));
devUPnP.setModelNumber((String) sr.getProperty(UPnPDevice.MODEL_NUMBER));
devUPnP.setModelURL((String) sr.getProperty(UPnPDevice.MODEL_URL));
devUPnP.setSerialNumber((String) sr.getProperty(UPnPDevice.SERIAL_NUMBER));
devUPnP.setUDN((String) sr.getProperty(UPnPDevice.UDN));
devUPnP.setUPC((String) sr.getProperty(UPnPDevice.UPC));
devUPnP.setLocation(id+"/gen-desc.xml");
addServices(id,devUPnP,sr);
addDevices(id,devUPnP,sr);
parent.addDevice(devUPnP); // twa: essential!!!!!!!
devUPnP.setPresentationURL((String) sr.getProperty(UPnPDevice.PRESENTATION_URL));
}
/**
* Method used to create a new Service in CyberLink world without creating the XML
*
* @param id ServiceId
* @param devUPnP the CyberLink device that where the new Service will be created
* @param sr ServiceReference to OSGi Device that used as source of the information
* for the creation of the device
*/
private static void addServices(String id,Device devUPnP, ServiceReference sr) {
UPnPDevice devOSGi = (UPnPDevice) Activator.bc.getService(sr);
if( devOSGi == null) { //added by twa to prevent a null pointer exception
Activator.logger.WARNING("UPnP Device that cotains serviceId="
+id+" is deregistered from the framework while is exported");
return;
}
UPnPService[] services = devOSGi.getServices();
if(services==null || services.length==0)
return;
for (int i = 0; i < services.length; i++) {
Service ser = new Service();
devUPnP.addService(ser);
ser.setServiceType(services[i].getType() );
ser.setServiceID(services[i].getId());
ser.setSCPDURL(id+"/service/"+i+"/gen-desc.xml");
ser.setDescriptionURL(id+"/service/"+i+"/gen-desc.xml");
ser.setControlURL(id+"/service/"+i+"/ctrl");
ser.setEventSubURL(id+"/service/"+i+"/event");
UPnPAction[] actions = services[i].getActions();
for (int j = 0; j < actions.length; j++) {
boolean valid=true;
Action act = new Action(ser.getServiceNode());
act.setName(actions[j].getName());
ArgumentList al = new ArgumentList();
String[] names=actions[j].getInputArgumentNames();
if(names!=null){
for (int k = 0; k < names.length; k++) {
UPnPStateVariable variable = actions[j].getStateVariable(names[k]);
if(variable==null){
/*
* //TODO Create a stict and relaxed behavior of the base driver which
* export as much it can or export only 100% complaint UPnPDevice service
*/
Activator.logger.WARNING(
"UPnP Device that cotains serviceId="+id+" contains the action "
+actions[j].getName()+" with the Input argument "+names[k]
+" not related to any UPnPStateVariable. Thus this action won't be exported");
valid=false;
break;
}
Argument a = new Argument();
a.setDirection(Argument.IN);
a.setName(names[k]);
a.setRelatedStateVariableName(variable.getName());
al.add(a);
}
}
names=actions[j].getOutputArgumentNames();
if(names!=null && valid){
for (int k = 0; k < names.length; k++) {
UPnPStateVariable variable = actions[j].getStateVariable(names[k]);
if(variable==null){
/*
* //TODO Create a stict and relaxed behavior of the base driver which
* export as much it can or export only 100% complaint UPnPDevice service
*/
Activator.logger.WARNING(
"UPnP Device that cotains serviceId="+id+" contains the action "
+actions[j].getName()+" with the Output argument "+names[k]
+" not related to any UPnPStateVariable. Thus this action won't be exported");
}
Argument a = new Argument();
a.setDirection(Argument.OUT);
a.setName(names[k]);
a.setRelatedStateVariableName(variable.getName());
al.add(a);
}
}
if(valid) {
act.setArgumentList(al);
ser.addAction(act);
}
}
UPnPStateVariable[] vars = services[i].getStateVariables();
for (int j = 0; j < vars.length; j++) {
StateVariable var = new StateVariable();
var.setDataType(vars[j].getUPnPDataType());
var.setName(vars[j].getName());
var.setSendEvents(vars[j].sendsEvents());
String[] values = vars[j].getAllowedValues();
if(values!=null){
AllowedValueList avl = new AllowedValueList(values);
var.setAllowedValueList(avl);
}else if(vars[j].getMaximum()!= null){
AllowedValueRange avr = new AllowedValueRange(
vars[j].getMaximum(),
vars[j].getMinimum(),
vars[j].getStep()
);
var.setAllowedValueRange(avr);
}
if(vars[j].getDefaultValue()!=null)
try {
var.setDefaultValue(Converter.toString(
vars[j].getDefaultValue(),vars[j].getUPnPDataType()
));
} catch (Exception ignored) {
}
ser.addStateVariable(var);
}
Activator.bc.ungetService(sr);
}
}
public static Device createCyberLinkDevice(ServiceReference sr){
Node root = buildRootNode();
Device devUPnP = buildRootDeviceNode(root,sr);
return devUPnP;
}
}