📄 contentdirectoryservice.java
字号:
package no.auc.one.portableplayer.communication.mediaserver;
import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import no.auc.one.portableplayer.communication.*;
import no.auc.one.portableplayer.communication.soap.*;
import no.auc.one.portableplayer.utils.*;
import no.auc.one.portableplayer.librarymanager.*;
import org.apache.log4j.*;
/**
* Describes a UPnP Content Directory service of a Media Server device.
*/
public class ContentDirectoryService extends UPnPService implements Cloneable {
private static Logger LOG;
/**
* To request all available content to be returned.
*/
public static final int REQUEST_ALL = 0;
private static final int BROWSEFLAG_DIRECT_CHILDREN = 0;
private static final int BROWSEFLAG_METADATA = 1;
// To support clone() method.
private ContentDirectoryService(
String type,
String id,
String scpd,
String eventSub,
String control)
{
super(type, id, scpd, eventSub, control);
LOG = Logger.getLogger("CDS");
}
/**
* Construct a new class instance based on the UPnPService.
*
* @param service Service to base this class instance on.
*/
public ContentDirectoryService(
UPnPService service)
{
super(
service.getServiceType(),
service.getServiceID(),
service.getScpdURL(),
service.getEventSubURL(),
service.getControlURL());
}
/**
* Create a clone of this class instance.
*
* @return Clone of this class instance.
*/
public Object clone() {
return new ContentDirectoryService(
getServiceType(),
getServiceID(),
getScpdURL(),
getEventSubURL(),
getControlURL());
}
/**
* Browse and retrieve all available children of a container.
*
* @param containerId ID for the requested container.
*/
public ContentContainer browseDirectChildren(String containerId)
throws IOException
{
return browseDirectChildren(containerId, 0, REQUEST_ALL);
}
/**
* Initial browsing of a container of the media server's content directory
* service.
*
* @param containerId ID for the container to retrieve content from.
* @param startIndex Index for elements to be retrieved.
* @param requestedCount Requested count of elements to be retrieved.
* REQUEST_ALL(=0) means get all available elements.
*
* @return Returns a ContentContainer object which includes the children of
* it in a MediaContent array.
*
* @throws IOException
*/
public ContentContainer browseDirectChildren(
String containerId,
int startIndex,
int requestedCount) throws IOException
{
ContentContainer cc = null;
try {
ContentContainerHandler ccHandler = new ContentContainerHandler();
invokeBrowse(
containerId,
BROWSEFLAG_DIRECT_CHILDREN,
startIndex,
requestedCount,
ccHandler);
MediaContent[] mc = ccHandler.getMediaContent();
System.out.println(
"browse result: total matches=" + ccHandler.getTotalMatches() +
"\tnumber returned=" + ccHandler.getNumberReturned() +
"\tmc length=" + mc.length);
cc = new ContentContainer(
containerId,
"0",
"container",
mc);
} catch (NoSuchElementException nse) {
LOG.fatal(nse);
}
return cc;
}
/**
* Continued browsing of a container. This method should be used to
* continue browsing a container already retrieved from the 'initial'
* browseDirectChildren method overload.
*/
public void browseDirectChildren(
ContentContainer container,
int startIndex,
int requestedCount) throws IOException
{
try {
ContentContainerHandler ccHandler = new ContentContainerHandler();
System.out.println(
"Invoking browse for container ID=" + container.getObjectID() +
", startindex=" + startIndex + ", reqcount=" + requestedCount);
invokeBrowse(
container.getObjectID(),
BROWSEFLAG_DIRECT_CHILDREN,
startIndex,
requestedCount,
ccHandler);
System.out.println(
"Total matches: " + ccHandler.getTotalMatches() +
", Elemements fetched: " + ccHandler.getNumberReturned());
if(container.totalLength() == -1) { // container is currently empty
System.out.println("Container is currently empty.");
/*
container = new ContentContainer(
container.getObjectID(),
container.getParentID(),
container.getName(),
ccHandler.getTotalMatches());
*/
container.setTotalLength(ccHandler.getTotalMatches());
container.insertMediaContentAt(
0,
ccHandler.getMediaContent());
/*
if (container.totalLength() != ccHandler.getTotalMatches()) {
System.out.println(
"container.totalLength(" + container.totalLength() +
" != totalMatches(" + ccHandler.getTotalMatches());
retContainer = new ContentContainer(
container.getObjectID(),
container.getParentID(),
container.getName());
retContainer.insertMediaContentAt(
ccHandler.getMediaContent());
*/
} else {
System.out.println(
"container.totalLength(" + container.totalLength() +
") == ccHHandler.totalMatches(" +
ccHandler.getTotalMatches() + ")");
MediaContent[] mc = ccHandler.getMediaContent();
// XXX Is this test redundant?
if (mc.length > (container.totalLength() - startIndex)) {
System.out.println(
"Ouch, mc.length(" + mc.length +
") > container.length(" + container.totalLength() +
") - startIndex(" + startIndex +
") Nope test is not redundant!");
}
/*
container = new ContentContainer(
container.getObjectID(),
container.getParentID(),
container.getName(),
ccHandler.getTotalMatches());
container.insertMediaContentAt(
0,
container.getMediaContent());
*/
container.insertMediaContentAt(
startIndex,
mc);
}
} catch (NoSuchElementException nse) {
LOG.fatal(nse);
}
}
/**
* Retrieve metadata for an object.
*
* For example Windows Media Connect (WMC) does not include metadata in
* the response to a Browse request with the BrowseDirectChildren flag.
*
* @param objectId Requested object
*
* @return MediaContent for the specific object. Notice that the callee
* should use the instanceof operator to test what kind of
* object was returned (one of the classes derived from
* MediaContent).
*
* @throws IOException
*/
public MediaContent browseMetadata(String objectId) throws IOException {
MediaContent mc = null;
try {
// XXX MetadataResultHandler mrh = new MetadataResultHandler();
// XXX invokeBrowse(objectID, BROWSEFLAG_METADATA, 0, 1, resultParser);
// Do something with mrh?
} catch (NoSuchElementException nse) {
LOG.fatal(nse);
}
return mc;
}
/**
* Invokes the browse action at the server side.
*
* Used by the public methods browseDirectChildren and browseMetadata.
*/
private void invokeBrowse(
String objectID,
int browseFlag,
int startIndex,
int requestedCount,
DefaultHandler resultParser) throws IOException
{
SoapInvoke si = new SoapInvoke(
"\"urn:schemas-upnp-org:service:ContentDirectory:1#Browse\"",
getControlURL());
StringBuffer buffer = new StringBuffer();
// XXX: Not all devices like to get the <?xml..?> part. Should perhaps
// try first to send a request with the <?xml..?> and if an error
// is returned then try to send a new request without.
//
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
buffer.append(
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"");
buffer.append(
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n");
buffer.append("<s:Body>\r\n");
buffer.append
("<u:Browse xmlns:u=\"urn:schemas-upnp-org:service:");
buffer.append("ContentDirectory:1\">\r\n");
buffer.append("<ObjectID>" + objectID + "</ObjectID>\r\n");
buffer.append("<BrowseFlag>");
buffer.append(
(browseFlag == BROWSEFLAG_DIRECT_CHILDREN) ?
"BrowseDirectChildren" : "BrowseMetadata");
buffer.append("</BrowseFlag>\r\n");
buffer.append("<Filter>*</Filter>\r\n");
buffer.append(
"<StartingIndex>" + startIndex + "</StartingIndex>\r\n");
buffer.append(
"<RequestedCount>" + requestedCount + "</RequestedCount>\r\n");
buffer.append("<SortCriteria></SortCriteria>\r\n");
buffer.append("</u:Browse>\r\n");
buffer.append("</s:Body>\r\n");
buffer.append("</s:Envelope>\r\n");
si.setBody(buffer.toString());
String resp = si.invoke(
"\"urn:schemas-upnp-org:service:ContentDirectory:1#Browse\"");
GenericSoapResultParser gparser = new GenericSoapResultParser(
new ByteArrayInputStream(resp.getBytes()),
resultParser);
gparser.parseSoapResult();
if (resultParser instanceof ContentContainerHandler) {
BrowseResultParser brp = (BrowseResultParser)resultParser;
brp.setNumberReturned(gparser.getNumberReturned());
brp.setTotalMatches(gparser.getTotalMatches());
} else {
System.out.println(
"Nope, result parser does not implement BrowseResultParser.");
}
}
private class GenericSoapResultParser {
private InputStream is;
private DefaultHandler resultParserHandler;
private SAXParser parser;
private GenericSoapResultHandler gh;
public GenericSoapResultParser(InputStream is, DefaultHandler dh) {
try {
SAXParserFactory pfactory = SAXParserFactory.newInstance();
parser = pfactory.newSAXParser();
this.is = is;
resultParserHandler = dh;
} catch (SAXException se) {
LOG.debug("SAXException caught in GSRP::ctor");
LOG.debug(se);
} catch (ParserConfigurationException pce) {
LOG.debug("PCE in GSRP::ctor");
LOG.debug(pce);
}
}
public void parseSoapResult() {
try {
gh = new GenericSoapResultHandler();
parser.parse(is, gh);
parser.parse(
new ByteArrayInputStream(
gh.resultElement.getBytes()),
resultParserHandler);
} catch (SAXException se) {
LOG.debug("Error in generic soap result parser");
LOG.debug(se);
} catch (IOException ioe) {
LOG.debug("IOException in GSRP");
LOG.debug(ioe);
}
}
public int getNumberReturned() {
return gh.numberReturned;
}
public int getTotalMatches() {
return gh.totalMatches;
}
private class GenericSoapResultHandler extends DefaultHandler {
public String resultElement;
public int totalMatches = 0;
public int numberReturned = 0;
private int currentElement;
private final int ELEMENT_IS_UNKNOWN = -1;
private final int ELEMENT_IS_RESULT = 0;
private final int ELEMENT_IS_NUMBER_RETURNED = 1;
private final int ELEMENT_IS_TOTAL_MATCHES = 2;
public GenericSoapResultHandler() {
currentElement = ELEMENT_IS_UNKNOWN;
}
public void characters(
char[] ch,
int start,
int length) throws SAXException
{
String txt = new String(ch, start, length);
switch(currentElement) {
case ELEMENT_IS_RESULT:
resultElement = txt;
break;
case ELEMENT_IS_NUMBER_RETURNED:
numberReturned = Integer.parseInt(txt);
break;
case ELEMENT_IS_TOTAL_MATCHES:
totalMatches = Integer.parseInt(txt);
break;
}
currentElement = ELEMENT_IS_UNKNOWN;
}
public void startElement(
String uri,
String localName,
String qName,
Attributes attr) throws SAXException
{
if (qName.equals("Result")) {
currentElement = ELEMENT_IS_RESULT;
} else if (qName.equals("NumberReturned")) {
currentElement = ELEMENT_IS_NUMBER_RETURNED;
} else if (qName.equals("TotalMatches")) {
currentElement = ELEMENT_IS_TOTAL_MATCHES;
} else {
currentElement = ELEMENT_IS_UNKNOWN;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -