You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yacy_search_server/source/net/sbbi/upnp/services/UPNPService.java

328 lines
13 KiB

/*
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by SuperBonBon Industries (http://www.sbbi.net/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "UPNPLib" and "SuperBonBon Industries" must not be
* used to endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* info@sbbi.net.
*
* 5. Products derived from this software may not be called
* "SuperBonBon Industries", nor may "SBBI" appear in their name,
* without prior written permission of SuperBonBon Industries.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT,INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of SuperBonBon Industries. For more information on
* SuperBonBon Industries, please see <http://www.sbbi.net/>.
*/
package net.sbbi.upnp.services;
import org.apache.commons.jxpath.*;
import org.apache.commons.jxpath.xml.*;
import java.util.*;
import java.io.IOException;
import java.net.*;
import net.sbbi.upnp.JXPathParser;
import net.sbbi.upnp.devices.*;
/**
* Representation of an UPNP service
* @author <a href="mailto:superbonbon@sbbi.net">SuperBonBon</a>
* @version 1.0
*/
@SuppressWarnings("unchecked")
public class UPNPService {
protected String serviceType;
protected String serviceId;
private int specVersionMajor;
private int specVersionMinor;
protected URL SCPDURL;
protected String SCPDURLData;
protected URL controlURL;
protected URL eventSubURL;
protected UPNPDevice serviceOwnerDevice;
protected Map UPNPServiceActions;
protected Map UPNPServiceStateVariables;
private final String USN;
private boolean parsedSCPD = false;
private DocumentContainer UPNPService;
public UPNPService( JXPathContext serviceCtx, URL baseDeviceURL, UPNPDevice serviceOwnerDevice ) throws MalformedURLException {
this.serviceOwnerDevice = serviceOwnerDevice;
serviceType = (String)serviceCtx.getValue( "serviceType" );
serviceId = (String)serviceCtx.getValue( "serviceId" );
SCPDURL = UPNPRootDevice.getURL( (String)serviceCtx.getValue( "SCPDURL" ), baseDeviceURL );
controlURL = UPNPRootDevice.getURL( (String)serviceCtx.getValue( "controlURL" ), baseDeviceURL );
eventSubURL = UPNPRootDevice.getURL( (String)serviceCtx.getValue( "eventSubURL" ), baseDeviceURL );
USN = serviceOwnerDevice.getUDN().concat( "::" ).concat( serviceType );
}
public String getServiceType() {
return serviceType;
}
public String getServiceId() {
return serviceId;
}
public String getUSN(){
return USN;
}
public URL getSCPDURL() {
return SCPDURL;
}
public URL getControlURL() {
return controlURL;
}
public URL getEventSubURL() {
return eventSubURL;
}
public int getSpecVersionMajor() {
lazyInitiate();
return specVersionMajor;
}
public int getSpecVersionMinor() {
lazyInitiate();
return specVersionMinor;
}
public UPNPDevice getServiceOwnerDevice() {
return serviceOwnerDevice;
}
/**
* Retreives a service action for its given name
* @param actionName the service action name
* @return a ServiceAction object or null if no matching action for this service has been found
*/
public ServiceAction getUPNPServiceAction( String actionName ) {
lazyInitiate();
return (ServiceAction)UPNPServiceActions.get( actionName );
}
/**
* Retreives a service state variable for its given name
* @param stateVariableName the state variable name
* @return a ServiceStateVariable object or null if no matching state variable has been found
*/
public ServiceStateVariable getUPNPServiceStateVariable( String stateVariableName ) {
lazyInitiate();
return (ServiceStateVariable)UPNPServiceStateVariables.get( stateVariableName );
}
public Iterator getAvailableActionsName() {
lazyInitiate();
return UPNPServiceActions.keySet().iterator();
}
public int getAvailableActionsSize() {
lazyInitiate();
return UPNPServiceActions.keySet().size();
}
public Iterator getAvailableStateVariableName() {
lazyInitiate();
return UPNPServiceStateVariables.keySet().iterator();
}
public int getAvailableStateVariableSize() {
lazyInitiate();
return UPNPServiceStateVariables.keySet().size();
}
private void parseSCPD() {
try {
DocumentContainer.registerXMLParser( DocumentContainer.MODEL_DOM, new JXPathParser() );
UPNPService = new DocumentContainer( SCPDURL, DocumentContainer.MODEL_DOM );
JXPathContext context = JXPathContext.newContext( this );
Pointer rootPtr = context.getPointer( "UPNPService/scpd" );
JXPathContext rootCtx = context.getRelativeContext( rootPtr );
specVersionMajor = Integer.parseInt( (String)rootCtx.getValue( "specVersion/major" ) );
specVersionMinor = Integer.parseInt( (String)rootCtx.getValue( "specVersion/minor" ) );
parseServiceStateVariables( rootCtx );
Pointer actionsListPtr = rootCtx.getPointer( "actionList" );
JXPathContext actionsListCtx = context.getRelativeContext( actionsListPtr );
Double arraySize = (Double)actionsListCtx.getValue( "count( action )" );
UPNPServiceActions = new HashMap();
for ( int i = 1; i <= arraySize.intValue(); i++ ) {
ServiceAction action = new ServiceAction();
action.name = (String)actionsListCtx.getValue( "action["+i+"]/name" );
action.parent = this;
Pointer argumentListPtr = null;
try {
argumentListPtr = actionsListCtx.getPointer( "action["+i+"]/argumentList" );
} catch ( JXPathException ex ) {
// there is no arguments list.
}
if ( argumentListPtr != null ) {
JXPathContext argumentListCtx = actionsListCtx.getRelativeContext( argumentListPtr );
Double arraySizeArgs = (Double)argumentListCtx.getValue( "count( argument )" );
List orderedActionArguments = new ArrayList();
for ( int z = 1; z <= arraySizeArgs.intValue(); z++ ) {
ServiceActionArgument arg = new ServiceActionArgument();
arg.name = (String)argumentListCtx.getValue( "argument["+z+"]/name" );
String direction = (String)argumentListCtx.getValue( "argument["+z+"]/direction" );
arg.direction = direction.equals( ServiceActionArgument.DIRECTION_IN ) ? ServiceActionArgument.DIRECTION_IN : ServiceActionArgument.DIRECTION_OUT;
String stateVarName = (String)argumentListCtx.getValue( "argument["+z+"]/relatedStateVariable" );
ServiceStateVariable stateVar = (ServiceStateVariable)UPNPServiceStateVariables.get( stateVarName );
if ( stateVar == null ) {
throw new IllegalArgumentException( "Unable to find any state variable named " + stateVarName + " for service " + getServiceId() + " action " + action.name + " argument " + arg.name );
}
arg.relatedStateVariable = stateVar;
orderedActionArguments.add( arg );
}
if ( arraySizeArgs.intValue() > 0 ) {
action.setActionArguments( orderedActionArguments );
}
}
UPNPServiceActions.put( action.getName(), action );
}
parsedSCPD = true;
} catch ( Throwable t ) {
throw new RuntimeException( "Error during lazy SCDP file parsing at " + SCPDURL, t );
}
}
private void parseServiceStateVariables( JXPathContext rootContext ) {
Pointer serviceStateTablePtr = rootContext.getPointer( "serviceStateTable" );
JXPathContext serviceStateTableCtx = rootContext.getRelativeContext( serviceStateTablePtr );
Double arraySize = (Double)serviceStateTableCtx.getValue( "count( stateVariable )" );
UPNPServiceStateVariables = new HashMap();
for ( int i = 1; i <= arraySize.intValue(); i++ ) {
ServiceStateVariable srvStateVar = new ServiceStateVariable();
String sendEventsLcl = null;
try {
sendEventsLcl = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/@sendEvents" );
} catch ( JXPathException defEx ) {
// sendEvents not provided defaulting according to specs to "yes"
sendEventsLcl = "yes";
}
srvStateVar.parent = this;
srvStateVar.sendEvents = sendEventsLcl.equalsIgnoreCase( "no" ) ? false : true;
srvStateVar.name = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/name" );
srvStateVar.dataType = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/dataType" );
try {
srvStateVar.defaultValue = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/defaultValue" );
} catch ( JXPathException defEx ) {
// can happend since default value is not
}
Pointer allowedValuesPtr = null;
try {
allowedValuesPtr = serviceStateTableCtx.getPointer( "stateVariable["+i+"]/allowedValueList" );
} catch ( JXPathException ex ) {
// there is no allowed values list.
}
if ( allowedValuesPtr != null ) {
JXPathContext allowedValuesCtx = serviceStateTableCtx.getRelativeContext( allowedValuesPtr );
Double arraySizeAllowed = (Double)allowedValuesCtx.getValue( "count( allowedValue )" );
srvStateVar.allowedvalues = new HashSet();
for ( int z = 1; z <= arraySizeAllowed.intValue(); z++ ) {
String allowedValue = (String)allowedValuesCtx.getValue( "allowedValue["+z+"]" );
srvStateVar.allowedvalues.add( allowedValue );
}
}
Pointer allowedValueRangePtr = null;
try {
allowedValueRangePtr = serviceStateTableCtx.getPointer( "stateVariable["+i+"]/allowedValueRange" );
} catch ( JXPathException ex ) {
// there is no allowed values list, can happen
}
if ( allowedValueRangePtr != null ) {
srvStateVar.minimumRangeValue = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/allowedValueRange/minimum" );
srvStateVar.maximumRangeValue = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/allowedValueRange/maximum" );
try {
srvStateVar.stepRangeValue = (String)serviceStateTableCtx.getValue( "stateVariable["+i+"]/allowedValueRange/step" );
} catch ( JXPathException stepEx ) {
// can happend since step is not mandatory
}
}
UPNPServiceStateVariables.put( srvStateVar.getName(), srvStateVar );
}
}
private void lazyInitiate() {
if ( !parsedSCPD )
synchronized( this ) {
if ( !parsedSCPD )
parseSCPD();
}
}
/**
* Used for JXPath parsing, do not use this method
* @return a Container object for Xpath parsing capabilities
*/
public Container getUPNPService() {
return UPNPService;
}
public String getSCDPData() {
if ( SCPDURLData == null ) {
try {
java.io.InputStream in = SCPDURL.openConnection().getInputStream();
int readen = 0;
byte[] buff = new byte[512];
StringBuffer strBuff = new StringBuffer();
while( ( readen = in.read( buff ) ) != -1 ) {
strBuff.append( new String( buff, 0, readen ) );
}
in.close();
SCPDURLData = strBuff.toString();
} catch ( IOException ioEx ) {
return null;
}
}
return SCPDURLData;
}
}