I have a music player that downloads a directory from the FTP server to the SD card. And the player downloads and accepts server settings (there are two versions of ME and CE), but it happens after downloading the application crashes. When I delete some folders after downloading it works normally in ME mode, but when I download it and it takes the CE mode all the time the application crashes.
public class FTPManager {
public static final String LOG_TAG = FTPManager.class.getName();
private static final String HOST = "*******";
private static final String LOGIN = "*******";
private static final String PASSWORD = "*******";
private static final int REPEAT_TIMEOUT_MILLIS = 5 * 1000;
private int mCommandAttempts;
private String host;
private String login;
private String password;
private FTPClient mFtpClient;
private FTPManager(String host, String login, String password) {
this.host = host;
this.login = login;
this.password = password;
mFtpClient = new FTPClient();
}
public FTPManager() {
this(HOST, LOGIN, PASSWORD);
}
public boolean connect() {
mCommandAttempts = 5;
return attemptConnect();
}
private boolean attemptConnect() {
try {
mFtpClient.connect(host);
mFtpClient.login(this.login, password);
mFtpClient.setPassive(true);
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptConnect();
}
}
return true;
}
public List<String> listFiles() {
return listFiles(FTPFile.TYPE_FILE);
}
public List<String> listDirectores() {
return listFiles(FTPFile.TYPE_DIRECTORY);
}
private List<String> listFiles(int type) {
mCommandAttempts = 5;
return attemptListFiles(type);
}
private List<String> attemptListFiles(int type) {
ArrayList<String> names = new ArrayList<>();
try {
FTPFile[] files = mFtpClient.list();
for (FTPFile file : files) {
if (file.getType() == type) {
names.add(file.getName());
}
}
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return names;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptListFiles(type);
}
}
return names;
}
public boolean downloadFile(OutputStream outputStream, String ftpName) {
mCommandAttempts = 5;
return attemptDownloadFile(outputStream, ftpName);
}
private boolean attemptDownloadFile(OutputStream outputStream, String ftpName) {
try {
mFtpClient.download(ftpName, outputStream, 0, null);
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptDownloadFile(outputStream, ftpName);
}
}
return false;
}
public boolean changeDirectory(String path) {
mCommandAttempts = 5;
return attemptChangeDirectory(path);
}
private boolean attemptChangeDirectory(String path) {
try {
mFtpClient.changeDirectory(path);
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
try {
TimeUnit.MILLISECONDS.sleep(REPEAT_TIMEOUT_MILLIS);
} catch (InterruptedException e1) {
Log.e(LOG_TAG, e.toString());
return false;
}
mCommandAttempts--;
if (mCommandAttempts > 0) {
return attemptChangeDirectory(path);
}
}
return false;
}
public boolean release() {
if (mFtpClient != null) try {
mFtpClient.logout();
mFtpClient.disconnect(true);
mFtpClient = null;
return true;
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
return false;
}
return false;
}
}
And
public class FTPDirectory implements Parcelable {
private StringBuilder builder;
public FTPDirectory(String host) {
builder = new StringBuilder(host);
}
protected FTPDirectory(Parcel in) {
builder = new StringBuilder(in.readString());
}
public static final Creator<FTPDirectory> CREATOR = new Creator<FTPDirectory>() {
#Override
public FTPDirectory createFromParcel(Parcel in) {
return new FTPDirectory(in);
}
#Override
public FTPDirectory[] newArray(int size) {
return new FTPDirectory[size];
}
};
public FTPDirectory append(String path) {
builder.append("/").append(path);
return this;
}
public String getPath() {
return builder.toString();
}
public static FTPDirectory getImgDirectory() {
return new FTPDirectory("/img");
}
public static FTPDirectory getAdDirectory() {
return new FTPDirectory("/adv");
}
public static FTPDirectory getMusicDirectory() {
return new FTPDirectory("/music");
}
public static FTPDirectory getChannelDirectory(String channel, int index) {
return getChannelRootDirectory(channel)
.append(Integer.toString(index));
}
public static FTPDirectory getChannelRootDirectory(String channel) {
return getMusicDirectory()
.append(channel);
}
#Override
public String toString() {
return "FTPDirectory{" +
"Path=" + builder.toString() +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getPath());
}
}
I think somewhere here there may be a mistake. It turns out that one file reads and the other does not, but the format is the same. Please help to solve the problem.
Related
The streams used to work, but suddenly just stopped two days ago, and I can't get it fixed.
The client creates and successfully sends a User object and a Message object (serialize by the client and deserialize by the server). When the clients receives any of the two classes (serialized by the server and deserialized by the client), I get exceptions, mainly:
java.io.UTFDataFormatException
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3704)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3658)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3458)
at java.base/java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1239)
at java.base/java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:804)
at java.base/java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:988)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2032)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2209)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
at Model.MessageClient$1.run(MessageClient.java:69)
at java.base/java.lang.Thread.run(Thread.java:833)
Every so often, I get:
java.io.InvalidClassException: Model.Message; class invalid for deserialization
at java.base/java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:174)
at java.base/java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:921)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2210)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
Client side - streams
public MessageClient(String ip, int port, String usernameStr, ImageIcon icon, Controller controller) {
this.user = new User(usernameStr, icon);
this.controller = controller;
this.port = port;
this.ip = ip;
this.messageBuffer = new Buffer<>();
this.contacts = new ArrayList<>(); //(ArrayList<Model.User>) readObjectFromFile("files/contacts");
setUpStreams();
setUpThreads();
}
public void setUpStreams(){
try {
s = new Socket(ip, port);
try {
ois = new ObjectInputStream(s.getInputStream());
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(user);
oos.flush();
users = new ArrayList<>();
setUpThreads();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void setUpThreads(){
t1 = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Object o = ois.readObject();
if (o.getClass().isAssignableFrom(Message.class)) {
receiveMessage((Message) o);
}
if (o.getClass().isAssignableFrom(ArrayList.class)) {
updateUsers((ArrayList<Model.User>) o);
}
} catch(EOFException e){
System.out.println("stopped");
t2.stop();
t1.stop();
} catch(IOException | ClassNotFoundException e){
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
}
});
t2 = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Message currMessage = messageBuffer.get();
oos.writeObject(currMessage);
oos.flush();
} catch(IOException | InterruptedException e){
e.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
Server-side streams
#Override
public synchronized void run() {
while (socket.isConnected() && !socket.isClosed()) {
try {
Object o = ois.readObject();
ih.addToBuffer((Model.Message) o);
} catch (EOFException e) {
try {
socket.close();
t2.stop();
t1.stop();
} catch (IOException ex) {
ex.printStackTrace();
}
} catch (IOException | ClassNotFoundException e) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
chm.put(user, null);
clients.remove(this);
sendAll(new Message(user.getUsername() + " has disconnected", null));
}
private class InputHandler implements Runnable{
private Buffer<Model.Message> inputBuffer;
public InputHandler(){
inputBuffer = new Buffer<>();
}
public void addToBuffer(Message msg){
inputBuffer.put(msg);
}
#Override
public synchronized void run() {
Object o = null;
while (!Thread.interrupted()) {
Message temp = null;
Message sendable = null;
try {
temp = inputBuffer.get();
sendable = new Message(temp.getText(), temp.getIcon(), temp.getRecipients(), temp.getSender());
sendable.setCurrID();
sendable.setUploaded(new Timestamp(System.currentTimeMillis()));
sendSelect(sendable ,sendable.getSender());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void sendSelect(Message msg, User selectedUser){
Client currClient;
if(!chm.containsKey(selectedUser)) {
try {
oos.writeObject(new Message(selectedUser.getUsername() + "not found", null));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
} else if ((currClient = chm.get(selectedUser)) != null) {
try {
currClient.oos.writeObject((Model.Message) msg);
currClient.oos.flush();
msg.setDownloaded(new Timestamp(System.currentTimeMillis()));
callback.downloadTimestamp(msg);
} catch (IOException e) {
e.printStackTrace();
}
} else {
addUnsent(selectedUser, msg);
}
}
The classes I serialized copy and pasted.
The classpath is the same, all fields are serializable and the have no-arg constructors. I also made sure both encoding on are set to UTF-8
Message
package Model;
import javax.swing.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.LinkedList;
public class Message implements Serializable{
#Serial
private static final long serialVersionUID = -3930131856060689940L;
private static int nextID = 0;
private int currID;
private final String text;
private final ImageIcon icon;
private Timestamp uploaded;
private Timestamp downloaded;
private final User sender;
private final LinkedList<User> recipients;
public Message(){
currID = nextID;
nextID++;
this.text = null;
this.icon = null;
sender = null;
recipients = null;
}
public Message(String text, User sender){
currID = nextID;
nextID++;
this.text = text;
this.icon = null;
this.sender = sender;
this.recipients = null;
}
public Message(String text, ImageIcon icon, User sender) {
currID = nextID;
nextID++;
this.text = text;
this.icon = icon;
this.sender = sender;
this.recipients = null;
}
public Message(String text, ImageIcon icon, LinkedList<User> recipients, User sender) {
currID = nextID;
nextID++;
this.text = text;
this.icon = icon;
this.sender = sender;
this.recipients = recipients;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Message){
if( ((Message) obj).getCurrID() == this.currID ){
return true;
}
}
return false;
}
public String getText() {
return text;
}
public ImageIcon getIcon() {
return icon;
}
public Timestamp getUploaded() {
return uploaded;
}
public Timestamp getDownloaded() {
return downloaded;
}
public Model.User getSender(){return sender;}
public int getCurrID(){return currID;}
public void setCurrID(){currID = nextID; nextID++;}
public LinkedList<User> getRecipients(){
return recipients;
}
public void setUploaded(Timestamp uploaded) {
this.uploaded = uploaded;
}
public void setDownloaded(Timestamp downloaded) {
this.downloaded = downloaded;
}
}
User
package Model;
import javax.swing.*;
import java.io.Serial;
import java.io.Serializable;
public class User implements Serializable{
#Serial
private static final long serialVersionUID = -5886308724572898536L;
private String username;
private ImageIcon image;
public User(String username, ImageIcon image){
this.username = username;
this.image = image;
}
public int hashCode() {
return username.hashCode();
}
public boolean equals(Object obj) {
if(obj!=null && obj instanceof User)
return username.equals(((User)obj).getUsername());
return false;
}
public String getUsername() {
return username;
}
#Override
public String toString(){
return username;
}
}
The issue was I called setUpThread() twice, messing with the input stream. So if you get this kind of problem, make sure you don't initialize your threads (that are reading input stream from the sockets) more than once.
I'm trying to write couple of object using ObjectOutputStream to a file. After that, I read the file with ObjectInputStream. The problem is, I can only read first object in the file. When I opened the file with notepad++, I can see the entries for other objects.
Here writer part
public class FileProcess {
private ObjectOutputStream output;
private Accounts account;
public FileProcess() {}
public void WriteObject(Accounts account) {
this.account = account;
openFile();
addRecords();
closeFile();
}
private void openFile() {
try {
output = new ObjectOutputStream(Files.newOutputStream(Paths.get("record_files.txt"),CREATE,APPEND));
}catch (Exception e) {
System.out.println("\nError opening file");
}
}
private void addRecords() {
try {
output.writeObject(account);
}
catch (Exception e) {
System.out.printf("Error writing file %s",e);
}
}
private void closeFile() {
try {
if(output != null)
output.close();
} catch (Exception e) {
System.out.println("\nError closing file");
}
}
}
And Reader part
abstract class User {
private String userID;
private int password;
private String position;
private ObjectInputStream input;
public User(String userID, int password, String position) {
this.userID = userID;
this.password = password;
this.position = position;
}
boolean signIn() {
boolean found_check = false;
openFile();
found_check = checkRecords();
closeFile();
return found_check;
}
private void closeFile() {
try {
if(input != null)
input.close();
} catch (Exception e) {
System.out.println("Error closing file");
}
}
private boolean checkRecords() {
try {
while(true) {
Accounts account = (Accounts) input.readObject();
System.out.printf("%s %d %s",account.getUserID(),account.getPassword(),account.getPosition());
}
}
catch (Exception e) {
System.out.println("\nError reading file");
return false;
}
return false;
}
private void openFile() {
try {
input = new ObjectInputStream(Files.newInputStream(Paths.get("record_files.txt")));
}catch (Exception e) {
System.out.println("Error opening file");
}
}
}
Accounts class implements Serializable
public class Accounts implements Serializable {
private String userID;
private int password;
private String position;
public Accounts(String userID, int password, String position) {
try {
this.userID = userID;
this.password = password;
this.position = position;
}
catch (Exception e) {
System.out.printf(e.toString());
}
}
}
Your code is throwing the following exception: java.io.StreamCorruptedException: invalid type code: AC.
There's a good question and answer here
This was discovered by adding e.printStackTrace(); to the exception handler in User.checkRecords.
I´m try to build a application which, by threads, are listening to directory for changes. Everything works fine, but there is a little bug. I´m very new to the whole threads-thing... So, this problem probably based on my ignorance...
The program can se all the changes in the picked directory, BUT, when the threads are running, i cant modify the files inside the directory... Those are locked in the process...
I will be very happy if someone perhaps can give me some tips in how i can solve this.
Thank you in advance
DirWatch
public class DirWatch implements Runnable{
Path dirPath;
private boolean run = true;
private boolean created = false;
private boolean modified = false;
private boolean compressed = false;
private boolean isJSON = false;
/**
*
* #param path
* #throws IOException
*/
public void setWatchPath(String path) throws IOException {
dirPath = Paths.get(path);
try {
Boolean isFolder = (Boolean) Files.getAttribute(dirPath, "basic:isDirectory", new LinkOption[]{NOFOLLOW_LINKS});
if (!isFolder) {
throw new IllegalArgumentException("Path: " + dirPath + " is not a folder");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
System.out.println("Watching path: " + path);
}
public void setDirPathWatchRun(boolean run){
this.run = run;
}
public boolean isCreated() {
return created;
}
public void setCreated(boolean created) {
this.created = created;
}
public boolean isModified() {
return modified;
}
public void setModified(boolean modified) {
this.modified = modified;
}
public boolean isCompressed() {
return compressed;
}
public void setCompressed(boolean compressed) {
this.compressed = compressed;
}
public boolean isJSON() {
return isJSON;
}
public void setJSON(boolean JSON) {
isJSON = JSON;
}
private void checkFileType(String fileName){
String extension = fileName.substring(fileName.length() - 4);
if(extension.equalsIgnoreCase(FILE_TYPE.TAR.getFileType())){
setCompressed(true);
System.out.println(extension);
}
if(extension.equalsIgnoreCase(".json")){
setJSON(true);
}
}
#Override
public void run() {
FileSystem fs = dirPath.getFileSystem ();
try(WatchService service = fs.newWatchService()) {
dirPath.register(service, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
WatchKey key = null;
while(run) {
key = service.take();
WatchEvent.Kind<?> kind = null;
for(WatchEvent<?> watchEvent : key.pollEvents()) {
kind = watchEvent.kind();
if (OVERFLOW == kind) {
System.out.println("OVERFLOW");
continue;
} else if (ENTRY_CREATE == kind) {
System.out.println("New path created: " + watchEvent.context().toString());
setCreated(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_DELETE == kind){
System.out.println("Path deleted: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
} else if (ENTRY_MODIFY == kind) {
System.out.println("Path modified: " + watchEvent.context().toString());
setModified(true);
checkFileType(watchEvent.context().toString());
}
}
if(!key.reset()) {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Method Watch in another class
private void watch() throws IOException {
watchJSON = new DirWatch();
watchTAR = new DirWatch();
watchTAR.setWatchPath(serverArgs.getCompressedPath());
watchJSON.setWatchPath(serverArgs.getExtractedPath());
Runnable checkSourceActions = new Runnable() {
#Override
public void run() {
while(true) {
if (watchJSON.isCreated() || (watchJSON.isModified())) {
server();
}
if(watchTAR.isCreated() || (watchTAR.isModified())) {
extractFiles(fileHandler);
createManifest(fileHandler);
server();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread1 = new Thread(watchJSON);
Thread thread3 = new Thread(watchTAR);
Thread thread2 = new Thread(checkSourceActions);
thread1.start();
thread2.start();
thread3.start();
}
When I try to change the file while the program is running
I have a programm which communicates with MPlayer through Input and Outputstream of the Process.
It works quite good, but I can only communicate with the Process in the Main Thread, and not in any other. Is there a posibility to get arround that?
synchronized-Methods or blocks didn't brought a solution
private String getProperty(String property) {
System.out.println("CurThread: " + Thread.currentThread().getName());
String cmd = "";
cmd = String.format("pausing_keep_force get_property %s", property);
mplayerIn.println(cmd);
mplayerIn.flush();
String rightAnswer = String.format("ANS_%s=", property);
String errorAnswer = "ANS_ERROR";
String answer;
String value = "";
try {
while ((answer = mplayerOut.readLine()) != null) {
if (answer.startsWith(rightAnswer)) {
value = answer.substring(rightAnswer.length());
break;
}
if (answer.startsWith(errorAnswer)) {
value = "";
break;
}
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("Property Error:" + property);
}
return value;
}
edit: ProcessCommunicator
public class ProcessCommunicator extends Thread {
private String cmd;
private BufferedReader is;
private PrintStream os;
List<MessageReceivedListener> listeners;
public boolean addListener(MessageReceivedListener listener) {
return listeners.add(listener);
}
public boolean removeListener(MessageReceivedListener listener) {
if (listeners.contains(listener)) {
return listeners.remove(listener);
}
return false;
}
public ProcessCommunicator(String cmd) {
this.cmd = cmd;
listeners = new ArrayList<>();
}
public void write(String cmd) {
System.out.println(cmd);
os.println(cmd);
os.flush();
}
public void fireEvent(String msg) {
for (MessageReceivedListener listener : listeners) {
listener.received(msg);
}
}
Process p;
#Override
public void run() {
try {
p = Runtime.getRuntime().exec(cmd);
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
os = new PrintStream(p.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
String line;
try {
while ((line = is.readLine()) != null) {
System.err.println(line);
fireEvent(line.trim());
}
} catch (IOException e) {
e.printStackTrace();
}
}
boolean waitForProperty;
String propertyResult;
public String readProperty(String property) {
final String rightAnswer = String.format("ANS_%s=", property);
propertyResult = "";
MessageReceivedListener messageListener = new MessageReceivedListener() {
#Override
public void received(String s) {
if (s.startsWith(rightAnswer)) {
waitForProperty = false;
propertyResult = s.substring(rightAnswer.length());
} else if (s.startsWith("ANS_ERROR")) {
waitForProperty = false;
propertyResult = "";
}
}
};
addListener(messageListener);
waitForProperty = true;
write(String.format("pausing_keep_force get_property %s", property));
int i = 5;
while (waitForProperty && i > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(".");
i--;
}
System.out.println("END");
removeListener(messageListener);
return propertyResult;
}
}
I'm using the Bluecove library to devolep an Obex ftp client/server on android 2.X.
So far i managed to connect as a client from android to a pc.
I tried the bluecove example code for a server but doesn't work.
Is it possible to develop a server on android 2.X. Does any one have the code to do it.
Thank you.
public class OBEXServer implements Runnable {
private SessionNotifier serverConnection;
private boolean isStoped = false;
private boolean isRunning = false;
public final UUID OBEX_OBJECT_PUSH = new UUID(0x1105);
public static final String SERVER_NAME = "OBEX Object Push";
private UserInteraction interaction;
private OBEXServer(UserInteraction interaction) {
this.interaction = interaction;
}
public static OBEXServer startServer(UserInteraction interaction) {
OBEXServer srv = new OBEXServer(interaction);
Thread thread = new Thread(srv);
thread.start();
while (!srv.isRunning && !srv.isStoped) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new Error(e);
}
}
if (!srv.isRunning) {
throw new Error("Can't start server");
}
return srv;
}
/*
* (non-Javadoc)
*
* #see java.lang.Runnable#run()
*/
public void run() {
isStoped = false;
LocalDevice localDevice;
try {
localDevice = LocalDevice.getLocalDevice();
if (!localDevice.setDiscoverable(DiscoveryAgent.GIAC)) {
Logger.error("Fail to set LocalDevice Discoverable");
}
serverConnection = (SessionNotifier) Connector.open("btgoep://localhost:" + OBEX_OBJECT_PUSH + ";name="
+ SERVER_NAME);
} catch (Throwable e) {
Logger.error("OBEX Server start error", e);
isStoped = true;
return;
}
try {
ServiceRecord record = localDevice.getRecord(serverConnection);
String url = record.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
Logger.debug("BT server url: " + url);
final int OBJECT_TRANSFER_SERVICE = 0x100000;
try {
record.setDeviceServiceClasses(OBJECT_TRANSFER_SERVICE);
} catch (Throwable e) {
Logger.debug("setDeviceServiceClasses", e);
}
DataElement bluetoothProfileDescriptorList = new DataElement(DataElement.DATSEQ);
DataElement obbexPushProfileDescriptor = new DataElement(DataElement.DATSEQ);
obbexPushProfileDescriptor.addElement(new DataElement(DataElement.UUID, OBEX_OBJECT_PUSH));
obbexPushProfileDescriptor.addElement(new DataElement(DataElement.U_INT_2, 0x100));
bluetoothProfileDescriptorList.addElement(obbexPushProfileDescriptor);
record.setAttributeValue(0x0009, bluetoothProfileDescriptorList);
final short ATTR_SUPPORTED_FORMAT_LIST_LIST = 0x0303;
DataElement supportedFormatList = new DataElement(DataElement.DATSEQ);
// any type of object.
supportedFormatList.addElement(new DataElement(DataElement.U_INT_1, 0xFF));
record.setAttributeValue(ATTR_SUPPORTED_FORMAT_LIST_LIST, supportedFormatList);
final short UUID_PUBLICBROWSE_GROUP = 0x1002;
final short ATTR_BROWSE_GRP_LIST = 0x0005;
DataElement browseClassIDList = new DataElement(DataElement.DATSEQ);
UUID browseClassUUID = new UUID(UUID_PUBLICBROWSE_GROUP);
browseClassIDList.addElement(new DataElement(DataElement.UUID, browseClassUUID));
record.setAttributeValue(ATTR_BROWSE_GRP_LIST, browseClassIDList);
localDevice.updateRecord(record);
} catch (Throwable e) {
Logger.error("Updating SDP", e);
}
try {
int errorCount = 0;
int count = 0;
isRunning = true;
while (!isStoped) {
RequestHandler handler = new RequestHandler();
try {
count++;
Logger.debug("Accepting OBEX connections");
handler.connectionAccepted(serverConnection.acceptAndOpen(handler));
} catch (InterruptedIOException e) {
isStoped = true;
break;
} catch (Throwable e) {
if ("Stack closed".equals(e.getMessage())) {
isStoped = true;
}
if (isStoped) {
return;
}
errorCount++;
Logger.error("acceptAndOpen ", e);
continue;
}
errorCount = 0;
}
} finally {
close();
Logger.debug("OBEX Server finished!");
isRunning = false;
}
}
public void close() {
isStoped = true;
try {
if (serverConnection != null) {
serverConnection.close();
}
Logger.debug("OBEX ServerConnection closed");
} catch (Throwable e) {
Logger.error("OBEX Server stop error", e);
}
}
private static File homePath() {
String path = "bluetooth";
boolean isWindows = false;
String sysName = System.getProperty("os.name");
if (sysName != null) {
sysName = sysName.toLowerCase();
if (sysName.indexOf("windows") != -1) {
isWindows = true;
path = "My Documents";
}
}
File dir;
try {
dir = new File(System.getProperty("user.home"), path);
if (!dir.exists()) {
if (!dir.mkdirs()) {
throw new SecurityException();
}
}
} catch (SecurityException e) {
dir = new File(new File(System.getProperty("java.io.tmpdir"), System.getProperty("user.name")), path);
}
if (isWindows) {
dir = new File(dir, "Bluetooth Exchange Folder");
}
if (!dir.exists()) {
if (!dir.mkdirs()) {
return null;
}
} else if (!dir.isDirectory()) {
dir.delete();
if (!dir.mkdirs()) {
return null;
}
}
return dir;
}
private void showStatus(final String message) {
interaction.showStatus(message);
}
private class RequestHandler extends ServerRequestHandler {
Timer notConnectedTimer = new Timer();
boolean isConnected = false;
boolean receivedOk = false;
Connection cconn;
void connectionAccepted(Connection cconn) {
Logger.debug("Received OBEX connection");
showStatus("Client connected");
this.cconn = cconn;
if (!isConnected) {
notConnectedTimer.schedule(new TimerTask() {
public void run() {
notConnectedClose();
}
}, 1000 * 30);
}
}
void notConnectedClose() {
if (!isConnected) {
Logger.debug("OBEX connection timeout");
try {
cconn.close();
} catch (IOException e) {
}
if (!receivedOk) {
showStatus("Disconnected");
}
}
}
public int onConnect(HeaderSet request, HeaderSet reply) {
isConnected = true;
notConnectedTimer.cancel();
Logger.debug("OBEX onConnect");
return ResponseCodes.OBEX_HTTP_OK;
}
public void onDisconnect(HeaderSet request, HeaderSet reply) {
Logger.debug("OBEX onDisconnect");
if (!receivedOk) {
showStatus("Disconnected");
}
}
public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
Logger.debug("OBEX onSetPath");
return super.onSetPath(request, reply, backup, create);
}
public int onDelete(HeaderSet request, HeaderSet reply) {
Logger.debug("OBEX onDelete");
return super.onDelete(request, reply);
}
public int onPut(Operation op) {
Logger.debug("OBEX onPut");
try {
HeaderSet hs = op.getReceivedHeaders();
String name = (String) hs.getHeader(HeaderSet.NAME);
if (name != null) {
Logger.debug("name:" + name);
showStatus("Receiving " + name);
} else {
name = "xxx.xx";
showStatus("Receiving file");
}
Long len = (Long) hs.getHeader(HeaderSet.LENGTH);
if (len != null) {
Logger.debug("file lenght:" + len);
interaction.setProgressValue(0);
interaction.setProgressMaximum(len.intValue());
}
File f = new File(homePath(), name);
FileOutputStream out = new FileOutputStream(f);
InputStream is = op.openInputStream();
int received = 0;
while (!isStoped) {
int data = is.read();
if (data == -1) {
Logger.debug("EOS received");
break;
}
out.write(data);
received++;
if ((len != null) && (received % 100 == 0)) {
interaction.setProgressValue(received);
}
}
op.close();
out.close();
Logger.debug("file saved:" + f.getAbsolutePath());
showStatus("Received " + name);
receivedOk = true;
return ResponseCodes.OBEX_HTTP_OK;
} catch (IOException e) {
Logger.error("OBEX Server onPut error", e);
return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
} finally {
Logger.debug("OBEX onPut ends");
interaction.setProgressDone();
}
}
public int onGet(Operation op) {
Logger.debug("OBEX onGet");
try {
HeaderSet hs = op.getReceivedHeaders();
String name = (String) hs.getHeader(HeaderSet.NAME);
return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
} catch (IOException e) {
Logger.error("OBEX Server onGet error", e);
return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
} finally {
Logger.debug("OBEX onGet ends");
}
}
public void onAuthenticationFailure(byte[] userName) {
Logger.debug("OBEX AuthFailure " + new String(userName));
}
}
}