📄 serverdevice.java
字号:
package no.auc.one.portableplayer.lms;
import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.rms.*;
import no.auc.one.portableplayer.Main;
import no.auc.one.portableplayer.communication.upnphosting.*;
import no.auc.one.portableplayer.settings.Settings;
//import no.auc.one.portableplayer.lms.SourceContainer.MusicContainer.AllTrackContainer;
//import no.auc.one.portableplayer.utils.StringEscapeUtils;
import org.apache.log4j.Logger;
/**
* ServerDevice can have several Services, and each Service can have serveral
* Actions and UPnPStateVariables.each Action can have several UPnPActionArgument,
* also each UPnPStateVariable can have default value or defined value.
*
* Currently, there is only one Service---CDS,and inside the CDS,there is only one
* Browse Action.
*
* XXX:
* Should make a little change in the invoke action part later
* and in the ActionArgument part to limit the value.
*
*@version 1.0
*@since JDK 1.5.0
*/
public final class ServerDevice extends UPnPHostingDeviceBase {
private static Logger LOG = Logger.getLogger("LMS");
private static String mediaRoot = Settings.getInstance().getAppProperty(
"ONEPP-MediaRoot");
private static String indexStoreName = "Media_Server_Index";
private static String contentLocationPrefix = null;
private static ServerDevice selfRef = null;
private ContentDirectoryService cds=null;
private ConnectionManagerService cms=null;
private Hashtable services;
private Timer taskScheduler;
private ServerDevice(){
try {
LOG.debug("ServerDevice ctor");
//
// Use '/' as a default mediaRoot
//
if (mediaRoot == null) {
LOG.warn("onepp.mediaroot property does not exist. Using /");
mediaRoot = "/";
}
//
// Expect mediaRoot to have a / suffix
//
if (!mediaRoot.endsWith("/")) {
mediaRoot += "/";
}
LOG.debug("mediaRoot = " + mediaRoot);
UPnPHosting hosting = UPnPHosting.getInstance();
StringBuffer fileRealUrl = new StringBuffer();
fileRealUrl.append("http://");
fileRealUrl.append(hosting.getLocalAddress());
fileRealUrl.append(":");
fileRealUrl.append(hosting.getLocalPort());
fileRealUrl.append("/");
fileRealUrl.append(ContentDirectoryHandler.NAMESPACE);
fileRealUrl.append("/");
contentLocationPrefix = fileRealUrl.toString();
System.out.println("Content Location Prefix: " + contentLocationPrefix);
taskScheduler = new Timer();
taskScheduler.schedule(
new FileIndexGenerator(),
0, // Start immediately
300000); // Index every 5. minute
// XXX Should add a FileSystemListener here. E.g. if the
// mediaRoot is unmounted then CDS should stop / return 404 /
// whatever (maybe a 3xx or 5xx is best? Currently
// unavailable...). And of course make it available once the
// storage medium has been mounted back again.
UPnPHosting.getInstance().registerHttpHandler(
ContentDirectoryHandler.NAMESPACE,
new ContentDirectoryHandler());
cds = ContentDirectoryService.getInstance();
cms = ConnectionManagerService.getInstance();
LOG.debug("Created CDS");
services=new Hashtable(2);
services.put(cds.serviceId(),cds);
services.put(cms.serviceId(),cms);
LOG.debug("Finished serverdevice ctor");
} catch (IOException e) {
LOG.fatal("Error generating contentLocationPrefix");
e.printStackTrace();
} catch (RecordStoreException rse) {
System.out.println("Error with RS while creating CD Handler");
rse.printStackTrace();
}
}
public static ServerDevice getInstance() {
if (selfRef == null) {
selfRef = new ServerDevice();
}
return selfRef;
}
public String friendlyName(){
return Settings.getInstance().lmsFriendlyName();
}
public String manufacturer(){
return "Agder University College";
}
public String manufacturerUrl(){
return "http://ikt.hia.no/aml";
}
public String modelDescription(){
return "Local Media Server of " + System.getProperty("microedition.hostname");
}
public String modelName(){
return "AUC ONE Local Media Server";
}
public String modelNumber(){
return "1.0";
}
public String modelUrl(){
return "http://ikt.hia.no/aml";
}
public String serialNumber(){
return "1234567890";
}
public String upc(){
return "0987654321";
}
public String deviceType() {
return "urn:schemas-upnp-org:device:MediaServer:1";
}
public String udn() {
return Settings.getInstance().lmsUdn();
}
public Hashtable serviceTable(){
return services;
}
public static String getIndexStoreName() {
return indexStoreName;
}
public static String getMediaRoot() {
return mediaRoot;
}
public static String getContentLocationPrefix() {
return contentLocationPrefix;
}
private final class ContentDirectoryHandler extends no.auc.one.portableplayer.communication.upnphosting.HttpRequestHandler {
public static final String NAMESPACE = "content";
private RecordStore rs;
public ContentDirectoryHandler() throws RecordStoreException {
rs = RecordStore.openRecordStore(indexStoreName, true);
}
public String allowedMethods() {
return "GET";
}
public byte[] handleGetRequest(HttpRequest req) {
FileConnection file = null;
InputStream fileStream = null;
OutputStream requestStream = null;
try {
String uri = req.getRequestUri();
int objectId = Integer.parseInt(
uri.substring(uri.lastIndexOf('/') + 1, uri.lastIndexOf('.')));
System.out.println("ObjectID requested: " + objectId);
ByteArrayInputStream bais = new ByteArrayInputStream(
rs.getRecord(objectId));
DataInputStream dis = new DataInputStream(bais);
String classType = dis.readUTF();
// XXX Must be changed if we want to return containers later
if (!classType.startsWith("object.item")) {
StringBuffer sb = new StringBuffer();
sb.append("HTTP/1.1 403 Forbidden\r\n");
sb.append("Content-Length: 0\r\n");
sb.append("\r\n");
return sb.toString().getBytes();
}
Item reqItem = new Item(dis);
file = (FileConnection)Connector.open(
reqItem.getLocalUrl());
SocketConnection reqSc = req.getSocketConnection();
fileStream = file.openInputStream();
int fileSize = (int)file.fileSize();
int maxBufferSize = reqSc.getSocketOption(
SocketConnection.RCVBUF);
System.out.println("Beginning to send the data..");
StringBuffer sb = new StringBuffer(128);
sb.append("HTTP/1.1 200 OK\r\n");
//
// XXX Should do something more fancy fore MIME type mapping
//
sb.append("Content-Type: ");
if (classType.startsWith("object.item.imageItem")) {
sb.append("image/jpeg");
} else if (classType.startsWith("object.item.audioItem")) {
sb.append("audio/mpeg");
} else if (classType.startsWith("object.item.presentationItem")) {
sb.append("application/vnd.ms-powerpoint");
} else {
sb.append("application/octet-stream");
}
sb.append("\r\n");
sb.append("Content-Length: ");
sb.append(file.fileSize());
sb.append("\r\n");
sb.append("Connection: close\r\n");
// XXX Add server + date headers etc.
sb.append("\r\n");
requestStream = reqSc.openOutputStream();
byte[] header = sb.toString().getBytes();
requestStream.write(header);
int fileDataToWrite =
(maxBufferSize - header.length) > fileSize ?
fileSize : maxBufferSize - header.length;
byte[] fileData = new byte[fileDataToWrite];
fileStream.read(fileData, 0, fileDataToWrite);
requestStream.write(fileData);
requestStream.flush();
int fileDataWritten = fileDataToWrite;
while(fileDataWritten < fileSize) {
fileDataToWrite = (fileSize - fileDataWritten) > maxBufferSize ?
maxBufferSize : fileSize - fileDataWritten;
fileData = new byte[fileDataToWrite];
fileStream.read(fileData);
requestStream.write(fileData);
requestStream.flush();
fileDataWritten += fileDataToWrite;
}
} catch (InvalidRecordIDException iride) {
LOG.warn("RecordID probably not found");
iride.printStackTrace();
} catch (RecordStoreNotOpenException rsnoe) {
LOG.fatal("Strange... RS is closed");
rsnoe.printStackTrace();
} catch (RecordStoreException rse) {
LOG.warn("RecordStoreException occured while streaming content");
rse.printStackTrace();
} catch (IOException ioe) {
LOG.warn("IOException while streaming content");
ioe.printStackTrace();
} finally {
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException ioe) {
LOG.warn("IOException while closing fileStream");
LOG.warn(ioe);
ioe.printStackTrace();
}
}
if (file != null) {
try {
file.close();
} catch (IOException ioe) {
LOG.warn("IOException while closing file");
LOG.warn(ioe);
ioe.printStackTrace();
}
}
if (requestStream != null) {
try {
requestStream.close();
} catch (IOException ioe) {
LOG.warn("IOException while closing requestStream");
LOG.warn(ioe);
ioe.printStackTrace();
}
}
}
return null;
}
}
private final class FileIndexGenerator extends TimerTask {
private RecordStore rs;
private FileConnection mediaRootConnection;
private Container root = null;
private StorageFolder music = null;
private StorageFolder pictures = null;
private StorageFolder presentations = null;
public FileIndexGenerator() throws IOException,
RecordStoreNotOpenException,
InvalidRecordIDException,
RecordStoreException
{
System.out.println("File sytem roots available:");
for (Enumeration e = FileSystemRegistry.listRoots();
e.hasMoreElements();)
{
System.out.println((String)e.nextElement());
}
mediaRootConnection = (FileConnection)Connector.open(
"file:///" + mediaRoot);
// XXX Because the server port probably is different then the
// last time the index was run the index must be deleted.
try {
RecordStore.deleteRecordStore(indexStoreName);
} catch (RecordStoreNotFoundException rsnfe) {
// Index didn't exist... no worries
}
rs = RecordStore.openRecordStore(indexStoreName, true);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -